1

I want to extract various data from URLs that will be converted to UTF-8 no matter what the encoding methods is used in original page (or at least it will work on most of the source encodings).

So, after looking and searching many discussions and answers, I finally came with the following code, with which I am parsing HTML data twice (once for detecting encoding and a second time for getting the actual data). This is working at least on all the checked URLs. But I think that the code is poorly written.

Can anyone let me know if there are any better alternatives to do the same or if I need any improvements on the code?

<?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";
?>
4

2 回答 2

1

你的问题太开放了,我已经投票结束了。但是,我仍然会提供一个答案的存根,希望它能为您指明正确的方向。

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

  • 小型网站上的大多数网站管理员只是header("Content-type: text/html; charset=utf-8")因为他们听说这是一种很好的做法,而没有实际编码。不考虑这一点将导致 UTF-8 输出损坏
  • 一些网站管理员则相反:他们不设置标头,尽管使用 UTF-8 编码,他们的网络服务器仍会输出 ISO-8859-1 标头。在页面上可见,这无关紧要 - 重要的是DOMDocument(我最近遇到了这个问题)
  • iconv双 utf-8 编码从来都不好玩。

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

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

大编码问题之外的其他性能指标包括:

  • 将您的代码分段为结果函数。你在那里有很多重复——学习使用函数来避免多次显式地编写相同的核心函数。
  • 这个:

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

太可怕了。您可以轻松地将其替换为 strpos 调用,这将使这组特定的 ifs 速度提高约 5-10 倍。* $metas = $dom_doc->getElementsByTagName('meta');- 你知道当你使用这个方法时 DOMDocument 会遍历你的整个 DOM,对吧?考虑将 XPath 查询限制为仅head标记(它始终是 html 的第一个子项,即文档。XPath: /html/head[0]

于 2013-04-30T13:08:15.313 回答
0

关于性能,unset();当您完成变量或值时,即使您要重置它们的值,也应该使用它们,但如果您在脚本中进一步需要该值,则不需要。PHP 无法回收内存,并将重新使用从 unset 命令释放的预分配内存以供将来使用。

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

这些将有助于提高性能和内存利用率。

于 2013-04-30T09:48:11.697 回答