W3docs

popen()

La función popen() de PHP permite ejecutar comandos de shell e interactuar con ellos mediante una tubería de un solo sentido para leer o escribir datos.

Introducción

La función popen() ejecuta un comando de shell en un proceso hijo separado y abre una tubería hacia él — un flujo unidireccional del que puedes leer la salida del comando o escribir datos en él. Es la herramienta de PHP para transmitir datos hacia o desde un programa externo línea por línea, en lugar de esperar a que el comando completo finalice.

Esta página cubre lo que devuelve popen(), sus modos r y w, por qué siempre debes combinarlo con pclose(), cómo difiere de exec() y shell_exec(), y las reglas de seguridad que debes seguir antes de pasar cualquier entrada de usuario a un shell.

Cuándo usar popen()

Utiliza popen() cuando necesites un flujo, no un resultado de una sola vez:

  • Modo lectura ("r") — procesa la salida de un comando de forma incremental, por ejemplo, supervisar un registro, leer un listado grande de find, o extraer filas de una CLI de base de datos sin almacenar todo en memoria.
  • Modo escritura ("w") — envía datos a la entrada estándar de un comando, por ejemplo, canalizar texto a gzip, mail o un filtro personalizado.

Si solo quieres la salida completa de un comando como string, shell_exec() o exec() es más sencillo. Si necesitas leer y escribir en el mismo proceso a la vez, usa proc_open() — las tuberías de popen() son unidireccionales.

Sintaxis

popen(string $command, string $mode): resource|false
  • $command — el comando de shell a ejecutar, exactamente como lo escribirías en una terminal.
  • $mode — la dirección de la tubería: "r" para leer la salida estándar del comando, o "w" para escribir en su entrada estándar. En algunos sistemas puedes agregar "b" (binario) o "t" (texto), por ejemplo "rb".

Valor de retorno: un recurso de puntero de archivo que pasas a funciones como fgets() y fwrite(), o false si la tubería no se pudo abrir. El puntero no es un identificador de archivo normal — debes cerrarlo con pclose(), nunca con fclose().

Cómo funciona

Cuando llamas a popen(), PHP bifurca un proceso hijo que ejecuta $command a través del shell y conecta uno de sus flujos estándar a una tubería:

  • En modo "r", la tubería está conectada a la stdout del comando — lees lo que el comando imprime.
  • En modo "w", la tubería está conectada a la stdin del comando — lo que escribes se convierte en la entrada del comando.

Al transmitir en flujo, puedes comenzar a procesar la salida antes de que el comando haya terminado, lo que mantiene el uso de memoria estable incluso para salidas enormes.

Ejemplos

Ejemplo 1: Leer la salida de un comando

<?php

// Read mode: stream the output of a directory listing line by line.
$handle = popen('ls -l', 'r');

if ($handle === false) {
    exit("Could not open the pipe.\n");
}

while (!feof($handle)) {
    $line = fgets($handle);
    echo $line;
}

pclose($handle);

feof() comprueba si se ha llegado al final del flujo, fgets() lee una línea a la vez, y pclose() cierra la tubería y espera a que el proceso hijo finalice. Siempre verifica el valor de retorno: si popen() falla, devuelve false, y leer desde false genera errores.

En Windows, reemplaza ls -l con el comando equivalente, por ejemplo dir.

Ejemplo 2: Escribir en la entrada de un comando

<?php

// Write mode: pipe a line of text into grep's standard input.
$handle = popen('grep "example"', 'w');

if ($handle === false) {
    exit("Could not open the pipe.\n");
}

fwrite($handle, "This line has the word example.\n");
fwrite($handle, "This line does not match.\n");

pclose($handle);

Aquí fwrite() envía dos líneas a la entrada estándar de grep. grep filtra por la palabra example, por lo que solo se imprime la primera línea. pclose() luego cierra la tubería.

Ejemplo 3: Comprimir datos al vuelo

<?php

// Stream text straight into gzip and save a compressed file.
$handle = popen('gzip > output.txt.gz', 'w');

if ($handle !== false) {
    fwrite($handle, "Some data to compress.\n");
    pclose($handle);
}

Esto canaliza datos directamente en gzip sin escribir un archivo intermedio sin comprimir.

popen() vs. exec() y shell_exec()

FunciónDevuelve¿Streaming?Dirección
popen()un recurso de tuberíasí (lectura o escritura)unidireccional (stdin o stdout)
exec()última línea + array de salidanosolo salida
shell_exec()salida completa como stringnosolo salida
proc_open()recurso de procesobidireccional (stdin y stdout)

Usa popen() cuando quieras transmitir en flujo; usa los otros cuando solo necesites el resultado final.

Seguridad: nunca pases entrada de usuario sin procesar

popen() ejecuta su argumento a través del shell, por lo que cualquier entrada de usuario sin escapar es un riesgo de inyección de comandos. Siempre escapa los argumentos antes de construir un comando:

<?php

$userInput = $_GET['name'] ?? 'world';

// escapeshellarg() wraps the value in quotes and neutralizes shell metacharacters.
$command = 'echo Hello ' . escapeshellarg($userInput);

$handle = popen($command, 'r');
echo fgets($handle);
pclose($handle);

Usa escapeshellarg() para argumentos individuales y escapeshellcmd() para comandos completos. Mejor aún, evita pasar datos de usuario al shell cuando una función nativa de PHP pueda hacer el trabajo.

Errores comunes

  • Olvidar pclose(). Dejar la tubería abierta filtra el recurso y nunca obtienes el estado de salida del proceso hijo. pclose() devuelve el código de salida del comando.
  • Usar fclose() en lugar de pclose(). Un recurso de popen() es una tubería de proceso, no un archivo simple — ciérralo con pclose().
  • Ignorar un retorno false. Si el comando no puede iniciarse, popen() devuelve false; compruébalo antes de leer o escribir.
  • Mezclar direcciones. Una sola tubería popen() es de solo lectura o solo escritura. Para ambas, usa proc_open().

Conclusión

popen() abre una tubería unidireccional hacia un comando de shell para que puedas transmitir su salida ("r") o enviarle datos de entrada ("w") sin almacenar todo en memoria. Siempre verifica el valor de retorno, cierra la tubería con pclose(), y escapa cualquier entrada de usuario con escapeshellarg() antes de que llegue al shell. Para conocer los ayudantes de lectura y escritura usados con la tubería, consulta fgets() y fwrite().

Práctica

Práctica
¿Cuál es la función del comando 'popen' en PHP?
¿Cuál es la función del comando 'popen' en PHP?
Was this page helpful?