etiquetas - inicio y fin en php
continuar procesando php después de enviar la respuesta http (10)
Hay otro enfoque y vale la pena considerarlo si no quieres manipular los encabezados de respuesta. Si inicia un hilo en otro proceso, la función llamada no esperará su respuesta y volverá al navegador con un código http finalizado. Deberá configurar pthread .
class continue_processing_thread extends Thread
{
public function __construct($param1)
{
$this->param1 = $param1
}
public function run()
{
//Do your long running process here
}
}
//This is your function called via an HTTP GET/POST etc
function rest_endpoint()
{
//do whatever stuff needed by the response.
//Create and start your thread.
//rest_endpoint wont wait for this to complete.
$continue_processing = new continue_processing_thread($some_value);
$continue_processing->start();
echo json_encode($response)
}
Una vez que ejecutamos $ continue_processing-> start () PHP no esperará el resultado de retorno de este hilo y, por lo tanto, hasta el punto rest_endpoint. Se hace.
Algunos enlaces para ayudar con pthreads
Buena suerte.
Mi script es llamado por el servidor. Desde el servidor, recibiré ID_OF_MESSAGE
y TEXT_OF_MESSAGE
.
En mi script ANSWER_TO_ID
el texto entrante y ANSWER_TO_ID
respuesta con params: ANSWER_TO_ID
y RESPONSE_MESSAGE
.
El problema es que estoy enviando una respuesta al "ID_OF_MESSAGE"
ID_OF_MESSAGE "ID_OF_MESSAGE"
, pero el servidor que me envía el mensaje me enviará el mensaje tal como se me entregó (significa que puedo enviarle una respuesta a ese ID), después de recibir la respuesta http 200.
Una de las soluciones es guardar el mensaje en la base de datos y crear un cron que se ejecutará cada minuto, pero necesito generar un mensaje de respuesta de inmediato.
¿Hay alguna solución sobre cómo enviar al servidor http respuesta 200 y que continúe ejecutando script php?
Muchas gracias
He visto muchas respuestas aquí que sugieren usar ignore_user_abort(true);
pero este código no es necesario. Todo lo que hace es asegurarse de que su script continúe ejecutándose antes de enviar una respuesta en caso de que el usuario aborte (cerrando su navegador o presionando escape para detener la solicitud). Pero eso no es lo que estás preguntando. Estás pidiendo continuar la ejecución DESPUÉS de que se envíe una respuesta. Todo lo que necesitas es lo siguiente:
// Buffer all upcoming output...
ob_start();
// Send your response.
echo "Here be response";
// Get the size of the output.
$size = ob_get_length();
// Disable compression (in case content length is compressed).
header("Content-Encoding: none");
// Set the content length of the response.
header("Content-Length: {$size}");
// Close the connection.
header("Connection: close");
// Flush all output.
ob_end_flush();
ob_flush();
flush();
// Close current session (if it exists).
if(session_id()) session_write_close();
// Start your background work here.
...
Si le preocupa que su trabajo de fondo tarde más tiempo que el límite de tiempo predeterminado de ejecución del script de PHP, entonces pegue set_time_limit(0);
en la cima.
Le hice esta pregunta a Rasmus Lerdorf en abril de 2012, citando estos artículos:
- https://www.zulius.com/how-to/close-browser-connection-continue-execution/
- cerrar una conexión temprano
- http://php.net/manual/en/features.connection-handling.php
Sugerí el desarrollo de una nueva función incorporada de PHP para notificar a la plataforma que no se generará ningún otro resultado (en stdout?) (Tal función podría encargarse de cerrar la conexión). Rasmus Lerdorf respondió:
Ver Gearman . Realmente no quieres que tus servidores web de frontend hagan un procesamiento back-end como este.
Puedo ver su punto, y apoyar su opinión para algunas aplicaciones / escenarios de carga! Sin embargo, bajo algunos otros escenarios, las soluciones de vcampitelli et al, son buenas.
Modificó la respuesta por @vcampitelli un poco. No creas que necesitas el encabezado close
. Estaba viendo encabezados duplicados cercanos en Chrome.
<?php
ignore_user_abort(true);
ob_start();
echo ''{}'';
header($_SERVER["SERVER_PROTOCOL"] . " 202 Accepted");
header("Status: 202 Accepted");
header("Content-Type: application/json");
header(''Content-Length: ''.ob_get_length());
ob_end_flush();
ob_flush();
flush();
sleep(10);
Pasé unas horas sobre este tema y he venido con esta función que funciona en Apache y Nginx:
/**
* respondOK.
*/
protected function respondOK()
{
// check if fastcgi_finish_request is callable
if (is_callable(''fastcgi_finish_request'')) {
/*
* This works in Nginx but the next approach not
*/
session_write_close();
fastcgi_finish_request();
return;
}
ignore_user_abort(true);
ob_start();
$serverProtocole = filter_input(INPUT_SERVER, ''SERVER_PROTOCOL'', FILTER_SANITIZE_STRING);
header($serverProtocole.'' 200 OK'');
header(''Content-Encoding: none'');
header(''Content-Length: ''.ob_get_length());
header(''Connection: close'');
ob_end_flush();
ob_flush();
flush();
}
Puede llamar a esta función antes de su procesamiento prolongado.
Por algunas razones oscuras, ninguna de estas soluciones funciona cuando se usa MAMP PRO (Apache, MySQL, PHP).
Sí. Puedes hacerlo:
ignore_user_abort(true);
set_time_limit(0);
ob_start();
// do initial processing here
echo $response; // send the response
header(''Connection: close'');
header(''Content-Length: ''.ob_get_length());
ob_end_flush();
ob_flush();
flush();
// now the request is sent to the browser, but the script is still running
// so, you can continue...
Si está utilizando el procesamiento FastCGI o PHP-FPM, puede:
session_write_close(); //close the session
fastcgi_finish_request(); //this returns 200 to the user, and processing continues
// do desired processing ...
$expensiveCalulation = 1+1;
error_log($expensiveCalculation);
Fuente: http://fi2.php.net/manual/en/function.fastcgi-finish-request.php
Utilizo la función php register_shutdown_function para esto.
void register_shutdown_function ( callable $callback [, mixed $parameter [, mixed $... ]] )
http://php.net/manual/en/function.register-shutdown-function.php
Editar : Lo anterior no está funcionando. Parece que fui engañado por alguna documentación antigua. El comportamiento de register_shutdown_function ha cambiado desde el link link PHP 4.1
en caso de utilizar php file_get_contents, el cierre de la conexión no es suficiente. php aún espera la eof bruja enviada por el servidor.
mi solución es leer ''Contenido-Longitud:''
aquí hay una muestra:
response.php:
<?php
ignore_user_abort(true);
set_time_limit(500);
ob_start();
echo ''ok''."/n";
header(''Connection: close'');
header(''Content-Length: ''.ob_get_length());
ob_end_flush();
ob_flush();
flush();
sleep(30);
Observe la "/ n" en respuesta a la línea de cierre, si no la leída fget mientras espera eof.
read.php:
<?php
$vars = array(
''hello'' => ''world''
);
$content = http_build_query($vars);
fwrite($fp, "POST /response.php HTTP/1.1/r/n");
fwrite($fp, "Content-Type: application/x-www-form-urlencoded/r/n");
fwrite($fp, "Content-Length: " . strlen($content) . "/r/n");
fwrite($fp, "Connection: close/r/n");
fwrite($fp, "/r/n");
fwrite($fp, $content);
$iSize = null;
$bHeaderEnd = false;
$sResponse = '''';
do {
$sTmp = fgets($fp, 1024);
$iPos = strpos($sTmp, ''Content-Length: '');
if ($iPos !== false) {
$iSize = (int) substr($sTmp, strlen(''Content-Length: ''));
}
if ($bHeaderEnd) {
$sResponse.= $sTmp;
}
if (strlen(trim($sTmp)) == 0) {
$bHeaderEnd = true;
}
} while (!feof($fp) && (is_null($iSize) || !is_null($iSize) && strlen($sResponse) < $iSize));
$result = trim($sResponse);
Como puede ver, este script dosent espera alrededor de eof si se alcanza el largo del contenido.
espero que ayude