0

CSV, JSON, and XML parsing in PHP

Intermediate5 min read·php-13-006

Concept

PHP's stream system abstracts I/O into a uniform interface. Files, HTTP responses, network sockets, in-memory buffers, compressed data, and encrypted data are all accessed through the same fopen()/fread()/fwrite() interface using different URL wrappers.

Built-in stream wrappers:

  • file:// or bare path: Regular filesystem (default).
  • php://: In-process streams.
    • php://stdin, php://stdout, php://stderr: Standard I/O for CLI.
    • php://input: Raw POST body (read-only, only readable once by default).
    • php://output: Current output buffer.
    • php://memory: In-memory read/write stream (grows as needed).
    • php://temp: Like php://memory but switches to temp file when data exceeds memory_limit (2MB default threshold).
    • php://filter: Apply stream filters on the fly.
  • http:// / https://: Read from HTTP URLs (when allow_url_fopen = On). Security risk — validate URLs carefully.
  • compress.zlib://: Read/write gzip-compressed data.
  • compress.bzip2://: Read/write bzip2-compressed data.
  • data://: Inline data (like a data URI).

Stream context: Configure stream behavior with stream_context_create(array $options). Pass as third argument to fopen()/file_get_contents(). Used to set HTTP method, headers, timeouts, SSL options.

Stream filters: Apply transformations (base64 encode/decode, compression, encryption) as data passes through a stream via stream_filter_append().

Code Example

php
<?php
declare(strict_types=1);

// php://memory — in-memory read/write
$mem = fopen('php://memory', 'r+');
fwrite($mem, "hello world");
rewind($mem);
echo fread($mem, 1024); // "hello world"
fclose($mem);

// php://temp — in-memory, spills to disk if large
$temp = fopen('php://temp', 'r+');
fwrite($temp, str_repeat('x', 1024 * 1024 * 3)); // 3MB — goes to disk
fclose($temp);

// HTTP stream context — make HTTP requests with fopen
$ctx = stream_context_create([
    'http' => [
        'method'  => 'POST',
        'header'  => "Content-Type: application/json\r\nAccept: application/json\r\n",
        'content' => json_encode(['key' => 'value']),
        'timeout' => 5,
        'ignore_errors' => true, // get body even on 4xx/5xx responses
    ],
    'ssl' => [
        'verify_peer'      => true,
        'verify_peer_name' => true,
    ],
]);
$response = file_get_contents('https://api.example.com/endpoint', false, $ctx);

// Read HTTP response code
$meta = stream_get_meta_data(fopen('https://example.com', 'r', false, $ctx));
// $meta contains 'wrapper_data' with HTTP response headers

// Compress file with gzip stream
file_put_contents('compress.zlib:///tmp/data.gz', file_get_contents('/tmp/data.txt'));
// Read it back
$decompressed = file_get_contents('compress.zlib:///tmp/data.gz');

// php://filter — encode file content in-line
$b64 = file_get_contents('php://filter/convert.base64-encode/resource=/path/to/file');

// Custom stream wrapper (advanced)
// Implement: stream_open, stream_read, stream_write, stream_seek, stream_tell, stream_eof, stream_stat, stream_close
// Then: stream_wrapper_register('myproto', MyStreamWrapper::class);
// Usage: fopen('myproto://resource', 'r');

// Stream context for filesystem (timeout, permissions)
$ctx = stream_context_create(['file' => ['umask' => 0022]]);
file_put_contents('/tmp/test.txt', "content", 0, $ctx);