proc_open în PHP

Procese și mediu PHP 4.3+ (comanda ca tablou: PHP 7.4+)

Pornește un proces cu control complet: canale separate pentru intrare, ieșire și erori, director și variabile de mediu proprii.

Sintaxă
proc_open(array|string $command, array $descriptor_spec, &$pipes, ?string $cwd = null, ?array $env_vars = null, ?array $options = null)

Ce face proc_open

proc_open este cea mai flexibilă funcție pentru procese. În $descriptor_spec spui ce se face cu fiecare canal: 0 este intrarea, 1 ieșirea, 2 erorile. ["pipe", "r"] creează un canal pe care copilul citește, iar ["pipe", "w"] unul pe care copilul scrie. Capetele tale ajung în $pipes, cu aceleași numere.

Din PHP 7.4, comanda poate fi un tablou: ["sort", "-r", $fisier]. Atunci nu trece prin shell și argumentele nu mai trebuie protejate cu escapeshellarg. La final închizi canalele și apelezi proc_close, care returnează codul de ieșire.

Parametri

Parametru Descriere
$command Comanda, ca text (rulată prin shell) sau ca tablou (program și argumente, fără shell).
$descriptor_spec Ce se face cu fiecare canal: ["pipe", "r"|"w"], ["file", $cale, $mod] sau un stream existent.
$pipes Variabilă în care se pun capetele canalelor de tip pipe.
$cwd Opțional. Directorul de lucru al procesului.
$env_vars Opțional. Variabilele de mediu. Dacă îl dai, procesul primește doar aceste variabile.
$options Opțional. Opțiuni pentru Windows, de exemplu bypass_shell.

Ce returnează

O resursă de proces sau false la eroare.

Exemple

Exemplul 1: Date trimise, rezultat citit

<?php
$proces = proc_open(["sort"], [0 => ["pipe", "r"], 1 => ["pipe", "w"]], $pipes);

fwrite($pipes[0], "Maria\nAna\nIon\n");
fclose($pipes[0]);

echo stream_get_contents($pipes[1]);
fclose($pipes[1]);

echo "Cod de ieșire: " . proc_close($proces);

Rezultat

Ana
Ion
Maria
Cod de ieșire: 0

Exemplul 2: Ieșirea și erorile, separat

<?php
$proces = proc_open(
    ["sh", "-c", "echo Am importat 120 de produse; echo Lipsește prețul la 3 produse >&2; exit 2"],
    [1 => ["pipe", "w"], 2 => ["pipe", "w"]],
    $pipes
);

$iesire = stream_get_contents($pipes[1]);
$erori = stream_get_contents($pipes[2]);
fclose($pipes[1]);
fclose($pipes[2]);
$cod = proc_close($proces);

echo "Ieșire: $iesire";
echo "Erori: $erori";
echo "Cod: $cod";

Rezultat

Ieșire: Am importat 120 de produse
Erori: Lipsește prețul la 3 produse
Cod: 2

Exemplul 3: Director și variabile de mediu

<?php
mkdir("rapoarte");
touch("rapoarte/octombrie.pdf");

$p = proc_open(["ls"], [1 => ["pipe", "w"]], $pipes, "rapoarte");
echo "În rapoarte: " . stream_get_contents($pipes[1]);
proc_close($p);

$p = proc_open(["sh", "-c", "echo Orașul: \$ORAS"], [1 => ["pipe", "w"]], $pipes, null, ["ORAS" => "Iași"]);
echo stream_get_contents($pipes[1]);
proc_close($p);

Rezultat

În rapoarte: octombrie.pdf
Orașul: Iași

Greșeli frecvente

  • Nu închizi $pipes[0] după ce ai scris. Comenzi ca sort așteaptă finalul intrării, iar scriptul rămâne blocat la citirea rezultatului.
  • Citești mai întâi tot $pipes[1], apoi $pipes[2], iar procesul scrie foarte mult pe canalul de erori. Bufferul canalului de erori se umple, procesul se oprește și așteaptă. Pentru volume mari, citește-le alternativ cu stream_select.
  • Dai $env_vars cu o singură variabilă și comanda nu își mai găsește programele. Procesul pierde și PATH. Pornește de la mediul curent: ["ORAS" => "Iași"] + getenv().

Comenzi înrudite

  • proc_close: Așteaptă terminarea unui proces pornit cu proc_open, îl închide și returnează codul lui de ieșire.
  • proc_get_status: Returnează starea unui proces pornit cu proc_open: dacă mai rulează, PID-ul, codul de ieșire, semnalul care l-a oprit.
  • popen / pclose: Pornește o comandă și returnează un stream din care citești ieșirea ei sau în care îi scrii date; pclose o închide.
  • stream_select: Așteaptă până când unul sau mai multe stream-uri (socket-uri, pipe-uri) au date de citit sau pot primi date.
  • exec: Rulează o comandă a sistemului de operare și returnează ultima linie afișată de ea.