Акценты в загруженном файле заменены на '?'

Я создаю инструмент импорта данных для административного раздела веб-сайта, над которым я работаю. Данные представлены на французском и английском языках и содержат много символов с диакритическими знаками. Всякий раз, когда я пытаюсь загрузить файл, проанализировать данные и сохранить их в своей базе данных MySQL, акценты заменяются на «?».

У меня есть текстовые файлы, содержащие данные (кодировка iso-8859-1), которые я загружаю на свой сервер с помощью библиотеки загрузки файлов CodeIgniter. Затем я прочитал файл в PHP.

Мой код похож на этот:

$this->upload->do_upload()
$data = array('upload_data' => $this->upload->data());

$fileHandle = fopen($data['upload_data']['full_path'], "r");

while (($line = fgets($fileHandle)) !== false) {
    echo $line;
}

Это создает строки с заменой акцентов на «?». Все остальное правильно.

Если я загружаю свой загруженный файл со своего сервера по FTP, кодировка по-прежнему iso-8850-1, но разница показывает, что файл изменился. Однако, если я открою файл в TextEdit, он отобразится правильно.

Я попытался использовать метод PHP stream_encoding, чтобы явно установить для моего файлового потока значение iso-8859-1, но в моей сборке PHP нет этого метода.

Когда у меня закончились идеи, я попытался обернуть свои строки как в utf8_encode, так и в utf8_decode. Ни один из них не работал.

Если у кого-нибудь есть какие-либо предложения о том, что я мог бы попробовать, я был бы очень благодарен.


person Katfish    schedule 22.06.2011    source источник


Ответы (3)


Важно видеть, происходит ли повреждение до или после отправки запроса в mySQL. Здесь происходит слишком много возможных вещей, чтобы можно было их точно определить. Вы можете вывести свой MySql, чтобы проверить это?

Предполагая, что ваш запрос правильно сформирован (нет искажений на этапе вывода запроса), есть несколько вещей, которые вы должны проверить.

  1. Какова кодировка символов самой базы данных? (сопоставление)

  2. Какова кодировка соединения - это может быть неправильно настроено в вашей конфигурации mysql и может быть установлено вручную с помощью команды «SET NAMES»

В моем собственном приложении я выдаю «SET NAMES utf8» в качестве моего первого запроса после установления соединения, поскольку я не могу изменить конфигурацию MySQL.

Видеть это. http://dev.mysql.com/doc/refman/5.0/en/charset-connection.html

Изменить: если проблема не связана с mysql, я бы проверил следующее

  1. Вы говорите, что кодировка файла "кодировка iso-8859-1" - могу я спросить, как вы в этом уверены?

  2. Что произойдет, если вы сохраните сам файл как utf8 (без спецификации) и попытаетесь его переобработать?

  3. В какой кодировке находится файл php, выполняющий преобразование? (Что вы используете для написания своего php - он может «управлять» этим для вас нежелательным образом)

  4. (в сторону) Подходят ли файлы, которые вы обрабатываете, для обработки с использованием fgetcsv? http://php.net/manual/en/function.fgetcsv.php

person calumbrodie    schedule 22.06.2011
comment
Если я напрямую вывожу строки, считываемые fgets(), вместо диакритических знаков в них появляются вопросительные знаки. Я не думаю, что проблема связана с MySQL. - person Katfish; 23.06.2011
comment
Я проверил кодировку файла, используя file -I <filepath> в командной строке. Я создаю и редактирую файлы PHP с помощью Eclipse, и они кодируются как ascii. Я загружаю файлы с помощью Filezilla, но кодировка, по-видимому, сохраняется благодаря этому - когда я загружаю файлы, которые я ранее загрузил, они все еще имеют свои исходные кодировки. - person Katfish; 23.06.2011
comment
Согласно вашему предложению № 2, я сохранил свой исходный файл с кодировкой utf-8, и это сработало. Поскольку я не могу гарантировать, что мои пользователи будут использовать эту кодировку, есть ли способ сделать преобразование при загрузке файла? - person Katfish; 23.06.2011
comment
@kissmyface работает правильно, когда мой загруженный файл использует utf-8, но файлы, которые будут загружены, выгружаются из внешней базы данных, которая сохраняет данные экспорта с помощью iso-8859-1 (который, согласно hakre, поддерживает французский акцент). Если я конвертирую файл, мне нужно конвертировать его на моем сервере. - person Katfish; 23.06.2011
comment
@kissmyface Я использовал mb_convert_encoding() для преобразования строки в iso-8859-1, и это сработало! Спасибо! - person Katfish; 23.06.2011

