xrea広告でwordpressに不具合が発生する理由

無料版xreaサーバーにwordpressを設置すると管理画面において様々な不具合に遭遇します。
ですが、その件について調べても回避方法ばかりで、原因については”広告が原因らしい”以上の事がわかりませんでした。

“動けばそれでいい”は主義に反するので、きちんと調べてみましょう。
直し方を知りたいだけの方は他のサイト様をご覧ください。
なお、以降の記述はwordpress3.2.1-jaをPHP5.2.5がインストールされているXREA無料サーバーの自動広告挿入をONの上で動かした場合の物となります。


この記事の目次

問題を正確に把握する

まずは起きている問題を正確に把握しましょう。

管理ページはどこも以下のように表示が乱れています。

どうやらスタイルシートがおかしいようなので、片っ端からソースを覗いてみます。
するとwp-admin/load-styles.php(パラメーターは省略)の中身が

このようにバイナリファイルをテキストエディタで開いたかのようになっています。
また、Content-Typeもtext/htmlとなっており(text/cssでなければいけない)、明らかに動作がおかしいことがわかります。

さらに、管理画面の外観->ウィジェット(このブログでいう右側のメニューなどを編集する機能です)では、本来D&D出来るはずの項目が全く反応しません。
今度はjavascriptが怪しいのでソースから探してみると、wp-admin/load-scripts.php(パラメーターは省略)がCSSの時と同様に化けていました。
Content-Typeも同様にtext/htmlになっていました(application/x-javascript; charset=UTF-8が正しい)。
※javascriptは色々難しい事情があり、上記のapplication/x-javascriptは見方によっては正しくないこともありますが、今回は関係ないので割愛。

ざっと調べた範囲ですが、どうやらこの二点が主な問題点のようです。

本当に原因は広告なのか

.htaccessにLayoutIgnoreURI *と記述して自動広告挿入をOFFにし、本当に治るのか確かめてみます。
すると、確かに文字化けせずContent-Typeも正常化したことがわかります。

しかし、自動広告挿入がONであってもCSSやjavascriptは広告挿入対象ではありません。
一体何が起こっているのでしょう?

xreaの広告挿入処理をハック

ハックはハックでも「調べる、解析する」の方で、クラッキング(破壊する、損害を負わせる)という意味ではありません、念のため。

ためしに「//test」の一行をjavascriptとして返すphpを作って広告の挙動を試してみます。
※実際に試したコード


<php
header('Content-Type: application/x-javascript; charset=UTF-8');
echo "//test";
exit;

すると、1行目に謎の空行が挿入されていました。
また、Content-Typeもtext/htmlになっています。
もちろん自動広告挿入がOFFだと正常動作、ますます謎です。

なぜこのようなことが起きるのでしょうか?
どうやらheader命令よりも前に空行が出力されているのが原因のようでした。
実際phpのマニュアル(http://php.net/manual/ja/function.header.php)にて

header() 関数は、 通常の HTML タグまたは PHP からの出力にかかわらず、すべての実際の 出力の前にコールする必要があることです。

と説明されています。

おそらく、自動広告挿入がONであれば必ず1行は挿入される処理なのでしょう。
そしてPHPでは(自分が知っている範囲では)Content-Typeを変更する方法はheader関数以外にないので、それが原因でPHPのデフォルトであるtext/htmlになってしまうこともわかりました。

ですが、これだけだと本来テキストであるはずの出力が化けている理由がわかりません。
今度はまた別方面から調べてみましょう。

テキストが化ける理由を探す

まずheader関数が失敗するらしいことはわかったので、広告自動挿入ONとOFFで来ているhttpヘッダーを比べてみます。
すると、自動広告挿入がOFFの時だけ「Content-Encoding: deflate」が返っていることがわかります。

ためしにload-styles.phpとload-scripts.phpを覗いてみると、最後の方にある


		header('Content-Encoding: deflate');
		$out = gzdeflate( $out, 3 );

というコードでテキストを圧縮していることがわかりました。

どうやらブラウザが対応している場合は圧縮して返すが、header関数が失敗してしまうため、ブラウザはテキストだと勘違いしてそのまま使うために化けているようです。
実際、この圧縮処理を丸々コメントアウトしてみたところ、広告挿入処理がONであってもきちんとテキストは出力されるようになりました。
(※正確には、PHPはContent-Typeによってechoやprintの処理を分岐しているため、ブラウザに送信する以前から破損データとなっています)

まとめ

・自動広告挿入がONだと、たとえどんな内容でも空行が挿入される(xrea広告自動挿入機能の弊害)
・たとえ空行だろうと1行でも出力されるとheader関数が失敗する(PHPの動作仕様)
・header関数でContent-TypeとContent-Encodingを設定しているため、これらが失敗することで不具合が発生している

ちなみにload-*.php側の修正だけで完全に回避することはできません
(どうやってもContent-Typeを設定する方法がないため)
ここまで延々調べましたが、結局LayoutIgnoreURIで広告を解除するのが一番妥当な回避策となります。

要するにPHP使うならサーバー代金ぐらい払おう、というお話でした。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です