Signatur
Beschreibung
proc_open() ist die mächtigere Alternative zu exec() oder shell_exec(), da sie volle Kontrolle über die Standardein- und -ausgabe (stdin, stdout, stderr) des Kindprozesses ermöglicht. Über den Parameter $descriptor_spec wird festgelegt, welche Dateideskriptoren des Prozesses als Pipes, Dateien oder bestehende Ressourcen geöffnet werden.
Der Rückgabewert ist eine Prozessressource, über die der Prozess mit proc_get_status() überwacht, mit proc_terminate() beendet oder mit proc_close() sauber geschlossen werden kann. Die dabei erzeugten Pipes werden in $pipes als Array von Stream-Ressourcen zurückgegeben und können mit den üblichen Stream-Funktionen wie fwrite() oder fread() verwendet werden.
Typische Anwendungsfälle sind das Ausführen von Shell-Werkzeugen mit interaktiver Dateneingabe (z. B. GPG, ImageMagick, ffmpeg), das Starten von Hintergrundprozessen oder das bidirektionale Kommunizieren mit externen Programmen. Ab PHP 7.4 kann $command auch ein Array sein, wodurch Shell-Escaping umgangen und die Kommandozeile direkt zusammengesetzt wird – empfohlen für Sicherheitskritisches.
Wichtig ist, alle Pipes zu schließen (fclose()) bevor proc_close() aufgerufen wird, da sonst Deadlocks entstehen können, wenn der Kindprozess auf das Leeren seiner Puffer wartet.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $command Pflicht | array|string | Das auszuführende Kommando als String (wird über die Shell interpretiert) oder ab PHP 7.4 als Array, wobei das erste Element das Programm und die weiteren Elemente die Argumente sind. Die Array-Form umgeht Shell-Interpolation und ist sicherer. | |
| $descriptor_spec Pflicht | array | Ein assoziatives Array, das festlegt, wie Dateideskriptoren des Kindprozesses behandelt werden. Schlüssel sind die Dateideskriptor-Nummern (0 = stdin, 1 = stdout, 2 = stderr). Werte sind entweder ['pipe', 'r'/'w'] für eine Pipe, ['file', '/pfad/datei', 'r'/'w'/'a'] für eine Datei oder eine bereits geöffnete Stream-Ressource. |
|
| $pipes Pflicht | array | Wird als Referenz übergeben und nach dem Aufruf mit den geöffneten Stream-Ressourcen befüllt, die den in $descriptor_spec definierten Pipes entsprechen (indiziert nach Dateideskriptor-Nummer). |
|
| $cwd | ?string | null | Das Arbeitsverzeichnis, in dem der Kindprozess gestartet wird. Bei null wird das aktuelle Arbeitsverzeichnis des PHP-Prozesses verwendet. |
| $env_vars | ?array | null | Ein assoziatives Array mit Umgebungsvariablen für den Kindprozess (z. B. ['HOME' => '/tmp', 'PATH' => '/usr/bin']). Bei null wird die aktuelle Umgebung des PHP-Prozesses vererbt. |
| $options | ?array | null | Optionale zusätzliche Optionen. Unter Windows sind suppress_errors (Fehler unterdrücken) und bypass_shell (Shell umgehen) möglich. Unter Unix steht blocking_pipes zur Verfügung. |
Rückgabewert
proc_get_status(), proc_terminate(), proc_close()) verwendet werden kann. Im Fehlerfall wird false zurückgegeben.Beispiele
Text durch einen externen Prozess (grep) leiten
<?php
$descriptors = [
0 => ['pipe', 'r'], // stdin: PHP schreibt hier hinein
1 => ['pipe', 'w'], // stdout: PHP liest hier heraus
2 => ['pipe', 'w'], // stderr: Fehlerausgabe
];
$process = proc_open(['grep', 'php'], $descriptors, $pipes);
if (is_resource($process)) {
// Eingabe an stdin schreiben
fwrite($pipes[0], "Das ist php\nDas ist Python\nNochmal php hier\n");
fclose($pipes[0]);
// Ausgabe von stdout lesen
$output = stream_get_contents($pipes[1]);
fclose($pipes[1]);
// Fehlerausgabe von stderr lesen
$errors = stream_get_contents($pipes[2]);
fclose($pipes[2]);
$exitCode = proc_close($process);
echo "Ausgabe:\n" . $output;
echo "Exit-Code: " . $exitCode . "\n";
}
Ausgabe eines Befehls in eine Datei umleiten
<?php
$descriptors = [
0 => ['pipe', 'r'], // stdin
1 => ['file', '/tmp/ausgabe.txt', 'w'], // stdout in Datei schreiben
2 => ['file', '/tmp/fehler.txt', 'w'], // stderr in Datei schreiben
];
$process = proc_open(
['ls', '-la', '/var/www'],
$descriptors,
$pipes,
'/tmp', // Arbeitsverzeichnis
['HOME' => '/tmp'] // Umgebungsvariablen
);
if (is_resource($process)) {
fclose($pipes[0]); // stdin sofort schließen
$exitCode = proc_close($process);
echo "Prozess beendet mit Exit-Code: $exitCode\n";
echo file_get_contents('/tmp/ausgabe.txt');
}
Hintergrundprozess starten und Status abfragen
<?php
$descriptors = [
0 => ['pipe', 'r'],
1 => ['pipe', 'w'],
2 => ['pipe', 'w'],
];
// sleep simuliert einen lang laufenden Prozess
$process = proc_open(['sleep', '2'], $descriptors, $pipes);
if (is_resource($process)) {
$status = proc_get_status($process);
echo "PID: " . $status['pid'] . "\n";
echo "Läuft noch: " . ($status['running'] ? 'ja' : 'nein') . "\n";
// Prozess vorzeitig beenden
proc_terminate($process);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);
echo "Prozess beendet.\n";
}
// Wichtig · Fallstricke
Sicherheitshinweis: Werden Benutzereingaben in das Kommando eingebaut, muss zwingend escapeshellarg() (bei String-Kommandos) verwendet oder die Array-Form genutzt werden, um Command-Injection zu verhindern. Die Array-Form (ab PHP 7.4) ist grundsätzlich vorzuziehen, da keine Shell-Interpretation stattfindet.
Deadlock-Gefahr: Beim Lesen und Schreiben auf Pipes gleichzeitig kann es zu Deadlocks kommen, wenn der Puffer des Kindprozesses voll ist und PHP blockiert wartet. Bei großen Datenmengen sollte stream_select() zur nicht-blockierenden Kommunikation eingesetzt werden.
Ressourcen-Verwaltung: Alle geöffneten Pipe-Ressourcen aus $pipes müssen mit fclose() geschlossen werden, bevor proc_close() aufgerufen wird. Andernfalls wartet der Kindprozess möglicherweise auf weiteren Input und terminiert nicht.
Auf Systemen mit aktiviertem safe_mode (PHP < 5.4) oder eingeschränktem disable_functions in der php.ini kann proc_open() deaktiviert oder eingeschränkt sein.