Файлы, загруженные на ваш сервер, должны возвращаться такими же при загрузке. Это означает, что кодировку файла (который представляет собой просто набор двоичных данных) менять не следует. Вместо этого вы должны позаботиться о том, чтобы сохранить двоичную информацию этого файла без изменений.

Чтобы добиться этого с вашей базой данных, создайте поле BLOB. Это правильный тип столбца для этого. Это просто двоичные данные.

Предполагая, что вы используете MySQL, это ссылка: Типы BLOB и TEXT обратите внимание на BLOB.

person hakre    schedule 23.06.2011
comment
Я не храню файл в своей базе данных; просто строки, которые я читаю из файла. - person Katfish; 23.06.2011
comment
Каков тип данных поля в базе данных? - person hakre; 23.06.2011
comment
Поле в базе данных является текстовым, но я потерял свои акценты, прежде чем что-либо сохранить в базе данных. Если я повторяю строки, когда читаю их из своего файла, они не имеют акцентов. - person Katfish; 23.06.2011
comment
Где вы их повторяете? Ваш браузер? Вы проверили порядок байтов с помощью функции hex_dump()? - person hakre; 23.06.2011

Проблема в том, что вы используете iso-8859-1 вместо utf-8. Чтобы закодировать его в правильной кодировке, вы должны использовать функцию iconv, например:

$output_string = iconv('utf-8", "utf-8//TRANSLIT", $input_string);

iso-8859-1 не имеет кодировки для каких-либо акцентов.

Было бы намного лучше, если бы все было в формате utf-8, так как он обрабатывает практически все символы, известные человеку.

person timw4mail    schedule 22.06.2011
comment
Я только что попытался использовать iconv(), но это не удалось с ошибкой «Обнаружен недопустимый символ во входной строке». Я также пытался использовать iso-8859-1 в качестве набора входных символов. Если iso-8859-1 не имеет какой-либо кодировки акцента, как он отображает акценты? Программы типа TextEdit автоматически преобразовывают кодировку перед ее отображением? - person Katfish; 23.06.2011
comment
@Katfish: ISO-8859-1 IIRC охватывает французский акцент. Если вы храните файлы в базе данных, вы должны хранить их как BLOB и доставлять их как есть с их собственной кодировкой. Не искажайте их, как предлагается в этом ответе, прежде чем сохранить их в базе данных. Храните их КАК ЕСТЬ. - person hakre; 23.06.2011
comment
@hakre Я сохраняю в своей базе данных только строки, которые я читал из своих файлов. Файлы удаляются после того, как я их анализирую. - person Katfish; 23.06.2011
comment
Если вы храните строки, они могут быть искажены MySQL, чтобы соответствовать кодировке вашей базы данных/таблицы/столбца (или даже клиентом для подключения к вашей базе данных). Сохраните их в поле BLOB. Строка в PHP — это двоичная строка, поэтому вы фактически имеете дело с двоичными данными. - person hakre; 23.06.2011
comment
@hakre Если я использую поле BLOB, сможет ли PHP прочитать его, как если бы это была строка? - person Katfish; 23.06.2011
comment
Да. Все строки в PHP являются двоичными. Это не проблема. Кстати, вы можете использовать file_get_contents(), чтобы просто прочитать весь файл в строку. - person hakre; 23.06.2011
comment
@hakre Я знаю, но каждая строка моего файла — это строка базы данных, и мне нужно иметь дело с каждой по отдельности. - person Katfish; 23.06.2011
comment
@Katfish: Затем вы должны определить кодировку, необходимую для вашей организации данных, и сделать ее видимой для пользователя в форме загрузки, какая кодировка ожидается для файла. - person hakre; 23.06.2011