简体   繁体   English

如何使用php exec()来运行另一个脚本并在后台运行,而不是等待脚本完成

[英]how to use php exec(), to run another script and run in the backround, and not wait for the script to finish

I am wanting to execute a large, database intensive script, but do not need to wait for the process to finish. 我想执行一个大型的数据库密集型脚本,但是不需要等待该过程完成。 I would simply like to call the script, let it run in the background and then redirect to another page. 我只想调用该脚本,让它在后台运行,然后重定向到另一个页面。

EDIT: i am working on a local Zend community server, on Windows 7. I have access to remote linux servers where the project also resides, so i can do this on linux or windows. 编辑:我正在Windows 7上的本地Zend社区服务器上工作。我可以访问项目所在的远程linux服务器,因此我可以在linux或Windows上执行此操作。

i have this 我有这个

public function createInstanceAction()
{
    //calls a seperate php process which creates the instance
    exec('php -f /path/to/file/createInstance.php');


    Mage::getSingleton('adminhtml/session')->addSuccess(Mage::helper('adminhtml')->__('Instance creation process started. This may take up to a few minutes.'));
    $this->_redirect('instances/adminhtml_instances/');
    return;
}

this works perfectly, but the magento application hangs around for the process to finish. 这可以完美运行,但是magento应用程序会挂起以完成该过程。 it does everything i expect, logging to file from time to time, and am happy with how its running. 它可以完成我所期望的一切,不时记录到文件中,并对它的运行方式感到满意。 Now all i would like to do is have this script start, the controller action does not hang around, but instead redirects and thats that. 现在,我要做的就是启动此脚本,控制器动作不会挂起,而是重定向并完成。 from what I have learnt about exec(), you can do so by changing the way i call exec() above, to : 从我对exec()的了解中,您可以通过将上述调用exec()的方式更改为:

exec('php -f /path/to/file/createInstance.php > /dev/null 2>&1 &');

which i took from here 我从这里带走的

if i add "> /dev/null 2>&1 &" to the exec call, it doesnt wait around as expected, but it does not execute the script anymore. 如果我将“> / dev / null 2>&1&”添加到exec调用中,它不会按预期等待,但不再执行脚本了。 Could someone tell me why, and if so, tell me how i can get this to work please? 有人可以告诉我原因,如果可以,请告诉我如何使它工作?

Could this be a permission related issue? 这可能是与许可相关的问题吗?

thanks 谢谢

EDIT : Im assuming it would be an issue to have any output logged to file if i call the exec function with (/dev/null 2>&1 &) as that would cancel that. 编辑:我假设如果我用(/ dev / null 2>&1&)调用exec函数,将任何输出记录到文件中都会是一个问题,因为那会取消它。 is that correct? 那是对的吗?

After taking time to fully understand my own question and the way it could be answered, i have prepared my solution. 在花了一些时间完全理解我自己的问题以及可以解决该问题的方式之后,我准备了解决方案。

Thanks to all for your suggestions, and for excusing my casual, unpreparedness when asking the question. 感谢所有您的建议,并在提出问题时原谅我的随意,准备不足。

The answer to the above question depends on a number of things, such as the operating system you are referring to, which php modules you are running and even as far as what webserver you are running. 上述问题的答案取决于许多因素,例如您所指的操作系统,正在运行的php模块,甚至运行的Web服务器。 So if i had to start the question again, the first thing i would do is state what my setup is. 因此,如果我不得不再次开始这个问题,我要做的第一件事就是说明我的设置是什么。

I wanted to achieve this on two environments : 我想在两个环境中实现这一目标:

