2010-02-23 4 views
43

En PHP, j'exécute une commande avec exec(), et elle retourne si elle réussit une URL;PHP StdErr après Exec()

$url = exec('report'); 

Cependant, je veux vérifier stderr, si quelque chose s'est mal passé. Comment pourrais-je lire le flux? Je veux utiliser php: // stderr, mais je ne suis pas sûr de savoir comment l'utiliser.

+0

Je vous recommande d'utiliser le composant Symfony/Process. –

Répondre

65

Si vous voulez exécuter une commande et obtenir les deux stderr et stdout, pas « fusionné », une solution serait probablement d'utiliser proc_open, qui fournit un niveau de contrôle sur la commande qui est en cours d'exécution - y compris d'une manière à canaliser stdin/stdout/stderr.


Et voici un exemple: nous allons considérer que nous avons ce script shell, dans test.sh, qui écrit à la fois stderr et stdout:

#!/bin/bash 

echo 'this is on stdout'; 
echo 'this is on stdout too'; 

echo 'this is on stderr' >&2; 
echo 'this is on stderr too' >&2; 


Maintenant, laissez le code de certains PHP, en temp.php - Tout d'abord, nous initialisons les descripteurs i/o:

$descriptorspec = array(
    0 => array("pipe", "r"), // stdin 
    1 => array("pipe", "w"), // stdout 
    2 => array("pipe", "w"), // stderr 
); 


Et puis, exécutez la commande test.sh, en utilisant les descripteurs, dans le répertoire courant et dire i/o devrait être de/à $pipes:

$process = proc_open('./test.sh', $descriptorspec, $pipes, dirname(__FILE__), null); 


Nous pouvons maintenant lire les deux tuyaux de sortie :

$stdout = stream_get_contents($pipes[1]); 
fclose($pipes[1]); 

$stderr = stream_get_contents($pipes[2]); 
fclose($pipes[2]); 


Et, si nous affichons le contenu de ces deux variables:

echo "stdout : \n"; 
var_dump($stdout); 

echo "stderr :\n"; 
var_dump($stderr); 


Nous obtenons la sortie suivante lors de l'exécution du script temp.php:

$ php ./temp.php 
stdout : 
string(40) "this is on stdout 
this is on stdout too 
" 
stderr : 
string(40) "this is on stderr 
this is on stderr too 
" 


Hope this helps :-)

+3

Lorsque vous utilisez ceci, assurez-vous que vous utilisez tous proc_close lorsque vous avez terminé pour des raisons de propreté. –

+0

Pourquoi rediriger le résultat dans un processus var? –

+3

@BriceFavre Il le met dans un processus var afin qu'il puisse le fermer plus tard avec proc_close, qui retournera aussi le code retour avec lequel le processus s'est terminé. '$ returnCode = proc_close ($ process);' –

6

Une autre façon d'obtenir unmerged stdout/stderr.

$pp_name = "/tmp/pp_test"; 
@unlink($pp_name); 
posix_mkfifo($pp_name, 0777); 
$pp = fopen($pp_name, "r+"); 
stream_set_blocking($pp, FALSE); 
exec("wget -O - http://www.youtube.com 2>$pp_name", $r_stdout); 
$r_stderr = stream_get_contents($pp); 
var_dump($r_stderr); 
fclose($pp); 
unlink($pp_name); 

Si vous voulez ignorer stdout et obtenir seulement stderr, vous pouvez essayer ceci:

exec("wget -O - http://www.youtube.com 2>&1 >/dev/null", $r_stderr); 
30

Une petite fonction qui pourrait être utile:

function my_shell_exec($cmd, &$stdout=null, &$stderr=null) { 
    $proc = proc_open($cmd,[ 
     1 => ['pipe','w'], 
     2 => ['pipe','w'], 
    ],$pipes); 
    $stdout = stream_get_contents($pipes[1]); 
    fclose($pipes[1]); 
    $stderr = stream_get_contents($pipes[2]); 
    fclose($pipes[2]); 
    return proc_close($proc); 
} 

Le code de sortie est retourné et STDOUT et STDERR sont des paramètres de référence si vous en avez besoin.

+2

Nice et simple, fonctionne parfaitement. Merci d'avoir posté!!! –