Определение кодировки текста

Автоматическое определение кодировки текста

PHP скрипт для автоматического определения кодировки текста.

<?php
define('LOWERCASE',3);
   define('UPPERCASE',1);
   function detect_cyr_charset($str) {
      $charsets = Array(
         'k' => 0,
         'w' => 0,
         'd' => 0,
         'i' => 0,
         'm' => 0
      );
      for ( $i = 0, $length = strlen($str); $i < $length; $i++ ) {
         $char = ord($str[$i]);
      //non-russian characters
      if ($char < 128 || $char > 256) continue;
      //CP866
      if (($char > 159 && $char < 176) || ($char > 223 && $char < 242))
         $charsets['d']+=LOWERCASE;
      if (($char > 127 && $char < 160)) $charsets['d']+=UPPERCASE;
      //KOI8-R
      if (($char > 191 && $char < 223)) $charsets['k']+=LOWERCASE;
      if (($char > 222 && $char < 256)) $charsets['k']+=UPPERCASE;
      //WIN-1251
      if ($char > 223 && $char < 256) $charsets['w']+=LOWERCASE;
      if ($char > 191 && $char < 224) $charsets['w']+=UPPERCASE;
      //MAC
      if ($char > 221 && $char < 255) $charsets['m']+=LOWERCASE;
      if ($char > 127 && $char < 160) $charsets['m']+=UPPERCASE;
      //ISO-8859-5
      if ($char > 207 && $char < 240) $charsets['i']+=LOWERCASE;
      if ($char > 175 && $char < 208) $charsets['i']+=UPPERCASE;
   }
   arsort($charsets);
   return key($charsets);
} 
?>

Добавлено: 26 Мая 2018 21:39:35 Добавил: Андрей Ковальчук

Определение кодировки страницы сайта.

Чтение страницы сайта и преобразование в UTF-8 или в Windows-1251
При формированнии карт сайтов с помощью сервиса периодически сталкивался с проблемами некорректного указания кодировки страницы или неуказания кодовой страницы вообще. В настоящий момент у меня работает функция анализа кодовой страницы похожая на представленную ниже.

Представленный ниже пример читает страницу, преобразует её в UTF-8, загружает в DOM-объект, получает из него title и выводит его в кодировке windows-1251.

<form method=\"get\">
Страница для анализа: <input type=\"text\" name=\"url\">
</form>

PHP анализ и обработка:
<?php
$url=@$_GET['url'];

echo "<br>Страница <b>".$url."</b><br>\n";

   $curl = curl_init($url);
   curl_setopt($curl, CURLOPT_RETURNTRANSFER,true);
   curl_setopt($curl, CURLOPT_HEADER, 1);    // включать header в вывод
   curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);    // следовать любому "Location: " header
   curl_setopt($curl, CURLOPT_TIMEOUT, 20);    // максимальное время в секундах, для работы CURL-функций.
   $html = @curl_exec($curl);
   @file_put_contents($file,$html);
   $header_size = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
   curl_close($curl); // close cURL handler

   $headers = substr($html, 0, $header_size - 4)."\n";
   $body = substr($html, $header_size);

if (preg_match("|Content-Type: .*?charset=(.*)\n|imsU", $headers, $results))$ct0=trim($results[1]);
else $ct0=false;

if (preg_match_all('/(<meta\s*http-equiv=[\'\"]Content-Type[\'\"]\s*content=[\'\"][^;]*;\s*charset=([^\"\']*?)(?:"|\;|\')[^>]*>)/i',$body,$arr,PREG_PATTERN_ORDER)){
    $ct1=strtolower(trim($arr[2][0]));
    // не учитываю, что заголовки могут быть разными. Это в платной версии.
    if ($ct1=='utf-8')$ct1=false;
    $ct0=false; // meta не добавлять
}else $ct1=false;

if ($ct1){
    echo "<br>Преобразование ".$ct1." -> UTF-8";
    $body=@iconv($ct1,'utf-8//IGNORE',$body);
}

