Определите кодировку и сделайте все в UTF-8 - PullRequest
287 голосов
/ 26 мая 2009

Я читаю много текстов из различных RSS-каналов и вставляю их в свою базу данных.

Конечно, в каналах используется несколько различных кодировок символов, например, UTF-8 и ISO-8859-1.

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

  1. «ß» в «Fußball» в моей базе данных должно выглядеть так: «ÂŸ». Если это «В», оно отображается правильно.

  2. Иногда «ß» в «Fußball» в моей базе данных выглядит так: «ÃƒÂŸ». Тогда это отображается неправильно, конечно.

  3. В других случаях «ß» сохраняется как «ß» - то есть без каких-либо изменений. Тогда это также отображается неправильно.

Что я могу сделать, чтобы избежать случаев 2 и 3?

Как я могу сделать все в той же кодировке, желательно UTF-8? Когда я должен использовать utf8_encode(), когда я должен использовать utf8_decode() (ясно, каков эффект, но когда я должен использовать функции?) И когда я ничего не должен делать с вводом?

Можете ли вы помочь мне и скажите, как сделать так, чтобы кодировка была одинаковой? Возможно с функцией mb_detect_encoding()? Могу ли я написать функцию для этого? Итак, мои проблемы:

  1. Как узнать, какую кодировку использует текст?
  2. Как преобразовать его в UTF-8 - какой бы ни была старая кодировка?

Будет ли такая функция работать?

function correct_encoding($text) {
    $current_encoding = mb_detect_encoding($text, 'auto');
    $text = iconv($current_encoding, 'UTF-8', $text);
    return $text;
}

Я проверял это, но это не работает. Что с ним не так?

Ответы [ 24 ]

2 голосов
/ 26 мая 2009

Разработка кодировки символов RSS-каналов кажется сложной . Даже обычные веб-страницы часто опускают или лгут об их кодировке.

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

2 голосов
/ 23 мая 2010

Я знаю, что это старый вопрос, но я считаю, что полезный ответ никогда не повредит. У меня были проблемы с моей кодировкой между настольным приложением, SQLite и переменными GET / POST. Некоторые из них будут в UTF-8, некоторые - в ASCII, и, в основном, все будет испорчено, когда в игру вступят иностранные символы.

Вот мое решение. Он очищает ваш GET / POST / REQUEST (я пропустил куки, но вы можете добавить их при желании) на каждой странице загрузки перед обработкой. Хорошо работает в шапке. PHP выдаст предупреждения, если не сможет автоматически определить кодировку источника, поэтому эти предупреждения подавляются с помощью @.

//Convert everything in our vars to UTF-8 for playing nice with the database...
//Use some auto detection here to help us not double-encode...
//Suppress possible warnings with @'s for when encoding cannot be detected
try
{
    $process = array(&$_GET, &$_POST, &$_REQUEST);
    while (list($key, $val) = each($process)) {
        foreach ($val as $k => $v) {
            unset($process[$key][$k]);
            if (is_array($v)) {
                $process[$key][@mb_convert_encoding($k,'UTF-8','auto')] = $v;
                $process[] = &$process[$key][@mb_convert_encoding($k,'UTF-8','auto')];
            } else {
                $process[$key][@mb_convert_encoding($k,'UTF-8','auto')] = @mb_convert_encoding($v,'UTF-8','auto');
            }
        }
    }
    unset($process);
}
catch(Exception $ex){}
2 голосов
/ 26 мая 2009

Все просто: когда вы получаете что-то, что не является UTF8, вы должны кодировать это в utf8.

Итак, когда вы выбираете определенный канал, который является ISO-8859-1, анализируйте его через utf8_encode.

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

1 голос
/ 26 мая 2009

php.net / mb_detect_encoding

echo mb_detect_encoding($str, "auto");

или

echo mb_detect_encoding($str, "UTF-8, ASCII, ISO-8859-1");

Я действительно не знаю, каковы результаты, но я бы посоветовал вам взять некоторые из ваших каналов с различными кодировками и попробовать, если mb_detect_encoding работает или нет.

обновление
auto - это сокращение от "ASCII, JIS, UTF-8, EUC-JP, SJIS". он возвращает обнаруженную кодировку, которую можно использовать для преобразования строки в utf-8 с помощью iconv .

