Skip to content

fix(php): stop the install when the PHP CLI disables functions ee needs - #49

Merged
mrrobot47 merged 4 commits into
masterfrom
fix/php-disabled-functions
Oct 29, 2026
Merged

mrrobot47 merged 4 commits into
masterfrom
fix/php-disabled-functions

Conversation

@mrrobot47

@mrrobot47 mrrobot47 commented Oct 29, 2026 •

Copy link
Copy Markdown
Member

Problem

When the host's PHP CLI disables functions that ee calls, the installer still finishes successfully, and the first ee site … command dies. EasyEngine/easyengine#1956 is a HestiaCP server on Ubuntu 24.04: the installer kept the existing PHP 8.3, ee cli info ran fine, and ee site create failed with:

PHP Fatal error:  Uncaught Error: Call to undefined function EE\Site\Type\pcntl_signal() in phar:///usr/local/bin/ee/vendor/easyengine/site-command/src/helper/class-ee-site.php:87

Root cause

HestiaCP writes disable_functions = pcntl_alarm,pcntl_fork,…,pcntl_signal,pcntl_signal_dispatch,… into /etc/php/<version>/cli/php.ini (bin/v-add-web-php, install/upgrade/versions/1.8.12.sh). Since PHP 8, a disabled function is removed from the function table, so calling it is a fatal "undefined function" error. EE_Site_Command::__construct() calls pcntl_signal() for every site command. ee cli info never builds a site object, so the installer's first run doesn't hit it.

The installer keeps any existing php and only checks the curl, sqlite3 and zip extensions. pcntl is loaded on such hosts; only its functions are disabled.

Fix

A new check_php_functions step in check_dependencies. It runs after PHP and its extensions are set up, and Docker setup now runs after it, so a refused host doesn't get Docker installed first. The step asks the host PHP CLI whether the functions ee calls unguarded exist, the ones hardened php.ini files tend to list: curl_exec, disk_free_space, escapeshellarg, exec, getmypid, ini_set, pcntl_signal, pcntl_signal_dispatch, php_uname, posix_getegid, posix_geteuid, posix_getpwuid, proc_close, proc_open. If any are unavailable, the install stops before anything else is installed:

-----> Checking required PHP functions
ERROR: The PHP CLI (/usr/bin/php) disables functions EasyEngine needs: pcntl_signal, pcntl_signal_dispatch.
       disable_functions is set in: /etc/php/8.3/cli/php.ini
       To fix it, create /etc/php/8.3/cli/conf.d/99-easyengine.ini that sets disable_functions to the same list without these functions, or edit php.ini directly.
       Only the PHP CLI configuration needs the change, not PHP-FPM. Then re-run the installer.
  • A function counts as unavailable only when function_exists() is false, so nothing PHP itself still allows is reported. PHP matches disable_functions names case-sensitively and splits the list on commas and whitespace. The disable_functions list is only used to word the message ("disables" vs "lacks") and to name the ini files that set it.
  • On PHP 7, calling a disabled function only warns. So for disabled pcntl_* functions there, the step prints a warning (no rollback on signals) and doesn't stop the install.
  • When a conf.d file itself sets disable_functions, an override there might not load last, so the message asks to edit the listed files instead.
  • The installer doesn't edit the PHP configuration itself.

How tested

Repro recipe: a throwaway ubuntu:24.04 amd64 container, like the reporter's noble host.

  1. Pre-install php8.3-cli from ppa:ondrej/php.
  2. Apply HestiaCP's exact v-add-web-php line to the CLI php.ini.
  3. Stub the Docker daemon.
  4. Run setup.sh with the real phar and ee.
Run Installer ee site create site.test --type=wp --cache
Current master (byte-identical to what https://rt.cx/ee4 serves) rc 0 Call to undefined function EE\Site\Type\pcntl_signal(), rc 255 (same for ee site list)
Current master, same recipe without the Hestia line (control) rc 0 gets past the constructor ("Starting site creation")
This branch rc 1 with the message above, before Docker and the phar are installed –
This branch, re-run after adding the suggested conf.d/99-easyengine.ini rc 0 gets past the constructor
  • Debian 12, Hestia line, PHP 8.3 from sury: same before/after results.
  • No regressions: full installer runs on fresh ubuntu:22.04, 24.04, 26.04, rolling, devel, debian:12 and 13 all return rc 0, the check passes, and site create gets past the constructor. Host prep passes on the same 7 images.
  • PHP 7.4 with pcntl (php:7.4-cli): disabled pcntl_signal only warns (rc 0), and disabled exec stops the install.

Tests:

  • tests/unit/php_functions.bats:
    • Report parsing and messages with a stubbed php, including the PHP 7 warning, and that each error is at most 4 lines.
    • That check_dependencies runs the check after PHP setup and before Docker.
    • Real-PHP cases (functions disabled with comma/space separators, a clean PHP), which skip when no suitable php is installed.
  • tests/integration/host-prep.sh: on every matrix distro, the stock PHP passes the check, and a HestiaCP-style disable_functions file in the CLI scan dir is refused with the functions and the file named, and the message asks to edit that file in at most 4 lines.

Refs EasyEngine/easyengine#1956

HestiaCP and similar panels put pcntl_signal, pcntl_signal_dispatch and other functions into disable_functions of the CLI php.ini. PHP 8 removes disabled functions, so the install succeeded and the first `ee site` command died with "Call to undefined function EE\Site\Type\pcntl_signal()".

check_php_functions asks the host PHP CLI whether the functions ee calls are available and stops before Docker and the phar are installed, naming the functions, the ini files that disable them and a conf.d override that survives panel upgrades. On PHP 7, where calling a disabled function only warns, disabled pcntl_* functions only get a warning.

Refs EasyEngine/easyengine#1956
Bats cases for the report parsing, the messages, PHP 7's warn-only pcntl case and the check's place in check_dependencies, plus real-PHP cases when php is installed. Host prep now asserts on every matrix distro that the stock PHP passes and that a HestiaCP-style disable_functions file in the CLI scan dir is refused with the functions and the file named.
The error no longer assumes a hosting panel set disable_functions. It names the functions and ini files, says why EasyEngine needs them, and suggests a conf.d override that a tool rewriting php.ini on upgrade leaves alone, or editing php.ini directly. When a conf.d file itself disables them, the override would not win, so it asks to edit the listed files instead. Continuation lines use ee_log_verbose instead of hand-typed indentation.
Drop the line repeating that EasyEngine needs the functions and fold the conf.d override and the php.ini alternative into one line, so every variant of the disabled-functions error is at most 4 lines. The missing-functions error uses the same "To fix it" wording. Tests assert the line counts.
@rtBot
rtBot requested a balanced review from Copilot October 29, 2026 07:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

@mrrobot47
mrrobot47 merged commit a730c4a into master Oct 29, 2026
10 checks passed
@mrrobot47
mrrobot47 deleted the fix/php-disabled-functions branch October 29, 2026 11:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants