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

时间:2012-07-15 14:15:38

标签: php magento

我想要执行一个大型的数据库密集型脚本,但不需要等待该过程完成。我只想调用脚本,让它在后台运行,然后重定向到另一个页面。

编辑: 我正在使用Windows 7上的本地Zend社区服务器。 我可以访问项目所在的远程linux服务器,所以我可以在linux或windows上执行此操作。

我有这个

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;
}

这完美无缺,但是magento应用程序会挂起以完成整个过程。它做我所期望的一切,不时记录到文件,并对它的运行方式感到满意。现在我想做的就是让这个脚本启动,控制器动作不会挂起,而是重定向,那就是那个。根据我对exec()的了解,你可以通过改变我上面调用exec()的方式来实现:

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

我从here

获取的

如果我添加“> / dev / null 2>& 1&”对于exec调用,它不会按预期等待,但它不再执行脚本。有人可以告诉我为什么,如果是的话,请告诉我如何让这个工作起来好吗?

这可能是与许可相关的问题吗?

感谢

编辑:我假设如果我用(/ dev / null 2>& 1&)调用exec函数将任何输出记录到文件将是一个问题,因为这会取消它。那是对的吗?

5 个答案:

答案 0 :(得分:2)

在花时间充分了解我自己的问题及其解决方法之后,我已经准备好了我的解决方案。

感谢所有人提出的建议,并在提出问题时放弃了我的随意和毫无准备。

上述问题的答案取决于许多因素,例如您所指的操作系统,您正在运行的php模块,甚至是您正在运行的Web服务器。所以,如果我不得不再次提出这个问题,那么我要做的第一件事就是陈述我的设置。

我想在两种环境中实现这一目标:

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

要做到这一点,我希望它在部署到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
}

简而言之,一旦你理解了问题就提出问题。有很多方法可以实现上述目标,这只是一个适用于我的开发和生产环境的解决方案。

感谢所有人的帮助。

答案 1 :(得分:1)

PHP popen

从文档中(这应该可以帮助你做其他事情,而这个过程正在运行;不确定关闭当前的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);

解决方案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.

答案 2 :(得分:1)

您可以编写一个包装脚本,比如说createInstance.sh

#! /bin/bash

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

然后从PHP中调用脚本:

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

应该从脚本中立即分离新的php进程。如果这没有帮助,你可能会尝试使用SIGABRT,SIGTERM或SIGINT而不是SIGHUP,我不知道确切地发送了哪个信号。

答案 3 :(得分:1)

我已经能够使用:

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

$command例如:

php script.php --parameter 1

我注意到了一些奇怪的行为。例如,运行mysql命令行不起作用,只有php脚本似乎可以工作。

此外,运行cd /path/to/dir && php nohup $command ...也不起作用,我必须在PHP脚本中chdir(),然后运行命令使其工作。

答案 4 :(得分:0)

Zend Server附带的PHP可执行文件似乎是导致尝试在后台运行脚本(使用exec中的&符号和运算符)失败的原因。

我们使用我们的标准PHP可执行文件测试了它,它工作正常。这与Zend Server附带的版本有关,虽然我们有限的尝试弄清楚发生了什么并没有改变任何东西。