pclose()
Die PHP-Funktion pclose() schließt einen Prozess-Dateizeiger, der mit popen() geöffnet wurde, und gibt den Exit-Status des Prozesses zurück.
Die PHP-Funktion pclose()
Die PHP-Funktion pclose() schließt einen Prozess-Dateizeiger — den speziellen Stream, den popen() zurückgibt, wenn ein externer Befehl gestartet wird. Während fclose() einfach ein normales Datei-Handle schließt, tut pclose() noch etwas mehr: Es wartet, bis der zugrunde liegende Prozess beendet ist, und liefert dessen Exit-Status zurück.
Diese Seite behandelt die Syntax, den Rückgabewert (einschließlich eines subtilen Fallstricks), ein vollständiges Lese-und-Schließ-Beispiel sowie die Frage, wann stattdessen proc_open() verwendet werden sollte.
Warum pclose() existiert
popen() führt einen Shell-Befehl aus und stellt eine Pipe bereit, über die entweder Eingaben hineingeschrieben ('w'-Modus) oder die Ausgabe gelesen werden kann ('r'-Modus). Diese Pipe wird durch einen echten Betriebssystemprozess unterstützt. Wenn das Handle einfach aufgegeben — oder mit der falschen Funktion geschlossen wird — kann der Prozess als Zombie verbleiben und sein Exit-Code geht verloren. pclose() ist das korrekte Gegenstück: Es leert die Pipe, blockiert bis der Kindprozess beendet ist, räumt ihn auf und gibt den Exit-Code zurück, damit das Skript auf Erfolg oder Misserfolg reagieren kann.
Jedes
popen()sollte immer mit einempclose()kombiniert werden. Die Verwendung vonfclose()auf einempopen()-Handle ist undefiniertes Verhalten.
Syntax
pclose(resource $handle): intParameter
Die Funktion nimmt einen einzigen Parameter entgegen:
$handle— der Prozess-Dateizeiger, der vonpopen()zurückgegeben wurde. Es ist ungültig, eine andere Art von Ressource zu übergeben.
Rückgabewert
pclose() gibt den Beendigungsstatus des Prozesses als Integer zurück (dies ist der Rohwert des C-pclose-Aufrufs — auf den meisten Systemen befindet sich der eigentliche Exit-Code im High-Byte). Es gibt -1 zurück, wenn der Prozess nicht aufgeräumt werden konnte. Bei älteren PHP-Versionen gibt die Übergabe eines ungültigen Handles eine Warnung aus und gibt FALSE zurück.
Um den einfachen Exit-Code auf einem Unix-ähnlichen System zu erhalten, wird der Wert um 8 Bit nach rechts verschoben:
$status = pclose($handle);
$exitCode = $status >> 8; // 0 means the command succeededBeispiel
Einen Befehl öffnen, seine Ausgabe lesen und dann die Pipe schließen und das Ergebnis prüfen:
<?php
// Run an external command and read its output.
$handle = popen('ls -la', 'r');
if ($handle === false) {
die("Failed to start the command.\n");
}
$output = '';
while (!feof($handle)) {
$output .= fread($handle, 1024);
}
echo $output;
// Close the pipe and capture the process exit status.
$status = pclose($handle);
$exitCode = $status >> 8;
echo "Command exited with code: $exitCode\n";Ein Prozess-Dateizeiger wird mit popen() geöffnet, die vollständige Ausgabe in einer Schleife mit fread() gelesen (ein einzelnes fread erfasst bei größerer Ausgabe möglicherweise nicht alles), dann wird die Pipe mit pclose() geschlossen und der Exit-Code dekodiert. Ein Exit-Code von 0 bedeutet konventionell Erfolg.
Häufige Fallstricke
fclose()undpclose()nicht vermischen. Ein Handle vonpopen()muss mitpclose()geschlossen werden, und ein Handle vonfopen()mitfclose().pclose()blockiert. Es wartet, bis der Kindprozess beendet ist. Wenn der Befehl nie endet, hängt das Skript dort.- Vor dem Schließen lesen.
pclose()kann ungelesene gepufferte Ausgabe verwerfen; daher sollte die Pipe zuerst vollständig gelesen werden. - Eine Richtung pro Pipe. Eine
popen()-Pipe ist entweder lesbar oder schreibbar, nicht beides — für bidirektionale Kommunikation wirdproc_open()benötigt.
Wann stattdessen proc_open() verwendet werden sollte
popen()/pclose() eignen sich hervorragend für einen schnellen Einmal-Befehl, bei dem nur die Ausgabe benötigt wird oder Eingaben hineingefüttert werden müssen. Wenn beides gleichzeitig benötigt wird, getrennte stdout- und stderr-Streams, Umgebungssteuerung oder ein Arbeitsverzeichnis, sollte proc_open() verwendet werden — es bietet vollständige bidirektionale Kontrolle über den gestarteten Prozess.
Fazit
pclose() ist der notwendige Begleiter zu popen(): Es schließt die Prozess-Pipe, wartet auf das Ende des Befehls und gibt dessen Exit-Status zurück, damit überprüft werden kann, ob der Befehl erfolgreich war. Die beiden sollten immer zusammen verwendet werden, die Pipe vor dem Schließen gelesen und auf Unix-Systemen der Status um 8 Bit nach rechts verschoben werden, um den eigentlichen Exit-Code zu erhalten. Für alles, was über eine einzelne Richtungspipe hinausgeht, sollte proc_open() verwendet werden.