質問
PHPでFPUTCSVを使用して、データベースクエリのコンマ区切りファイルを出力しています。 ubuntuでgeditでファイルを開くと、それは正しいように見えます - 各レコードにはラインブレークがあります(目に見えるラインブレーク文字はありませんが、各レコードが分離されていることを知ることができ、OpenOfficeスプレッドシートでそれを開くとファイルを正しく表示できます)。
ただし、これらのファイルをWindowsでクライアントに送信しており、そのシステムでは、ファイルが1つの大きな長い行として届きます。 Excelで開くと、複数の行がまったく認識されません。
私はここでいくつかの質問を読みました、それはかなり似ています これです, 、本当に有益なものへのリンクが含まれています 偉大なニューライン分裂 説明。
残念ながら、クライアントに「よりスマートな」エディターでファイルを開くように言うことはできません。彼らはそれらをExcelで開くことができる必要があります。正しいNewline文字が追加されていることを確認して、任意のOSのスプレッドシートプログラムでファイルを開くことができるプログラム的な方法はありますか?
FPUTCSVはそれについて選択的であるため、すでにすべての値の周りに引用符を強制するためにカスタム関数を使用しています。私はこのようなことをしようとしました:
function my_fputcsv($handle, $fieldsarray, $delimiter = "~", $enclosure ='"'){
$glue = $enclosure . $delimiter . $enclosure;
return fwrite($handle, $enclosure . implode($glue,$fieldsarray) . $enclosure."\r\n");
}
しかし、ファイルがWindowsテキストエディターで開かれている場合、単一の長い行として表示されます。
解決 8
私は最終的に専門家交換で答えを得ました。これがうまくいったものです:
function my_fputcsv($handle, $fieldsarray, $delimiter = "~", $enclosure ='"'){
$glue = $enclosure . $delimiter . $enclosure;
return fwrite($handle, $enclosure . implode($glue,$fieldsarray) . $enclosure.PHP_EOL);
}
標準のFPUTCSVの代わりに使用されます。
他のヒント
// Writes an array to an open CSV file with a custom end of line.
//
// $fp: a seekable file pointer. Most file pointers are seekable,
// but some are not. example: fopen('php://output', 'w') is not seekable.
// $eol: probably one of "\r\n", "\n", or for super old macs: "\r"
function fputcsv_eol($fp, $array, $eol) {
fputcsv($fp, $array);
if("\n" != $eol && 0 === fseek($fp, -1, SEEK_CUR)) {
fwrite($fp, $eol);
}
}
これは、@John Douthatの素晴らしい答えの改善されたバージョンであり、カスタムデリミターとエンクロージャーを使用し、FPUTCSVの元の出力を返す可能性を維持します。
function fputcsv_eol($handle, $array, $delimiter = ',', $enclosure = '"', $eol = "\n") {
$return = fputcsv($handle, $array, $delimiter, $enclosure);
if($return !== FALSE && "\n" != $eol && 0 === fseek($handle, -1, SEEK_CUR)) {
fwrite($handle, $eol);
}
return $return;
}
PHP関数FPUTCSVを使用すると、 nのみを書き込み、カスタマイズできません。これにより、Microsoft環境の関数は価値がなくなりますが、一部のパッケージではLinux Newlineも検出されます。
それでも、FPUTCSVの利点により、ファイルに送信する直前に新しいライン文字を交換するソリューションを掘り下げました。これは、FPUTCSVを最初にPHP TEMPストリームのビルドにストリーミングすることで実行できます。次に、新しいライン文字を必要なものに適応させ、ファイルに保存します。このような:
function getcsvline($list, $seperator, $enclosure, $newline = "" ){
$fp = fopen('php://temp', 'r+');
fputcsv($fp, $list, $seperator, $enclosure );
rewind($fp);
$line = fgets($fp);
if( $newline and $newline != "\n" ) {
if( $line[strlen($line)-2] != "\r" and $line[strlen($line)-1] == "\n") {
$line = substr_replace($line,"",-1) . $newline;
} else {
// return the line as is (literal string)
//die( 'original csv line is already \r\n style' );
}
}
return $line;
}
/* to call the function with the array $row and save to file with filehandle $fp */
$line = getcsvline( $row, ",", "\"", "\r\n" );
fwrite( $fp, $line);
または、ネイティブUnix形式( nのみ)で出力し、結果のファイルでUNIX2DOSを実行して、適切な場所で r nに変換することができます。データには含まれていないことに注意してください。また、〜のデフォルトのセパレーターを使用していることがわかります。 tのデフォルトセパレーターを試してください。
として Webbiedave 指摘された(thx!)おそらく最もきれいな方法は、ストリームフィルターを使用することです。
それは他のソリューションよりも少し複雑ですが、それらに書き込み後に編集できないストリームでも機能します(ダウンロードのように $handle = fopen('php://output', 'w');
)
これが私のアプローチです:
class StreamFilterNewlines extends php_user_filter {
function filter($in, $out, &$consumed, $closing) {
while ( $bucket = stream_bucket_make_writeable($in) ) {
$bucket->data = preg_replace('/([^\r])\n/', "$1\r\n", $bucket->data);
$consumed += $bucket->datalen;
stream_bucket_append($out, $bucket);
}
return PSFS_PASS_ON;
}
}
stream_filter_register("newlines", "StreamFilterNewlines");
stream_filter_append($handle, "newlines");
fputcsv($handle, $list, $seperator, $enclosure);
...
私は似たような状況に対処してきました。これは、Windowsフレンドリーなラインエンドを使用してCSVファイルを出力することがわかったソリューションです。
http://www.php.net/manual/en/function.fputcsv.php#90883
ファイルをクライアントにストリーミングしようとしていて、FSEEKSを使用できないため、使用できませんでした。
Windowsのニーズ \r\n
として ラインブレイク/キャリッジ 別々の行を表示するためにコンボを返します。