Streams and Wrappers

The Stream Abstraction and Wrappers

Every handle fopen() returns is a stream, and the scheme before :// picks the wrapper that implements it; a bare path means file://. php://memory and php://temp are read-write buffers; temp moves to a file past 2 MB (or /maxmemory:N). php://stdin, stdout and stderr are the standard streams, php://input the raw request body, and compress.zlib://, data:// and zip:// read gzip files, data: URLs and archive entries. Run this with printf 'dune\nemma\n' | php streams.php:

streams.php: one API over stdin, a temp buffer, gzip and a data: URLPHP
<?php
declare(strict_types=1);
while (($line = fgets(STDIN)) !== false) echo 'stdin: ', strtoupper($line);  // php://stdin
$tmp = fopen('php://temp/maxmemory:1024', 'r+');
fwrite($tmp, str_repeat('x', 1000)); echo 'inode ', fstat($tmp)['ino'];
fwrite($tmp, str_repeat('x', 1000)); echo ' -> ', fstat($tmp)['ino'], "\n";
$gz = 'compress.zlib://' . __DIR__ . '/access.log.gz';
file_put_contents($gz, str_repeat("GET /books/42 200\n", 10_000));
printf("gzip: %d bytes on disk, %d read back\n", filesize(__DIR__ . '/access.log.gz'),
  strlen(file_get_contents($gz)));
echo file_get_contents('data://text/plain;base64,' . base64_encode("Hello, data://\n"));
Output
stdin: DUNE
stdin: EMMA
inode 0 -> 304841
gzip: 502 bytes on disk, 180000 read back
Hello, data://

The inode appears once the buffer passes its limit, so php://temp can hold a large export without risking memory. data:// obeys allow_url_fopen: with it off, PHP 8.5 reports "data:// wrapper is disabled in the server configuration".