fgetcsv() удаляет символы с диакритическими знаками (т. Е. не ASCII) - как исправить?


Похожие вопросы:
Некоторые символы в CSV-файле не считываются во время PHP fgetcsv() ,
fgetcsv() игнорирует специальные символы, когда они находятся в начале строки

В моем приложении есть форма, в которой пользователи могут загружать файл CSV (его 5 внутренних пользователей всегда загружали допустимый файл - разделенный запятыми, в кавычках, записи заканчиваются на LF), а затем файл импортируется в базу данных с помощью PHP:

$fhandle = fopen($uploaded_file,'r');
while($row = fgetcsv($fhandle, 0, ',', '"', '\\')) {
    print_r($row);
    // further code not relevant as the data is already corrupt at this point
}

Для причины, по которым я не могу изменить, пользователи загружают файл, закодированный в кодировке Windows-1250 - однобайтовой 8-битной кодировке символов.

Проблема: и некоторые (не все!) символы за пределами 127 ("расширенный ASCII") отбрасываются в fgetcsv(). Пример данных:

"15","Ústav"
"420","Špičák"
"7","Tmaň"

Становится

Array (
  0 => 15
  1 => "stav"
)
Array (
  0 => 420
  1 => "pičák"
)
Array (
  0 => 7
  1 => "Tma"
)

(Обратите внимание, что č сохранен, но Ú удален)

В документации для fgetcsv говорится, что "начиная с 4.3.5 fgetcsv() теперь безопасен для двоичных файлов", но похоже, что это не так. Неужели я что-то не так, или эта функция сломана, и мне следует искать другой способ анализа CSV?

Author: Community, 2010-09-03

1 answers

Оказывается, я недостаточно хорошо прочитал документацию - fgetcsv() только несколько безопасен для двоичных файлов. Это безопасно для простого ASCII в документации также говорится:

Примечание:

Эта функция учитывает настройки локали . Если LANG, например , en_US.UTF-8, эта функция неправильно считывает файлы в однобайтовой кодировке

Другими словами, fgetcsv() пытается быть безопасным для двоичных файлов, но на самом деле это не (потому что он также одновременно вмешивается в кодировку), и он, вероятно, исказит данные, которые он читает (поскольку этот параметр не настроен в php.ini, а скорее читается из $LANG).

Я обошел проблему, прочитав строки с помощью fgets (который работает с байтами, а не символами) и используя функцию CSV из комментария в документах для их анализа в массив:

$fhandle = fopen($uploaded_file,'r');
while($raw_row = fgets($fhandle)) { // fgets is actually binary safe
    $row = csvstring_to_array($raw_row, ',', '"', "\n");
    // $row is now read correctly
}
 13
Author: Piskvor, 2018-04-05 09:15:19