respuestas por peticiones peticion parametros formulario enviar desde datos con php fork

por - Continuar con la ejecución de PHP después de enviar una respuesta HTTP



peticiones http java (13)

¿Cómo puedo hacer que PHP 5.2 (ejecutando como apache mod_php) envíe una respuesta HTTP completa al cliente, y luego siga ejecutando operaciones por un minuto más?

La larga historia

Tengo un script PHP que tiene que ejecutar algunas solicitudes de bases de datos largas y enviar correos electrónicos, lo que tarda de 45 a 60 segundos en ejecutarse. Este script es llamado por una aplicación que no tengo control. Necesito que la aplicación informe cualquier mensaje de error recibido del script PHP (la mayoría de los errores de parámetros no son válidos).

La aplicación tiene un retraso de tiempo de espera inferior a 45 segundos (no sé el valor exacto) y, por lo tanto, registra cada ejecución del script PHP como un error. Por lo tanto, necesito PHP para enviar la respuesta HTTP completa al cliente lo más rápido posible (idealmente, tan pronto como se hayan validado los parámetros de entrada), y luego ejecutar la base de datos y el procesamiento del correo electrónico.

Estoy ejecutando mod_php, por lo que pcntl_fork no está disponible. Podría solucionar este problema guardando los datos para procesarlos en la base de datos y ejecutar el proceso real desde cron , pero estoy buscando una solución más corta.


¿Qué tal si llamamos a una secuencia de comandos en el servidor de archivos para que se ejecute como si se hubiera activado en la línea de comandos? Puedes hacer esto con el exec de PHP.


Bah, malentendí tus requerimientos. Parece que en realidad son:

  • El script recibe información de una fuente externa que no controla
  • El script procesa y valida la entrada, y permite que la aplicación externa sepa si son buenos o no y finaliza la sesión.
  • Script inicia un proceso de larga ejecución.

En este caso, entonces sí, usar una cola de trabajos externa y / o cron funcionaría. Después de validar la entrada, inserte los detalles del trabajo en la cola y salga. A continuación, se puede ejecutar otro script, recoger los detalles del trabajo de la cola e iniciar el proceso más largo. Alex Howansky tiene la idea correcta.

Perdón, admito que hojeé un poco la primera vez.


En su archivo de configuración de Apache php.ini , asegúrese de que el buffer de salida esté desactivado:

output_buffering = off


Es posible usar cURL para eso, con un tiempo de espera muy corto. Este sería su archivo principal:

<?php> $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "http://example.com/processor.php"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_TIMEOUT_MS, 10); //just some very short timeout curl_exec($ch); curl_close($ch); ?>

Y este es tu archivo de procesador:

<?php ignore_user_abort(true); //very important! for($x = 0; $x < 10; $x++) //do some very time-consuming task sleep(10); ?>

Como puede ver, el script superior tendrá un tiempo de espera después de un corto tiempo (10 milisegundos en este caso). Es posible que CURLOPT_TIMEOUT_MS no funcione así, en este caso, sería equivalente a curl_setopt($ch, CURLOPT_TIMEOUT, 1) .

Por lo tanto, cuando se haya accedido al archivo del procesador, hará sus tareas sin importar que el usuario (es decir, el archivo de llamada) cancele la conexión.

Por supuesto, también puede pasar los parámetros GET o POST entre las páginas.


Haga que la secuencia de comandos que maneja la solicitud inicial cree una entrada en una cola de procesamiento y luego regrese de inmediato. Luego, cree un proceso separado (a través de cron quizás) que ejecute regularmente los trabajos pendientes en la cola.


Lo que necesitas es este tipo de configuración


Puede crear una solicitud http entre el servidor y el servidor. (no se necesita navegador). El secreto para crear una solicitud http de fondo es establecer un tiempo de espera muy pequeño, por lo que se ignora la respuesta.

Esta es una función de trabajo que he usado para ese pupose:

31 DE MAYO Solicitud de fondo asincrónico de PHP Otra forma de crear una solicitud asincrónica en PHP (simulando el modo de fondo).

/** * Another way to make asyncronous (o como se escriba asincrono!) request with php * Con esto se puede simpular un fork en PHP.. nada que envidarle a javita ni C++ * Esta vez usando fsockopen * @author PHPepe * @param unknown_type $url * @param unknown_type $params */ function phpepe_async($url, $params = array()) { $post_params = array(); foreach ($params as $key => &$val) { if (is_array($val)) $val = implode('','', $val); $post_params[] = $key.''=''.urlencode($val); } $post_string = implode(''&'', $post_params); $parts=parse_url($url); $fp = fsockopen($parts[''host''], isset($parts[''port''])?$parts[''port'']:80, $errno, $errstr, 30); $out = "POST ".$parts[''path'']." HTTP/1.1/r/n"; $out.= "Host: ".$parts[''host'']."/r/n"; $out.= "Content-Type: application/x-www-form-urlencoded/r/n"; $out.= "Content-Length: ".strlen($post_string)."/r/n"; $out.= "Connection: Close/r/n/r/n"; if (isset($post_string)) $out.= $post_string; fwrite($fp, $out); fclose($fp); } // Usage: phpepe_async("http://192.168.1.110/pepe/feng_scripts/phprequest/fork2.php");

