fwrite() и UTF8

Я создаю файл, используя php fwrite(), и я знаю, что все мои данные находятся в UTF8 (я провел обширное тестирование по этому поводу - при сохранении данных в БД и выводе на обычную веб-страницу все работает нормально и сообщает как utf8.), но я мне говорят, что файл, который я вывожу, содержит данные, отличные от utf8 :( Есть ли команда в bash (CentOS) для проверки формата файла?

При использовании vim он показывает содержимое как:

Ничего не делайте.... Это отличный сайт со всем... Мы только что запустили/

Будем признательны за любую помощь: либо подтверждение того, что файл является UTF8, либо как записать содержимое utf8 в файл.

ОБНОВЛЕНИЕ

Чтобы уточнить, откуда я знаю, что у меня есть данные в UTF8, я сделал следующее:

  1. DB установлен в utf8 при сохранении данных
  2. в базу данных я сначала запускаю это:

    $enc = mb_detect_encoding($data);

    $data = mb_convert_encoding($data, "UTF-8", $enc);

  3. Непосредственно перед запуском fwrite я проверил данные с помощью Обратите внимание, что каждый фрагмент данных возвращает «IS utf-8».

    if (strlen($data)==mb_strlen($data, 'UTF-8')) print 'NOT UTF-8'; else print 'IS utf-8';

Спасибо!


person Lizard    schedule 13.06.2011    source источник
comment
См. этот вопрос для функции PHP, которая проверяет строку UTF-8 побитно. Он называется can_be_valid_utf8_statemachine(). По крайней мере, он более точен в своем результате, чем ваш подход к сравнению strlen.   -  person hakre    schedule 14.06.2011
comment
Прежде чем кодировать что-то в UTF-8, вы должны убедиться, что это UTF-8, потому что после кодирования в UTF-8 это всегда будет UTF-8. Так что вы просто не можете проверить это позже.   -  person hakre    schedule 14.06.2011


Ответы (8)


Если вы знаете, что данные находятся в UTF8, вам нужно настроить заголовок.

Я написал решение, отвечающее другому треду.

Решение следующее: поскольку знак порядка байтов UTF-8 равен \xef\xbb\xbf, мы должны добавить его в заголовок документа.

<?php
function writeStringToFile($file, $string){
    $f=fopen($file, "wb");
    $file="\xEF\xBB\xBF".$file; // this is what makes the magic
    fputs($f, $string);
    fclose($f);
}
?>

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

person Florin Sima    schedule 31.08.2012
comment
Спецификация UTF8 означает 0xEF, 0xBB, 0xBF, что я и предложил. Теперь вы, очевидно, можете создать файл в формате UTF-8, изменив настройки в своей среде IDE. Но того же можно добиться, используя только PHP. - person Florin Sima; 10.09.2012
comment
Также для записей и для тех, кто может наткнуться на это решение, это не та строка, которая делает магию $file="\xEF\xBB\xBF".$file;, как заявил @FlorinSima. Эта строка только добавляет спецификацию в файл (UTF-8 с спецификацией). Скорее, строка, которая делает файл UTF-8, это $f=fopen($file, "wb"); - person Felix Imafidon; 21.04.2017
comment
Это решение мне не помогло, однако этот (принятый ответ) сработал: stackoverflow.com/questions/21988581/ - person charel-f; 21.06.2019
comment
любой универсальный способ установить заголовок на основе знания имени набора символов? - person Fanky; 15.01.2020

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

Чтобы быть в безопасности, вы должны использовать fopen() с флагом двоичного режима. это b. После этого fwrite() сохранит ваши строковые данные «как есть», и это в PHP до сих пор двоичные данные, потому что строки в PHP являются двоичными строками.

Общие сведения. В некоторых системах текстовые и двоичные данные различаются. Двоичный флаг будет явно указывать PHP на таких системах использовать двоичный вывод. Когда вы имеете дело с UTF-8, вы должны позаботиться о том, чтобы данные не были изменены. Это предотвращается обработкой строковых данных как двоичных данных.

Однако: Если это не так, как вы сказали в своем вопросе, что кодировка данных UTF-8 сохраняется, значит, ваша кодировка была нарушена, и даже безопасная двоичная обработка сохранит статус сломанного. Тем не менее, с бинарным флагом вы по-прежнему гарантируете, что это не fwrite() часть вашего приложения, которая ломает что-то.

В другом ответе здесь справедливо написано, что вы не знаете кодировку, если у вас есть только данные. Однако вы можете проверить данные, если они подтверждают кодировку UTF-8 или нет, что дает вам хотя бы некоторую возможность проверить кодировку. Функция в PHP, которая делает это, я разместил в вопросе, связанном с UTF-8, поэтому он может быть вам полезен, если вам нужно отлаживать вещи: Ответ на: SimpleXML и китайский ищите can_be_valid_utf8_statemachine, это название функции.

person hakre    schedule 13.06.2011
comment
Это на самом деле не решает вопрос. Он не использует кодировку, на которую может отрицательно повлиять изменение символов новой строки. На самом деле, большинство широко используемых кодировок либо совместимы с ASCII, либо, по крайней мере, сохраняют символы ASCII до тех пор, пока кодовая точка находится значительно выше блока C0. - person Artefacto; 14.06.2011
comment
Состояние двоичной безопасности функции важно, когда вы имеете дело с кодировками. fwrite(), безусловно, не является источником проблемы, но ИМХО стоит отметить в контексте вопроса, поскольку ОП не уверен, является ли fwrite источником ошибки. Однако я с вами, что я не верю, что это на самом деле источник ошибки. Поэтому я оставил несколько советов, как лучше проверить, действительно ли строковые данные закодированы в UTF-8 или могут быть, по крайней мере. - person hakre; 14.06.2011

//add BOM to fix UTF-8 in Excel
fputs($fp, $bom =( chr(0xEF) . chr(0xBB) . chr(0xBF) ));

Мне эта часть подходит :)

