想从主PHP脚本运行后台PHP脚本

时间:2013-08-03 20:08:52

标签: php windows email shell-exec

在构建要回馈给用户的页面时,我想提交一个后台脚本来对数据库中的数据进行一些数值分析,并通过电子邮件将结果发送给用户。此过程可能需要一分钟左右,因此我不希望在运行时延迟页面服务。

有没有办法从构建页面的脚本触发另一个PHP脚本,以便它可以发送页面并在另一个脚本在后台运行时完成?

测试时,这个TEST.PHP:

<?php
set_time_limit(0);
mail ('myemail@myemail.com','Test Email from ClockPie', 'foobar');
?>

然后我把它放在构建页面服务的脚本中:

...
shell_exec ('test.php'); 
...

我在Windoze 7家庭高级版下运行。这有什么明显的错误吗?

是的,我知道这实际上是一个重复的问题,还有其他关于同样事情的现有问题,但我在StackOverflow这里只是添加 peon 来简单地添加评论并参与讨论: - (

5 个答案:

答案 0 :(得分:-1)

shell_exec()就像坐在命令提示符下键入字符串值并按回车键。你不能只输入“test.php”并激活它,你需要运行PHP,并将它指向你的php文件。

根据您安装php的方式,您可以简单地将其更改为shell_exec('php test.php');,或者您可能必须提供PHP的路径,如shell_exec('C:\php\bin\php.exe test.php');。路径取决于您的环境。

在您显示的代码中,如果您只是发送一封电子邮件,那么这不应该花费几秒钟,所以我甚至不会沿着这条路走下去。但我不认为这是您的代码的最终结果,只是一个示例。

答案 1 :(得分:-1)

您可以做的是输出页面并flush(),以便将所有数据发送给用户。然后你发了电子邮件。用户将看到该页面,但在后台仍在加载。这不需要shell_exec();

之类的任何内容

像phpBB这样的软件也可以使用这种方法来处理cron作业需要相当长的时间。

flush()文档:http://php.net/manual/en/function.flush.php

基础程序架构:

  1. 构建&amp;回声页
  2. flush()
  3. 发送电子邮件

答案 2 :(得分:-1)

以下代码适用于我的系统。请注意,我只是一个业余爱好者,而不是专家,所以这可能不属于“最佳实践”类别,我不知道安全隐患可能是什么,但这绝对有效,创建了多个线程,所有运行同时。别介意文件夹名称'卡路里'。当我把这个示例代码汇总在一起时,恰好是我正在处理的文件夹。

main.php:

error_log('Hello, world, from main!');

$numberOfThreadsToCreate = 3;

for($i = 0; $i < $numberOfThreadsToCreate; ++$i) {
    error_log("Main starting child {$i}");

    $fp = fsockopen('localhost', 8888);
    if(!$fp) {
        error_log("$errstr ($errno)");
        exit;
    }

    $firstSleep = $numberOfThreadsToCreate - $i;
    $header = "GET /Calories/thread.php?threadID={$i}&firstSleep={$firstSleep}"
                . " HTTP/1.1\r\n"
                . "Host: localhost\r\n"
                . "Connection: Close\r\n\r\n";

    $r = fputs($fp, $header); 
    fclose($fp);

    sleep(1);
}

for($i = 0; $i < 5; ++$i) {
    sleep(1);
    error_log('Main is still running');
}

error_log("Goodbye, cruel world, from main!");


thread.php

$myThreadID = $_GET['threadID'];
$sleep = $_GET['firstSleep'];

error_log("Hello, world, from child thread, ID={$myThreadID}!");
for($i = 0; $i < 5; ++$i) {
    error_log("Child {$myThreadID} sleeping for {$sleep} seconds");
    sleep($sleep);
    $sleep = 1;
}

error_log("Goodbye, cruel world, from child thread, ID={$myThreadID}!");

日志文件结果:

Hello, world, from main!
Main starting child 0
Hello, world, from child thread, ID=0!
Child 0 sleeping for 3 seconds
Main starting child 1
Hello, world, from child thread, ID=1!
Child 1 sleeping for 2 seconds
Main starting child 2
Hello, world, from child thread, ID=2!
Child 2 sleeping for 1 seconds
Child 1 sleeping for 1 seconds
Child 2 sleeping for 1 seconds
Child 0 sleeping for 1 seconds
Child 1 sleeping for 1 seconds
Child 2 sleeping for 1 seconds
Child 0 sleeping for 1 seconds
Main is still running
Child 1 sleeping for 1 seconds
Child 2 sleeping for 1 seconds
Child 0 sleeping for 1 seconds
Main is still running
Child 1 sleeping for 1 seconds
Child 2 sleeping for 1 seconds
Child 0 sleeping for 1 seconds
Main is still running
Goodbye, cruel world, from child thread, ID=1!
Goodbye, cruel world, from child thread, ID=2!
Main is still running
Goodbye, cruel world, from child thread, ID=0!
Main is still running
Goodbye, cruel world, from main!

答案 3 :(得分:-1)

如果要分叉另一个PHP进程,则需要使用pcntl_fork。但是我不认为这是最好的方法。相反,我会让浏览器访问的脚本将要处理的数据添加到队列中。然后设置一个计划任务,运行每隔“x”分钟,处理队列并在完成后通过电子邮件发送给用户。

当然,我假设如果队列中实际上没有任何内容(例如,它需要几毫秒才能完成),您将使此预定脚本非常轻量级。如果没有,你将每隔几分钟就停止服务器,在这种情况下,查看类似pcntl_fork的内容将是更好的解决方案。

这样做的一个缺点是,如果将其设置为运行,例如每5分钟一次,但处理数据只需2分钟,用户将需要等待最多3分钟才能收到电子邮件。如果这是一个问题,请调整它以便更频繁地运行。

答案 4 :(得分:-1)

你可以使用shell_exec()来运行你的'sub php script'asynchronously,这意味着它将在你的主php脚本继续运行时在后台运行,通过附加激活你的'sub php'的命令脚本'与&amp;符号。所以,它会是这样的:

$cmd="php /path/to/you/php/sub/script.php &";
shell_exec($cmd);
//main script continues running here, while sub script runs in the background...