skip to content

In a PHP-FPM pool file, what is the difference between php_value and php_admin_value, and when do you use each?

level: middleimportance: should knowfreq 42%

answer

  1. both override php.ini for one pool
  2. admin versions cannot be changed by ini_set()
  3. _flag variants for booleans
  4. disable_functions appends
  5. web server can pass PHP_VALUE too

basics

~20 s

Both 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

for a junior

Recall that pool files can set php.ini directives per pool, and that the admin forms cannot be changed by the application.

for a middle

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.

for a senior

Use admin values as policy — open_basedir, memory and upload limits, disable_functions, log paths — and know the append and startup-only quirks.

for a principal

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