エドソンの回答のコメントで述べたように、コードの最後の行で「ヘッダーは既に送信されました」という警告が表示されると予想していました。
header('Content-Length: '.$streamSize);
出力はこのヘッダーが送信される前に書き込まれるためですが、彼の例は問題なく動作します。
いくつかの調査により、次の結論に至りました。
出力バッファ (ユーザーのバッファでも、デフォルトの PHP のバッファでも) を使用するときは、HTTP ヘッダーとコンテンツを好きなように送信できます。どのプロトコルでも、本文の前にヘッダーを送信する必要があることはわかっていますが (したがって、「ヘッダー」という用語)、出力バッファー層を使用すると、PHP がこれを処理します。出力ヘッダー (header()、setcookie()、session_start()) を使用する PHP 関数は、実際には、ヘッダー バッファーを埋めるだけの内部 sapi_header_op() 関数を使用します。次に、printf() などを使用して出力を書き込むと、出力バッファー (1 つを想定) に書き込まれます。出力バッファーが送信される場合、PHP は最初にヘッダーの送信を開始し、次に本文の送信を開始します。PHP がすべてを処理します。この動作が気に入らない場合は、出力バッファー レイヤーを無効にする以外に選択肢はありません。
と
ほとんどの構成での PHP バッファーのデフォルト サイズは 4096 バイト (4KB) です。これは、PHP バッファーが最大 4KB のデータを保持できることを意味します。この制限を超えるか、PHP コードの実行が終了すると、バッファリングされたコンテンツは、 PHP が使用されているバックエンド (CGI、mod_php、FastCGI) に自動的に送信されます。PHP-CLI では、出力バッファリングは常に Off です。
Edson のコードが機能するのは、出力バッファーがバッファー サイズを超えていないために自動的にフラッシュされなかったからです (そして、最後のヘッダーが送信される前にスクリプトが明らかに終了していません)。
出力バッファ内のデータがバッファ サイズを超えるとすぐに、警告が発生します。または彼の例では、データが
$get_users_stmt->fetch(PDO::FETCH_ASSOC)
が大きすぎます。
これを防ぐには、ob_start() および ob_end_flush(); を使用して出力バッファリングを自分で管理する必要があります。以下のように:
// Turn on output buffering
ob_start();
// Define handle to output stream
$basic_info = fopen("php://output", 'w');
// Define and write header row to csv output
$basic_header = array('Header1', 'Header2');
fputcsv($basic_info, $basic_header);
$count = 0; // Auxiliary variable to write csv header in a different way
// Get data for remaining rows and write this rows to csv output
while($user_row = $get_users_stmt->fetch(PDO::FETCH_ASSOC)) {
if ($count == 0) {
// Write select column's names as CSV header
fputcsv($basic_info, array_keys($user_row));
} else {
//Write data row
fputcsv($basic_info, $user_row);
}
$count++;
}
// Get size of output after last output data sent
$streamSize = ob_get_length();
//Close the filepointer
fclose($basic_info);
// Send the raw HTTP headers
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename=test.csv');
header('Expires: 0');
header('Cache-Control: no-cache');
header('Content-Length: '. ob_get_length());
// Flush (send) the output buffer and turn off output buffering
ob_end_flush();
ただし、他の制限にはまだ縛られています。