Signatur
Beschreibung
popen() startet einen externen Betriebssystem-Prozess über die Shell und gibt einen Dateizeiger zurück, der entweder zum Lesen der Prozessausgabe (r) oder zum Schreiben in den Prozess (w) genutzt werden kann. Der Zeiger verhält sich wie ein gewöhnlicher Datei-Handle und kann mit Funktionen wie fgets(), fgetcsv() oder fwrite() verwendet werden.
Die Funktion ist nützlich, wenn man mit externen Programmen kommunizieren möchte, ohne temporäre Dateien zu verwenden, z. B. beim Lesen komprimierter Daten (gzip), beim Ausführen von Shell-Skripten oder beim Weiterleiten von Daten an Kommandozeilen-Werkzeuge wie sort oder mail.
Das Schließen des Prozesses erfolgt mit pclose(), das auch den Exit-Code des Prozesses zurückgibt. Im Gegensatz zu proc_open() erlaubt popen() nur eine Richtung (entweder lesen oder schreiben, nicht beides gleichzeitig).
Der Befehl wird über die System-Shell ausgeführt (/bin/sh -c auf Unix, cmd.exe /c auf Windows), was Shell-Expansion und Pipes innerhalb des Befehls ermöglicht, aber auch Sicherheitsrisiken birgt.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $command Pflicht | string | Der auszuführende Shell-Befehl als Zeichenkette. Benutzereingaben müssen mit escapeshellcmd() und/oder escapeshellarg() abgesichert werden. |
|
| $mode Pflicht | string | Öffnungsmodus: 'r' zum Lesen der Prozessausgabe (stdout), 'w' zum Schreiben in die Prozesseingabe (stdin). Auf Windows kann zusätzlich 'b' für Binärmodus angegeben werden, z. B. 'rb'. |
Rückgabewert
pclose() geschlossen werden muss. Bei einem Fehler (z. B. ungültiger Befehl oder fehlende Berechtigung) wird false zurückgegeben.Beispiele
Ausgabe eines externen Befehls zeilenweise lesen
<?php
$handle = popen('ls -la /tmp', 'r');
if ($handle === false) {
die('Prozess konnte nicht geöffnet werden.');
}
while (!feof($handle)) {
$line = fgets($handle);
if ($line !== false) {
echo htmlspecialchars($line) . "\n";
}
}
$exitCode = pclose($handle);
echo "Exit-Code: " . $exitCode . "\n";
Daten in einen Prozess schreiben (z. B. sendmail)
<?php
$empfaenger = escapeshellarg('empfaenger@example.com');
$handle = popen('sendmail -t -i ' . $empfaenger, 'w');
if ($handle === false) {
die('sendmail konnte nicht gestartet werden.');
}
fwrite($handle, "To: empfaenger@example.com\n");
fwrite($handle, "Subject: Test-Nachricht\n");
fwrite($handle, "\n");
fwrite($handle, "Dies ist der Nachrichtentext.\n");
$exitCode = pclose($handle);
echo "Exit-Code: " . $exitCode . "\n";
Komprimierte Datei über gzip lesen
<?php
$datei = escapeshellarg('/var/log/syslog.gz');
$handle = popen('gzip -dc ' . $datei, 'r');
if ($handle === false) {
die('Datei konnte nicht geöffnet werden.');
}
$zeilenAnzahl = 0;
while (!feof($handle) && $zeilenAnzahl < 5) {
$zeile = fgets($handle);
if ($zeile !== false) {
echo htmlspecialchars($zeile);
$zeilenAnzahl++;
}
}
pclose($handle);
// Wichtig · Fallstricke
Sicherheitshinweis: Da der Befehl über die System-Shell ausgeführt wird, stellt das Einfügen von Benutzereingaben ohne Bereinigung ein erhebliches Command-Injection-Risiko dar. Argumente immer mit escapeshellarg() und den Befehl selbst mit escapeshellcmd() absichern. Niemals rohe Benutzereingaben in den Befehlsstring einbetten.
Nur eine Richtung: popen() unterstützt entweder Lesen oder Schreiben, nicht beides gleichzeitig. Für bidirektionale Kommunikation mit einem Prozess ist proc_open() die geeignetere Wahl.
Fehlerausgabe: Standardmäßig wird stderr des Kindprozesses nicht über den zurückgegebenen Handle zugänglich gemacht. Um stderr ebenfalls zu lesen, kann man im Befehl 2>&1 verwenden, um stderr auf stdout umzuleiten.
safe_mode / open_basedir: In alten PHP-Versionen mit aktiviertem safe_mode war popen() eingeschränkt. Ab PHP 5.4 ist safe_mode entfernt; stattdessen greift ggf. disable_functions in der php.ini.