简体   繁体   English

从PHP脚本运行perl文件,但不等待Windows Server上的输出

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

Im trying to execute a perl script from within a php script. 我试图从一个PHP脚本中执行一个Perl脚本。 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. 我已经使用exec,popen和proc_open等各种方法进行了此工作,但是我遇到了一些问题,好的老Google并没有给我答案。

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). 我需要从php文件中运行.pl脚本(将一个变量传递给数字的脚本),但要停止php脚本等待.pl完成(.pl可能需要4-5个小时在服务器上运行)。 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. 我不希望perl脚本返回任何输出(perl脚本将其输出记录到mysql db),所以我只需要它在服务器上运行并让php脚本继续运行即可。

There are some barriers to get past as its running on a Windows machines running apache, php, mysql. 由于它在运行apache,php,mysql的Windows计算机上运行,​​因此存在一些障碍。

I think Ive seen the solution for linux but it needs to stay on the Windows machine. 我想我已经看过Linux的解决方案,但它必须保留在Windows机器上。

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): 我目前正在尝试使用下面的代码(proc_open行上的35是我需要传递给perl脚本的测试ID)使用proc_open方法:

$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. 现在,此代码确实执行了perl脚本,但是Ive放置在它后面的while循环(仅用于测试)从未执行(即,我没有等待perl脚本完成以查看是否执行),因为它必须等待.pl完成。

I can see 3 options: 我可以看到3个选项:

  • Use fork in your perl script to fork off the actual work with the parent process existing right after fork. 在您的perl脚本中使用fork在fork之后立即存在的父进程中完成实际工作。 This may not work correctly or at all on Windows, however, but worth a try. 但是,这可能无法正常运行或根本无法在Windows上运行,但是值得一试。

    Please see the following " fork on Windows" references: 请参阅以下“ Windows上的fork ”参考:

  • 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/... . 如果PHP可以启动URL请求(类似于Perl的LWP或wget),则将您的Perl脚本转换为CGI脚本(简单),粘贴到Apache的CGI目录中,并通过适当的URL调用它到http://localhost/... Then time out the URL request via either some iternal PHP timeout or regular HTTP timeout in worst case. 然后在某些情况下,通过某些内部PHP超时或常规HTTP超时来使URL请求超时。 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() 在非常糟糕的情况下,请在Perl代码中执行相同的技巧,因为Perl绝对可以支持通过LWP库进行URL调用以及通过alarm()超时

  • Have a scheduler launch your Perl script every X minutes. 让调度程序每X分钟启动一次Perl脚本。 The script should start with the following logic: if (-e $flag_file) { unlink $flag_file; do_long_work() } else { exit 0; } 该脚本应以以下逻辑开头: if (-e $flag_file) { unlink $flag_file; do_long_work() } else { exit 0; } if (-e $flag_file) { unlink $flag_file; do_long_work() } else { exit 0; } 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. if (-e $flag_file) { unlink $flag_file; do_long_work() } else { exit 0; } ,其中$flag_file是服务器上的特殊位置(例如C:\\temp\\myscript_start_perl.txt ),而do_long_work()包含需要完成的实际工作。

    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. 然后,当PHP脚本需要启动Perl脚本时,它仅创建一个空的标志文件(相同的C:\\temp\\myscript_start_perl.txt ),Perl脚本将在下次调度程序执行该文件时注意到该文件。

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). 创建一个始终运行的Perl程序(在启动时运行或使用Win32 :: Daemon运行)。 Connect to it using sockets or http. 使用套接字或http连接到它。 It is easy, as there are plenty of ready servers on CPAN 这很容易,因为CPAN上有很多现成的服务器

Also, It may be possible to do this from another Perl program using Win32::Job or Win32::Process or some other CPAN module. 同样,使用Win32 :: Job或Win32 :: Process或某些其他CPAN模块,可以从另一个Perl程序中执行此操作。

I recently published a module for tasks like this: Win32::Detached 我最近发布了一个用于执行以下任务的模块: Win32 :: Detached

Add it to your perl script and it will daemonize itself, allowing your PHP script to move on. 将其添加到您的perl脚本中,它将自行守护进程,从而允许您的PHP脚本继续运行。

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. 由于这似乎是其他人想知道的事情,因此Id以为Id分享了我的解决方案。

  1. I downloaded a tiny program called Hstart (40kb) from here: http://www.ntwind.com/software/utilities/hstart.html 我从此处下载了一个名为Hstart(40kb)的微型程序: http ://www.ntwind.com/software/utilities/hstart.html

  2. I extracted the files to c:\\windows\\system32. 我将文件提取到c:\\ windows \\ system32。

The hstart program has the ability to run batch files without opening a command window. hstart程序无需打开命令窗口即可运行批处理文件。 It wont work calling the .pl file directly so I had to create a .bat to call the .pl as follows. 它无法直接调用.pl文件,因此我必须创建一个.bat来按如下方式调用.pl。

  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. 创建了一个与我的.pl文件相同目录的.bat文件,该文件基本上使用本地安装的perl并传递了一个变量来调用perl脚本。 As show here: 如此处所示:

    perl script.pl %1 perl script.pl%1

  2. In my PHP script I used the following command to call my perl file. 在我的PHP脚本中,我使用以下命令来调用我的perl文件。

    $cmd = 'hstart /NOCONSOLE "run.bat ' . $id . '" > log.log'; $ cmd ='hstart / NOCONSOLE“ run.bat'。$ id。'”> log.log'; exec($cmd); 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. 运行php文件会导致hstart由于设置了标志而用noconsole打开,使用我作为变量传递的$ id打开perl文件,并将隐藏的控制台窗口的所有输出发送到我的命令指定的log.log中。 All I can see is perl.exe running in my task manager. 我所看到的只是在任务管理器中运行的perl.exe。

As I said far from perfect but it works. 正如我所说的那样,它远非完美,但确实可行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM