Page 1 of 1

How to wait for a process executed by proc_open() in php?

Posted: Sat Jan 25, 2014 9:23 pm
by nitin1
**What i am doing :->**
I am taking a source file (say .c) through php by running apache server on local host. I am saving that file in "/code/" directory and compiling and executing this source file using proc_open() in php. Now i want to wait main php script until the process created by "proc_open()" terminates, so i used "pcntl_waitpid()". But i think there is a problem in using "pcntl_waitpid()" because the script after the "pcntl_waitpid()" is not executing.
Process created by "pcntl_waitpid()" takes input from "/code/input.txt" file and gives output to "/code/output.txt" file, so for redirecting purpose i am using proc_open() , so that i can easily redirect streams.

**My machine configuration:-**
OS -> Ubuntu 12.04 LTs
PHP 5.3.10
APACHE 2.2.22
Running on local host

**Permissions :-**
/code -> 777
Folder where main php file resides -> 777 (I know that 777 is not good due to security reasons , but as i am running script on local server so i have no problem with these permissions.)

**What i want :-**
Can any one tell me any way so that i can stop main php script until the process created by proc-open() terminates or if anyone can tell me other way to meet my requirement of redirection ?

**Here is a part of the code :**

Code: Select all

                $descriptors = array(
    			2 => array("pipe","w")
    		);
    
    	
    
    
    		$process = proc_open($cmd,$descriptors,$pipes,$code);
    
    		sleep(2);
    
    		if(is_resource($process))
    		{
    			$status = proc_get_status($process);
    			$pid = $status ["pid"];
    		
    			echo getmypid()."<br />";
    
    
    			echo $pid;
    
    			if(pcntl_waitpid($pid,$child_status) == -1)
    			{
    				fclose($pipes[2]);
    				proc_close($process);
    				exit("Sorry!Unable to compile the source_file.\n");
    
    			
    			}
    
    
    			while(!file_exists("/code/test"))
    			{
    
    				proc_close($process);
    				echo stream_get_contents($pipes[2]),"\n";
    				fclose($pipes[2]);
    				exit("Sorry!Unable to compile the source_file.\n");
    			}
    
    			echo "Compiled Successfully!\n";
    			echo "Running test cases...\n";
    
    			fclose($pipes[2]);
    
    			proc_close($process);
    
    		}
    		else
    		{
    			exit("Sorry!Unable to compile the source_file.\n");
    		}
  
**THANK YOU!**

Re: How to wait for a process executed by proc_open() in php

Posted: Sun Jan 26, 2014 7:17 am
by Weirdan
I'd imagine your child process stops waiting for you to read it's output from it's stdout/stderr, and since you don't do this before doing blocking wait, you essentially get a deadlock (child waits for parent to read its output while parent waits for child to finish).

Look into stream_select which lets you to react on changes in descriptors status, or just read from descriptors until there's no data. Alternatively, since you want to save the data into a file anyway, you may pass file resource instead of pipe descriptor into proc_open:

Code: Select all

$outfile = tempnam("/code", "out");
$out = fopen($outfile, "w");
$errfile = tempnam("/code", "err");
$err = fopen($errfile, "w");

$process = proc_open($cmd,array(1 => $out, 2 => $err));
// .......
This should prevent child process from hanging as stdout and stderr are redirected directly to files.

Re: How to wait for a process executed by proc_open() in php

Posted: Fri Jan 31, 2014 11:59 pm
by nitin1
Hello Weirdan! Thanx for reply
I have tried your method , but it is still giving me error .

Here is my code :

Code: Select all

<?php
        	$cmd = "gcc -g test.c -o test";
        
        	$descriptors = array(
        		2 => array("pipe","w+")
        	);
        
        	$process = proc_open($cmd,$descriptors,$pipes);
        
        	stream_set_blocking($pipes[2],0);
        
        	if($error = stream_get_contents($pipes[2]))
        	{
        		die($error);
        	}
        
        	fclose($pipes[2]);
        	proc_close($process);
        
        	$cmd = "./test";
        
        	$descriptors = array(
        		0 => array("file","input.txt","r"),
        		1 => array("file","output.txt","w"),
        		2 => array("pipe","w+")
        	);
        
        	$process = proc_open($cmd,$descriptors,$pipes);
        
        	stream_set_blocking($pipes[2],0);
        
        	if($error = stream_get_contents($pipes[2]))
        	{
        		die($error);
        	}
        	else
        	{
        	/*line -> 38 */	stream_set_blocking($pipes[1],1);
        
        	/*line -> 40 */	$read = array($pipes[1],$pipes[2]);
        	  	$write = NULL;
        		$except = NULL;
        		$tv_sec = 0;
        		$tv_usec = 1000;
        
       /*line -> 46*/ 		if(false === ($rs = stream_select($read,$write,$except,$tv_sec,$tv_usec)) )
        		{
        			die("Error in stream_reader");
        		}
        		
       /*line -> 51*/ 		fclose($pipes[0]);
       /*line -> 52*/ 		fclose($pipes[1]);
        		fclose($pipes[2]);
        
        		proc_close($process);
        	}
        
        	$out = @fopen("output.txt","r");
        	$test = @fopen("test.txt","r");
        
        	while((($out_buffer = fgets($out)) !== false) && (($test_buffer = fgets($test)) !== false))
        	{
        		if($out_buffer !== $test_buffer)
        		{
        			die("Error in output.");
        		}
        	}
        
        	if(!feof($out) || !feof($test))
        	{
        		die("Error in output.");
        	}
        
        
        ?>
AND HERE IS MY ERROR :


Undefined offset: 1 in file.php on line 38
stream_set_blocking() expects parameter 1 to be resource, null given in file.php on line 38
Undefined offset: 1 in file.php on line 40
stream_select(): supplied argument is not a valid stream resource in file.php on line 46
stream_select(): supplied argument is not a valid stream resource in file.php on line 46
stream_select(): supplied argument is not a valid stream resource in file.php on line 46
Undefined offset: 0 in file.php on line 51
fclose() expects parameter 1 to be resource, null given in file.php on line 51
Undefined offset: 1 in file.php on line 52
fclose() expects parameter 1 to be resource, null given in file.php on line 52


Please help me , i have strucked here ....please

Re: How to wait for a process executed by proc_open() in php

Posted: Sat Feb 01, 2014 10:33 am
by Weirdan
You only get a pipe for every "pipe" element you passed in descriptors to proc_open. You don't get a pipe for "file" element. That's why you get undefined errors for $pipes[0] and $pipes[1] - because you specified corresponding elements in $desc as files.

If you redirect everything to files you don't need select() at all.