fputcsv и коды новой строки

Я использую fputcsv в PHP для вывода файла с разделителями-запятыми запроса базы данных. При открытии файла в gedit в Ubuntu он выглядит корректно – каждая запись имеет разрыв строки (нет видимых символов разрыва строки, но вы можете сказать, что каждая запись разделена, и открытие ее в электронной таблице OpenOffice позволяет мне правильно просматривать файл.)

Однако мы отправляем эти файлы клиенту в Windows, и в их системах файл поставляется в виде одной большой длинной строки. Открывая его в Excel, он не распознает несколько строк.

Я прочитал здесь несколько вопросов, которые очень похожи, в том числе и этот , который включает ссылку на действительно информативное объяснение Великой Новой Шрифты .

К сожалению, мы не можем просто сказать нашим клиентам, чтобы они открывали файлы в «умном» редакторе. Они должны иметь возможность открывать их в Excel. Есть ли какой-либо программный способ обеспечения добавления правильных символов новой строки, чтобы файл можно было открыть в программе для работы с электронными таблицами на любой ОС?

Я уже использую настраиваемую функцию для принудительного цитирования всех значений, поскольку fputcsv является выборочным. Я пробовал сделать что-то вроде этого:

function my_fputcsv($handle, $fieldsarray, $delimiter = "~", $enclosure ='"'){ $glue = $enclosure . $delimiter . $enclosure; return fwrite($handle, $enclosure . implode($glue,$fieldsarray) . $enclosure."\r\n"); } 

Но когда файл открывается в текстовом редакторе Windows, он все равно отображается как одна длинная строка.

 // 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.

Тем не менее преимущества 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 в соответствующих местах. Просто будьте осторожны, чтобы ваши данные не содержали \ n. Кроме того, я вижу, что вы используете разделитель по умолчанию ~. попробуйте разделитель по умолчанию из \ t.

Я занимаюсь подобной ситуацией. Вот решение, которое я нашел, выводя CSV-файлы с дружественными окнами.

http://www.php.net/manual/en/function.fputcsv.php#90883

Я не смог использовать, так как я пытаюсь передать файл клиенту и не могу использовать fseeks.

Как указывал 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); ... 

Окна требуют \r\n как комбинированное преобразование строк / кареток , чтобы показать отдельные строки.

В конце концов я получил ответ на обмене экспертами; вот что сработало:

 function my_fputcsv($handle, $fieldsarray, $delimiter = "~", $enclosure ='"'){ $glue = $enclosure . $delimiter . $enclosure; return fwrite($handle, $enclosure . implode($glue,$fieldsarray) . $enclosure.PHP_EOL); } 

для использования вместо стандартного fputcsv.