繁体   English   中英

检测编码并使用PHP将所有内容转换为UTF-8

[英]Detect Encoding and Convert Everything to UTF-8 with PHP

我想从将要转换为UTF-8的URL中提取各种数据,而不管原始页面中使用了什么编码方法(或者至少它将对大多数源编码都起作用)。

因此,在查看并搜索了许多讨论和答案之后,我终于提供了以下代码,使用该代码我对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输出失真
  • 一些网站管理员的做法与此相反:他们没有设置标头,并且尽管UTF-8编码,他们的Web服务器仍输出ISO-8859-1标头。 在页面上可见,这无关紧要-对DOMDocument来说很重要(我最近遇到过此问题)
  • iconv双utf-8编码从来都不是一件好事。

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

如果您希望在需要担心UTF-8的情况下找到良好的目标,请解析Google Play主页。 他们发出格式错误的答复(这是最初迫使我通过UTF-8解码直到一切正常的方法)。 它还将向您显示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]

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM