W3docs

popen()

La fonction popen() de PHP permet d'exécuter des commandes shell et d'interagir avec elles via un canal de communication unidirectionnel.

Introduction

La fonction popen() exécute une commande shell dans un processus enfant séparé et ouvre un pipe vers celui-ci — un flux unidirectionnel depuis lequel vous pouvez lire la sortie de la commande ou y écrire des données en entrée. C'est l'outil PHP pour diffuser des données vers ou depuis un programme externe ligne par ligne, sans attendre la fin complète de la commande.

Cette page explique ce que popen() retourne, ses modes r et w, pourquoi il faut toujours l'associer à pclose(), en quoi elle diffère de exec() et shell_exec(), et les règles de sécurité à respecter avant de transmettre des données utilisateur à un shell.

Quand utiliser popen()

Utilisez popen() lorsque vous avez besoin d'un flux, et non d'un résultat ponctuel :

  • Mode lecture ("r") — traiter la sortie d'une commande de façon incrémentielle, par exemple surveiller un journal, lire un grand résultat de find, ou récupérer des lignes d'un CLI de base de données sans tout mettre en mémoire.
  • Mode écriture ("w") — envoyer des données vers l'entrée standard d'une commande, par exemple transmettre du texte à gzip, mail, ou un filtre personnalisé.

Si vous voulez simplement obtenir la sortie complète d'une commande sous forme de chaîne, shell_exec() ou exec() est plus simple. Si vous devez lire et écrire dans le même processus simultanément, utilisez proc_open() — les pipes de popen() sont unidirectionnels.

Syntaxe

popen(string $command, string $mode): resource|false
  • $command — la commande shell à exécuter, exactement comme vous la saisiriez dans un terminal.
  • $mode — la direction du pipe : "r" pour lire la sortie standard de la commande, ou "w" pour écrire vers son entrée standard. Sur certains systèmes, vous pouvez ajouter "b" (binaire) ou "t" (texte), par exemple "rb".

Valeur de retour : une ressource de type pointeur de fichier à passer aux fonctions comme fgets() et fwrite(), ou false si le pipe n'a pas pu être ouvert. Ce pointeur n'est pas un descripteur de fichier ordinaire — vous devez le fermer avec pclose(), jamais avec fclose().

Fonctionnement

Lorsque vous appelez popen(), PHP crée un processus enfant qui exécute $command via le shell et connecte l'un de ses flux standard à un pipe :

  • En mode "r", le pipe est relié à la stdout de la commande — vous lisez ce qu'elle affiche.
  • En mode "w", le pipe est relié à la stdin de la commande — ce que vous écrivez devient l'entrée de la commande.

Comme il s'agit d'un flux, vous pouvez commencer à traiter la sortie avant que la commande ne soit terminée, ce qui maintient une empreinte mémoire faible même pour des sorties volumineuses.

Exemples

Exemple 1 : Lecture de la sortie d'une commande

<?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() vérifie si la fin du flux a été atteinte, fgets() lit une ligne à la fois, et pclose() ferme le pipe et attend la fin du processus enfant. Vérifiez toujours la valeur de retour : si popen() échoue, elle retourne false, et lire depuis false déclenche des erreurs.

Sur Windows, remplacez ls -l par la commande équivalente, par exemple dir.

Exemple 2 : Écriture vers l'entrée d'une commande

<?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);

Ici, fwrite() envoie deux lignes vers l'entrée standard de grep. grep filtre pour le mot example, donc seule la première ligne est affichée. pclose() ferme ensuite le pipe.

Exemple 3 : Compression de données à la volée

<?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);
}

Cet exemple envoie des données directement dans gzip sans écrire de fichier intermédiaire non compressé.

popen() vs. exec() et shell_exec()

FonctionRetourneStreaming ?Direction
popen()une ressource pipeoui (lecture ou écriture)unidirectionnel (stdin ou stdout)
exec()dernière ligne + tableau de sortienonsortie uniquement
shell_exec()sortie complète sous forme de chaînenonsortie uniquement
proc_open()ressource de processusouibidirectionnel (stdin et stdout)

Utilisez popen() lorsque vous souhaitez streamer ; utilisez les autres lorsque vous avez simplement besoin du résultat final.

Sécurité : ne jamais transmettre des données utilisateur brutes

popen() exécute son argument via le shell, donc toute entrée utilisateur non échappée représente un risque d'injection de commande. Échappez toujours les arguments avant de construire une commande :

<?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);

Utilisez escapeshellarg() pour les arguments individuels et escapeshellcmd() pour les commandes entières. Mieux encore, évitez de transmettre des données utilisateur au shell lorsqu'une fonction PHP native peut accomplir la tâche.

Pièges courants

  • Oublier pclose(). Laisser le pipe ouvert fait fuir la ressource et vous ne récupérez jamais le statut de sortie de l'enfant. pclose() retourne le code de sortie de la commande.
  • Utiliser fclose() à la place de pclose(). Une ressource popen() est un pipe de processus, pas un fichier ordinaire — fermez-la avec pclose().
  • Ignorer un retour false. Si la commande ne peut pas démarrer, popen() retourne false ; vérifiez-le avant de lire ou d'écrire.
  • Mélanger les directions. Un pipe popen() unique est en lecture seule ou en écriture seule. Pour les deux, utilisez proc_open().

Conclusion

popen() ouvre un pipe unidirectionnel vers une commande shell afin de streamer sa sortie ("r") ou de lui envoyer des données ("w") sans tout mettre en mémoire tampon. Vérifiez toujours la valeur de retour, fermez le pipe avec pclose(), et échappez toute entrée utilisateur avec escapeshellarg() avant qu'elle n'atteigne le shell. Pour en savoir plus sur les fonctions de lecture et d'écriture utilisées avec le pipe, consultez fgets() et fwrite().

Pratique

Pratique
Quelle est la fonction de la commande 'popen' en PHP ?
Quelle est la fonction de la commande 'popen' en PHP ?
Was this page helpful?