W3docs

popen()

The popen() function is a popular feature of the PHP programming language that allows you to execute shell commands and interact with them from within your PHP

Introduction

The popen() function runs a shell command in a separate child process and opens a pipe to it — a one-way stream you can either read the command's output from or write input into. It's PHP's tool for streaming data to or from an external program line by line, instead of waiting for the whole command to finish.

This page covers what popen() returns, its r and w modes, why you must always pair it with pclose(), how it differs from exec() and shell_exec(), and the security rules you must follow before passing any user input to a shell.

When to Use popen()

Reach for popen() when you need a stream, not a one-shot result:

  • Read mode ("r") — process a command's output incrementally, e.g. tailing a log, reading a large find listing, or piping rows out of a database CLI without buffering everything in memory.
  • Write mode ("w") — feed data into a command's standard input, e.g. piping text into gzip, mail, or a custom filter.

If you just want the full output of a command as a string, shell_exec() or exec() is simpler. If you need to read and write the same process at once, use proc_open()popen() pipes are one-directional.

Syntax

popen(string $command, string $mode): resource|false
  • $command — the shell command to run, exactly as you'd type it in a terminal.
  • $mode — the pipe direction: "r" to read the command's standard output, or "w" to write to its standard input. On some systems you may add "b" (binary) or "t" (text), e.g. "rb".

Return value: a file-pointer resource you pass to functions like fgets() and fwrite(), or false if the pipe could not be opened. The pointer is not a normal file handle — you must close it with pclose(), never fclose().

How It Works

When you call popen(), PHP forks a child process that runs $command through the shell and connects one of its standard streams to a pipe:

  • In "r" mode, the pipe is wired to the command's stdout — you read what the command prints.
  • In "w" mode, the pipe is wired to the command's stdin — what you write becomes the command's input.

Because it streams, you can start handling output before the command has finished, which keeps memory flat even for huge outputs.

Examples

Example 1: Reading a Command's Output

<?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() checks whether the end of the stream has been reached, fgets() reads one line at a time, and pclose() closes the pipe and waits for the child process to exit. Always check the return value: if popen() fails it returns false, and reading from false triggers errors.

On Windows, replace ls -l with the equivalent command, e.g. dir.

Example 2: Writing to a Command's Input

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

Here fwrite() sends two lines to grep's standard input. grep filters for the word example, so only the first line is printed. pclose() then closes the pipe.

Example 3: Compressing Data on the Fly

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

This pipes data directly into gzip without writing an intermediate uncompressed file.

popen() vs. exec() and shell_exec()

FunctionReturnsStreaming?Direction
popen()a pipe resourceyes (read or write)one-way (stdin or stdout)
exec()last line + array of outputnooutput only
shell_exec()full output as a stringnooutput only
proc_open()process resourceyestwo-way (stdin and stdout)

Use popen() when you want to stream; use the others when you just need the finished result.

Security: Never Pass Raw User Input

popen() runs its argument through the shell, so any unescaped user input is a command-injection risk. Always escape arguments before building a command:

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

Use escapeshellarg() for individual arguments and escapeshellcmd() for whole commands. Better still, avoid passing user data to the shell at all when a native PHP function can do the job.

Common Pitfalls

  • Forgetting pclose(). Leaving the pipe open leaks the resource and you never get the child's exit status. pclose() returns the command's exit code.
  • Using fclose() instead of pclose(). A popen() resource is a process pipe, not a plain file — close it with pclose().
  • Ignoring a false return. If the command can't start, popen() returns false; check for it before reading or writing.
  • Mixing directions. A single popen() pipe is read-only or write-only. For both, use proc_open().

Conclusion

popen() opens a one-way pipe to a shell command so you can stream its output ("r") or feed it input ("w") without buffering everything in memory. Always check the return value, close the pipe with pclose(), and escape any user input with escapeshellarg() before it reaches the shell. To learn the read and write helpers used with the pipe, see fgets() and fwrite().

Practice

Practice
What is the function of the 'popen' command in PHP?
What is the function of the 'popen' command in PHP?
Was this page helpful?