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

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

作成日: 更新日:

基本的な使い方

readfile関数は、指定されたファイルを読み込み、その内容を直接出力バッファに書き込む関数です。この関数は、特にWebアプリケーションにおいて、サーバー上のファイルをユーザーのWebブラウザに直接表示したり、ダウンロードさせたりする際に非常に役立ちます。例えば、PDFファイルや画像ファイル、テキストファイルなどをWebページ上で提供したい場合に利用されます。

readfile関数は、ファイルをメモリに読み込むことなく直接出力を行うため、非常に大きなファイルを扱う場合でもシステムのメモリ消費を抑えることができます。これは、ダウンロードサービスなど、大量のデータ転送が必要なアプリケーションにとって重要な利点です。

この関数は、読み込みたいファイルのパスを引数として受け取ります。ファイルが見つかり、読み込みに成功した場合は、読み込んだバイト数を整数値として返します。しかし、ファイルが見つからない、または読み込み権限がないなどの理由で失敗した場合は、falseを返します。

readfile関数を使用する際には、ファイルの内容が出力される前に適切なHTTPヘッダー(Content-TypeContent-Dispositionなど)を設定することが重要です。これにより、ブラウザがファイルの種類を正しく認識し、表示またはダウンロードの動作を適切に行うことができます。この関数は、Webサイト上でファイルコンテンツを効率的に提供するための基本的な機能として広く利用されています。

構文(syntax)

1readfile('path/to/your/file.txt');

引数(parameters)

string $filename, bool $use_include_path = false, resource $context = null

  • string $filename: 読み込むファイルの名前を指定します。
  • bool $use_include_path = false: trueに設定すると、PHPのinclude_path内を検索してファイルを読み込みます。
  • resource $context = null: ストリームコンテキストを指定します。

戻り値(return)

int|false

readfile関数は、指定されたファイルを読み込んで直接出力し、読み込んだバイト数を返します。ファイルが存在しない、または読み込めない場合はfalseを返します。

サンプルコード

PHP readfileでファイルをダウンロードする

1<?php
2
3/**
4 * Downloads a specified file to the client browser using PHP's readfile() function.
5 * This script demonstrates how to force a file download with appropriate HTTP headers.
6 */
7
8/**
9 * Initiates a file download to the client browser.
10 *
11 * @param string $filePath The full path to the file on the server to be downloaded.
12 * @param string|null $suggestedFileName (Optional) The filename to suggest to the client browser.
13 *                                     If not provided, the base name of $filePath is used.
14 * @return void This function terminates script execution after attempting the download.
15 */
16function downloadFileWithReadfile(string $filePath, ?string $suggestedFileName = null): void
17{
18    // 1. Check if the file exists on the server.
19    if (!file_exists($filePath)) {
20        http_response_code(404); // Set HTTP status to 404 Not Found.
21        echo "Error: The requested file was not found.";
22        exit; // Terminate script execution.
23    }
24
25    // 2. Determine the filename for the client's download.
26    //    Uses the provided name, or the original file's base name if not specified.
27    $fileNameForClient = $suggestedFileName ?? basename($filePath);
28
29    // 3. Get the file size. This is crucial for the Content-Length header.
30    $fileSize = filesize($filePath);
31    if ($fileSize === false) {
32        http_response_code(500); // Internal Server Error.
33        echo "Error: Could not determine file size.";
34        exit;
35    }
36
37    // 4. Set HTTP Headers for File Download.
38    //    'Content-Type: application/octet-stream' forces a download dialog for any file type.
39    //    'Content-Disposition: attachment' tells the browser to download, with a suggested filename.
40    //    'Expires: 0', 'Cache-Control', 'Pragma': Prevent caching of the download.
41    //    'Content-Length': Informs the browser about the file size for progress indication.
42    header('Content-Type: application/octet-stream');
43    header('Content-Disposition: attachment; filename="' . $fileNameForClient . '"');
44    header('Expires: 0');
45    header('Cache-Control: must-revalidate');
46    header('Pragma: public');
47    header('Content-Length: ' . $fileSize);
48
49    // 5. Clean any output buffers. This prevents any unintended output (like whitespace
50    //    before the <?php tag) from corrupting the file download.
51    if (ob_get_level()) {
52        ob_end_clean();
53    }
54
55    // 6. Read the file and output its content directly to the browser.
56    //    readfile() efficiently streams the file, ideal for large files.
57    //    It returns the number of bytes read on success, or false on failure.
58    $bytesSent = readfile($filePath);
59
60    // Basic error logging if readfile itself fails.
61    if ($bytesSent === false) {
62        error_log("Failed to send file '{$filePath}' using readfile.");
63    }
64
65    // 7. Terminate script execution. This is essential to ensure no further
66    //    script output or HTML is appended after the file content.
67    exit;
68}
69
70// --- Example Usage ---
71// This part demonstrates how to use the downloadFileWithReadfile function.
72// For a fully standalone demonstration, we'll create a dummy file.
73$dummyFilePath = __DIR__ . '/sample_report.pdf'; // Example for a "PDF" file.
74
75// Create a dummy file if it doesn't exist.
76// For this example, it's just a text file but we name it .pdf to simulate a typical download.
77if (!file_exists($dummyFilePath)) {
78    file_put_contents($dummyFilePath, "This is a dummy PDF content for demonstration.\n\n" .
79                                       "Report Title: Sample Download\n" .
80                                       "Date: " . date('Y-m-d') . "\n" .
81                                       "Content generated by PHP readfile example.");
82}
83
84// Call the function to initiate the download.
85// When this PHP script is accessed via a web browser (e.g., http://localhost/your_script.php),
86// it will trigger the download of 'sample_report.pdf', suggesting 'monthly_report.pdf' as filename.
87downloadFileWithReadfile($dummyFilePath, 'monthly_report.pdf');
88
89// Any code written here will not be executed because downloadFileWithReadfile() calls exit().
90
91?>

