2

I'm writing a couple of PHP scripts to execute a program, capture it's STDOUT and capture the return code when it finishes. These programs could return instantly, or finish in 20 mins, so I need to monitor when they finish.

I can't find a way to start a program in the background and capture the return code [to an external log file]. If I simply use exec, or proc_open, my php script will block, which is no good when the process takes 20 mins.

Even if I can't capture the return code, I need to know when the process has finished. (I can put error codes in the STDOUT instead)

I can use exec("start my.exe"); and catch the STDOUT, but I can't get the return code (and also not know when it's finished)

I've thought of doing it via a batch file exec(start my.bat); and in the batch file catch the return code, but my command line has dynamic options, so I'd quite to do something like;
exec("start cmd \"echo hello\");

Edit: But I've not found a way to dynamically make a batch-command list on the command line. If anyone knows an approach I'd be very grateful.
cmd /C "echo hello" is the solution to this

Doesn't need to be cross-platform, strictly windows (xp-7)

Soylent Graham
  • 847
  • 1
  • 12
  • 22

2 Answers2

2

Have a look at this: Executing background processes from PHP on Windows. It explains some of the possibilities.

Álvaro González
  • 142,137
  • 41
  • 261
  • 360
0

Okay, this is where I've gotten to so far. I figured I don't need a dynamic batch file, I can just supply args (duh). So I can just call exec("start Batch.bat log.txt stdout.txt c:\my.exe a b c"); and monitor the log files with some ajax (as I do now)

REM first 2 params are log filenames
set LogFilename=%1
shift
set StdOutFilename=%1
shift

REM Code to concatonate all following params from here
REM http://stackoverflow.com/questions/761615/is-there-a-way-to-indicate-the-last-n-parameters-in-a-batch-file
set params=%1
:loop
shift
if [%1]==[] goto afterloop
set params=%params% %1
goto loop
:afterloop

REM command line is everything after the log-filename param
set CommandLine=%params%
@echo log: %LogFilename%
@echo stdout: %StdOutFilename%
@echo command: %CommandLine%

if ["%LogFilename%"]==[]        exit 255;
if ["%StdOutFilename%"]==[] exit 254;
if ["%CommandLine%"]==[]        exit 253;

REM execute command hidden(/B), wait for it to finish so we can get the return code (/WAIT) and output to stdlog
@start /B /WAIT %CommandLine% >> %StdOutFilename%

REM log return code "RET X"
@echo RET %ERRORLEVEL% >> %LogFilename%

And the calling PHP code;

$BatchCommandLine = "start /D $Cwd /B /WAIT execute.bat $LogName %StdLogName $Exe $Params";  
$OutputLine = exec( $BatchCommandLine, $Output, $ReturnCode );  
if ( $ReturnCode != 0 )  
echo "Batch file failed to execute";  

*EDIT: * Oops, exec() doesn't launch in the background even with start. Still, solved my other problems...

Soylent Graham
  • 847
  • 1
  • 12
  • 22
  • Obviously that should be ERRORLEVEL and not %ERRORLEVEL% http://blogs.msdn.com/b/oldnewthing/archive/2008/09/26/8965755.aspx – Soylent Graham Dec 10 '10 at 14:50