Konfigurationsdateien gehören zu den Grundbausteinen jeder PHP-Anwendung. Datenbankzugangsdaten, API-Schlüssel, Debug-Einstellungen und Pfade sollten nicht hart im Code stehen, sondern in einer separaten Datei. PHP bietet dafür die Funktion parse_ini_file(), die INI-Dateien einliest und als Array zurückgibt. Dieses Tutorial erklärt die Funktion im Detail, zeigt wichtige Sicherheitsaspekte und stellt Alternativen vor.
Grundlagen von parse_ini_file()
Die Funktion parse_ini_file() liest eine INI-Datei und gibt deren Inhalt als assoziatives Array zurück. Die Syntax ist denkbar einfach:
<?php
/* parse_ini_file(
* string $dateiname,
* bool $process_sections = false,
* int $scanner_mode = INI_SCANNER_NORMAL
* ): array|false
*/
$config = parse_ini_file('config.ini');
if ($config === false) {
die('Konfigurationsdatei konnte nicht '
. 'gelesen werden.');
}
echo 'App-Name: ' . $config['app_name'];
?>
Eine einfache INI-Datei sieht so aus:
; Kommentar in der INI-Datei
app_name = "Meine Anwendung"
debug = false
max_upload_size = 10485760
admin_email = admin@example.com
Jede Zeile besteht aus einem Schlüssel, einem Gleichheitszeichen und einem Wert. Zeilen, die mit einem Semikolon beginnen, sind Kommentare und werden ignoriert. Werte in Anführungszeichen werden als Strings behandelt, Werte ohne Anführungszeichen werden nach Möglichkeit interpretiert.
Vor dem Einlesen sollte geprüft werden, ob die Datei existiert und lesbar ist. Die Kombination aus file_exists() und is_readable() gibt differenzierte Fehlermeldungen:
<?php
$pfad = __DIR__ . '/config.ini';
if (!file_exists($pfad)) {
die('Konfigurationsdatei nicht gefunden: '
. $pfad);
}
if (!is_readable($pfad)) {
die('Keine Leseberechtigung: ' . $pfad);
}
$config = parse_ini_file($pfad);
?>
Sektionen verwenden (process_sections)
INI-Dateien unterstützen Sektionen, die mit eckigen Klammern gekennzeichnet werden. Der zweite Parameter von parse_ini_file() steuert, ob diese Sektionen als verschachtelte Arrays geparst werden.
; config.ini mit Sektionen
[database]
host = "localhost"
name = "meine_db"
user = "db_user"
password = "geheim123"
[mail]
smtp_host = "smtp.example.com"
smtp_port = 587
from = "noreply@example.com"
[app]
name = "Meine Anwendung"
debug = false
timezone = "Europe/Berlin"
<?php
/* Zweiter Parameter: true fuer Sektionen */
$config = parse_ini_file(
'config.ini', true
);
/* Zugriff ueber verschachteltes Array */
echo $config['database']['host']; // localhost
echo $config['mail']['smtp_port']; // 587
echo $config['app']['name'];
?>
Ohne true als zweiten Parameter werden alle Schlüssel in einem flachen Array zusammengefasst. Bei gleichnamigen Schlüsseln in verschiedenen Sektionen überschreibt der letzte Wert die vorherigen. Sektionen machen die Konfiguration übersichtlicher und vermeiden Namenskonflikte.
INI_SCANNER_TYPED: Korrekte Datentypen
Standardmässig gibt parse_ini_file() alle Werte als Strings zurück. Das führt zu einem häufigen Problem: Der Wert false in der INI-Datei wird zum String "false", der bei einer Prüfung mit if als true gewertet wird, weil ein nicht-leerer String in PHP truthy ist.
Seit PHP 5.6.1 gibt es den dritten Parameter INI_SCANNER_TYPED, der dieses Problem löst:
<?php
/* config.ini:
* debug = false
* max_items = 50
* api_key = "abc123"
*/
/* OHNE INI_SCANNER_TYPED */
$config = parse_ini_file('config.ini');
var_dump($config['debug']);
// string(0) "" (false wird zu leerem String!)
var_dump($config['max_items']);
// string(2) "50"
/* MIT INI_SCANNER_TYPED */
$config = parse_ini_file(
'config.ini', false, INI_SCANNER_TYPED
);
var_dump($config['debug']);
// bool(false)
var_dump($config['max_items']);
// int(50)
?>
Mit INI_SCANNER_TYPED werden true, on und yes als bool(true) geparst, false, off, no und none als bool(false), ganzzahlige Werte als int und null als NULL. Es empfiehlt sich, diesen Modus immer zu verwenden, um typbedingte Fehler zu vermeiden.
Eine Kombination mit Sektionen ist möglich:
<?php
$config = parse_ini_file(
'config.ini',
true, // Sektionen aktivieren
INI_SCANNER_TYPED // Typen erhalten
);
?>
INI-Dateien absichern
Konfigurationsdateien enthalten oft sensible Daten wie Datenbankpasswörter oder API-Schlüssel. Wenn eine INI-Datei im Web-Root liegt und der Webserver sie nicht blockiert, kann sie über eine URL direkt im Browser aufgerufen werden. Das ist eine kritische Sicherheitslücke.
Methode 1: Datei ausserhalb des Document Root ablegen
Die sicherste Lösung ist, die Konfigurationsdatei ausserhalb des öffentlich zugänglichen Verzeichnisses zu speichern:
<?php
/* Document Root: /var/www/html/
* Config-Datei: /var/www/config/app.ini
* Die Config liegt AUSSERHALB von html/ */
$config = parse_ini_file(
'/var/www/config/app.ini',
true,
INI_SCANNER_TYPED
);
?>
Methode 2: Zugriff per .htaccess blockieren
Wenn die Datei im Web-Root bleiben muss (z.B. auf Shared Hosting), kann eine .htaccess-Regel den direkten Zugriff unterbinden:
# .htaccess im selben Verzeichnis
<FilesMatch ".ini$">
Require all denied
</FilesMatch>
Methode 3: PHP-Dateiendung verwenden
Ein einfacher Trick: Die Datei config.ini.php nennen und als erste Zeile einen PHP-Abbruch einfügen. Wenn jemand die Datei direkt aufruft, bricht PHP ab und der INI-Inhalt wird nicht ausgegeben:
; <?php exit; ?>
; Alles unterhalb dieser Zeile ist
; fuer den Browser nicht sichtbar
[database]
host = "localhost"
password = "geheim"
parse_ini_file() ignoriert die PHP-Zeile, weil sie mit einem Semikolon als Kommentar markiert ist. Der Webserver führt die Datei als PHP aus und bricht sofort ab.
Typische Stolperfallen
Die INI-Syntax hat einige nicht offensichtliche Eigenheiten, die regelmässig für Verwirrung sorgen.
Sonderzeichen in Werten
Semikolons leiten in INI-Dateien Kommentare ein. Ein Wert wie eine URL mit Query-String muss daher in Anführungszeichen stehen:
; FALSCH: Alles nach dem Semikolon
; wird als Kommentar interpretiert
callback = https://example.com?a=1;b=2
; RICHTIG: In Anfuehrungszeichen setzen
callback = "https://example.com?a=1;b=2"
; Gleichheitszeichen in Werten ebenfalls
formel = "2+2=4"
Reservierte Wörter
Die Wörter true, on, yes, false, off, no, none und null werden als spezielle Werte interpretiert. Wenn ein Wert buchstäblich "true" oder "false" heissen soll (etwa als String für eine API), muss er in Anführungszeichen stehen: status = "true".
parse_ini_file() gibt false zurück
Wenn die Funktion false zurückgibt, liegt das meist an einer dieser Ursachen: Die Datei existiert nicht, die Datei ist nicht lesbar, oder die INI-Syntax ist fehlerhaft (z.B. ein Schlüssel ohne Wert oder fehlerhafte Anführungszeichen). PHP gibt in diesen Fällen eine Warning aus, die im Error-Log zu finden ist.
Praxisbeispiel: Datenbankverbindung aus INI-Datei
Das folgende Beispiel zeigt einen vollständigen Workflow: Eine INI-Datei mit Datenbankzugangsdaten wird eingelesen, validiert und für eine PDO-Verbindung verwendet.
; /var/www/config/database.ini
[database]
host = "localhost"
port = 3306
name = "shop_db"
user = "shop_user"
password = "sicheres_passwort"
charset = "utf8mb4"
<?php
function datenbankVerbinden(
string $iniPfad
): PDO {
if (!file_exists($iniPfad)) {
throw new RuntimeException(
'DB-Konfiguration nicht gefunden.'
);
}
$config = parse_ini_file(
$iniPfad, true, INI_SCANNER_TYPED
);
if ($config === false
|| !isset($config['database'])
) {
throw new RuntimeException(
'DB-Konfiguration fehlerhaft.'
);
}
$db = $config['database'];
$dsn = sprintf(
'mysql:host=%s;port=%d;dbname=%s;'
. 'charset=%s',
$db['host'],
$db['port'] ?? 3306,
$db['name'],
$db['charset'] ?? 'utf8mb4'
);
return new PDO(
$dsn,
$db['user'],
$db['password'],
[
PDO::ATTR_ERRMODE
=> PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE
=> PDO::FETCH_ASSOC,
]
);
}
try {
$pdo = datenbankVerbinden(
'/var/www/config/database.ini'
);
echo 'Verbindung hergestellt.';
} catch (Exception $e) {
error_log($e->getMessage());
die('Datenbankfehler.');
}
?>
parse_ini_string() und umgebungsspezifische Konfigurationen
Neben parse_ini_file() gibt es parse_ini_string(), die einen INI-formatierten String statt einer Datei parst. Das ist nützlich, wenn der INI-Inhalt aus einer anderen Quelle stammt, zum Beispiel aus einer Datenbank oder einer API-Antwort.
<?php
$iniString = "
app_name = Testanwendung
debug = true
";
$config = parse_ini_string(
$iniString, false, INI_SCANNER_TYPED
);
echo $config['app_name']; // Testanwendung
var_dump($config['debug']); // bool(true)
?>
Für grössere Projekte empfiehlt sich die Aufteilung in umgebungsspezifische Konfigurationsdateien. Je nach Server-Umgebung wird eine andere Datei geladen:
<?php
$umgebung = getenv('APP_ENV') ?: 'production';
$iniPfad = __DIR__ . '/config/' . $umgebung . '.ini';
if (!file_exists($iniPfad)) {
die('Konfiguration fuer Umgebung "'
. $umgebung . '" nicht gefunden.');
}
$config = parse_ini_file(
$iniPfad, true, INI_SCANNER_TYPED
);
/* Auf dem Entwicklungsrechner:
* APP_ENV=development -> config/development.ini
* Auf dem Produktivserver:
* APP_ENV=production -> config/production.ini
*/
?>
Vergleich mit alternativen Config-Formaten
INI-Dateien sind nicht die einzige Möglichkeit, Konfigurationen in PHP zu verwalten. Je nach Anforderung gibt es bessere Alternativen.
| Format | Vorteile | Nachteile | Ideal für |
| INI | Einfach lesbar, native PHP-Funktion | Keine verschachtelten Strukturen, limitierte Typen | Einfache Key-Value-Konfigurationen |
| JSON | Verschachtelte Strukturen, breite Unterstützung | Keine Kommentare, strenge Syntax | Komplexe Konfigurationen, API-kompatibel |
| PHP-Array | Volle PHP-Power, Typsicherheit, OPcache | Sicherheitsrisiko bei eval/include | Framework-Konfigurationen (Laravel, Symfony) |
| .env | Standard für Umgebungsvariablen | Nur flache Struktur, kein nativer Parser | Deployment-spezifische Werte |
Für einfache Anwendungen mit flachen Konfigurationen (Host, Port, Benutzername) sind INI-Dateien eine gute Wahl. Sobald verschachtelte Strukturen oder Arrays benötigt werden, ist JSON oder ein PHP-Array die bessere Option. Die Funktion var_export() kann dabei helfen, PHP-Arrays als Konfigurationsdateien zu generieren.
Konfiguration cachen
parse_ini_file() liest und parst die Datei bei jedem Aufruf neu. Für häufig aufgerufene Seiten kann es sinnvoll sein, das Ergebnis zu cachen. Eine einfache Lösung ist eine statische Variable innerhalb einer Funktion:
<?php
function getConfig(): array
{
static $config = null;
if ($config === null) {
$config = parse_ini_file(
__DIR__ . '/config.ini',
true,
INI_SCANNER_TYPED
);
}
return $config;
}
/* Erster Aufruf: Datei wird gelesen */
$db = getConfig()['database'];
/* Zweiter Aufruf: Cache wird verwendet */
$mail = getConfig()['mail'];
?>
Die statische Variable bleibt während der gesamten Laufzeit des Scripts im Speicher. Bei einer Webanwendung mit vielen Includes, die alle die Konfiguration benötigen, spart das unnötige Dateizugriffe.
Arrays in INI-Dateien
INI-Dateien unterstützen auch einfache Arrays. Wenn mehrere Werte unter demselben Schlüssel gespeichert werden sollen, wird der Schlüssel mit eckigen Klammern versehen:
; config.ini mit Array-Werten
[erlaubte_domains]
domains[] = "example.com"
domains[] = "example.org"
domains[] = "test.example.com"
[dateiformate]
formate[] = "jpg"
formate[] = "png"
formate[] = "webp"
<?php
$config = parse_ini_file(
'config.ini', true, INI_SCANNER_TYPED
);
/* $config['erlaubte_domains']['domains']
ist jetzt ein Array */
foreach ($config['erlaubte_domains']['domains']
as $domain
) {
echo $domain . PHP_EOL;
}
// example.com
// example.org
// test.example.com
?>
Diese Array-Syntax ist praktisch für Listen von erlaubten Werten, IP-Adressen oder Dateiformaten. Für komplexere verschachtelte Strukturen stossen INI-Dateien allerdings an ihre Grenzen. In solchen Fällen sind JSON-Dateien oder PHP-Arrays die bessere Wahl.
Fehlerbehandlung mit eigener Wrapper-Funktion
Um die Fehlerbehandlung bei parse_ini_file() zu vereinheitlichen, empfiehlt sich eine Wrapper-Funktion, die Prüfungen und Parsing in einem Schritt erledigt:
<?php
function ladeIniConfig(
string $pfad,
bool $sektionen = true
): array {
if (!file_exists($pfad)) {
throw new RuntimeException(
'INI-Datei nicht gefunden: ' . $pfad
);
}
if (!is_readable($pfad)) {
throw new RuntimeException(
'INI-Datei nicht lesbar: ' . $pfad
);
}
$result = parse_ini_file(
$pfad, $sektionen, INI_SCANNER_TYPED
);
if ($result === false) {
throw new RuntimeException(
'INI-Syntax fehlerhaft: ' . $pfad
);
}
return $result;
}
/* Verwendung */
try {
$config = ladeIniConfig(__DIR__ . '/app.ini');
} catch (RuntimeException $e) {
error_log($e->getMessage());
die('Konfigurationsfehler.');
}
?>
Diese Funktion kann in jedem Projekt als zentrale Stelle für das Laden von Konfigurationen verwendet werden. Die spezifischen Fehlermeldungen erleichtern die Fehlersuche erheblich.
Zusammenfassung
parse_ini_file() ist eine unkomplizierte Lösung für einfache Konfigurationsdateien in PHP. Die wichtigsten Punkte: Immer INI_SCANNER_TYPED als dritten Parameter verwenden, damit Booleans und Zahlen als korrekte Typen geparst werden. Sektionen mit dem zweiten Parameter true aktivieren, um die Konfiguration übersichtlich zu gliedern. Und INI-Dateien niemals ungeschützt im Web-Root ablegen, sondern ausserhalb des Document Root speichern oder den Zugriff per .htaccess blockieren.
Für komplexere Konfigurationen mit verschachtelten Strukturen oder Arrays sind JSON-Dateien oder PHP-Arrays die bessere Wahl. Wer sich tiefer mit Dateifunktionen beschäftigen möchte, findet in den Tutorials zu file_exists() und is_readable() weitere nützliche Informationen.