Guide to Streaming Data in PHP
Introduction
Streaming data in PHP is a powerful technique, especially for handling large datasets. Using php://output
, you can write directly to the output buffer, bypassing memory constraints.
Why Stream Data
Streaming data ensures efficient memory usage and is particularly useful when dealing with large files like CSVs, JSON, or XML.
Example: Streaming CSV Data in PHP
Below is an example of creating a downloadable CSV file. The core functionality uses fopen('php://output', 'w');
to open a stream.
App\Lib\Stream\DownloadStream.php
<?php
namespace App\Lib\Stream;
/**
* Class DownloadStream
* Provides utilities for streaming downloadable content.
*
* @package App\Lib\Stream
*/
class DownloadStream
{
public static function getStream(string $fileName)
{
// Send headers for file download
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename={$fileName}");
// Open an output stream
$stream = fopen('php://output', 'w');
// Apply filters
stream_filter_prepend($stream, 'convert.iconv.utf-8/cp932'); // Convert to ShiftJIS
stream_filter_register('CrlfFilter', 'App\Lib\Stream\Filter\CrlfFilter');
stream_filter_append($stream, 'CrlfFilter'); // Convert line endings to CRLF
return $stream;
}
}
Creating a Custom Stream Filter for Line Endings
For Windows users, converting line endings to CRLF is often essential. Here’s how you can create a custom filter.
App\Lib\Stream\Filter\CrlfFilter.php
<?php
namespace App\Lib\Stream\Filter;
/**
* Class CrlfFilter
* Converts line endings to CRLF format.
*
* @package App\Lib\Stream\Filter
*/
class CrlfFilter extends \php_user_filter
{
public function filter($in, $out, &$consumed, $closing)
{
while ($bucket = stream_bucket_make_writeable($in)) {
// Normalize line endings
$bucket->data = preg_replace("/\r$/", "", $bucket->data);
$bucket->data = preg_replace("/\n$/", "", $bucket->data);
// Append CRLF
$bucket->data .= "\r\n";
$consumed += $bucket->datalen;
stream_bucket_append($out, $bucket);
}
return PSFS_PASS_ON;
}
}
Usage Example
The following code demonstrates how to create and download a CSV file using the DownloadStream
utility.
// Define the file name
$fileName = 'example.csv';
// Get the download stream
$stream = DownloadStream::getStream($fileName);
// Write the CSV header
fputcsv($stream, [
'last_name',
'first_name',
'company',
]);
// Write a CSV record
fputcsv($stream, [
'Jane',
'Doe',
'ABC Company',
]);
// Close the stream
fclose($stream);
Conclusion
Streaming data with php://output is an efficient way to handle large files without overwhelming memory. This approach is particularly suited for scenarios like exporting large datasets to CSV. By adding custom filters, you can further tailor the stream to specific requirements, such as encoding or line-ending conversions.
Happy Coding! 🚀