In a PHP-FPM pool file, what is the difference between php_value and php_admin_value, and when do you use each?
answer
- both override php.ini for one pool
- admin versions cannot be changed by ini_set()
- _flag variants for booleans
- disable_functions appends
- web server can pass PHP_VALUE too
basics
~20 sBoth set php.ini directives for one PHP-FPM pool. php_value is a default that ini_set() or .user.ini may still change where the directive allows; php_admin_value locks it. Use admin for security and resource limits, plain for defaults.
solid answer
~40 s`php_value[name]` and `php_admin_value[name]` (plus `php_flag`/`php_admin_flag` for booleans such as `on`, `off`, `1`, `0`, `true`, `false`, `yes`, `no`) override php.ini for the workers of one pool, applied when each worker starts. The difference is who can change them afterwards. A `php_value` stays changeable by the application's `ini_set()` and by per-directory `.user.ini` files, as far as the directive's INI mode allows. A `php_admin_value` marks the directive system-level for that pool, so `ini_set()` and `.user.ini` cannot change it. Use admin values for things an application must not loosen — `open_basedir`, `memory_limit`, `error_log`, `disable_functions` — and plain values for defaults an app may tune, such as `display_errors` in a staging pool. Two quirks: `disable_functions` in a pool appends to php.ini's list rather than replacing it, and `extension` loads a shared extension for that pool only.
go deeper
Recall that pool files can set php.ini directives per pool, and that the admin forms cannot be changed by the application.
Explain how php_admin_value makes a directive system-level for the pool, blocking ini_set() and .user.ini, and when a plain php_value is enough.
Use admin values as policy — open_basedir, memory and upload limits, disable_functions, log paths — and know the append and startup-only quirks.
Decide which settings are platform policy enforced per pool and which are left to application teams, and how that split is reviewed.
## Per-pool ini settings PHP reads `php.ini` once for the whole FPM installation, but different pools often need different settings: a bigger `memory_limit` for a reporting pool, a separate `error_log` per application, an `open_basedir` jail per site. Pool files can set any ini directive for their workers with four directive forms: | Form | For | Changeable later by the app? | |---|---|---| | `php_value[name] = value` | Any directive | Yes, where the directive's INI mode allows | | `php_flag[name] = on` | Boolean directives | Yes, as above | | `php_admin_value[name] = value` | Any directive | **No** | | `php_admin_flag[name] = off` | Boolean directives | **No** | Boolean forms accept `on`, `off`, `1`, `0`, `true`, `false`, `yes` or `no`. The values are applied when a worker process starts, after `php.ini` and any `-d` startup arguments, so they override php.ini for that pool. ## What "admin" changes Every PHP ini directive has an **INI mode** that says where it may be changed — for example only in php.ini (system level), or also in per-directory `.user.ini` files, or also at runtime with `ini_set()`. - A **`php_value`** sets the value but leaves the directive's changeability as it was. If the directive is normally user-changeable, the application can still call `ini_set('memory_limit', '1G')`, and a `.user.ini` in the document root can override it. - A **`php_admin_value`** sets the value **and** marks the directive as system-level for that pool, so later `ini_set()` calls fail and `.user.ini` files cannot touch it. So the choice is not about which directives you can set; it is about **who has the last word** — the administrator or the application. ## Choosing between them Use **`php_admin_value` / `php_admin_flag`** for policy: 1. Security jails and switches: `open_basedir`, `disable_functions`, `allow_url_include` style settings. 2. Resource limits the app must not raise: `memory_limit`, `max_execution_time`, `upload_max_filesize`, `post_max_size`. 3. Operational settings: `error_log`, `log_errors`, `session.save_path`, `sendmail_path`. Use **`php_value` / `php_flag`** for defaults an application may legitimately adjust: - `display_errors` on in a staging pool that a developer toggles; - `date.timezone` or `default_charset` as a sensible default the code may override. ## Quirks worth knowing - **`disable_functions` appends.** Setting it in a pool does not replace php.ini's list; the functions are added to it. - **`extension` loads a module.** `php_admin_value[extension] = sodium.so` loads that shared extension only in this pool's workers. - **Relative paths** in path-type settings are expanded with the pool's `prefix` (or the global prefix). - **Errors are logged, not fatal.** An unknown directive name produces an error in the FPM log such as `Unable to set php_value 'name'`, and the pool starts without it. - **Startup-only settings do not apply.** Settings that an extension reads once when PHP starts — for example a debugger's mode — cannot be changed per pool this way; they belong in php.ini. ## Checking the effective value The CLI never reads pool files, so `php -i` on the shell shows php.ini's value, not the pool's. Check from inside the pool instead: a temporary script served by that pool calling `ini_get('memory_limit')`, and a second call after `ini_set()`, shows both the value and whether it is locked. Remove the script afterwards. ## The same idea from the web server A FastCGI client can also send `PHP_VALUE` and `PHP_ADMIN_VALUE` parameters with a request, parsed as ini lines with user-level and system-level rights respectively. Web servers can use this to set per-virtual-host values, but it is also why a FastCGI port must never be reachable by untrusted clients: whoever can connect can rewrite settings such as `auto_prepend_file`. ## A worked example ```ini [reports] ; the app may raise this for one heavy export with ini_set() php_value[max_execution_time] = 60 ; hard ceiling the app cannot raise php_admin_value[memory_limit] = 512M php_admin_value[error_log] = /var/log/php/reports.log php_admin_flag[log_errors] = on php_admin_value[disable_functions] = exec,passthru,shell_exec,system ``` Here the export code can extend its time limit, but no code path can take more than 512 MB or re-enable the shell functions.
- A pool sets php_value[memory_limit] = 256M, but one script runs with 1G. How?`php_value` only sets a default. `memory_limit` is changeable at runtime, so the script (or a `.user.ini` in its directory) raised it with `ini_set('memory_limit', '1G')`. To enforce the ceiling, use `php_admin_value[memory_limit] = 256M`, which makes later `ini_set()` calls fail.
- You add php_admin_value[disable_functions] = exec to a pool, and php.ini already disables system. Which functions are disabled?Both. In a PHP-FPM pool, `disable_functions` is appended to the list from php.ini rather than replacing it, so `system` stays disabled and `exec` is added. A pool cannot use this directive to re-enable something php.ini disabled.
saying these in an interview costs you the question
- php_value can only set directives changeable at runtime
- php_admin_value only works for boolean settings
- A pool's disable_functions replaces the list from php.ini
- ini_set() can override a php_admin_value if the directive is user-changeable
- php_value settings are locked just like admin ones