PHP – Ejecutar un Script en segundo plano

Esto lo acabo de aprender hoy, esta buenísimo… la historia detrás de como llegue a adquirir tan suculento conocimiento (YUM!!!) va así:

El otro día llegó a mis manos un script (imposible de compartir 8P – pero los créditos van para Miguel Ángel de Limasoft) de cómo hacer llamadas automáticamente desde un Asterisk para confirmar si el número al que llamas está bien (activo, que si timbra) o es un número que está de baja (desactivado, inoperativo, como lo quieran llamar pero la cosa es que ya no sirve). Lo que hice fue un ligero arreglo agregándole una llamada a la base de datos para pasarle una lista de clientes con sus respectivos números telefónicos dentro de un array y con un simplísimo foreach a cada # (perdón pero ya me canse de escribir número a cada rato… oops!) hacer la actualización de la respectiva tabla y colocar a los números malos como desactivados y a los buenos como verificados.

Alguien por ahí se preguntará (con voz de Rafa Gorgori): ¿Y para qué quiero yo hacer semejante viaje para saber si un # timbra o no? Lo que me olvide de comentarles es que trabajo como desarrollador PHP freelancer en un Call Center y una verificación de este tipo les ahorra horas de trabajo al no tener que preocuparse por llamar a todos los #s que tienen en la lista de cada cliente sino solo a los #s buenos (eso si que es optimización del trabajo 8D).

Ahora viene lo bueno, el script corría de maravilla, pero en consola… ya se imaginarán el lío que tenía en manos al presentarle al boss lo bonito que se veían pasar las letras blancas en ese oscuro y turbulento fondo negro. Inmediatamente luego de ver como fruncía el ceño, ambos a la vez dijimos, Interfaz Gráfica, claaaro y la chamba que me iba a meter ahora para esto…

Pero como dicen por allí, no hay mal que por bien no venga. Un último asunto antes de pasar a lo nuestro es que un script de este tipo toma tanto tiempo en ejecutarse como números #s de teléfono tengamos en la lista, solo para sacar la cuenta, por cada confirmación de # se le daba un prudencial tiempo de 1.5 segundos para que haga la llamada y suponiendo que tenemos unos ridículos 2500  teléfonos nuevos… bueno las matemáticas (aunque no lo crean) no son mi fuerte pero son bastante segundos, y como algunos de ustedes entendidos lectores sabrán que el Apache tiene un tiempo máximo en que puede ejecutar un script para que luego la página deje de funcionar a cabalidad, es más que  todo por un tema de performance del servidor, allí es donde me vino la interrogante que papá Google tenía que quitarme, así que nos pusimos manos a la obra.

Para sacarme de encima la restricción del max execution time lo que me dije fue, “oye david pero cuando lo corremos por consola no tenemos ese problema”, ahí está la respuesta, pero si lo ejecutamos por web ya no es consola (por regla de 3 simple 8P), pero no había nada por qué preocuparme ya que nuestros amigos de PHP ya se habían tomado la molestia de incluirnos dentro de las mucha útiles funciones, una para ejecutar programas en segundo plano, y he aquí mi salvadora: system().

system ( <comando a ejecutar> , <valor de retorno [opcional]>  )

Y en palabras de php.net:

Si ejecutamos un programa con esta función y queremos dejarlo ejecutándose en segundo plano, hay que asegurarse que la salida del mismo es redireccionada a un fichero u otro flujo de salida o PHP se quedará esperando hasta que la ejecución del programa termine.

Frito el pescadito. Sólo me restaba averiguar cómo redireccionar la salida hacia otro lado y es aquí donde una  vez más, super Google hace su entrada y ZAZ! aparecieron por arte de magia estas páginas para sacarme de apuros: Running a Background Process from PHP on Linux10 cosas que quizás no sabías de PHP en la shell, vamos lean un poco y saquen sus propias conclusiones que aquí les van las mías:

En nuestro archivo PHP llamamos a la función system y le pasamos nuestros parámetros:

<?php $var1 = escapeshellcmd($v1);
$var2 = escapeshellcmd($v2); //...y así con cuanta variable más le queramos pasar
$orden = system( "php archivo.php $var1 $var2 >>out.txt 2>>error.txt &" ); ?> 

¿Qué quisimos decir con esto?

  1. Si se va a permitir que datos provenientes del usuario sean enviados a esta función, habría que utilizar escapeshellarg() o escapeshellcmd() para asegurarse que el usuario no intenta engañar al sistema para que ejecute comandos arbitrarios. Siempre es mejor tomar precauciones demás antes que terminar lamentándose por dejar huecos que puedan ser aprovechados por otros.
  2. A nuestra función system() solo le pasamos como parámetro el comando que va a ejecutar seguido por variables que consideremos adecuadas seguido del caracter >> o en su defecto > que le indican a la función que la salida del programa se grabe en un archivo de texto de nombre out.txt (la diferencia entre poner doble o solo un signo mayor, es que si le pones solo uno le estás diciendo que sobrescriba el archivo de texto cada vez que llame a la función, en cambio con >> se va agregando la salida de la nueva llamada por debajo).
  3. Lo que sigue del 2>>error.txt es una joyita más que encontré por esta página Bash scripting de supervivencia, y es que este “2” significa el flujo de errores generado por la ejecución del comando y lo grabamos también en un archivo de texto, nunca está demás información como esta para saber qué podemos estar haciendo mal, como se dice: es mejor que so-sobre a que so-falte, o algo por el estilo.
  4. Para poder recibir los parámetros que le pasamos al PHP por consola tenemos a nuestra disposición esto $argv, que es una de las tantas variables predefinidas que hay en PHP que contiene un array de todos los argumentos pasados a un script cuando se ejecuta desde la línea de comandos.

