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?

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

Заметка:

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

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

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

 $fhandle = fopen($uploaded_file,'r'); while($raw_row = fgets($fhandle, 0)) { // fgets is actually binary safe $row = csvstring_to_array($raw_row, ',', '"', "\n"); // $row is now read correctly }