データベースからセレクトしたデータを、PHPでCSV形式に変換し、CSVファイルとしてダウンロードさせる方法。
ロジックの中核部分は、php://memory
(読み書き可能なストリームで、一時データをファイルのように保存できるラッパー)を使用してファイルを生成していることと、 fputcsv
を使用して行をCSV形式にフォーマットし、ファイルポインタに書き込むことの二点である。
また、Windowsユーザにダウンロードさせることを前提として、改行コードや文字コードをWindows 7で都合がいいように\r\n
,SJIS
としている。
// ヘッダー定義
$header = array('col1', 'col2', 'col3');
// データベースからダウンロード用データ取得
$data = $db->load();
// ヘッダーとデータを合体
array_unshift($data, $header);
// ファイル名
$filename = 'ファイル名';
$fileContent = createCsvDownload($data, "\r\n");
$filename = mb_convert_encoding($filename,"SJIS-win","UTF-8");
header('Content-Disposition: attachment; filename=' . $filename);
header('Content-Type: application/csv');
print $fileContent;
/**
* CSVファイルダウンロード用データ生成関数
* @param array $content
* @param $newline default: LF
*
* @return 文字列
*/
function createCsvDownload(array $content, $newline = "\n") {
$out = fopen('php://memory', 'w');
if ($newline == "\r\n") {
stream_filter_register("msLineEnding", "ms_line_ending_filter");
stream_filter_append($out, "msLineEnding");
}
foreach ($content as $line) {
fputcsv($out, array_map(function($arr) { return mb_convert_encoding($arr,"SJIS-win","UTF-8"); }, $line));
}
rewind($out);
$fileContent = stream_get_contents($out);
fclose($out);
return $fileContent;
}
/**
* 行末改行記号をCRLFに変換するユーザ定義フィルタクラス
*/
class ms_line_ending_filter extends \php_user_filter {
function filter($in, $out, &$consumed, $closing) {
while ($bucket = stream_bucket_make_writeable($in)) {
$bucket->data = preg_replace("/\n$/", "", $bucket->data);
$bucket->data = preg_replace("/\r$/", "", $bucket->data);
$bucket->data = $bucket->data . "\r\n";
$consumed += $bucket->datalen;
stream_bucket_append($out, $bucket);
}
return PSFS_PASS_ON;
}
}
SymfonyのResponseオブジェクトを使う場合
use Symfony\Component\HttpFoundation\Response;
/**
*
* @param array $content
* @param $filename
* @param $newline default: LF
*
* @return Response
*/
function download(array $content, $filename, $newline = "\n") {
$filename = mb_convert_encoding($filename,"SJIS-win","UTF-8");
$fileContent = createCsvDownload($content, $newline);
return new Response($fileContent,200,array("Content-Type"=>"application/csv","Content-Disposition"=>"attachment; filename=$filename"));
}