Disabled PHP functions are a common reason shell execution, child-process handling, or other runtime features fail in one environment while the same code works elsewhere. Confirming the active list quickly separates an intentional runtime policy from missing binaries, permission problems, or application bugs.
The answer comes from the effective disable_functions directive for the exact PHP SAPI that handled the code. PHP reads the main php.ini file and any scanned .ini files at startup, PHP-FPM pools can append more entries with php_value[disable_functions] or php_admin_value[disable_functions], and current PHP 8+ releases remove disabled internal functions from the function table instead of leaving the older disabled-call warning behavior in place.
The safest check is therefore runtime-specific. CLI, PHP-FPM, and the Apache module can resolve different configuration trees, and request-level FastCGI admin settings can change the served result, so a shell check is only a baseline. When the failure appears only through a site or virtual host, confirm it through that same request path and remove the temporary probe afterward.
Related: How to disable PHP functions
Steps to show disabled PHP functions:
- Show which configuration files the current CLI runtime loads.
$ php --ini Configuration File (php.ini) Path: "/opt/homebrew/etc/php/8.5" Loaded Configuration File: "/opt/homebrew/etc/php/8.5/php.ini" Scan for additional .ini files in: "/opt/homebrew/etc/php/8.5/conf.d" Additional .ini files parsed: (none)
The loaded php.ini file and any scanned .ini files together determine the base disable_functions value for that CLI runtime.
Related: How to find PHP configuration files
- Read the effective disable_functions value from the current CLI runtime.
$ php -i | grep '^disable_functions' disable_functions => no value => no value
no value or a blank string means no disabled functions are configured for that SAPI.
- Print the resolved list one function per line when a script-friendly result is easier to compare or paste into diagnostics.
$ php -r '$disabled = trim((string) ini_get("disable_functions")); if ($disabled === "") { echo "No disabled functions configured for this PHP SAPI.\n"; } else { foreach (array_map("trim", explode(",", $disabled)) as $function) { if ($function !== "") { echo $function, PHP_EOL; } } }' No disabled functions configured for this PHP SAPI.Reading ini_get('disable_functions') is the parser-friendly check on current PHP releases because disabled internal functions are removed from the function table.
- Query the base PHP-FPM runtime when the failure appears only over the web.
$ php-fpm -i | grep -E '^(Server API =>|Loaded Configuration File =>|disable_functions =>)' Server API => FPM/FastCGI Loaded Configuration File => /opt/homebrew/etc/php/8.5/php.ini disable_functions => no value => no value
Some hosts expose only a versioned binary such as php-fpm8.3 or require the service configuration path with -y. This reports the startup PHP-FPM value, but request-level FastCGI admin settings can still append more entries for the served site.
- Search PHP-FPM pool files and web-server FastCGI overrides when the served runtime reports more disabled functions than CLI or the base PHP-FPM output.
$ sudo grep -REn 'php_(admin_)?value\[disable_functions\]|PHP_ADMIN_VALUE.*disable_functions' /etc/php/8.3/fpm/pool.d /etc/php-fpm.d /etc/nginx /etc/apache2 /etc/httpd 2>/dev/null /etc/php/8.3/fpm/pool.d/www.conf:491:php_admin_value[disable_functions] = exec,shell_exec,system,passthru,proc_open,popen
Replace 8.3 with the installed PHP major.minor version on Debian or Ubuntu systems. No output means the sampled pool and web-server files are not appending extra disabled functions.
- Create a temporary show-disabled-functions.php file inside the same document root or virtual host that serves the failing application.
<?php header('Content-Type: text/plain'); printf("SAPI: %s\n", PHP_SAPI); printf("Loaded php.ini: %s\n", php_ini_loaded_file() ?: 'none'); $disabled = trim((string) ini_get('disable_functions')); printf("disable_functions: %s\n", $disabled === '' ? 'no value' : $disabled); ?>
Use the same site, pool, or vhost as the failing request so the result reflects the web runtime instead of CLI.
- Request the temporary probe through the web server and read the reported SAPI, loaded file, and disabled list.
$ curl -s https://customer-portal.example.com/show-disabled-functions.php SAPI: fpm-fcgi Loaded php.ini: /etc/php/8.3/fpm/php.ini disable_functions: exec,shell_exec,system,passthru,proc_open,popen
This request confirms the live web-facing value after pool-level and request-level FastCGI overrides are applied.
- Remove the temporary probe after the check.
$ rm /var/www/customer-portal.example.com/public/show-disabled-functions.php
Leaving the file accessible exposes runtime details that can help an attacker profile the PHP environment.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