1.) Windows 7 running Zend server community edition. 1.)Windows 7运行Zend服务器社区版。 2.) Linux (my OS is Linux odysseus 2.6.32-5-xen-amd64 #1 SMP Fri Sep 9 22:23:19 UTC 2011 x86_64) 2.)Linux(我的操作系统是Linux Odysseus 2.6.32-5-xen-amd64#1 SMP Fri Sep 9 22:23:19 UTC 2011 x86_64)

to get this right, i wanted it to work either way when deploying to windows or linux, so i used php to determine what the operating system was. 为了达到这个目的,我希望它在部署到Windows或linux时都能以任何一种方式工作,所以我使用php来确定操作系统是什么。

public function createInstanceAction()
{

    //determines what operating system is Being used 
    if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')
    {
        //This is a windows server

        //call a seperate php process to run independently from the broswer action

        pclose(popen("start php /path/to/script/script.php","r"));

    }
    else
    {
        //assuming its linux, but in fact it simply means its not windows
        // to check for linux specifically use (strtoupper(substr(PHP_OS, 0, 3)) === 'LIN')
        exec('php -f /path/to/file/script.php >/dev/null 2>&1 &');
    }
    //the browser will not hang around for this process to complete, and you can contimue with whatever actions you want.

    //myscript log any out put so i can capture info as it runs
}

In short, ask questions once you understand them. 简而言之,一旦您理解了问题,就可以提出问题。 there are many ways to to achieve the above, and this is just one solution that works for my development and production environments. 有多种方法可以实现上述目标,而这只是一种适用于我的开发和生产环境的解决方案。

thanks for the help all. 谢谢大家的帮助。

PHP popen PHP Popen

From the docs (this should help you do other stuff, while that process is working; not sure if closing the current PHP process will kill the opened process): 从文档中获取信息(在该进程正常运行时,这应该可以帮助您完成其他工作;不确定关闭当前PHP进程是否会杀死打开的进程):

/* Add redirection so we can get stderr. */
$handle = popen('/path/to/executable 2>&1', 'r');
echo "'$handle'; " . gettype($handle) . "\n";
$read = fread($handle, 2096);
echo $read;
pclose($handle);

Solution 2: Trick the browser to close the connection (assuming there is a browser involved): 解决方案2:欺骗浏览器以关闭连接(假定涉及浏览器):

ob_start();
?><html><!--example html body--></html><?php
$strContents=ob_get_clean(); 

header("Connection: Close");
header("Content-encoding: none");//doesn't work without this, I don't know why:(

ignore_user_abort(true);

header("Content-type: text/html");
header("Content-Length: ".strlen($strContents));
echo $strContents;

flush();
//at this point a real browser would close the connection and finish rendering; 
//crappy http clients like some curl implementations (and not only) would wait for the server to close the connection, then finish rendering/serving results...:(

//TODO: add long running operations here, exec, or whatever you have.

You could write a wrapper-script, say createInstance.sh like 您可以编写一个包装脚本,比如说createInstance.sh

#! /bin/bash

trap "" SIGHUP
php -f "$1" > logfile.txt 2>&1 &

Then you call the script from within PHP: 然后,您从PHP中调用脚本:

exec('bash "/path/to/file/createInstance.sh"');

which should detach the new php process most instantly from the script. 这应该最立即从脚本中分离新的php进程。 If that doesen't help, you might try to use SIGABRT, SIGTERM or SIGINT instead of SIGHUP, I don't know exactly which signal is sent. 如果那没有帮助,您可以尝试使用SIGABRT,SIGTERM或SIGINT而不是SIGHUP,我不知道确切发送哪个信号。

I've been able to use: 我已经可以使用:

shell_exec("nohup $command  > /dev/null & echo $!")

Where $command is for example: $command为例:

php script.php --parameter 1

I've noticed some strange behavior with this. 我注意到了一些奇怪的行为。 For example running mysql command line doesn't work, only php scripts seem to work. 例如,运行mysql命令行不起作用,只有php脚本似乎起作用。

Also, running cd /path/to/dir && php nohup $command ... doesn't work either, I had to chdir() within the PHP script and then run the command for it to work. 另外,运行cd /path/to/dir && php nohup $command ...也不起作用,我不得不在PHP脚本中使用chdir() ,然后运行命令使其正常工作。

The PHP executable included with Zend Server seems to be what's causing attempts to run a script in the background (using the ampersand & operator in the exec) to fail. Zend Server附带的PHP可执行文件似乎是导致尝试在后台运行脚本(使用exec中的&运算符)的尝试失败的原因。

We tested this using our standard PHP executable and it worked fine. 我们使用标准的PHP可执行文件对此进行了测试,并且效果很好。 It's something to do with the version shipped with Zend Server though our limited attempts to figure out what that was going on have not turned anything up. 这与Zend Server随附的版本有关,尽管我们有限的尝试来弄清楚发生了什么,但并没有发现任何问题。

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

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