proc_open / Composer Troubleshooting (cPanel + CloudLinux + Imunify360)¶
Symptom:
In Process.php line 165:
The Process class relies on proc_open, which is not available on your PHP installation.
1. Quick test¶
2. Identify the exact runtime¶
php -r 'var_dump(PHP_BINARY, php_ini_loaded_file(), get_cfg_var("disable_functions"), function_exists("proc_open"));'
php --ini
Run from the project directory and as the account user — cPanel's /usr/local/bin/php wrapper picks the PHP version from the MultiPHP setting of the domain matching the cwd. A .cagefs suffix in PHP_BINARY is normal under CloudLinux CageFS.
Composer's own runtime:
3. ini vs. extension¶
true→ an ini file is disabling it (continue to step 4)false→ extension / compiled-in
4. Find the ini that wins¶
grep -rn 'disable_functions' /opt/cpanel/ea-php8*/root/etc/php.d/
ls -la ./php.ini ./.user.ini # CLI reads php.ini from the cwd first
Only ; is a valid comment char in php.ini — # is not.
5. Definitive: strace the ini load order¶
strace -f -tt -o /tmp/composer_strace.log composer update
grep -n '\.ini"' /tmp/composer_strace.log | grep -v ENOENT
The last .ini opened wins.
6. Imunify360 hardening (the actual cause here)¶
/opt/cpanel/ea-phpXX/root/etc/php.d/i360.ini loads the i360 extension, which then reads:
This file is parsed after all normal ini files and overrides them. It is generated by Imunify360 Proactive Defense — do not hand-edit, it gets regenerated.
imunify360-agent config show | grep -iA5 PROACTIVE # key is PROACTIVE_DEFENCE (British spelling)
imunify360-agent config update '{"PROACTIVE_DEFENCE": {"php_immunity": false}}'
php -r 'var_dump(function_exists("proc_open"));'
Re-enable after the deploy:
7. Workarounds¶
php -d disable_functions= /usr/local/bin/composer update -o # ini-based blocks only
composer update --no-scripts && composer dump-autoload -o --no-scripts
/opt/cpanel/ea-php83/root/usr/bin/php /usr/local/bin/composer update --dry-run --no-scripts
/usr/local/bin/composer uses #!/usr/bin/env php, so it runs under the system default PHP — pin the version explicitly by calling the binary directly.
Test composer.json (PHP 8+)¶
{
"name": "test/php8-composer-test",
"type": "project",
"require": {
"php": ">=8.0",
"monolog/monolog": "^3.0",
"guzzlehttp/guzzle": "^7.8",
"symfony/console": "^6.4",
"vlucas/phpdotenv": "^5.6",
"ramsey/uuid": "^4.7"
},
"require-dev": {
"phpunit/phpunit": "^10.5"
},
"autoload": {
"psr-4": { "App\\": "src/" }
},
"config": {
"optimize-autoloader": true,
"sort-packages": true
},
"minimum-stability": "stable",
"prefer-stable": true
}
Side note¶
Class App\View\Components\confirmModal located in ./app/View/Components/confirm-modal.php
does not comply with psr-4 autoloading standard
Non-fatal. PSR-4 requires the filename to match the class name → rename to confirmModal.php.