PHP HTML Diff

HTMLファイルの差分を表示するようなスクリプト
まずPEARを見たが、そのものズバリはないけど、Text_Diffというのがあった。

Perlだとそれっぽいのがあるような感じだ。

ロジックは割合単純そうなPythonのものというのもあった。

HTML Diff is a simple Python program that uses Python's difflib to highlight changes in HTML documents

PerlPythonの例を見ると、結局、HTMLのタグを区切りにして、HTMLの文字列を細かく切り刻んでから、diffを取ればいいようだ、ということになった。
また、日本語で一行が長い時に、まるまる一行が差分になってしまうのは嫌なので、適当に区切りたい。以下を参考に文字の種類で半角、全角などの境い目で区切る。

/*
 * シフトJISにおける文字種別の定義
 * ref. http://module.jp/blog/regex_unicode_prop.html
 * ref. http://www.din.or.jp/~ohzaki/perl.htm#Character
 */
$latin1 = '[\x21-\x7E]';                                    // Latin-1
$hankana = '[\xA6-\xDF]';                                   // 半角カナ
$zenhira = '(?:\x82[\x9F-\xF1])';                           // 全角ひらがな
$zenkana = '(?:\x83[\x40-\x96])';                           // 全角カタカナ
//$kanji  = '(?:[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])'; // シフトJIS文字全体
$kanji1 = '(?:\x81[\x40-\x7E\x80-\xFC])';                   // 0x81 ひらがなより前
$kanji2 = '(?:\x82[\x40-\x7E\x80-\x9E])';                   // 0x82 ひらがなより前
$kanji3 = '(?:\x83[\x97-\xFC])';                            // 0x83 カタカナより後
$kanji4 = '(?:[\x84-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])';   // それ以外

/** シフトJISにおいて文字種別で分割する正規表現 */
$regex_char_type = "{$latin1}+|{$hankana}+|{$zenhira}+|{$zenkana}+|(?:{$kanji1}|{$kanji2}|{$kanji3}|{$kanji4})+";

/** HTMLのコメント、タグと単語で区切る正規表現 */
$regex_sep_tags_words = '/(<!--.*-->|<[^>]*>|(?:'.$regex_char_type.'))/s';

$html1 = file_get_contents($filename1);
$html2 = file_get_contents($filename2);
$html1 = preg_split($regex_sep_tags_words, $html1, -1, PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE);
$html2 = preg_split($regex_sep_tags_words, $html2, -1, PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE);

require_once 'Text/Diff.php';
$diff = &new Text_Diff($html1, $html2);

色々なデータを試すときっともう少し改良の余地はあると思うけど、とりあえずこんな感じになった。(例えば上記の正規表現だとアルファベットの後にタグがあると分けられない。abc<br>など。)
後はdiffを<ins>や<del>で囲めば、それらしく見えるものができる。
本当はText_Diff_Rendererを実装するのが本筋なのかもしれない。