开发者

Run perl file from PHP script but not wait for output on Windows Server

Im trying to execute a p开发者_JAVA技巧erl script from within a php script. I have had this working using various methods such as exec, popen and proc_open but I have a couple of issues to get around which the good old Google isnt giving me the answers to.

I need to run the .pl script (passing one variable to the script which is a number) from within the php file but stop the php script from waiting until the .pl has finished (the .pl is likely to take 4-5 hours to run on the server). Im not expecting any return output from the perl script (the perl script logs its output to a mysql db) so I just need it to be running on the server and let the php script carry on.

There are some barriers to get past as its running on a Windows machines running apache, php, mysql.

I think Ive seen the solution for linux but it needs to stay on the Windows machine.

Im current trying a proc_open approach using the following code (the 35 on the proc_open line is a test id I need to pass to the perl script):

$descriptorspec = array(
0 => array("pipe","r"),
1 => array("pipe","w"),
2 => array("file","./error.log","a")
) ;

proc_close(proc_open('perl perlscript.pl 35', $descriptorspec, $pipes));

$i = 0;
while ($i < 1000) {
   echo ++$i;  
}

Now this code does execute the perl script but the while loop Ive placed after it (just for testing) never executes (ive not waited for the perl script to finish to see if it does) as it must be waiting for the .pl to finish.


I can see 3 options:

  • Use fork in your perl script to fork off the actual work with the parent process existing right after fork. This may not work correctly or at all on Windows, however, but worth a try.

    Please see the following "fork on Windows" references:

    • How can I fork a background processes from a Perl CGI script on Windows? (this mentions Proc::Background and Win32::Process->Create)
    • http://use.perl.org/~jjohn/journal/18668
    • http://www.xav.com/perl/lib/Pod/perlfork.html
  • If PHP can launch a URL request (similar to Perl's LWP or wget), then convert your Perl script into a CGI script (trivial), stick into your Apache's CGI directory, and call it via a proper URL to http://localhost/.... Then time out the URL request via either some iternal PHP timeout or regular HTTP timeout in worst case. In REALLY worst case, do the same trick from within Perl code since Perl can definitely support both the URL call via LWP libraries as well as timeout via alarm()

  • Have a scheduler launch your Perl script every X minutes. The script should start with the following logic: if (-e $flag_file) { unlink $flag_file; do_long_work() } else { exit 0; } where $flag_file is the special location on the server (say C:\temp\myscript_start_perl.txt), and do_long_work() contains the actual work needing to be done.

    Then, when PHP script needs to kick off the Perl script, it simply creates an empty flag file (the same C:\temp\myscript_start_perl.txt), which will be noticed by the Perl script next time the scheduler executes it.


There are two possibilities

  1. Use "start" program. You will not be able to use pipes, only command line arguments.

  2. Create an always-running Perl program (run at startup or using Win32::Daemon). Connect to it using sockets or http. It is easy, as there are plenty of ready servers on CPAN

Also, It may be possible to do this from another Perl program using Win32::Job or Win32::Process or some other CPAN module.


I recently published a module for tasks like this: Win32::Detached

Add it to your perl script and it will daemonize itself, allowing your PHP script to move on.


Thanks to everyone who answered this question. After much research and messing with different solutions I finally got something to work and suit our needs. Its far from perfect but hey it works so Im not going to complain too much.

Since this seems to be something other people want to know Id thought Id share my solution.

  1. I downloaded a tiny program called Hstart (40kb) from here: http://www.ntwind.com/software/utilities/hstart.html

  2. I extracted the files to c:\windows\system32.

The hstart program has the ability to run batch files without opening a command window. It wont work calling the .pl file directly so I had to create a .bat to call the .pl as follows.

  1. created a .bat file same directory as my .pl file which basically called the perl script using locally installed perl and passing a variable. As show here:

    perl script.pl %1

  2. In my PHP script I used the following command to call my perl file.

    $cmd = 'hstart /NOCONSOLE "run.bat ' . $id . '" > log.log'; exec($cmd);

  3. Running the php file causes hstart to open with noconsole due to the flag set, open the perl file with the $id I passed as a variable and send all output of the hidden console window to log.log as specified with my command. All I can see is perl.exe running in my task manager.

As I said far from perfect but it works.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