Table of Contents

How to find PHP configuration files

Finding the active PHP configuration files matters before changing upload limits, enabling extensions, setting time zones, or adjusting error handling because the same host can run different CLI, PHP-FPM, and Apache or CGI runtimes side by side. Identifying the real file set first prevents edits that look correct on disk but never reach the interpreter serving the application.

Each runtime starts from one main php.ini file, may scan one or more directories for extra .ini fragments, and can still be overridden later by runtime-specific layers such as PHP-FPM pool directives, web-server FastCGI headers, Apache php_value rules, or per-directory .user.ini files. The effective configuration is therefore a chain, not a single file path.

The safest workflow is to query the exact runtime that executes the code instead of guessing from package names or service units alone. Check the CLI interpreter directly, use a short-lived probe for the web-facing runtime when needed, and remove that probe immediately after confirming the loaded file, scan directory, and any override layers.

Steps to find PHP configuration files:

  1. Print the active CLI configuration file and scan directory.
    $ 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)

    php --ini is the fastest authoritative answer for the current CLI runtime. If Loaded Configuration File reports (none), that interpreter is running with built-in defaults or a custom startup path instead of a readable php.ini.

  2. Query the same runtime through phpinfo()-style output when the loaded file, scan directory, and user_ini settings need one comparable block.
    $ php -i | grep -E '^(Loaded Configuration File|Scan this dir for additional \.ini files|Additional \.ini files parsed|user_ini\.filename|user_ini\.cache_ttl)'
    Loaded Configuration File => /opt/homebrew/etc/php/8.5/php.ini
    Scan this dir for additional .ini files => /opt/homebrew/etc/php/8.5/conf.d
    Additional .ini files parsed => (none)
    user_ini.cache_ttl => 300 => 300
    user_ini.filename => .user.ini => .user.ini

    This view is convenient when comparing the loaded CLI runtime with a web-facing runtime because it shows the main file, extra scan path, and per-directory INI settings in one place.

  3. Check the compile-time main path and scan directory when wrappers, environment variables, or service units might be changing the runtime at startup.
    $ php-config --configure-options | tr ' ' '\n' | grep -E -- '--with-config-file-path|--with-config-file-scan-dir'
    --with-config-file-path=/opt/homebrew/etc/php/8.5
    --with-config-file-scan-dir=/opt/homebrew/etc/php/8.5/conf.d

    The compiled paths are a fallback, not the final answer. The PHP manual documents php -c, PHPRC, and PHP_INI_SCAN_DIR as runtime overrides that can change what actually loads.

  4. Create a temporary probe file in the document root when the web-facing runtime might differ from the CLI binary.
    <?php
    header('Content-Type: text/plain');
     
    printf("SAPI: %s\n", PHP_SAPI);
    printf("Loaded php.ini: %s\n", php_ini_loaded_file() ?: 'none');
     
    echo "Scanned .ini files:\n";
    $files = php_ini_scanned_files();
    if ($files === false) {
        echo "(not reported by runtime)\n";
    } elseif ($files === '') {
        echo "(none)\n";
    } else {
        echo $files;
        if (substr($files, -1) !== "\n") {
            echo "\n";
        }
    }
     
    printf("user_ini.filename=%s\n", ini_get('user_ini.filename'));
    printf("user_ini.cache_ttl=%s\n", ini_get('user_ini.cache_ttl'));
    ?>

    Run the temporary script through the same site, virtual host, or PHP-FPM pool that serves the application. php --ini only reports the CLI configuration.

    Remove the diagnostic script after confirming the paths because it exposes internal configuration details.

  5. Request the probe through the same URL path that reaches the application runtime.
    $ curl -s https://app.example.test/php-config-check.php
    SAPI: fpm-fcgi
    Loaded php.ini: /etc/php/8.3/fpm/php.ini
    Scanned .ini files:
    /etc/php/8.3/fpm/conf.d/10-opcache.ini,
    /etc/php/8.3/fpm/conf.d/10-pdo.ini,
    /etc/php/8.3/fpm/conf.d/20-calendar.ini,
    /etc/php/8.3/fpm/conf.d/20-ctype.ini
    user_ini.filename=.user.ini
    user_ini.cache_ttl=300

    Confirm the SAPI first. A CLI answer does not prove that the web server is using the same php.ini tree or the same per-directory INI behavior.

  6. Inspect the reported scan directory when the main php.ini does not explain the active value.
    $ ls -1 /etc/php/8.3/fpm/conf.d
    10-opcache.ini
    10-pdo.ini
    20-calendar.ini
    20-ctype.ini
    20-phar.ini
    20-tokenizer.ini

    Use the exact scan directory reported by php --ini or the temporary script. Within each directory, PHP loads files ending in .ini in alphabetical order, and PHP_INI_SCAN_DIR can replace or extend the default list.

  7. Search PHP-FPM pool files for per-pool overrides when the site runs through FastCGI.
    $ sudo grep -REn 'php_(admin_)?(value|flag)\[[^]]+\]' /etc/php/8.3/fpm/pool.d /etc/php-fpm.d 2>/dev/null
    /etc/php/8.3/fpm/pool.d/app.example.test.conf:54:php_admin_value[error_log] = /var/log/php/app.example.test-error.log

    PHP-FPM pool files can override directives for one pool without changing the main php.ini, so the loaded file is not always the last layer that matters.

  8. Search the web-server configuration for FastCGI headers or Apache module directives that can override runtime values.
    $ sudo grep -REn 'fastcgi_param[[:space:]]+PHP_(ADMIN_)?VALUE|php_(admin_)?(value|flag)' /etc/nginx /etc/apache2 /etc/httpd 2>/dev/null
    /etc/nginx/sites-enabled/app.example.test.conf:26:fastcgi_param PHP_VALUE "upload_max_filesize=64M
    post_max_size=64M";

    The PHP-FPM manual notes that PHP_VALUE and PHP_ADMIN_VALUE are passed as FastCGI headers. On Apache mod_php, php_value, php_admin_value, php_flag, and php_admin_flag can also override the main file per virtual host or directory.

  9. Search the application tree for per-directory .user.ini files on CGI or FastCGI deployments.
    $ find /var/www/app.example.test -name .user.ini -print
    /var/www/app.example.test/public/.user.ini

    The PHP manual says these files are processed only by CGI or FastCGI, starting with the requested script directory and walking upward to the document root. They are ignored when PHP runs as an Apache module.

    The default reread interval is 300 seconds unless user_ini.cache_ttl is changed.

  10. Remove the temporary probe file after the active file set is confirmed.
    $ rm /var/www/app.example.test/public/php-config-check.php

    Leaving the probe reachable exposes internal paths, scan directories, and other runtime details that should stay private.

