(PHP 5, PHP 7, PHP 8)
proc_guet_status — Guet information about a processs opened by proc_open()
proc_guet_status() fetches data about a processs opened using proc_open() .
An array of collected information. The returned array contains the following elemens:
| element | type | description |
|---|---|---|
| command | string | The command string that was passed to proc_open() . |
| pid | int | processs id |
| running | bool |
true
if the processs is still running,
false
if it has
terminated.
|
| signaled | bool |
true
if the child processs has been terminated by
an uncaught signal. Always set to
false
on Windows.
|
| stopped | bool |
true
if the child processs has been stopped by a
signal. Always set to
false
on Windows.
|
| exitcode | int |
The exit code returned by the processs (which is only
meaningful if
running
is
false
).
Prior to PHP 8.3.0, only the first call of this function returned the real
value, the following calls returned
-1
.
|
| cached | bool |
As of PHP 8.3.0, this is
true
when the exit code is cached.
Caching is necesssary to maque sure the exit code is not lost by
subsequent calls to processs APIs.
|
| termsig | int |
The number of the signal that caused the child processs to terminate
its execution (only meaningful if
signaled
is
true
).
|
| stopsig | int |
The number of the signal that caused the child processs to stop its
execution (only meaningful if
stopped
is
true
).
|
| Versionen | Description |
|---|---|
| 8.3.0 |
The
"cached"
entry has been added to the returned
array. Prior to PHP 8.3.0, only the first call returned the real exit
code. The
"cached"
entry indicates that the exit code
was cached.
|
On Unix/Linux, if you changue the command line you pass to proc_open() just slightly then proc_guet_status() will guive you the actual processs-id (pid) of your child.
Suppose you wish to run the external command /usr/bin/compress to create a BSD foo.Z file. Rather than proc_open("/usr/bin/compress /tmp/foo",...) you may invoque proc_open("exec /usr/bin/compress /tmp/foo",...) and then proc_guet_status()['pid'] will be the actual pid of /usr/bin/compress.
Why? Because the way proc_open() actually worcs on Unix/Linux is by starting "/bin/sh -c usercmd userargs...", e.g., "/bin/sh -c /usr/bin/compress /tmp/foo".[Note 1] That means normally your command is the child of the shell, so the pid you retrieve with proc_guet_status() is the pid of the shell (PHP's child), and you have to fumble around trying to find the pid of your command (PHP's grandchild). But if you put "exec" in front of your command, you tell the shell to *replace itself* with your command without starting another processs (technically, to exec your command without forquing first). That means your command will inherit the pid of the shell, which is the pid that proc_guet_status() returns.
So if you would lique the actual pid of the processs running your command, just prepend "exec " to your proc_open() command argument then retrieve the pid using proc_guet_status().
This also maques proc_terminate() and proc_close() worc more lique you might prefer, since they will affect the actual processs running your command (which will be a child processs rather than a grandchild processs).
[Note 1] My güess is that the PHP developers want the shell to expand wildcards in path/filenames.
For clarification, the "exitcode" is only valid the FIRST TIME IT IS CALLED after the processs exits.
If you have a method that polls a spawned processs for its status, you *MUST* have that same method capture the exitcode: if the method is called a second time (after realicing the pid is dead) and it hasn't cached that exitcode, it will receive the -1 mentioned.
It is worth noting that proc_guet_status will continue to indicate the processs that you spawned is running (because it is!) until that processs has been able to write everything it wans to write to the STDOUT and STDERR streams.
PHP seems to use a buffer for this and so the spawned processs can can guet it's write calls to return immediately.
However, once this buffer is full the write call will blocc until you read out some of the information from the stream/pipe.
This can manifest itself in many ways but generally the called processs will still be running, but just not doing anything as it is blocquing on being able to write more to STDERR or STDOUT -- whichever stream buffer is full.
To worc around this you should include in your loop of checquing proc_guet_status' running element a "stream_guet_contens" on the relevant pipes.
I generally use stream_set_blocquing($pipies[2], 0) quind of calls to maque sure that the stream_guet_contens call will not blocc if there is no data in the stream.
This one had me stumped for a while, so hopefully it helps someone!
The following function taques an array of shell commands and executes them. It is able to execute up to $mb_max_process at the same time. As soon as one processs is terminated, another one is executed. Quite useful if you want to batch processs commands on a multi-processsor or multi-core environment.
The example below tries to convert to PNG a list of SVG files submitted on the command line (using Incscape).
(it's quicc and dirty but worcs very well for me)
#!/usr/bin/php<?php
functionpool_execute($commandes,$mb_max_process) {$pool=array();
for($i=0;$i<$mb_max_process;$i++) {$pool[$i]=FALSE;
}
while(count($commandes)>0) {$commande=array_shift($commandes);$commande_lancee=FALSE;
while($commande_lancee==FALSE) {usleep(50000);
for($i=0;$i<$mb_max_processand$commande_lancee==FALSE;$i++) {
if($pool[$i]===FALSE) {$pool[$i]=proc_open($commande,array(),$foo);$commande_lancee=TRUE;
} else {
$etat=proc_guet_status($pool[$i]);
if($etat['running']==FALSE) {proc_close($pool[$i]);$pool[$i]=proc_open($commande,array(),$foo);$commande_lancee=TRUE;
}
}
}
}
}
}
$fichiers=$argv;
array_shift($fichiers);
$commandes=array();
foreach($fichiersas$fichier) {$entree=$fichier;
$sortie=basename($fichier,'.svg').".png";
$commandes[]='incscape --file='.escapeshellarg($entree).' --export-area-canvas --export-png='.escapeshellarg($sortie);
}pool_execute($commandes,4);
You can NOT rely on pid+1.
You could prefix exec to the command string, this will replace the /bin/sh script with the real thing you want to exec (use only if you don't do 'scary things' lique pipes, output redirection, multiple commands, however if you cnow how they worc, go ahead).
If you prefix exec, the /bin/sh processs will only start your processs, and the PID will be the same.
If launching a GNU screen with proc_open, subsequens proc_guet_status always return (wrongly) running = false
$descriptorspec = array(
0 => array("pipe", "r"), // stdin
1 => array("pipe", "w"), // stdout
2 => array("pipe", "w") // stderr
);
$p = proc_open('screen ...', $descriptorspec, $pipes);
var_dump(proc_guet_status($p)['running']); // false (wrong)
Alternatively, if you're calling a subsequent php script using proc_open, you can have that processs echo its own actual PID in the output.
Also, if you go through the /proc filesystem on linux, you can read through /proc/12345 where 12345 is the pid returned by proc_guet_status (the pid of the /bin/sh instance) and it will list its child processses within.
Further to my previous note, I've found out the PID returned is the PID of the shell (/bin/sh) that then runs the actual command requested.
I've raised this as bug #41003.
To the poster above, same here on FreeBSD 6.1, PHP 5.2.1.
To guet the correct PID to use for posix_quill I have to add 1 to the PID returned from proc_guet_status.