WordPress のアップグレードと一緒に、そのままになっていた akismet-multibyteview のアップグレードもしました。1.20 からはダッシュボードのボックス枠(名前はあるんでしょうか。hook が activity_box_end なので、アクティビティーボックス?)にマルチバイトスパムの数が表示されるようになってさらに便利に。
サイト内トラックバックが捕獲されてしまったので早速リンクから一覧に飛ぼうとしたのですが、File Not Found になってしまいました。ブラウザのアドレス覧を見ると http://edit-comments.php?page=akismet-admin&multibyte=true
となっています。ソースコードでもやはりおかしなことに。
こういうのを見るとついつい調べてみたくなります。早速ハックです。
ソースを見る
何はともあれ、ソースコードを見ます。該当の処理は akismet-multibyteview.php
の関数 akismet_stats_mbinfo が行っています。1.21 では139行目から始まっていて、目的の場所は156行目です。
if ( $mbs_count ) {
echo
'<li><a href="' . clean_url("{$this->akismet_admin_uri}&multibyte=true") .
'"><strong>要チェック</strong></a>: スパムじゃないかもしれないコメントを ' .
$mbs_count.' 件捕獲中です。</li>';
} else {
echo '<li>この中に日本語を含むものはありません。</li>';
}
clean_url()
という関数が使われています。URL として正しくなるように修正をするもので、WordPress ME2.1.3では wp-includes/formatting.php
で次のように定義されていました。
function clean_url( $url, $protocols = null ) {
if ('' == $url) return $url;
$url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%]|i', '', $url);
$strip = array('%0d', '%0a');
$url = str_replace($strip, '', $url);
$url = str_replace(';//', '://', $url);
// Append http unless a relative link starting with / or a php file.
if ( strpos($url, '://') === false &&
substr( $url, 0, 1 ) != '/' && !preg_match('/^[a-z0-9]+?\.php/i', $url) )
$url = 'http://' . $url;
$url = preg_replace('/&([^#])(?![a-z]{2,8};)/', '&$1', $url);
if ( !is_array($protocols) )
$protocols = array('http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet');
if ( wp_kses_bad_protocol( $url, $protocols ) != $url )
return '';
return $url;
}
1078行目で、:// を含まなく / で始まっていなくて半角英数字+拡張子 php になっていない場合に http:// をつけるという処理をしています。
そして、引数の文字列に含まれる変数 $this->akismet_admin_uri は、同じファイルの62行目で次のように定義されています。
$this->akismet_admin_uri = 'edit-comments.php?page=akismet-admin';
さて、ここで関数に渡される引数を確認してみます。変数が展開されると、引数は edit-comments.php?page=akismet-admin&multibyte=true
となります。拡張子は php ですが、半角英数のファイル名ではありません。ハイフン(-)が入ってしまっています。そのため、clean_url()
は http:// をつけてしまっていました。
初めは akismet-multibyteview のバグだと思い解析をしていましたが、実は WordPress 側のバグでした。2.2.1 のコードでは次のように修正されています。
if ( strpos($url, '://') === false &&
substr( $url, 0, 1 ) != '/' && !preg_match('/^[a-z0-9-]+?\.php/i', $url) )
$url = 'http://' . $url;
作者のひろまささんはすでに2.3系になっていますので気が付かなかったのかもしれません。
修正
コアファイルのほうを修正してもいいのですが、影響範囲が少ないプラグインのほうを直してしまいます。固定アドレスなので、関数の処理は必要ないと判断。156行目を次のように変更しました。ついでに & を文字参照にしてあります。やらなくても大丈夫ですが、気分的に。
'<li><a href="' . "./{$this->akismet_admin_uri}&multibyte=true" .
これによってリンク先が正しくなり、マルチバイトスパムの一覧に飛ぶことができるようになりました。