I use the following code to open a process with proc_open, and to save the handle and the pipes to a file:
$command = "COMMAND_TO_EXECUTE";
$descriptors = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("file", "error-output.txt", "a") // stderr is a file to write to
);
$pipes = array();
$processHandle = proc_open($command, $descriptors, $pipes);
if (is_resource($processHandle)) {
$processToSave = array(
"process" => $processHandle,
"pipes" => $pipes
);
file_put_contents("myfile.bin", serialize($processToSave) );
}
And in a second moment i need to retrieve this file handle from the file, i've used this code:
$processArray = unserialize(file_get_contents("myfile.bin"));
$processHandle = $processArray["process"];
$pipes = $processArray["pipes"];
But when I print a var_dump of $processHandle and $pipes after retrieving from file, I'll get integers instead of resource or process, but why??
var_dump($processHandle) -> int(0)
var_dump($pipes) - > array(2) { int(0), int(0) }
And at this point of course, if I try to close the pipes, i will get an error, resource expected, integer given.
How can I make this working? (NOTE: This is the solution I'm looking for)
But alternatively, I can get also the pid of process and then use this pid to stop or kill or do anything else with the process, but what about the pipes?
How can I read/write or save error from/to the process?
Thank you
Found the solution to myself, it's not to possible to serialize resource and when the script has done, those resource handler were free.
Solution was to create a daemon listening on a port, wich on request launch and stop process. Because the process is always running, it can maintain a list of handler process and stop when requested.
Related
I am trying to move a file from one folder to another at a specific time. In order to achieve this I am trying to use the Linux at command with a pipe :
`mv file /to/dest | at h:m d.m.y`
This is what I've written:
$move = "mv $filename /destination/folder";
$at = "at $my_datetime";
$res = execute_pipe($move,$at);
where the execute_pipe function is defined as following:
function execute_pipe($cmd1 , $cmd2)
{
$proc_cmd1 = proc_open($cmd1,
array(
array("pipe","r"), //stdin
array("pipe","w"), //stdout
array("pipe","w") //stderr
),
$pipes);
$output_cmd1 = stream_get_contents($pipes[1]);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
$return_value_cmd1 = proc_close($proc_cmd1);
$proc_cmd2 = proc_open($cmd2,
array(
array("pipe","r"), //stdin
array("pipe","w"), //stdout
array("pipe","w") //stderr
),
$pipes);
fwrite($pipes[0], $output_cmd1);
fclose($pipes[0]);
$output_cmd2 = stream_get_contents($pipes[1]);
fclose($pipes[1]);
fclose($pipes[2]);
$return_value_cmd2 = proc_close($proc_cmd2);
return $output_cmd2;
}
The problem is that the files get moved right away, ignoring the at command. What am I missing? Is there a better way to do this?
To me it seems like your problem has nothing to do with PHP. You're just using the Shell incorrectly.
The Man page of at reads:
at and batch read commands from standard input or a specified file
which are to be executed at a later time, using /bin/sh.
But your usage of the shell does execute your "mv file /destination" command, and then pipes the OUTPUT of that command to at. On a successful moving operation that output will ne nothing. So by using the pipe you actually move the file right away and tell at to do nothing at your specified time.
Read the man page of at by typing man at into your terminal to resolve the issue. Hint: if you want to use STD INPUT, echo'ing your command might help ;)
I'm trying to spawn a process using following statement
$cmd = "Hello.scala";
$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("pipe", "w")
);
$process = proc_open($cmd, $descriptorspec, $pipes, $cwd, null);
through PHP script. I'm using spawned process to execute a simple Scala program and capturing program's output. But unfortunately I'm not getting success. Child process runs successfully but after few seconds its getting terminated due to sigterm signal.
$stat = proc_get_status($process);
if ($stat['signaled'] && $stat['termsig'] == 9){
echo "Process got sigterm";
}
finally its printing Process got sigterm. I tried all the way to increase CPU time using ulimit in httpd and I also tried to set max execution time but no success. I will really appreciate any help on this.
I'm using proc_open with pdftk to pre-fill some forms with data, this works pretty well, but rather than save the result to a file and then read the file back, I'd like to print the file directly out. I've got this working so I'm not having any problems. But I'd like to direct the output of proc_open directly to the stream returned to the user so that I don't have to hold the value in memory in php. So far I have the following:
$descriptorspec = array(
0 => array("pipe","r"),
1 => array("pipe","w"),
2 => array("file","error.txt","a") );
$process = proc_open($command, $descriptorspec, $pipes);
if( is_resource( $process ) ) {
fwrite($pipes[0], $fdf);
fclose($pipes[0]);
echo stream_get_contents($pipes[1]));
fclose($pipes[1]);
proc_close($process);
}
I'd like to direct the result directly out to the use as you would get in the above code, without actually saving the value in a variable and then printing it out. Is there a way to direct a stream in php's output directly to the output. I'd like to do this to save memory and reduce the time it takes for the code to run.
Does anyone know of a function for a stream in php that prints the stream result directly out. Or is there a setting for proc_open that does this. Either way I fear this may not work at all, as I may need to add a content-length header to the output to display the PDF directly. If anyone knows of the function to print the stream directly out, is there also a way to get the byte length of the stream without actually reading it in.
Since no one has posted an answer this I may as well post the answer I've found.
Open a stream to php://output with fopen mode w, and use stream_copy_to_stream to send the data from the proc_open process to the user directly. There does not appear to be an easy method to get the length or size of the data in the stream however.
$descriptorspec = array(
0 => array("pipe","r"),
1 => array("pipe","w"),
2 => array("file","error.txt","a") );
$process = proc_open($command, $descriptorspec, $pipes);
if( is_resource( $process ) ) {
fwrite($pipes[0], $fdf);
fclose($pipes[0]);
/* New Code */
if( $fout = fopen("php://output","w") ) {
stream_copy_to_stream($pipes[1],$fout);
fclose($fout);
}
fclose($pipes[1]);
$result = proc_close($process);
}
I would like the output of one process created with proc_open to be piped to another one created with proc_open (in php). For example. In bash I can do:
[herbert#thdev1 ~]$ cat foo
2
3
1
[herbert#thdev1 ~]$ cat foo | sort
1
2
3
[herbert#thdev1 ~]$
I would like to simulate this in php using proc_open (instead of shell_exec) in order to have control over return-codes, pipes, etc. So I want something like this:
$catPipes=array();
$sortPipes=array();
$cwd = '/tmp';
$env = array();
$catProcess = proc_open("cat foo", array(
0 => array("pipe", "r"),
1 => array("pipe", "w")
), $catPipes, $cwd, $env);
$sortProcess = proc_open("sort", array(
0 => array("pipe", "r", $catPipes[1]),
1 => array("pipe", "w"),
), $sortPipes, $cwd, $env);
echo stream_get_contents($sortPipes[1]);
fclose($sortPipes[1]);
//proc_close(this) ... proc_close(that) ... etc
Would someone know how I can simulate the "|" of bash in php, i.e. connect the second descriptor of the cat-process to the first descriptor of the sort-process? Any help would be appreciated! But please do not redirect me to shell_exec, as I want to be able to check exit-codes and log errors :).
EDIT:
My needs-to-work-business-solution btw is:
while(!feof($searchPipes[1])) fwrite($lookupPipes[0], stream_get_line($searchPipes[1], 40000));
Which is basically what the OS would do, but I do not want to my own pipe-management, as I have a kernel/posix for that, and let's be honest, it's not 1976 :)
Yes, you can -- but i think you have to define this the way round. That you can use the STDIN of "sort" as STDOUT pipe for "cat". Have a look at the following, which works for me:
<?php
$txt = "a\nc\ne\nb\nd\n";
$fh = fopen('data://text/plain;base64,' . base64_encode($txt), 'r');
$sort_pipes = array();
$sort_proc = proc_open(
'sort',
array(
array('pipe', 'r'),
STDOUT
),
$sort_pipes
);
$cat_pipes = array();
$cat_proc = proc_open(
'cat',
array(
$fh,
$sort_pipes[0]
),
$cat_pipes
);
In the first two rows i defined a data stream from a text string that i do not have to rely on a file somewhere in the filesystem. Note, that i have a list of unsorted characters stored in the data stream (a, c, e, b, d). Running the script above should return a sorted list to STDOUT.
Note, that you can specify resources as descriptors, too. In this case you must omit the array notation, so:
STDOUT
instead of
array(STDOUT)
etc.
Btw.: you can even write directly to a file specified by a file name. You can find further information on the descriptor specification in the manual entry for proc_open at http://en.php.net/manual/de/function.proc-open.php
EDIT
The other way works too, of course: you can also write "cat" to an STDOUT pipe array('pipe', 'w') and use $cat_pipes[1] as STDIN for "sort". :)
I'm trying to get
`mysql -uroot`;
to enter the MySQL interactive client just as executing
$ mysql -uroot
from the shell does.
It's okay if the PHP script exists after (or before), but I need it to invoke the MySQL client.
I've tried using proc_open() and of course system(), exec() and passthru(). Wondering if anyone has any tips.
New solution:
<?php
$descriptorspec = array(
0 => STDIN,
1 => STDOUT,
2 => STDERR
);
$process = proc_open('mysql -uroot', $descriptorspec, $pipes);
Old one:
Save for tab completion (you could probably get it in there if you read out bytes with fread instead of using fgets), this gets you on your way, lots left to tweak:
<?php
$descriptorspec = array(
0 => array("pty"),
1 => array("pty"),
2 => array("pty")
);
$process = proc_open('mysql -uroot', $descriptorspec, $pipes);
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
stream_set_blocking(STDIN,0);
do {
echo stream_get_contents($pipes[1]);
echo stream_get_contents($pipes[2]);
while($in = fgets(STDIN)) fwrite($pipes[0],$in);
} while (1);
I guess it does work, but it's waiting for some input. Try sending some sql commands to it's stdin. Of course, since the backtick operator doesn't support IO remapping, you'll need more complex process handling.