PHPのreadfile関数は、指定されたファイルを読み込み、その内容を直接Webブラウザなどの出力バッファに送信するための機能を提供します。この関数は、特に大きなファイルをユーザーにダウンロードさせる際に、ファイルを一度にメモリに読み込むのではなく、ストリームとして効率的に出力するため、システムリソースを節約できる利点があります。

第一引数$filenameには、ダウンロードさせたいファイルの完全なパスを文字列で指定します。この引数は必須です。第二引数$use_include_pathは、PHPのinclude_path設定に基づいてファイルを検索するかどうかを制御する論理値で、通常はfalseで十分です。第三引数$contextはファイルストリームの振る舞いを細かく制御するためのリソースですが、ほとんどのダウンロードシナリオでは省略可能です。

readfile関数は、ファイルの読み込みと出力に成功した場合、送信されたバイト数を整数で返します。何らかの理由で処理に失敗した場合はfalseを返します。

サンプルコードでは、readfile関数を利用して、指定されたファイルをWebブラウザに強制的にダウンロードさせる方法が示されています。ファイルをダウンロードさせる際には、ブラウザがファイルを正しく処理できるように、Content-Type: application/octet-stream(任意のバイナリファイルとして扱う)、Content-Disposition: attachment; filename="..."(ダウンロードとして扱い、ファイル名を指定)、Content-Length(ファイルのバイトサイズを通知)などのHTTPヘッダーを適切に設定することが不可欠です。また、ファイルが存在しない場合のエラー処理や、出力バッファの意図しない内容がダウンロードを妨げないようにクリアすること、ダウンロード完了後にexitでスクリプトの実行を確実に終了させることが、安全で信頼性の高いファイルダウンロード処理を実装する上での重要なポイントとなります。

header()関数は、ファイルの出力より前に必ず呼び出す必要があります。特にContent-Lengthヘッダーを正しく設定するためには、filesize()関数でダウンロードするファイルのサイズを正確に取得することが重要です。また、readfile()関数でファイルの内容を出力する前に、ob_end_clean()関数で出力バッファをクリアし、意図しない出力がダウンロードファイルに混入するのを防いでください。ダウンロード処理が完了したら、必ずexit()関数を呼び出してスクリプトの実行を停止し、余計な出力によるファイル破損やセキュリティリスクを防ぎましょう。ファイルパスは、ユーザーからの直接の入力ではなく、信頼できる場所に限定するなど、セキュリティに十分注意して指定してください。

PHPでファイルを強制ダウンロードさせる

