Start · Sprachen · PHP · Referenz · proc_close

proc_close

Funktion

Schließt einen mit <code>proc_open()</code> gestarteten Prozess und gibt dessen Exitcode zurück.

seit PHP 4.3.0 Kategorie: misc

Signatur

proc_close(resource $process): int

Beschreibung

proc_close() beendet einen Prozess, der zuvor mit proc_open() gestartet wurde. Die Funktion wartet darauf, dass der Prozess vollständig beendet ist, und gibt anschließend seinen Exitcode zurück. Vor dem Aufruf sollten alle mit dem Prozess verbundenen Pipes (Datei-Handles) geschlossen werden, da es sonst zu einem Deadlock kommen kann – insbesondere wenn der Kindprozess auf das Schreiben in eine Pipe wartet, die noch nicht gelesen wurde.

Der zurückgegebene Exitcode entspricht dem Rückgabewert des gestarteten Prozesses: 0 steht üblicherweise für Erfolg, jeder andere Wert für einen Fehler. Auf Unix-Systemen wird der Exitcode über waitpid() ermittelt.

Diese Funktion ist essenziell für das saubere Ressourcen-Management, wenn externe Programme über proc_open() aufgerufen werden. Wird sie nicht aufgerufen, können Zombie-Prozesse entstehen oder Ressourcen belegt bleiben. Der Aufruf ist daher immer am Ende eines proc_open()-Blocks empfehlenswert, idealerweise in einem finally-Block.

Parameter

Name Typ Default Beschreibung
$process Pflicht resource Die Prozess-Ressource, die von proc_open() zurückgegeben wurde.

Rückgabewert

Typ
int
Beschreibung
Gibt den Exitcode des beendeten Prozesses zurück. 0 bedeutet üblicherweise Erfolg. Gibt -1 zurück, wenn der Exitcode nicht ermittelt werden konnte oder der übergebene Parameter keine gültige Prozess-Ressource ist.

Beispiele

Einfaches Beispiel: Externen Befehl ausführen und Exitcode auslesen

<?php
$descriptorspec = [
    0 => ['pipe', 'r'],  // stdin
    1 => ['pipe', 'w'],  // stdout
    2 => ['pipe', 'w'],  // stderr
];

$process = proc_open('ls -la /tmp', $descriptorspec, $pipes);

if (is_resource($process)) {
    // Ausgabe lesen
    $output = stream_get_contents($pipes[1]);
    $errors = stream_get_contents($pipes[2]);

    // Pipes ZUERST schließen, um Deadlocks zu vermeiden
    fclose($pipes[0]);
    fclose($pipes[1]);
    fclose($pipes[2]);

    // Prozess schließen und Exitcode ermitteln
    $exitCode = proc_close($process);

    echo "Ausgabe:\n" . $output;
    echo "Fehler:\n" . $errors;
    echo "Exitcode: " . $exitCode . "\n";
}
Ausgabe: (Inhalt von /tmp) Fehler: Exitcode: 0

Robuste Verwendung mit finally-Block

<?php
$descriptorspec = [
    0 => ['pipe', 'r'],
    1 => ['pipe', 'w'],
    2 => ['pipe', 'w'],
];

$process = proc_open('php -r "exit(42);"', $descriptorspec, $pipes);

if (!is_resource($process)) {
    throw new RuntimeException('Prozess konnte nicht gestartet werden.');
}

try {
    $stdout = stream_get_contents($pipes[1]);
    $stderr = stream_get_contents($pipes[2]);
} finally {
    // Sicherstellen, dass Pipes und Prozess immer geschlossen werden
    foreach ($pipes as $pipe) {
        if (is_resource($pipe)) {
            fclose($pipe);
        }
    }
    $exitCode = proc_close($process);
}

echo "Exitcode: " . $exitCode . "\n"; // Erwartet: 42
Exitcode: 42

// Wichtig · Fallstricke

Deadlock-Gefahr: Werden die Pipes nicht vor dem Aufruf von proc_close() geschlossen, kann ein Deadlock entstehen. Dies passiert, wenn der Kindprozess blockiert, weil er in eine volle Pipe schreiben möchte, während der Elternprozess in proc_close() auf das Ende des Kindprozesses wartet. Schließe daher immer zuerst alle Pipes, bevor du proc_close() aufrufst.

Sicherheitshinweis: Beim Übergeben von Benutzereingaben an proc_open() ist unbedingt escapeshellarg() oder escapeshellcmd() zu verwenden, um Shell-Injection zu verhindern. proc_close() selbst ist davon nicht betroffen.

Auf Windows-Systemen kann der Exitcode von dem auf Unix-Systemen abweichen. Das Verhalten bei Signals (z. B. SIGKILL) kann ebenfalls plattformabhängig sein.