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:
<?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".