1<?php
2
3/**
4 * 指定されたファイルを強制的にダウンロードさせるためのHTTPヘッダを設定し、
5 * ファイルの内容を出力してスクリプトの実行を終了します。
6 *
7 * この関数は、ブラウザがファイルを直接表示するのではなく、ダウンロードを促すようにするために使用されます。
8 * 特に「ダウンロードできない」問題(例: ブラウザがテキストファイルを直接表示してしまう)は、
9 * 正しいHTTPヘッダが設定されていない場合に発生することが多いです。
10 *
11 * @param string $filePath ダウンロード対象のファイルパス。
12 * @return void この関数はファイルの出力が成功した場合はexit()を呼び出してスクリプトを終了します。
13 *              ファイルが存在しない場合やreadfile()が失敗した場合もエラーメッセージを出力し、
14 *              exit()を呼び出して終了します。
15 */
16function serveFileForDownload(string $filePath): void
17{
18    // 1. ファイルが存在するか確認
19    if (!file_exists($filePath)) {
20        // HTTP 404 Not Found ヘッダを設定し、エラーメッセージを出力して終了
21        header('HTTP/1.0 404 Not Found');
22        echo 'Error: The requested file was not found.';
23        exit;
24    }
25
26    // 2. 強制ダウンロードのためのHTTPヘッダを設定
27    // これらのヘッダは、ブラウザにファイルをダウンロードさせることを指示します。
28    header('Content-Description: File Transfer');
29    header('Content-Type: application/octet-stream'); // 一般的なバイナリファイルとして扱う
30    header('Content-Disposition: attachment; filename="' . basename($filePath) . '"'); // ダウンロードファイル名を指定
31    header('Expires: 0'); // キャッシュを無効化
32    header('Cache-Control: must-revalidate'); // キャッシュを無効化
33    header('Pragma: public'); // キャッシュを無効化
34    header('Content-Length: ' . filesize($filePath)); // ファイルサイズを通知
35
36    // 3. 出力バッファが存在する場合はクリアする
37    // これにより、ファイルの内容が出力される前に余計な出力がされるのを防ぎ、
38    // ヘッダ送信が失敗するリスクを低減します。
39    if (ob_get_level()) {
40        ob_end_clean();
41    }
42
43    // 4. ファイルの内容を標準出力に出力
44    // readfile()は成功した場合は読み込んだバイト数を、失敗した場合はfalseを返します。
45    $bytesOutput = readfile($filePath);
46
47    // 5. readfile()の実行結果を確認
48    if ($bytesOutput === false) {
49        // readfileが失敗した場合の処理(例: ログに記録)
50        error_log('Failed to read file for download: ' . $filePath);
51        // エラーメッセージを出力し、スクリプトを終了
52        echo 'Error: Failed to process file for download.';
53        exit;
54    }
55
56    // 6. ファイルが正常に出力されたらスクリプトの実行を終了
57    // これにより、追加のHTMLやPHPの出力がファイルダウンロードを妨げるのを防ぎます。
58    exit;
59}
60
61// --------------------------------------------------------------------------
62// サンプルコードの実行例
63// --------------------------------------------------------------------------
64
65// ダウンロード対象のファイル名
66$sampleFileName = 'my_important_document.pdf'; // または 'my_important_document.txt'など
67// 現在のスクリプトと同じディレクトリにファイルを作成するパス
68$sampleFilePath = __DIR__ . '/' . $sampleFileName;
69
70// ダウンロード対象のファイルが存在しない場合、ダミーファイルを作成
71if (!file_exists($sampleFilePath)) {
72    // PDFや画像ファイルなど、特定のMIMEタイプを持つファイルを模倣する場合は
73    // そのMIMEタイプに合ったバイナリデータを用意する必要があります。
74    // ここでは単純なテキストファイルを作成します。
75    $content = "これはダウンロードされるべきサンプルファイルです。\n";
76    $content .= "もしこのテキストがブラウザに直接表示される場合、\n";
77    $content .= "ダウンロードが正しく機能していません(「ダウンロードできない」問題)。\n";
78    $content .= "その場合、HTTPヘッダの設定を確認してください。\n";
79    file_put_contents($sampleFilePath, $content);
80}
81
82// ファイルダウンロード処理を実行
83// このPHPスクリプトをWebブラウザで開くと、`my_important_document.pdf`
84// (または設定したファイル名)がダウンロードされるはずです。
85serveFileForDownload($sampleFilePath);
86
87// serveFileForDownload関数内でexit;が実行されるため、
88// 通常はこの行より後のコードは実行されません。
89
90?>

PHPのreadfile関数は、指定されたファイルの内容をウェブブラウザなどに出力するために使用されます。このサンプルコードは、特にブラウザがファイルを直接表示してしまう「ダウンロードできない」問題を解決し、ユーザーにファイルを強制的にダウンロードさせる方法を示しています。

readfile関数は、第一引数にファイルパス(string $filename)を受け取り、そのファイルを読み込み、ウェブサーバーの標準出力に直接書き出します。成功した場合は出力されたバイト数を整数(int)で返し、失敗した場合はfalseを返します。第二引数以降は通常の使用では省略可能です。

ファイルをダウンロードさせるには、Content-Type: application/octet-streamContent-Disposition: attachmentといったHTTPヘッダをreadfileの実行前に適切に設定することが重要です。これらのヘッダは、ブラウザに対し、表示ではなくファイルをダウンロードするよう指示します。

サンプルコードでは、ファイルが存在するか確認し、ダウンロード用のHTTPヘッダを設定した後、readfileでファイルの内容を出力します。また、出力バッファをクリアし、readfileの実行結果を確認してエラー処理を行い、最後にexit()でスクリプトの実行を終了することで、余計な出力がダウンロードを妨げないように配慮されています。これにより、指定されたファイルがブラウザで開かれることなく、安全にダウンロードされるようになります。

「ダウンロードできない」問題を解決するには、Content-TypeContent-Dispositionなど適切なHTTPヘッダをheader()関数で送信することが最も重要です。また、header()実行前に余計な出力がないようob_end_clean()でバッファをクリアし、ファイル出力後はexit;でスクリプトを確実に終了させましょう。これにより、ブラウザにファイルをダウンロードさせ、意図しない表示を防ぎます。ファイルパスは絶対パスで指定し、ユーザーからの入力の場合はディレクトリトラバーサル攻撃を防ぐため、basename()などで安全なファイル名のみを使用するよう注意してください。file_exists()readfile()の戻り値を確認し、エラー処理を怠らないようにしましょう。

関連コンテンツ