Чтение страницы сайта и преобразование в 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% страниц/сайтов в рунете.