PHPでXPathを使用する
文字化けするコード
こんな感じのコードでPHPのDOMXPathを試していたけども、いくつかのサイトで文字化けが発生する。
<?php class Index_Controllers_Index extends Sabel_Controller_Page { public function index() { $url = "http://b.hatena.ne.jp/entry/http://www.sabel.jp/"; $shr = new Sabel_Http_Request($url); $response = $shr->request(); $dom = new DOMDocument(); @$dom->loadHTML($response->getContents()); $xpath = new DOMXpath($dom); dump($xpath->query("//title")->item(0)->textContent); } }
例えばはてブなんかが文字化けする。
% php sabel.php "" ================================================ string(108) "��������� - Sabel PHP�������" ================================================
dumpした結果をそのまま貼りつけたんだけど、はてなに投稿時に変換された><
文字化けしないコード
これをちゃんと文字化けせずに使うには、DOMDocumentに渡す前にエンコーディングをHTML-ENTITIESに変えてやれば良い。
<?php class Index_Controllers_Index extends Sabel_Controller_Page { public function index() { $url = "http://b.hatena.ne.jp/entry/http://www.sabel.jp/"; $shr = new Sabel_Http_Request($url); $response = $shr->request(); $contents = $response->getContents(); $contents = mb_convert_encoding($contents, "HTML-ENTITIES", "auto"); $dom = new DOMDocument(); @$dom->loadHTML($contents); $xpath = new DOMXpath($dom); dump($xpath->query("//title")->item(0)->textContent); } }
結果
% php sabel.php "" ================================================ string(60) "はてなブックマーク - Sabel PHPフレームワーク" ================================================
mb_convert_encodingの第3引数にautoを渡してやれば殆どのサイトで大丈夫だと思う。
文字化けしないコード その2
もしも上記のコードでもダメな場合は、自力で文字コードを判断しないといけない。
<?php class Index_Controllers_Index extends Sabel_Controller_Page { public function index() { $url = "http://b.hatena.ne.jp/entry/http://www.sabel.jp/"; $shr = new Sabel_Http_Request($url); $response = $shr->request(); $contents = $response->getContents(); $charset = "Shift_JIS"; if (preg_match('/charset=([^"]+)/', $contents, $matches)) { $charset = $matches[1]; } $contents = mb_convert_encoding($contents, "HTML-ENTITIES", $charset); $dom = new DOMDocument(); @$dom->loadHTML($contents); $xpath = new DOMXpath($dom); dump($xpath->query("//title")->item(0)->textContent); } }
まとめ
PHPのDOMはちゃんとHTML-ENTITIESに変えてやれば文字化けしないはず。
何故文字化けするのかどうかは不明。
Sabelフレームワークを使ってテストしてるので、上記コードはSabel上でしか動かないはず。