Ya vamos terminando con esto, creo que lo alargue mucho (¿CREES? Y TODAVÍA PREGUNTAS!!! )

Bueeeno, ojala lo hayan entendido y les sirva de algo en sus futuros proyectos (o por lo menos me conformo con que lo hayan terminado de leer 8P)

Gracias por su compañía, cualquier duda que surja no duden en comentar que estaré más que contento de ayudarles (si estoy de ganas claro ¬¬).

Dios les bendiga!

Anuncios

Etiquetas: , , , , , , , , , , , ,

About David Del Valle

Keep moving forward...

9 responses to “PHP – Ejecutar un Script en segundo plano”

  1. dario says :

    Buen post David!
    Estoy metiendome en el tema, me podrias mostrar como te quedo el script para ver el uso del $argv.
    Gracias
    Dario.

    • david Del Valle says :

      Un APLAUSO para mi primer comentario de todos los tiempos!!! Gracias Dario por leerte el post y disculpa por la demora en responder, casi lo tenía abandonado mi blog pero me haz devuelto las ganas de hacerlo andar nuevamente.
      Te iba a responder directamente aquí pero a medida que lo iba escribiendo me dí cuenta que lo alargue un poco, es una mala costumbre 8P, y decidí hacer un nuevo post, PHP – Uso de la variable $argv, ojalá te guste y despeje todas tus dudas.
      Nuevamente te pido disculpas por la demora, espero aún te sirva… me avisas!

  2. cesar says :

    Mi problema es que tengo esta línea:

    system(“notepad >>logfile.log 2>>logfiel.log &”);

    La página abre el Bloc de Notas, pero se queda cargando hasta que cierre la ventana del Bloc de Notas, llevo un día investigando pero cualquiera de las soluciones que veo en la página de php no me funciona, ¿a que crees que se deba?

    • David Del Valle says :

      Hola César, una pregunta, lo que tu quieres es simplemente llamar un NOTEPAD (abrir un programa del lado del cliente) desde la página o abrir un archivo específico (en segundo plano – se supone que no tienes necesidad de verlo) y trabajar en él, porque lo segundo es lo que hace el comando SYSTEM.
      Ojo que SYSTEM manda a ejecutar un programa que se encuentra en el servidor de la aplicación, no en el cliente, te dejo con eso para que lo evalúes y si tienes un tiempo puedes darle una leída a la documentación de PHP sobre SYSTEM –> http://php.net/manual/es/function.system.php
      Me avisas cualquier cosa César. DTB

  3. JavierAPP (@pedrozopayares) says :

    Me gustó mucho la entrada de blog. Es un dato muy útil. Resulta que a esta hora de la mañana se me ha ocurrido la idea de lanzar desde un php otro php, pero en segundo plano, cosa que si, por ejemplo, tengo que guardar unos datos del usuario en una base de datos, el script principal no tenga que esperar a que termine de guardar para devolver el control al usuario. No estoy seguro, es solo un tema existencial y creo que igual se logra con llamadas asíncronas, pero bueno, de todas formas me pareció muy instructiva la entrada. Gracias por compartir la experiencia.

  4. Miriam says :

    Hola David, me da gusto haber encotnrado tu blog en una de las tantas busquedas de google, y me mucho más gusto pensar en que eres mi salvación en un error que marca el sistema web que estoy haciendo (que por cierto nada que ver con lo que explicas aquí 😀 ), comparado con el problema que explicas lo mio es una niñeria, pero soy novata en esto de PHP y javascript, lo mío era visualfoxpro, delphi y esas cosas, pero ni modo al cliente lo que pida, bueno el asunto esta en que tengo un script en javascript entre las siguientes líneas el problema es que php me marca este error: “Cannot send session cookie – headers already sent by (output started..” si quito la línea // STOP HIDING FROM OTHER BROWSERS –> deja de marcar el error, pero no puedo ejecutar entonces ninguna de mis funciones. Ups!!! esto se alargo, bueno espero que me puedas ayudar, ya me canse de darme topes jejejejejeje.

    • David Del Valle says :

      Hola Miriam, muchas gracias por tu comentario… claro que te puedo dar una mano, para eso estamos; pero necesito más información para saber que lo causa y cómo solucionarlo, si no fuera molestia me podrías mandar la parte inicial de tu código para ver si hay algo por ahí que se nos escapó 🙂
      Cualquier cosa estamos por acá… disculpa si me demoré en responder. DTB

  5. Wilcar Jose says :

    Excelente, lo que necesitaba. Muchas gracias.
    Para aplicaciones de hoy en día en donde el tiempo respuesta usuario debe ser mínimo, se deben implementar este tipo de soluciones.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google photo

Estás comentando usando tu cuenta de Google. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s

A %d blogueros les gusta esto: