From 1194a3e8ab8d9d420bd12b3498dd22fce8be5af5 Mon Sep 17 00:00:00 2001 From: Riddhesh Sanghvi Date: Thu, 29 Oct 2026 06:24:05 +0530 Subject: [PATCH] fix(site): keep site commands working when pcntl or shell_exec is disabled On PHP 8 a function listed in disable_functions is removed, so the unconditional pcntl_signal() calls in the EE_Site_Command constructor were a fatal "Call to undefined function" for every ee site command on hosts whose CLI php.ini disables pcntl_* (HestiaCP does this; EasyEngine/easyengine#1956). A PHP built without pcntl failed the same way. pcntl_signal() and pcntl_signal_dispatch() are now called only when they exist. Without them a site command still runs; it only loses the rollback on SIGINT/SIGTERM/SIGHUP/SIGUSR1 (logged as a debug line), and Ctrl+C still ends the SSL lock wait because the default signal action applies. With pcntl available nothing changes. ee site share now refuses up front with a clear error when shell_exec() is disabled, instead of a fatal after the old share was already torn down; a plain --disable still works. --- src/helper/class-ee-site.php | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/helper/class-ee-site.php b/src/helper/class-ee-site.php index f9dd4ff2..bc7b9730 100644 --- a/src/helper/class-ee-site.php +++ b/src/helper/class-ee-site.php @@ -84,10 +84,15 @@ abstract class EE_Site_Command { public function __construct() { $this->fs = new Filesystem(); - pcntl_signal( SIGTERM, [ $this, 'rollback' ] ); - pcntl_signal( SIGHUP, [ $this, 'rollback' ] ); - pcntl_signal( SIGUSR1, [ $this, 'rollback' ] ); - pcntl_signal( SIGINT, [ $this, 'rollback' ] ); + // A PHP without pcntl, or with it in disable_functions (fatal on PHP 8), only loses the rollback on signals. + if ( function_exists( 'pcntl_signal' ) ) { + pcntl_signal( SIGTERM, [ $this, 'rollback' ] ); + pcntl_signal( SIGHUP, [ $this, 'rollback' ] ); + pcntl_signal( SIGUSR1, [ $this, 'rollback' ] ); + pcntl_signal( SIGINT, [ $this, 'rollback' ] ); + } else { + EE::debug( 'PHP function pcntl_signal() is unavailable, so site commands interrupted by a signal (e.g. Ctrl+C) are not rolled back.' ); + } $shutdown_handler = new Shutdown_Handler(); register_shutdown_function( [ $shutdown_handler, 'cleanup' ], [ &$this ] ); } @@ -1768,7 +1773,9 @@ private function acquire_ssl_lock( $throw = false, $wait = self::SSL_LOCK_WAIT_S } sleep( 1 ); // This file has no declare(ticks), so run pending SIGINT/SIGTERM handlers here or Ctrl-C can't end the wait. - pcntl_signal_dispatch(); + if ( function_exists( 'pcntl_signal_dispatch' ) ) { + pcntl_signal_dispatch(); + } } } @@ -2450,6 +2457,11 @@ public function share( $args, $assoc_args ) { $this->fs = new Filesystem(); $ngrok = EE_SERVICE_DIR . '/ngrok/ngrok'; + // Everything but a plain --disable starts ngrok with shell_exec(). + if ( ( ! $disable || $refresh ) && ! function_exists( 'shell_exec' ) ) { + EE::error( 'Sharing a site needs the PHP function shell_exec(), which this PHP disables. Remove it from disable_functions for the PHP CLI.' ); + } + if ( $disable || $refresh ) { if ( $this->site_data->site_url === $active_publish ) { $this->ngrok_curl( false, $refresh );