PHP でのデータストリーミングガイド

PHP でのデータストリーミングガイド

岩佐 孝浩
岩佐 孝浩
3 min read
PHP

はじめに

PHP でのデータストリーミング は、特に大規模なデータセットを扱う際に非常に有用なテクニックです。php://output を使用することで、メモリの制約を回避しながら直接出力バッファに書き込むことができます。

データをストリームする理由

データをストリームすることで効率的なメモリ使用が可能となり、特に大きな CSV、JSON、XML ファイルを扱う際に有効です。

例: PHP で CSV データをストリームする

以下は、ダウンロード可能な CSV ファイルを作成する例です。この機能の中心は fopen('php://output', 'w'); を使用してストリームを開くことです。

App\Lib\Stream\DownloadStream.php

<?php

namespace App\Lib\Stream;

/**
 * Class DownloadStream
 * ダウンロード可能なコンテンツをストリームするユーティリティを提供します。
 *
 * @package App\Lib\Stream
 */
class DownloadStream
{
    public static function getStream(string $fileName)
    {
        // ファイルダウンロード用ヘッダを送信
        header("Content-Type: application/octet-stream");
        header("Content-Disposition: attachment; filename={$fileName}");

        // 出力ストリームを開く
        $stream = fopen('php://output', 'w');

        // フィルタを適用
        stream_filter_prepend($stream, 'convert.iconv.utf-8/cp932'); // ShiftJIS に変換
        stream_filter_register('CrlfFilter', 'App\Lib\Stream\Filter\CrlfFilter');
        stream_filter_append($stream, 'CrlfFilter'); // 改行コードを CRLF に変換

        return $stream;
    }
}

改行コード用のカスタムストリームフィルタを作成

Windows ユーザーにとって、改行コードを CRLF に変換することはしばしば必要です。以下はカスタムフィルタを作成する方法です。

App\Lib\Stream\Filter\CrlfFilter.php

<?php

namespace App\Lib\Stream\Filter;

/**
 * Class CrlfFilter
 * 改行コードを CRLF 形式に変換します。
 *
 * @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)) {
            // 改行コードを正規化
            $bucket->data = preg_replace("/\r$/", "", $bucket->data);
            $bucket->data = preg_replace("/\n$/", "", $bucket->data);

            // CRLF を追加
            $bucket->data .= "\r\n";

            $consumed += $bucket->datalen;
            stream_bucket_append($out, $bucket);
        }
        return PSFS_PASS_ON;
    }
}

使用例

以下のコードは、DownloadStream ユーティリティを使用して CSV ファイルを作成し、ダウンロードする方法を示しています。

// ファイル名を定義
$fileName = 'example.csv';

// ダウンロードストリームを取得
$stream = DownloadStream::getStream($fileName);

// CSV ヘッダーを書き込む
fputcsv($stream, [
    'last_name',
    'first_name',
    'company',
]);

// CSV レコードを書き込む
fputcsv($stream, [
    'Jane',
    'Doe',
    'ABC Company',
]);

// ストリームを閉じる
fclose($stream);

まとめ

php://output を使用したデータストリーミングは、大規模なファイルをメモリに負荷をかけずに扱う効率的な方法です。このアプローチは、特に大規模データセットを CSV にエクスポートする場合に適しています。さらに、カスタムフィルタを追加することで、エンコーディングや改行コード変換など、ストリームを特定の要件に合わせて柔軟に調整できます。

Happy Coding! 🚀

岩佐 孝浩

岩佐 孝浩

Software Developer at KAKEHASHI Inc.
AWS を活用したクラウドネイティブ・アプリケーションの要件定義・設計・開発に従事。 株式会社カケハシで、処方箋データ収集の新たな基盤の構築に携わっています。 Japan AWS Top Engineers 2020-2023