阿部寛のホームページをPHPでDOMる


HTML を正しい文字コードで DOMDocument にしたい

DOMDocument が勝手に meta 検出してくれたら良いのだけど。

とりあえず自前で文字コード検出して、うまく変換して、DOMDocument を作る実験。

阿部寛のホームページが安定して昔ながらの文字コードを使ってくれているので実験材料に良い。

http://abehiroshi.la.coocan.jp/

<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=x-sjis">
<title>阿部寛のホームページ</title>
</head>
<frameset cols=18,82>
<frame src=menu.htm marginheight=0 marginwidth=0 scrolling=auto name=left>
<frame src=top.htm marginheight=0 marginwidth=0 scrolling=auto name=right>
</frameset><noframes></noframes>

そもそも frame が懐かしい。


作成したコード

<?php

// HTML全体からtitleを取得
function html2title($html){
// まずは UTF-8 で決め打ち
$htmlEncoded = mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8');
$doc = new DOMDocument();
@$doc->loadHTML($htmlEncoded);

// metaからcharset検出
$charset = '';
$elements = $doc->getElementsByTagName("meta");
for($i = 0; $i < $elements->length; $i++){
$e = $elements->item($i);

// charset属性をチェック
// <meta charset="utf-8"/>
$node = $e->attributes->getNamedItem("charset");
if($node){
$charset = $node->nodeValue;
break;
}

// http-equiv属性をチェック
// <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
$node = $e->attributes->getNamedItem("http-equiv");
if($node && strcasecmp($node->nodeValue, 'content-type') == 0){
$node = $e->attributes->getNamedItem("content");
if($node && preg_match('/[\; ]charset ?\= ?([A-Za-z0-9\-\_]+)/', $node->nodeValue, $m)){
$charset = $m[1];
break;
}
continue;
}
}

// 検出されたcharsetがUTF-8じゃなかったら
if($charset !== '' && !preg_match('/^utf\-?8$/i', $charset)){
// 文字コード変換し直して
$htmlEncoded = mb_convert_encoding($html, 'HTML-ENTITIES', $charset);
// DOMも構築し直す
$doc = new DOMDocument();
@$doc->loadHTML($htmlEncoded);
}

// title取得
$elements = $doc->getElementsByTagName("title");
for($i = 0; $i < $elements->length; $i++){
$e = $elements->item($i);
return $e->textContent;
}

// titleが見つからなかった場合
return false;
}

// -- -- 実験コード -- -- //
// x-sjis の例
$body = file_get_contents("http://abehiroshi.la.coocan.jp/");
$title = html2title($body);
echo "title = $title\n";

// euc-jp の例
$body = file_get_contents("http://d.hatena.ne.jp/");
$title = html2title($body);
echo "title = $title\n";

// Shift_JIS の例
$body = file_get_contents("http://www.tohoho-web.com/www.htm");
$title = html2title($body);
echo "title = $title\n";

// UTF-8 の例
$body = file_get_contents("http://qiita.com/");
$title = html2title($body);
echo "title = $title\n";


実行結果

title = 阿部寛のホームページ

title = はてなダイアリー - 写真・画像・動画付き日記を無料で
title = とほほのWWW入門
title = Qiita - プログラマの技術情報共有サービス

はてなダイアリーがいまだに euc-jp だったというのが意外。


関連


おわり

おそらくこれまでに何千人もが同じようなコード書いてるような気がするわけで、

DRY原則に真っ向から立ち向かってしまっている感なんだけど、

良いサンプルが見つからなかったので自分で作ってしまった。

もっとスマートな(というかデファクトでかつ安心できる)方法があれば知りたいです。。。