我想只使用UTF8。问题是我不知道每个网页的字符集。如何检测并转换为UTF8?
<?php
$url = "http://vkontakte.ru";
$ch = curl_init($url);
$options = array(
CURLOPT_RETURNTRANSFER => true,
);
curl_setopt_array($ch, $options);
$data = curl_exec($ch);
// $data = magic($data);
print $data;
请参阅:http://paulisageek.com/tmp/curl-utf8
什么是magic()
?
答案 0 :(得分:25)
按照Gumbo和Pekka的建议,我写了curl_exec_utf8
/** The same as curl_exec except tries its best to convert the output to utf8 **/
function curl_exec_utf8($ch) {
$data = curl_exec($ch);
if (!is_string($data)) return $data;
unset($charset);
$content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
/* 1: HTTP Content-Type: header */
preg_match( '@([\w/+]+)(;\s*charset=(\S+))?@i', $content_type, $matches );
if ( isset( $matches[3] ) )
$charset = $matches[3];
/* 2: <meta> element in the page */
if (!isset($charset)) {
preg_match( '@<meta\s+http-equiv="Content-Type"\s+content="([\w/]+)(;\s*charset=([^\s"]+))?@i', $data, $matches );
if ( isset( $matches[3] ) ) {
$charset = $matches[3];
/* In case we want do do further processing downstream: */
$data = preg_replace('@(<meta\s+http-equiv="Content-Type"\s+content="[\w/]+\s*;\s*charset=)([^\s"]+)@i', '$1utf-8', $data, 1);
}
}
/* 3: <xml> element in the page */
if (!isset($charset)) {
preg_match( '@<\?xml.+encoding="([^\s"]+)@si', $data, $matches );
if ( isset( $matches[1] ) ) {
$charset = $matches[1];
/* In case we want do do further processing downstream: */
$data = preg_replace('@(<\?xml.+encoding=")([^\s"]+)@si', '$1utf-8', $data, 1);
}
}
/* 4: PHP's heuristic detection */
if (!isset($charset)) {
$encoding = mb_detect_encoding($data);
if ($encoding)
$charset = $encoding;
}
/* 5: Default for HTML */
if (!isset($charset)) {
if (strstr($content_type, "text/html") === 0)
$charset = "ISO 8859-1";
}
/* Convert it if it is anything but UTF-8 */
/* You can change "UTF-8" to "UTF-8//IGNORE" to
ignore conversion errors and still output something reasonable */
if (isset($charset) && strtoupper($charset) != "UTF-8")
$data = iconv($charset, 'UTF-8', $data);
return $data;
}
正则表达式主要来自http://nadeausoftware.com/articles/2007/06/php_tip_how_get_web_page_content_type
答案 1 :(得分:4)
转换很容易。检测是困难的部分。你可以尝试mb_detect_encoding,但这是一个非常不稳定的方法,它实际上是“猜测”内容类型,并且评论中的@troelskn高亮可以最好地猜测“粗略”差异(它是多字节编码吗?)但未能检测到类似字符集的细微差别。
正确的方法是IMO:
content-type
元标记content-type
标头与@ Gumbo的答案中的指南不同,我个人认为Meta标签应优先于服务器标头,因为我很确定如果存在Meta标签,那么这是一个更可靠的实际编码指示页面比服务器设置一些网站运营商甚至不知道如何改变。但是,正确的方法似乎是处理具有更高优先级的内容类型标头。
对于前者,我认为你可以使用get_meta_tags()。后者你应该已经从curl获得,你只需要解析它。 Here是如何系统地处理cURL提供的响应标头的完整示例。
转换将使用iconv:
$new_content = iconv("incoming-charset", "utf-8", $content);
答案 2 :(得分:1)
我非常高兴能找到这个答案,但注意到<meta>
标签检测存在缺陷。它似乎与任何内容类型标签都不匹配,而且还没有为新的HTML5样式标签配备:<meta charset="UTF-8">
。所以我写了这篇文章,希望它可以帮助你们,并再次感谢这个出色的解决方案!
/* 2: <meta> element in the page */
if (!isset($charset)) {
preg_match('/<[\s]*meta[^>]*charset="?([^\s"]+)\s?"/i', $data, $matches);
if (isset($matches[1])) {
$charset = $matches[1];
}
}
(P.S。我无法弄清楚如何将其作为评论发布,因为它显然不是一个完整的答案。)
答案 3 :(得分:0)
您可以尝试使用以下内容:
http://www.php.net/manual/en/function.mb-detect-encoding.php
http://www.php.net/manual/en/function.mb-convert-encoding.php
虽然这不是万无一失的。
答案 4 :(得分:0)
已定义订单how to specify the character encoding in HTML:
在确定文档的字符编码时(从最高优先级到最低优先级),符合条件的用户代理必须遵守以下优先级:
- “Content-Type”字段中的HTTP“charset”参数。
META
声明,其中“http-equiv”设置为“Content-Type”,值为“charset”设置。- 在指定外部资源的元素上设置
醇>charset
属性。
如果不存在字符编码声明,HTTP defines ISO 8859-1 as default character encoding。您也可以将其用作HTML的默认字符编码,或者只是拒绝处理响应。
对于XHTML,您还有XML declaration as source for the encoding:
在XML文档中,文档的字符编码在XML声明中指定(例如,
<?xml version="1.0" encoding="EUC-JP"?>
)。为了便携地呈现具有特定字符编码的文档,最好的方法是确保Web服务器提供正确的标头。如果无法做到这一点,那么想要明确设置其字符编码的文档必须同时包含XML声明和编码声明以及meta
http-equiv语句(例如<meta http-equiv="Content-type" content="text/html; charset=EUC-JP" />
)。在符合XHTML的用户代理中,XML声明的编码声明的值优先。
如果没有字符编码声明,XML defines UTF-8 and UTF-16 as default character encoding:
除非编码由更高级别的协议确定,否则如果XML实体不包含编码声明且其内容不是合法的UTF-8或UTF-16,则也是致命错误。
总而言之,订单是:
encoding
属性的XML声明。META
声明,其中“http-equiv”设置为“Content-Type”,值为“charset”设置。如果不存在字符编码声明,您可以将ISO 8859-1视为HTML的默认编码,并且必须假定UTF-8或UTF-16作为XHTML的默认编码。