<?php
function convertToUTF8($str) {
    $enc = mb_detect_encoding($str);

    if ($enc && $enc != 'UTF-8') {
        return iconv($enc, 'UTF-8', $str);
    } else {
        return $str;
    }
}
?>

я не проверял, так что никаких гарантий. и, может быть, есть более простой способ.

1 голос
/ 27 июля 2011

@ арфакс, который работал на меня. В моем случае это достаточно хорошо:

if (isUTF8($str)) { 
    echo $str; 
}
else
{
    echo iconv("ISO-8859-1", "UTF-8//TRANSLIT", $str);
}
0 голосов
/ 19 августа 2016

Ÿ - это моджибаке для ß. В вашей базе данных у вас может быть hex

DF if the column is "latin1",
C39F if the column is utf8 -- OR -- it is latin1, but "double-encoded"
C383C5B8 if double-encoded into a utf8 column

Вы должны не использовать любые функции кодирования / декодирования в PHP; вместо этого вы должны правильно настроить базу данных и соединение с ней.

Если задействован MySQL, см .: Проблема с символами utf8; то, что я вижу, не то, что я сохранил

0 голосов
/ 13 декабря 2016

Я нахожу решение здесь http://deer.org.ua/2009/10/06/1/

class Encoding
{
    /**
     * http://deer.org.ua/2009/10/06/1/
     * @param $string
     * @return null
     */
    public static function detect_encoding($string)
    {
        static $list = ['utf-8', 'windows-1251'];

        foreach ($list as $item) {
            try {
                $sample = iconv($item, $item, $string);
            } catch (\Exception $e) {
                continue;
            }
            if (md5($sample) == md5($string)) {
                return $item;
            }
        }
        return null;
    }
}

$content = file_get_contents($file['tmp_name']);
$encoding = Encoding::detect_encoding($content);
if ($encoding != 'utf-8') {
    $result = iconv($encoding, 'utf-8', $content);
} else {
    $result = $content;
}

Я думаю, что @ - плохое решение, и внесите некоторые изменения в решение с deer.org.ua;

0 голосов
/ 01 февраля 2014

Получить кодировку из заголовков и преобразовать ее в utf-8.

$post_url='http://website.domain';

/// Get headers ////////////////////////////////////////////////////////////
function get_headers_curl($url) 
{ 
    $ch = curl_init(); 

    curl_setopt($ch, CURLOPT_URL,            $url); 
    curl_setopt($ch, CURLOPT_HEADER,         true); 
    curl_setopt($ch, CURLOPT_NOBODY,         true); 
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 
    curl_setopt($ch, CURLOPT_TIMEOUT,        15); 

    $r = curl_exec($ch); 
    return $r; 
}
$the_header = get_headers_curl($post_url);
/// check for redirect /////////////////////////////////////////////////
if (preg_match("/Location:/i", $the_header)) {
    $arr = explode('Location:', $the_header);
    $location = $arr[1];

    $location=explode(chr(10), $location);
    $location = $location[0];

$the_header = get_headers_curl(trim($location));
}
/// Get charset /////////////////////////////////////////////////////////////////////
if (preg_match("/charset=/i", $the_header)) {
    $arr = explode('charset=', $the_header);
    $charset = $arr[1];

    $charset=explode(chr(10), $charset);
    $charset = $charset[0];
    }
///////////////////////////////////////////////////////////////////////////////
// echo $charset;

if($charset && $charset!='UTF-8') { $html = iconv($charset, "UTF-8", $html); }
0 голосов
/ 16 июля 2013

У меня была такая же проблема с phpQuery ( ISO-8859-1 вместо UTF-8 ), и этот хак помог мне:

$html = '<?xml version="1.0" encoding="UTF-8" ?>' . $html;

mb_internal_encoding('UTF-8'), phpQuery::newDocumentHTML($html, 'utf-8'), mbstring.internal_encoding и другие манипуляции не дали никакого эффекта.

0 голосов
/ 29 июня 2017

Ответ с наибольшим количеством голосов не работает. Вот мой и надеюсь, что это поможет.

function toUTF8($raw) {
    try{
        return mb_convert_encoding($raw, "UTF-8", "auto"); 
    }catch(\Exception $e){
        return mb_convert_encoding($raw, "UTF-8", "GBK"); 
    }
}
...