我正在尝试在页面/连接关闭后继续PHP脚本。
用户将每1小时POLL脚本,我想返回一些json输出,并希望在后台继续脚本。我正在使用共享主机,我无法使用cron作业。
这是我尝试过的。
ob_start();
ignore_user_abort();
echo "JSON_OUTPUT GOES HERE";
$ob_length = ob_get_length();
header("Content-Type : text/plain",TRUE);
header("Content-Length : $ob_length",TRUE);
header("Connection : Close",TRUE);
flush();
ob_flush();
ob_end_flush();
sleep(3);
echo "You cant see me..";
exit();
我正在使用Codeigniter框架,但它不能在我的实时服务器上运行。它等待3秒钟,然后输出You cant see me..
。
请帮帮我。
项目托管在LINUX / WINDOWS / WAMP-SERVER共享主机中。
答案 0 :(得分:10)
function closeOutput($stringToOutput){
set_time_limit(0);
ignore_user_abort(true);
header("Connection: close\r\n");
header("Content-Encoding: none\r\n");
ob_start();
echo $stringToOutput;
$size = ob_get_length();
header("Content-Length: $size",TRUE);
ob_end_flush();
ob_flush();
flush();
}
您可以像
一样使用它$outputContent = 'Contentent Goes Here...';
closeOutput( $outputContent );
sleep(5);
//do some background works ...
exit();
答案 1 :(得分:2)
首先,请勿在{{1}}之后和Connection
之前使用空格,:
而不是Header: value
。其次,Header : value
不强制浏览器停止获取当前响应并显示空白页面。这里http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html第14.10章说明:Connection: close
那么如果您的代码有效,您如何尝试:
Connection: close in either the request or the response header fields indicates that the connection SHOULD NOT be considered 'persistent' (section 8.1) after the current request/response is complete
在浏览器中打开此php文件,并在2-3秒后关闭标签(即使您在屏幕上看不到任何内容),等待一段时间并检查文件是否已创建。它正在我的linux机器上工作。
答案 2 :(得分:2)
由于Red发布的这种很酷的可能性,我编写了一个小实用程序类,它提供了一个队列,您可以在其中添加Closures以供以后执行:
<?php
namespace Company\Project\Utilities;
/**
* Class ContinueUtility
*
* @package Company\Project\Utilities
*/
class ContinueUtility {
/**
* Stored tasks
* @var array
*/
static protected $tasks = array();
/** Constant for new line in HTTP Header */
const HEADER_NEW_LINE = "\r\n";
/**
* Add task (closure/function) to queue, with set arguments
*
* @param \Closure $task
* @param array $arguments
* @return void
*/
public static function addTask(\Closure $task, array $arguments = array()) {
self::$tasks[] = array(
'closure' => $task,
'arguments' => $arguments
);
}
/**
* Returns TRUE if tasks has been set, otherwise FALSE
*
* @return boolean
*/
public static function hasTasks() {
return !empty(self::$tasks);
}
/**
* Clear all previous set tasks
*
* @return void
*/
protected static function clearTasks() {
self::$tasks = array();
}
/**
* Execute all previous set tasks
*
* @return void
*/
protected static function executeTasks() {
foreach (self::$tasks as $task) {
call_user_func_array($task['closure'], $task['arguments']);
}
}
/**
* Execute and clear all previous set tasks
*
* @return void
*/
public static function executeAndClearTasks() {
self::executeTasks();
self::clearTasks();
}
/**
* Closes the HTTP connection to client immediately and outputs given string.
*
* @param string $instantOutput
* @return void
*/
public static function closeConnection($instantOutput = '') {
set_time_limit(0);
ignore_user_abort(TRUE);
header('Connection: close' . self::HEADER_NEW_LINE);
header('Content-Encoding: none' . self::HEADER_NEW_LINE);
ob_start();
echo $instantOutput;
$size = ob_get_length();
header('Content-Length: ' . $size, TRUE);
ob_end_flush();
ob_flush();
flush();
}
}
这是将新任务添加到队列的方法:
use Company\Project\Utilities\ContinueUtility;
$a = 4;
$b = 5;
ContinueUtility::addTask(function($a, $b){
sleep(5);
$c = a + b;
file_put_contents(__DIR__ . '/whatever.log', $a . '+' . $b . '=' . $c);
}, array(
$a, $b
));
这就是你如何触发所有以前添加的任务的执行:
ContinueUtility::closeConnection('Ready.');
ContinueUtility::executeAndClearTasks();
答案 3 :(得分:0)
如果您使用的是PHP-FPM,则更简单,更通用的解决方案是只执行fastcgi_finish_request();
摘自PHP.net文档
此函数将所有响应数据刷新到客户端并完成请求。这样可以执行耗时的任务,而无需打开与客户端的连接。
这是Symfony处理其onTerminate
的方式。