person Du Peng    schedule 26.01.2016

Проблема в том, что ваши данные закодированы дважды. Я предполагаю, что ваш исходный текст выглядит примерно так:

Don’t do anything

с , то есть не прямым апострофом, а правая одинарная кавычка.

Если вы пишете PHP-скрипт с этим содержимым и кодируете его в UTF-8:

<?php
//File in UTF-8
echo utf8_encode("Don’t"); //this will double encode

Вы получите что-то похожее на ваш вывод.

person Artefacto    schedule 13.06.2011
comment
у меня нигде нет utf8_encode, а когда я его добавляю, становится еще хуже. - person Lizard; 14.06.2011
comment
Нет ничего лучше двойного кодирования. Всегда есть одна кодировка, вы не можете удвоить кодировку строки;) - person hakre; 14.06.2011
comment
@hakre Конечно, если мы хотим быть точным, я имел в виду, что преобразование ASCII/ISO-8859-1/что угодно в UTF-8 применялось к данным, которые уже были закодированы в UTF-8. - person Artefacto; 14.06.2011
comment
@Lizard Я никогда не говорил, что у тебя utf8_encode. Я просто показывал, какую коррупцию ты получаешь. А именно, что-то преобразует ваши данные в UTF-8, когда они уже в UTF-8. - person Artefacto; 14.06.2011

I know all my data is in UTF8 - неправильно.
Кодировка - это не формат файла. Итак, проверьте кодировку в заголовках страницы, откуда вы берете данные:
header("Content-type: text/html; charset=utf-8;");
И проверьте, действительно ли данные в многобайтной кодировке:
if (strlen($data)==mb_strlen($data, 'UTF-8')) print 'not UTF-8';
else print 'utf-8';

person OZ_    schedule 13.06.2011
comment
Я знаю, что все мои данные в UTF8 - я провел обширное тестирование - при сохранении данных в БД и выводе на обычную веб-страницу все работает нормально и сообщает как utf8. - person Lizard; 14.06.2011
comment
Это не означает, что ваши данные в UTF-8. Выход есть выход, вход есть вход. При сохранении данных в БД вы можете их конвертировать. Кроме того, файлы не могут иметь свойство encoding, только данные могут иметь кодировку. Итак, если ваш файл содержит данные в кодировке, отличной от utf, это абсолютно означает, что данные были в неправильной кодировке. Для гарантии - используйте код из моего ответа. - person OZ_; 14.06.2011
comment
я уверен, что это utf8. Я также тестировал ваш код, и каждая строка, которую я пишу в файл, говорит «utf-8», НЕТ упоминания «не UTF-8». - person Lizard; 14.06.2011
comment
Потом проблемы в vim, может какие локали не установились. В Debian напишите dpkg-reconfigure locales в консоли и убедитесь, что выбраны эти локали: en.GB UTF-8, en.US UTF-8, en.US UTF-8. - person OZ_; 14.06.2011
comment
Использование mb_detect_encoding очень неправильно. Вы должны быть уверены, что данные в UTF-8 только потому, что все заголовки были отправлены корректно. mb_detect_encoding это бесполезная функция, не используйте ее. Кроме того, если вы проверите if (strlen... после этого преобразования - это не сработает. - person OZ_; 14.06.2011
comment
OZ_: Ваш код вернет not UTF-8 для строки A. Я почти уверен, что у вас есть ошибка в вашей рутине. - person hakre; 14.06.2011
comment
@hakre, для символа A этот код должен возвращать not UTF-8. Я почти уверен, что вы не понимаете, как работает этот код. - person OZ_; 14.06.2011
comment
Ну A это UTF-8. Возможно, я не понимаю, для чего нужен ваш код, но, возможно, вы можете объяснить мне, почему он возвращает not UTF-8 для строк, которые равны UTF-8. - person hakre; 14.06.2011

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

$file= fopen('../logs/logs.txt','a');
fwrite($file,PHP_EOL."_____________________output_____________________".PHP_EOL);
fwrite($file,print_r($value,true));
person norullah karimi    schedule 26.03.2021

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

person Lizard    schedule 29.06.2011

Попробуйте этот простой метод, который является более полезным, и добавьте в начало страницы перед тегом <body> :

<head>
  <meta charset="utf-8">
</head>
person mohamed isam    schedule 05.12.2018
comment
Ваш ответ недействителен в этом случае, потому что теги ‹head› и ‹meta› применяются только на стороне клиента (HTML), а проблема на стороне сервера (PHP) (а не с полученной информацией). - person Sakura Kinomoto; 06.12.2018