【PHP8.x】fpassthru関数の使い方

fpassthru関数の使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

fpassthru関数は、開かれたファイルポインタから、残りのデータをすべて出力バッファへ直接出力する関数です。この関数は、fopen()などで作成されたファイルリソース(ファイルポインタ)を引数として受け取ります。ファイルポインタが指す現在の位置からファイルの終端(EOF)まで、残りの内容を順次読み込み、PHPの出力機構を通じて直接クライアント(例えばウェブブラウザ)へ送信します。

この関数の大きな利点は、特に大きなサイズのファイルを扱う際に、メモリ効率が非常に優れている点です。ファイルの内容をすべて一度にPHPのメモリに読み込むのではなく、データを読み出し次第すぐに出力するため、システムメモリの消費を最小限に抑えながら、効率的にファイルの内容を提供できます。

また、fpassthru関数はバイナリセーフであるため、テキストファイルはもちろんのこと、画像、音声、PDFといったあらゆる種類のバイナリファイルも、破損させることなく安全に出力することが可能です。関数は、出力したバイト数を整数で返します。もしエラーが発生した場合はfalseを返します。この関数を実行すると、ファイルポインタはファイルの終端に移動します。

構文(syntax)

1<?php
2$filePointer = fopen("php://temp", "r+");
3fwrite($filePointer, "This text will be output directly by fpassthru.");
4fseek($filePointer, 0);
5fpassthru($filePointer);
6fclose($filePointer);
7?>

引数(parameters)

resource $stream

  • stream: resource: 読み書き対象のストリームリソース

戻り値(return)

int|false

fpassthru関数は、ファイルポインタが指す位置からファイルストリームの終端までを標準出力にコピーします。成功した場合は、コピーされたバイト数が返されます。エラーが発生した場合はfalseが返されます。

サンプルコード

PHP fpassthru vs readfile 比較

1<?php
2
3declare(strict_types=1);
4
5/**
6 * fpassthru() と readfile() の違いを比較するためのサンプルコード
7 *
8 * readfile() は、指定したファイルの内容をすべて読み込み、直接出力します。
9 * 一方で fpassthru() は、すでに開かれているファイルポインタを受け取り、
10 * そのポインタの「現在位置」からファイルの終端までを出力します。
11 *
12 * この性質を利用すると、ファイルの一部(例えばヘッダー行)を先に読み込んで処理し、
13 * 残りの部分だけを効率的に出力する、といった柔軟な制御が可能になります。
14 */
15function demonstrateFpassthruVsReadFile(): void
16{
17    // デモ用の一時ファイルを作成
18    $filename = tempnam(sys_get_temp_dir(), 'demo_');
19    if ($filename === false) {
20        echo "一時ファイルの作成に失敗しました。\n";
21        return;
22    }
23
24    // ファイルに複数行のコンテンツを書き込む
25    $content = "Header: This is the first line to be processed separately.\n";
26    $content .= "Data: This is the second line.\n";
27    $content .= "Data: This is the third line.\n";
28    file_put_contents($filename, $content);
29
30    echo "--- fpassthru() の使用例 ---\n";
31
32    // ファイルを読み込みモード('r')で開く
33    $stream = fopen($filename, 'r');
34    if ($stream === false) {
35        echo "ファイルのオープンに失敗しました。\n";
36        unlink($filename); // 後片付け
37        return;
38    }
39
40    try {
41        // 1. ファイルの最初の行だけを fgets() で読み込む
42        //    これにより、ファイルポインタが2行目の先頭に移動する
43        $headerLine = fgets($stream);
44        echo "先に読み込んで処理した行: " . htmlspecialchars(trim($headerLine)) . "\n\n";
45
46        // 2. fpassthru() を使い、ポインタの現在位置からファイルの終端までを出力する
47        echo "残りの部分を fpassthru() で出力します:\n";
48        // fpassthru() は出力した文字数を返す
49        $bytes = fpassthru($stream);
50
51        echo "\nfpassthru() によって出力されたバイト数: " . $bytes . "\n";
52    } finally {
53        // 3. ファイルポインタを閉じる
54        fclose($stream);
55        // 4. 作成した一時ファイルを削除する
56        unlink($filename);
57    }
58
59    echo "\n--- (比較) readfile() の場合 ---\n";
60    echo "もし readfile('{$filename}') を使った場合、\n";
61    echo "ファイルの内容が区別なく一度にすべて出力されます。\n";
62}
63
64// 関数を実行してデモを表示
65demonstrateFpassthruVsReadFile();

PHP 8 の fpassthru 関数は、すでに開かれているファイルポインタ(resource型の $stream 引数で指定)が指す「現在位置」から、ファイルの終端までを直接出力するための関数です。この関数は、Webサーバーからクライアントへファイルを直接送る際や、大きなファイルを部分的に処理して出力する場合に特に役立ちます。

引数 $stream には、fopen() などで開かれた有効なファイルポインタを渡します。このポインタが指す現在位置から出力が開始されるため、例えばファイルのヘッダー部分を事前に fgets() などで読み込んで処理した後、残りのデータ部分だけを fpassthru で効率的に出力する、といった柔軟な制御が可能です。

関数が成功すると、出力されたバイト数が整数値として返されます。ファイルを開けない、または何らかの理由で出力に失敗した場合は false が返されます。

同種の機能を持つ readfile() 関数が、指定されたファイル全体を常に最初から出力するのに対し、fpassthru はファイルポインタの現在位置を利用することで、ファイルの内容の一部を読み飛ばしたり、特定の部分だけを出力したりできる点で異なります。これにより、大量のデータを含むファイルを扱う際に、メモリ消費を抑えつつ効率的なデータ転送を実現できます。

fpassthru関数は、すでに開かれたファイルポインタの「現在の位置」から終端までを直接出力します。readfile関数とは異なり、ファイル全体を常に最初から出力するわけではないため、ファイルの一部だけを先に処理し、残りを効率的に出力するといった柔軟な制御が可能です。

この関数を使用する際は、fopenで開いたファイルポ゚インタを必ずfcloseで閉じる必要があります。また、一時ファイルを使用する場合はunlinkで削除するなど、ファイルリソースの管理を徹底することが重要です。これを怠ると、リソースリークや不要なファイルが残る原因となります。

fpassthruは、正常に処理を終えると出力したバイト数を返しますが、失敗した場合はfalseを返します。そのため、戻り値を確認し、適切にエラーハンドリングを行うことで、より堅牢なコードになります。

関連コンテンツ

【PHP8.x】fpassthru関数の使い方 | いっしー@Webエンジニア