# Die php.ini erklärt: Aufbau, Ebenen und Vorrang

> Die php.ini erklärt: wo PHP seine Konfiguration sucht, welche Ebenen es gibt, was INI_SYSTEM und INI_PERDIR bedeuten und welcher Wert am Ende gilt.

Quelle: https://phpsos.de/php/php-ini-erklaert/  
Stand: 25.10.2026  
Anbieter: PHP SOS, PHP-Notfallhilfe und Server-Sicherheit. Soforthilfe per WhatsApp: https://wa.me/491736494914?text=Hallo%20PHP%20SOS%2C%20wir%20brauchen%20Hilfe%20mit%20unserem%20PHP-Server.%20Firma%3A%20%E2%80%A6%20Website%3A%20%E2%80%A6

**Kurz gesagt:** Die php.ini ist die zentrale Konfigurationsdatei von PHP. PHP liest sie beim Start, bei Servermodulen einmal, bei CGI und CLI bei jedem Aufruf. Dazu kommen Zusatzdateien aus einem Scan-Verzeichnis, Einstellungen im FPM-Pool oder in Apache, `.htaccess` bzw. `.user.ini` und `ini_set()` im Code. Welche Ebene einen Wert ändern darf, legt sein Änderungsmodus fest, etwa `INI_SYSTEM` oder `INI_PERDIR`. Werte über `php_admin_value` kann die Anwendung nicht mehr überschreiben.

## Was ist die php.ini?

Die php.ini ist eine Textdatei mit Einträgen nach dem Muster `name = wert`. Sie legt fest, wie PHP sich verhält: wie viel Speicher ein Skript nutzen darf, ob Fehler im Browser erscheinen, wie Sessions arbeiten und welche Erweiterungen geladen werden. Kommentare beginnen mit einem Semikolon.

Laut PHP-Handbuch wird die Datei beim Start von PHP gelesen. Bei Servermodulen wie mod_php geschieht das nur einmal, beim Start des Webservers, bei CGI und CLI bei jedem Aufruf. PHP-FPM liest seine Konfiguration beim Start und beim Neuladen des Dienstes. Eine Änderung ohne Neustart oder Reload wirkt deshalb meist nicht.

Seit PHP 8.3 kann ein Eintrag laut Handbuch auf eine Umgebungsvariable mit Ersatzwert verweisen:

```ini
memory_limit = ${PHP_MEMORY_LIMIT}
max_execution_time = ${PHP_MAX_EXECUTION_TIME:-30}
```

## Wo sucht PHP nach der php.ini?

Das Handbuch beschreibt eine feste Reihenfolge. Zuerst gilt ein ausdrücklich gesetzter Pfad, etwa `PHPIniDir` in Apache oder die Option `-c` bei CGI und CLI. Sonst baut PHP einen Suchpfad aus:

1. der Umgebungsvariable `PHPRC`,
2. unter Windows dem Registry-Eintrag `IniFilePath`,
3. dem aktuellen Arbeitsverzeichnis, außer bei SAPIs, die das abschalten, etwa der CLI,
4. dem Verzeichnis der PHP-Binärdatei bzw. des Moduls,
5. dem beim Kompilieren gesetzten Pfad `--with-config-file-path`.

In diesem Suchpfad sucht PHP zuerst eine Datei `php-SAPI.ini`, etwa `php-cli.ini`, und erst danach `php.ini`. Anschließend liest PHP alle `.ini`-Dateien aus dem Scan-Verzeichnis, das über `PHP_INI_SCAN_DIR` oder beim Kompilieren über `--with-config-file-scan-dir` festgelegt ist, in alphabetischer Reihenfolge. Welche Dateien geladen wurden, zeigt `php --ini` oder die Funktion `php_ini_scanned_files()`.

```bash
php --ini
php -r 'var_dump(php_ini_loaded_file(), php_ini_scanned_files());'
```