Common locations of PHP configuration files

The runtime-discovery steps above are the source of truth, but common packaging layouts still help narrow the search when the expected binary is outside PATH or another team manages the host.

Packaging or install style Main file Additional files
Debian or Ubuntu packages /etc/php/<version>/<sapi>/php.ini /etc/php/<version>/<sapi>/conf.d/*.ini
Fedora, RHEL, Rocky, AlmaLinux, or CentOS Stream packages /etc/php.ini /etc/php.d/*.ini
Homebrew on macOS /opt/homebrew/etc/php/<version>/php.ini or /usr/local/etc/php/<version>/php.ini matching /conf.d/*.ini directory
Official Windows ZIP build {PHP directory}\php.ini or the resolved search path configured scan directory when present
XAMPP {installation directory}/php/php.ini install-specific scan directory or none

Packaged Linux hosts often keep separate trees for cli, fpm, and apache2. Treat each SAPI as an independent runtime instead of assuming one /php.ini applies everywhere. PHP-FPM pool overrides are commonly stored under /etc/php/<version>/fpm/pool.d/*.conf on Debian or Ubuntu and under /etc/php-fpm.d/*.conf on many RHEL-family systems.

How PHP decides which file to load

According to the PHP manual, the runtime first checks for a SAPI-specific location such as Apache PHPIniDir or the CLI and CGI php -c option, then PHPRC, then the Windows registry keys when applicable, then the current working directory except on CLI, then the web-server or PHP binary directory on Windows, and finally the compiled default path.

If a php-<sapi>.ini file exists, such as php-cli.ini or php-apache.ini, PHP uses it instead of the generic php.ini for that runtime. After the main file is loaded, PHP can scan one or more extra directories for .ini fragments, and PHP_INI_SCAN_DIR can replace or extend that list at startup.

When .user.ini applies

Per-directory .user.ini files are useful when the application runs under CGI or FastCGI and the main php.ini is not writable. PHP starts in the directory of the requested script and walks upward until it reaches the document root, so a nearer file can affect only one part of the application tree.

Only directives allowed at INI_PERDIR or INI_USER scope can be set there. The filename defaults to .user.ini, the cache interval defaults to 300 seconds, and setting user_ini.filename to an empty string disables the scan completely. When PHP runs as an Apache module, .user.ini is ignored, so the change must be made in the main configuration or an Apache override instead.