Para obtener más información, puede consultar http://www.phpepe.com/2011/05/php-asynchronous-background-request.html


Puede dividir estas funciones en tres secuencias de comandos. 1. Inicie el proceso y llame al segundo a través de la ejecución o command , esto también es posible ejecutar a través de la llamada http. 2. el segundo ejecutará el procesamiento de la base de datos y al final comenzará el último 3. El último enviará un correo electrónico


Puede usar la función PHP register-shutdown-function que ejecutará algo después de que el script haya completado su diálogo con el navegador.

Consulte también ignore_user_abort , pero no debería necesitar esta función si usa la función register_shutdown_function. En la misma página, set_time_limit(0) evitará que el script agote el tiempo de espera.


Recomendaría generar una nueva solicitud asíncrona al final, en lugar de continuar el proceso con el usuario.

Puede generar la otra solicitud usando la respuesta aquí: ¿Llamadas PHP asíncronas?


Tenía este fragmento en mi caja de herramientas de "guiones especiales", pero se perdió (las nubes no eran comunes en aquel entonces), así que estaba buscando y presenté esta pregunta, sorprendido de ver que falta, busqué más y vine volver aquí para publicarlo:

<?php ob_end_clean(); header("Connection: close"); ignore_user_abort(); // optional ob_start(); echo (''Text the user will see''); $size = ob_get_length(); header("Content-Length: $size"); ob_end_flush(); // Strange behaviour, will not work flush(); // Unless both are called ! session_write_close(); // Added a line suggested in the comment // Do processing here sleep(30); echo(''Text user will never see''); ?>

De hecho, lo uso en algunos lugares. Y tiene sentido allí: un banklink está devolviendo la solicitud de un pago exitoso y tengo que llamar a muchos servicios y procesar una gran cantidad de datos cuando eso sucede. A veces lleva más de 10 segundos, pero el enlace bancario tiene un período de tiempo de espera fijo. Así que reconozco el enlace bancario y le muestro la salida, y hago mis cosas cuando ya se ha ido.


Uno puede usar "http fork" para uno mismo o para cualquier otro script. Quiero decir algo como esto:

// parent sript, called by user request from browser // create socket for calling child script $socketToChild = fsockopen("localhost", 80); // HTTP-packet building; header first $msgToChild = "POST /sript.php?&param=value&<more params> HTTP/1.0/n"; $msgToChild .= "Host: localhost/n"; $postData = "Any data for child as POST-query"; $msgToChild .= "Content-Length: ".strlen($postData)."/n/n"; // header done, glue with data $msgToChild .= $postData; // send packet no oneself www-server - new process will be created to handle our query fwrite($socketToChild, $msgToChild); // wait and read answer from child $data = fread($socketToChild, $dataSize); // close connection to child fclose($socketToChild); ...

Ahora el script secundario:

// parse HTTP-query somewhere and somehow before this point // "disable partial output" or // "enable buffering" to give out all at once later ob_start(); // "say hello" to client (parent script in this case) disconnection // before child ends - we need not care about it ignore_user_abort(1); // we will work forever set_time_limit(0); // we need to say something to parent to stop its waiting // it could be something useful like client ID or just "OK" ... echo $reply; // push buffer to parent ob_flush(); // parent gets our answer and disconnects // but we can work "in background" :) ...

La idea principal es:

  • script padre llamado por solicitud del usuario;
  • el padre llama a la secuencia de comandos hija (igual que la matriz u otra) en el mismo servidor (o cualquier otro servidor) y les proporciona datos de solicitud;
  • el padre dice que está bien para el usuario y finaliza;
  • niño trabaja.

Si necesita interactuar con un niño, puede usar DB como "medio de comunicación": el padre puede leer el estado del niño y escribir comandos, el niño puede leer comandos y escribir el estado. Si lo necesita para varios scripts secundarios, debe mantener el identificador secundario en el lado del usuario para discriminarlos y enviar ese ID al padre cada vez que desee verificar el estado del hijo respectivo.

Lo he encontrado aquí - http://linuxportal.ru/forums/index.php/t/22951/


Usar una cola, un ejecutivo o un cron sería una exageración en esta tarea simple. No hay razón para no permanecer dentro del mismo script. Esta combinación funcionó muy bien para mí:

ignore_user_abort(true); $response = "some response"; header("Connection: close"); header("Content-Length: " . mb_strlen($response)); echo $response; flush(); // releasing the browser from waiting // continue the script with the slow processing here...

lea más en: ¿Cómo continuar el proceso después de responder a la solicitud de ajax en PHP?