Beide Befehle zeigen den Stand der Kommandozeile. Für die Website kann eine andere Datei gelten, weil jede SAPI ihre eigene Konfiguration haben kann; mehr dazu unter [SAPI erklärt](https://phpsos.de/php/sapi-erklaert/).

## Änderungsmodi: Wer darf welchen Wert setzen?

Nicht jede Einstellung darf überall gesetzt werden. Das Handbuch ordnet jeder Direktive einen Änderungsmodus zu:

| Modus | Wo der Wert gesetzt werden darf |
|---|---|
| `INI_USER` | in Skripten per `ini_set()`, in der Windows-Registry und in `.user.ini` |
| `INI_PERDIR` | in php.ini, `.htaccess`, `httpd.conf` oder `.user.ini` |
| `INI_SYSTEM` | nur in php.ini oder `httpd.conf` |
| `INI_ALL` | überall |

Beispiele aus dem Handbuch: `memory_limit` hat den Modus `INI_ALL` und den Standard `128M`, `post_max_size` hat `INI_PERDIR` und den Standard `8M`, `upload_max_filesize` hat `INI_PERDIR` und den Standard `2M`. `expose_php` darf nur in der php.ini stehen.

`.user.ini`-Dateien werden laut Handbuch nur von CGI- und FastCGI-SAPIs gelesen, also auch von PHP-FPM. PHP sucht sie vom Verzeichnis des Skripts aufwärts bis zum Document Root und liest sie standardmäßig höchstens alle 300 Sekunden neu (`user_ini.cache_ttl`). Unter mod_php übernimmt `.htaccess` diese Rolle.

## Welcher Wert gilt am Ende? Die Ebenen im Vorrang

Vereinfacht gilt: Je später eine Ebene greift, desto eher setzt sich ihr Wert durch, sofern der Änderungsmodus es erlaubt.

1. **php.ini** der jeweiligen SAPI
2. **Zusatzdateien** aus dem Scan-Verzeichnis, alphabetisch
3. **Serverkonfiguration:** FPM-Pool mit `php_value` bzw. `php_admin_value`, Apache-VirtualHost
4. **Verzeichnisebene:** `.htaccess` bei mod_php, `.user.ini` bei FPM und CGI
5. **Laufzeit:** `ini_set()` im Anwendungscode

Die Ausnahme ist entscheidend: Werte über `php_admin_value` oder `php_admin_flag` können laut Handbuch nicht per `ini_set()` überschrieben werden. Damit sperren Admins sicherheitsrelevante Einstellungen gegen die Anwendung. Ausführlich beschrieben ist das unter [php_admin_value: Einstellungen gegen Überschreiben sperren](https://phpsos.de/blog/php-admin-value-sperren/).

## Die php.ini nach PHP2Shell: was sich geändert hat

Die Übergangsmaßnahmen von php.net zu PHP2Shell sind fast alle INI-Einstellungen: `memory_limit=-1` gesperrt gegen Überschreiben, begrenzte `post_max_size`, `session.upload_progress.enabled=0` und auf PHP 8.5 `fatal_error_backtraces=0`. php.net betont, dass `session.upload_progress.enabled` nicht über `ini_set()` oder `.user.ini` gesetzt werden soll, sondern in php.ini, FPM-Pool oder Serverkonfiguration, mit anschließendem Neustart aller Worker. Die vollständige Liste steht unter [Sofortmaßnahmen, wenn Sie noch nicht patchen können](https://phpsos.de/php2shell/sofortmassnahmen-ohne-patch/).

Mit den korrigierten Versionen 8.5.12, 8.4.27, 8.3.36 und 8.2.35 hat sich laut Handbuch auch `memory_limit` geändert: Es ist nun eine weiche Grenze. Die neue Einstellung `memory_hard_limit_percent` legt eine harte Grenze fest. Ohne eigenen Wert beträgt sie das Doppelte von `memory_limit`, bei mehr als `1G` den Wert plus `1G`. Wird sie überschritten, endet der Prozess sofort mit Exit-Status 137. Wie Sie beide Grenzen sinnvoll wählen, erklärt [memory_limit richtig setzen](https://phpsos.de/blog/memory-limit-richtig-setzen/).

> **Tipp:**
> Laut Handbuch gilt: Erkennt eine PHP-Version `memory_hard_limit_percent` nicht, ist sie von CVE-2026-109618 und CVE-2026-109619 betroffen. Bei Distributionen mit Backports belegt zusätzlich der Paket-Changelog den Stand.

## Wie hilft PHP SOS konkret?

- **Wirksame Werte ermitteln:** Wir lesen für jede SAPI aus, welche Dateien geladen werden und welcher Wert am Ende gilt.
- **Ebenen aufräumen:** Wir entfernen widersprüchliche Einträge aus Panels, Pools, `.htaccess` und `.user.ini`.
- **Sperren setzen:** Im Rahmen der [Server-Härtung](https://phpsos.de/leistungen/server-haertung/) legen wir sicherheitsrelevante Werte per `php_admin_value` fest.
- **Nachweisen:** Wir dokumentieren Einstellungen und Neustart, damit der Stand später belegbar ist.


## Häufige Fragen

**Wo liegt die php.ini?**  
Das hängt von Betriebssystem, Paket und SAPI ab. Unter Debian und Ubuntu gibt es je Version und SAPI eigene Ordner, etwa /etc/php/8.3/fpm/php.ini und /etc/php/8.3/cli/php.ini. Auf der Kommandozeile zeigt php --ini die geladenen Dateien, für die Website hilft php_ini_loaded_file() in einer kurzzeitigen Prüfdatei.

**In welcher Reihenfolge werden die Dateien im conf.d-Ordner gelesen?**  
Laut PHP-Handbuch liest PHP alle Dateien mit der Endung .ini im Scan-Verzeichnis in alphabetischer Reihenfolge. Spätere Dateien überschreiben Werte früherer. Deshalb tragen viele Dateien Zahlen wie 20- oder 99- im Namen.

**Warum wirkt meine Änderung an der php.ini nicht?**  
Häufige Gründe: Es wurde die Datei einer anderen SAPI geändert, der Dienst wurde nicht neu gestartet, ein Wert im FPM-Pool, in der Apache-Konfiguration oder in einer .user.ini überschreibt ihn, oder ein Hosting-Panel schreibt die Datei beim nächsten Speichern neu.

**Was ist memory_hard_limit_percent?**  
Eine neue Einstellung, die laut PHP-Handbuch mit den Sicherheitsreleases vom 21.10.2026 eingeführt wurde. Sie legt eine harte Speichergrenze als Prozentsatz von memory_limit fest. Das Handbuch weist darauf hin, dass eine PHP-Version, die diese Einstellung nicht kennt, von den PHP2Shell-Lücken betroffen ist.

## Quellen

- [PHP-Handbuch: Die Konfigurationsdatei](https://www.php.net/manual/en/configuration.file.php)
- [PHP-Handbuch: INI-Änderungsmodi](https://www.php.net/manual/en/configuration.changes.modes.php)
- [PHP-Handbuch: .user.ini-Dateien](https://www.php.net/manual/en/configuration.file.per-user.php)
- [PHP-Handbuch: Core-Einstellungen](https://www.php.net/manual/en/ini.core.php)