// добавляю в head Content-Type
if($ct0)$body=preg_replace('/<head[^>]*>/','<head>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
',$body);

$doc = new DOMDocument();

@$doc->loadHTML($body);

if ( ($tags = @$doc->getElementsByTagName('title')) ) {
    $title = @$tags->item(0)->nodeValue;
    print "<br>Заголовок страницы: ".@iconv("UTF-8", "windows-1251//IGNORE", $title).'<br />';
}
?>

Приведенный пример упрощен и не содержит обработку "трудных" случаев, когда кодовая страница в header указанна одна, а в META другая. Также не содержит обработку двойных мета с разными кодовыми страницами(и такое у меня попадалось). Полный пример дополнительно осуществляет кеширование и "борется" с кривыми страницами. Представленный код будет корректно работать на 95% страниц/сайтов в рунете.

Добавлено: 26 Мая 2018 21:37:18 Добавил: Андрей Ковальчук

Определение кодировки curl страницы

После получения страницы с помощью Curl-запроса Возникает необходимость привести её в требуемую кодирвку. Но вот тут и кроется "подвох". Мы часто не знаем начальную кодировку, из которой нужно перекодировать. Роясь в интернете, я нашел интересное решение charset_x_win, скачать можно здесь. Решение есть, но очень тяжелое. Потом я попробовал проанализировать что есть среди стандартных функций PHP... И нашел решение:

Определение кодировки полученной строки:

<?php
print mb_detect_encoding($str,"auto")."<br>\n"; // ASCII или UTF-8
?>

Преобразование кодировки полученной строки:
<?php
print mb_convert_encoding($str, "windows-1251", "auto")."<br>\n";
?>

Добавлено: 26 Мая 2018 21:35:51 Добавил: Андрей Ковальчук

Отправка писем в правильной кодировке на PHP

У меня часто спрашивают, как отсылать письма с помощью PHP в правильной кодировке: после отправки письма с русскими буквами, на почту людям приходит абракадабра.

А все дело в том, что для почты у нас принято использовать кодировку KOI8-R, а для веба — Win-1251 (ANSI) — так, и выходит — мы шлем с сайтов в win-1251, а почтовые программы открывают его как KOI8-R...

Выходов из ситуации хватает. Начиная, можно на самой веб странице можно использовать кодировку KOI8-R. Но я бы не советовал этого не делать — у некоторых посетителей могут возникнуть с кодировкой на самой странице. Так что оставим этот метод для ламеров, а применим более изящный, на PHP.

Итак, что же можно сделать? Первое что приходит в голову — а не проще ли перекодировать само сообщение? И в правду, нет нечего проще.

Тем более в PHP предусмотрена стандартная процедура — convert_cyr_string(string str, string from, string to); как Вы уже, наверное, догадались, функция перекодирует текст, содержащийся в переменной $str из кодировки $from в кодировку $to. Указание кодировки происходит посредством символов латинского алфавита, вот доступные параметры и соответствующие им кодировки:

k — KOI8-R
w — Win-1252
i — ISO8859-5
a — X-CP866
d — X-CP866
m — X-Mac-Cyrillic

Как видно из таблицы, в нашем случае, перед отправкой сообщения, содержащегося в переменной $msg, его нужно перекодировать из w в k (из Win-1251 в KOI8-R), это выглядит так: $msg = convert_cyr_string ($msg,w,k); вот и все, теперь можно спокойно отсылать наше письмо.

Добавлено: 24 Августа 2013 06:03:51 Добавил: Андрей Ковальчук

Проблема с кодировкой UTF-8 для XML

Столкнулся с одним неприятным багом PHP при работе с XML с кодировкой UTF-8. Если воспользоваться функцией DOMDocument::loadXML.

Есть исходный xml-файл: 1.xml

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <name>Имя</name>
   <description>Description</description>
</root>

Теперь хотим воспользоваться DOMDocument и подгрузить файл, далее дампим его содержимое на экран. В этом примере все будет работать на ура и результат будет идентичен файлу 1.xml.
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->load('1.xml');
echo $dom->saveXML();

Рассмотрим другую ситуацию, когда мы xml-данные как-то получаем, меняем, добавляем и в итоге передаем строку в функцию loadXML.
$xml = <<<XML
<root>
   <name>Имя</name>
   <description>Description</description>
</root>
XML;

$dom = new DOMDocument('1.0', 'UTF-8');
$dom->loadXML($xml);
echo $dom->saveXML();

А на выходе получаем нижеследующее. Куда делись наши символы на русском? И исчезла кодировка UTF-8?
<?xml version="1.0"?>
<root>
   <name>Имя</name>
   <description>Description</description>
</root>

Решение: нужно добавить заголовок xml-файла с кодировкой. Надеюсь в версии PHP 6 они сделают поддержку UTF-8 получше.
<?php
$dom = new DOMDocument('1.0', 'UTF-8');  
$dom->loadXML('<?xml version="1.0" encoding="UTF-8"?>' . "\n" . $xml);  
echo $dom->saveXML();
?>

Добавлено: 24 Августа 2013 05:53:59 Добавил: Андрей Ковальчук

Не работает функция iconv(), а нужно конвертнуть из UTF-8 в windows-1251

Что же делать, когда на хостинге не работает функция iconv() и php выдает Call to undefined function: iconv(), а нужно конвертнуть из UTF-8 в windows-1251

На помощь прийдет следующая функция:

function utf8_to_win($string){
    for ($c=0;$c<strlen($string);$c++){
        $i=ord($string[$c]);
        if ($i <= 127) @$out .= $string[$c];
            if (@$byte2){
                $new_c2=($c1&3)*64+($i&63);
                $new_c1=($c1>>2)&5;
                $new_i=$new_c1*256+$new_c2;
                if ($new_i==1025){
                    $out_i=168;
                } else {
                   if ($new_i==1105){
                        $out_i=184;
                    } else {
                        $out_i=$new_i-848;
                    }
                }
                @$out .= chr($out_i);
                $byte2 = false;
            }
            if (($i>>5)==6) {
                $c1 = $i;
                $byte2 = true;
            }
    }
    return $out;
}
?>

Добавлено: 24 Августа 2013 03:27:02 Добавил: Андрей Ковальчук

Не работает функция iconv(), а нужно конвертнуть из UTF-8 в windows-1251

Что же делать, когда на хостинге не работает функция iconv() и php выдает Call to undefined function: iconv(), а нужно конвертнуть из UTF-8 в windows-1251

На помощь прийдет следующая функция:

function utf8_to_win($string){
    for ($c=0;$c<strlen($string);$c++){
        $i=ord($string[$c]);
        if ($i <= 127) @$out .= $string[$c];
            if (@$byte2){
                $new_c2=($c1&3)*64+($i&63);
                $new_c1=($c1>>2)&5;
                $new_i=$new_c1*256+$new_c2;
                if ($new_i==1025){
                    $out_i=168;
                } else {
                   if ($new_i==1105){
                        $out_i=184;
                    } else {
                        $out_i=$new_i-848;
                    }
                }
                @$out .= chr($out_i);
                $byte2 = false;
            }
            if (($i>>5)==6) {
                $c1 = $i;
                $byte2 = true;
            }
    }
    return $out;
}
?>

Добавлено: 24 Августа 2013 03:27:02 Добавил: Андрей Ковальчук

ASCII to HEX средствами PHP

Для этого воспользуемся 4-я функциями:
strlen - подсчитаем кол-во символов
substr - возвращает часть строки
ord - возвращает ASCII-значение символа
dechex - 10-ричное в 16-ричное

и напишем несложный замысловатый код:

<?php
$my_url='microsoft.com';
$strlength = strlen($my_url);
    for($i=0; $i<$strlength; $i++){
        $returnval .= '%'.dechex(ord(substr($my_url, $i, 1)));
    }
echo 'http://'.$returnval;
?>

Выполнив этот скрипт мы получим адрес мелкомягких в таком виде http://%6d%69%63%72%6f%73%6f%66%74%2e%63%6f%6d

Добавлено: 21 Августа 2013 02:16:10 Добавил: Андрей Ковальчук