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: Likephp://memorybut switches to temp file when data exceedsmemory_limit(2MB default threshold).php://filter: Apply stream filters on the fly.
http:///https://: Read from HTTP URLs (whenallow_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);