PHP5でRSSフィード等のXMLをパースする時にハマってしまったら
PHP4からPHP5への移行でハマりました。
PHP5 + PEAR::XML_Unserializer という組み合わせなので、ほとんど有り得ないケースだとは思いますが一応書いておきます。いきなり結論。
UTF-8でない文字コードのXMLをパースする時は、文字コード変換するだけでなくXML宣言のencoding指定も忘れずに書き換えておきましょう
そもそも論として今のご時世にUTF-8じゃなくてEUC-JPとかShift_JISでXMLを出力してくれているという事実に殺意すら覚えるのですが、まぁそうも言ってられないので curl なり HTTP_Client で取得したRSSを
$rss = mb_convert_encoding($rss, 'UTF-8', 'Shift_JIS');
とかって問答無用にUTF-8に変換してあげる訳です。そしてそのままXML_Unserializerに食わせてやります。...がここでPHP5の場合はWarning発生。
Warning: xml_parse(): input conversion failed due to input error in /[path]/[to]/[pear]/XML/Parser.php on line 509
Warning: xml_parse(): Bytes: 0xA0 0xE3 0x82 0xB9 in /[path]/[to]/[pear]//XML/Parser.php on line 509
こんなWarningメッセージが大量に出力されてXMLをパース出来ません。さて、ここで愕然としてどうしたものか...とググってみたり試行錯誤すること1時間。XML_Unserializerに食わせる直前のRSSをデバッグ出力した所を眺めていて非常に痛い所に気が付きました。
<?xml version="1.0" encoding="Shift_JIS" ?>
<rss version="2.0">
...(省略)...
RSS全体としては mb_convert_encoding によってUTF-8にしていたものの、XML宣言では Shift_JIS というチグハグな状態になっていた訳でして、そりゃ変な挙動をしても文句言えませんね。
そんな訳で
$rss = mb_convert_encoding($rss, 'UTF-8', 'Shift_JIS');
$rss = str_replace('Shift_JIS', 'UTF-8', $rss);
ってな感じにしてやると Warning も無くなりすんなりパースok。厳密に言うと str_replace ではダメなケースも出てくる筈なのでそこはXML宣言の該当部分だけ置換するようにちゃんと書きましょうって事で。
PHP4では上記のような現象は発生せずPHP5でのみ発生した理由についてもっと深く理解しておきたい所ですが、今は時間がないので納得出来ないながらも華麗にスルー。また暇を見付けて調べます。
ちなみにこの現象、ほとんど無いであろう PHP5 + XML_Unserializer の組み合わせで僕は遭遇していたのですが、ググって調べる過程でPHP5のSimpleXMLを使っても同様のエラーが発生している旨の書き込みを発見しました。...ので、そういうもんなのかも知れません。
ようは、言ってる事(XML宣言)とやってる事(XMLの中身)とを一致させましょねという非常に当たり前の事なのでした。はは...(泣)
っていうか、もう全部UTF-8にしちゃおうよというのは極論でしょうかね。EUC-JPはまだ理解できますが、Shift_JISなんて勘弁して下さい。Windowsローカルだけで良いじゃないですか(T_T)
































