¿Cómo evito que PHP envíe datos al cliente mientras sigo ejecutando el código PHP en el servidor?

Esta pregunta me surgió cuando me encontré con un error que hizo que mi programa PHP se repitiera infinitamente. Aquí hay una situación de ejemplo:

Supongamos que tengo una página web PHP que recibe cargas de imágenes (la página quizás sea una página de respuesta para un formulario de carga de imágenes). En el servidor, el script debe almacenar la imagen en un archivo temporal. Luego, el script debe enviar un mensaje de confirmación al cliente y luego dejar de enviar datos para que el cliente no espere. La secuencia de comandos debe continuar ejecutándose, procesando la imagen (como cambiar su tamaño) antes de finalizar.

Creo que esta "técnica" podría ser útil para que el cliente no espere durante los procesos que consumen mucho tiempo, evitando así los tiempos de espera.

Además, ¿podría resolverse esto usando métodos HTTP?

preguntado el 24 de agosto de 12 a las 07:08

Sí. Esto se puede resolver en PHP enviando los encabezados HTTP correctos. Ver stackoverflow.com/a/12123551/895378 -

5 Respuestas

Sí.

Esto se puede hacer fácilmente sin ningún procesamiento asíncrono si utiliza correctamente los encabezados HTTP.

En condiciones normales, PHP dejará de procesarse tan pronto como el cliente del otro lado cierre la conexión. Si desea continuar procesando después de este evento, debe hacer una cosa: decirle a PHP que ignore los abortos del usuario. ¿Cómo?

ignore_user_abort()

Esto permitirá que su secuencia de comandos siga ejecutándose incluso después de que el cliente se deshaga de esquivar. Pero también nos enfrentamos al problema de cómo decirle al cliente que la solicitud que hizo ha finalizado para que cierre la conexión. Normalmente, PHP maneja de forma transparente el envío de estos encabezados por nosotros si no los especificamos. Aquí, sin embargo, debemos hacerlo explícitamente o el cliente no sabrá cuándo queremos que deje de leer la respuesta.

Para hacer esto, tenemos que enviar los encabezados HTTP apropiados para decirle al cliente cuándo cerrar:

Connection: close
Content-Length: 42

Esta combinación de encabezados le dice al cliente que una vez que lea 42 bytes de respuesta del cuerpo de la entidad, el mensaje ha terminado y debe cerrar la conexión. Hay un par de consecuencias de este método:

  1. Tienes que generar tu respuesta ANTES enviando cualquier salida porque debe determinar el tamaño de la longitud del contenido en bytes para poder enviar el encabezado correcto.
  2. Tienes que enviar estos encabezados ANTES haces eco de cualquier salida.

Entonces, su secuencia de comandos podría verse así:

<?php

ignore_user_abort();

// do work to determine the response you want to send ($responseBody)
$contentLength = strlen($responseBody);

header('Connection: close');
header("Content-Length: $contentLength");
flush();

echo $responseBody;

// --- client will now disconnect and you can continue processing here ---

El gran "Gotchya" con este método es que cuando está ejecutando PHP en un SAPI web, puede enfrentarse fácilmente a la directiva de límite de tiempo máximo si realiza un procesamiento que consume mucho tiempo después de que el cliente del usuario final cierra la conexión. Si esto es un problema, es posible que deba considerar una opción de procesamiento asíncrono usando cron porque no hay límite de tiempo cuando PHP se ejecuta en un entorno CLI. Alternativamente, puede simplemente aumentar el límite de tiempo de sus scripts en el entorno web usando set_time_limitdocumentos.

Vale la pena mencionar que si hace algo como esto, es posible que también desee agregar un cheque a connection_aborted()documentos mientras genera su cuerpo de respuesta para que pueda evitar el procesamiento adicional si el usuario cancela antes de completar la transferencia.

Respondido 25 ago 12, 17:08

Esta respuesta necesita más cencerro. - Salathe

Tengo el mismo problema cuando subo una imagen en Twitter y Facebook desde iPhone a través del servicio web de php.

Si el tiempo de procesamiento de la carga de la imagen no es mucho, puede consultar el comentario de @Musa esto puede ayudarlo, pero si lleva demasiado tiempo procesarlo, intente estos pasos.

 1. Image store in folder
 2. Fetch image from folder using cron 
 3. Cron run for every 2 min in backend

esto disminuirá su tiempo de procesamiento.

Espero que esto te ayude

Respondido el 16 de enero de 13 a las 13:01

Es recomendable hacerlo de forma asíncrona. Es decir, cree otro script que solo procese los archivos tmp creados previamente y ejecútelo con cron (ni siquiera involucre a Apache). Cuando php se ejecuta como módulo de servidor web, debe dedicarse a formar rápidamente una respuesta y luego desaparecer para liberar recursos para la próxima solicitud.

Estás haciendo lo correcto al pensar de esta manera; siga avanzando un pequeño paso arquitectónico más allá y desacople por completo la solicitud del trabajo pesado que debe llevarse a cabo.

Respondido 24 ago 12, 07:08

Derecha. Gracias. Pero sobre mi última línea: ¿Se puede resolver esto usando métodos HTTP? Solo estoy siendo curioso. - Mark Garcia

Definitivamente tienes razón: los scripts PHP nunca deben usarse para procesos pesados. Usaré cron. - Mark Garcia

Puedes hacerlo de varias maneras #

1 #

ob_start();
//output
header("Content-Length: ".ob_get_length());
header("Connection: close");
ob_end_flush();
//do other stuff

2 #

Usando system() o exec() de PHP, cierre el Proceso

3 #

Cierre el proceso usando Shell Script

Respondido 24 ago 12, 07:08

¿Podría el método n. ° 1 ser un problema cuando usa conexiones persistentes? jmarshall.com/easy/http/#http1.1c3 - Mark Garcia

Puedes usar ob_implicit_flush(), Activará o desactivará el vaciado implícito. El vaciado implícito dará como resultado una operación de vaciado después de cada llamada de salida, por lo que ya no serán necesarias las llamadas explícitas a flush().

referirse a

¿Cómo implemento este escenario usando PHP?

OR

Debe crear un cron independiente, que se ejecutará después de un período de tiempo específico, y lo hará de forma asíncrona, sin que el usuario sepa qué procesamiento está ocurriendo, o sin dejar que el usuario espere. De esta manera, incluso podrá detectar los casos fallidos también.

Y también debes intentar minimizar el tiempo de carga.

contestado el 23 de mayo de 17 a las 11:05

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.