检测编码和转换一切为UTF-8与PHP


Detect Encoding and Convert Everything to UTF-8 with PHP

我想从url中提取各种数据,这些数据将被转换为UTF-8,无论原始页面中使用什么编码方法(或者至少它将在大多数源编码上工作)。

因此,在查看和搜索了许多讨论和答案之后,我最终得到了以下代码,我用它解析HTML数据两次(一次用于检测编码,第二次用于获取实际数据)。这至少对所有已检查的url有效。但是我认为代码写得很差。

谁能让我知道是否有更好的替代方案来做同样的,或者如果我需要对代码进行任何改进?

<?php
header('Content-Type: text/html; charset=utf-8');
require_once 'curl.php';
require_once 'curl_response.php';
$curl = new Curl;
$url = "http://" . $_GET['domain'];
$curl_response = $curl->get($url);
$header_content_type = $curl_response->headers['Content-Type'];
$dom_doc = new DOMDocument();
libxml_use_internal_errors(TRUE);
$dom_doc->loadHTML('<?xml encoding="utf-8" ?>' . $curl_response);
libxml_use_internal_errors(FALSE);
$metas = $dom_doc->getElementsByTagName('meta');
foreach ($metas as $meta) {
    if (strtolower($meta->getAttribute('http-equiv')) == 'content-type') {
        $meta_content_type = $meta->getAttribute('content');
    }
    if ($meta->getAttribute('charset') != '') {
        $html5_charset = $meta->getAttribute('charset');
    }
}
if (preg_match('/charset=(.+)/', $header_content_type, $m)) {
    $charset = $m[1];
} elseif (preg_match('/charset=(.+)/', $meta_content_type, $m)) {
    $charset = $m[1];
} elseif (!empty($html5_charset)) {
    $charset = $html5_charset;
} elseif (preg_match('/encoding=(.+)/', $curl_response, $m)) {
    $charset = $m[1];
} else {
    // browser default charset
    // $charset = 'ISO-8859-1';
}
if (!empty($charset) && $charset != "utf-8") {
    $tmp = iconv($charset,'utf-8', $curl_response);
    libxml_use_internal_errors(TRUE);
    $dom_doc->loadHTML('<?xml encoding="utf-8" ?>' . $tmp);
    libxml_use_internal_errors(FALSE); 
}
$page_title = $dom_doc->getElementsByTagName('title')->item(0)->nodeValue;
$metas = $dom_doc->getElementsByTagName('meta');
foreach ($metas as $meta) {
    if (strtolower($meta->getAttribute('name')) == 'description') {
        $meta_description = $meta->getAttribute('content');
    }
    if (strtolower($meta->getAttribute('name')) == 'keywords') {
        $meta_tags = $meta->getAttribute('content');
    }
}
print $charset;
print "<hr>";
print $page_title;
print "<hr>";
print $meta_description;
print "<hr>";
print $meta_tags;
print "<hr>";
print "Memory Peak Usages: " . memory_get_peak_usage()/1024/1024 . " MB";
?>

你的问题太开放了,我已经投票否决了。然而,我仍然会提供一个答案的一小部分,希望它能给你指明正确的方向。

目前,您正在检查用户定义输入的字符集。这是一个非常非常非常非常糟糕的举动,原因有很多:

  • 大多数小网站的站长只会选择header("Content-type: text/html; charset=utf-8"),因为他们听说这是一个很好的做法,而不是真正的编码。不考虑这一点将导致混乱的UTF-8输出
  • 一些网站管理员做相反的事情:他们不设置报头,并且他们的web服务器输出ISO-8859-1报头,尽管使用UTF-8编码。在页面上可见,这并不重要-这对DOMDocument很重要(我最近遇到过这个问题)
  • iconv双utf-8编码从来都不好玩。

我强烈建议使用实用程序来解码UTF-8,直到在UTF-8扩展字符范围内没有更多的实体,然后编码一次,而不是依赖于iconv或多字节编码。原因很简单:这些人可能会搞错。您还可以设置一个错误处理程序来解析DOMDocument错误,以便捕获和重定向loadXML"由于XML格式错误而失败"错误,这与您的字符编码完全无关。基本上,你的问题的关键是不要盲目地做事情。

如果你想要好的目标,你需要担心UTF-8,解析Google Play的主页。它们发出格式错误的回复(这就是最初迫使我使用utf -8-decode-until-nothing- in- range方法的原因)。它还将向您展示DOMDocument可能由于各种各样的原因(不仅仅是字符集)而失败,并且您需要跟踪错误来处理它们。

在编码混乱之外的其他性能指标包括:

  • 将代码分割成结果函数。你有很多重复的地方——学会使用函数来停止多次显式编写相同的核心函数。
  • :

    if (preg_match('/charset=(.+)/', $header_content_type, $m)) { $charset = $m[1]; } elseif (preg_match('/charset=(.+)/', $meta_content_type, $m)) {

是可怕的。您可以很容易地用strpos调用替换它,这将使这组特定的if的速度提高约5-10倍。* $metas = $dom_doc->getElementsByTagName('meta'); -你知道DOMDocument将通过你的整个DOM当你使用这个方法,对吗?考虑将XPath查询限制为仅head标记(它始终是html的第一个子标记,html是文档)。XPath: /html/head[0])

在性能方面,你应该使用unset();当你完成变量或值,即使你要重置它们的值,但不是如果你需要的值进一步下降你的脚本。PHP不能回收内存,并且会重用unset命令释放的预分配内存以供将来使用。

你可以做的另一件事是获取大块代码并将其分割成返回结果值的函数。请记住,函数变量和内存在执行后会自动释放,除非你使用的是全局变量。