PHP 5.6 で mbstring 系の設定項目のいくつかが非推奨となったり、default_charset
のデフォルトが "UTF-8" になったり、昔は良く設定されていた mbstring.encoding_translation = On
設定されてると Wordpress の一部の機能で文字化けしたりと、php.ini をイマドキ風の設定にしなきゃならんのでは? ってことで、イマドキ風な気がする設定を試していたらハマりました。
現象は、Wordpress のメディアライブラリという、画像なんかを一覧する画面で、上の方のクルクル回るアイコンがクルクル回ったままで画像などのライブラリの内容が一切表示されなくなります。。他の機能は特に問題なく使えてる感じです。
ググると結構メディアライブラリが表示されなくなったという話はありますね。(それを見れば解決法も結構書いてありますが)
output_handler = mb_output_handler
mbstring.http_output = pass
他に色々あるけど、キモは上記のふたつの設定。ただし、この設定に
mbstring.encoding_translation = On
とやると、メニュー名やアップロードするファイル名に日本語を使うと文字化けしたりします。このとき、メディアライブラリを表示させたときのリクエストとレスポンスはこんな感じ。
(リクエスト[抜粋])
POST /wordpress/wp-admin/admin-ajax.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
action=query-attachments&post_id=0&query%5Borderby%5D=date&query%5Border%5D=DESC&query%5Bposts_per_page%5D=40&query%5Bpaged%5D=1
(レスポンス[抜粋])
HTTP/1.1 200 OK
Content-Type: application/json; charset=UTF-8
(JSONがずらずらと)
(リクエスト2度目[抜粋])
POST /wordpress/wp-admin/admin-ajax.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
(レスポンス2度目[抜粋])
HTTP/1.1 200 OK
Content-Type: application/json; charset=UTF-8
{"success":true,"data":[]}
2 度リクエストとレスポンスのやりとりがあって、最後で "success": true
でデータが空で終わりという判定なのかな? (よく知りません)
Content-Type:
がちゃんと application/json
で返ってます。
output_handler = mb_output_handler
;mbstring.http_output = pass
mbstring.* を全部コメントアウトしてデフォルトにする。すると、メディアライブラリが表示されなくなります。
(リクエスト[抜粋])
POST /wordpress/wp-admin/admin-ajax.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
action=query-attachments&post_id=0&query%5Borderby%5D=date&query%5Border%5D=DESC&query%5Bposts_per_page%5D=40&query%5Bpaged%5D=1
(レスポンス[抜粋])
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
(JSONずらずら)
応答が text/html
になってるので、JSON のデータは返ってきてるものの、Wordpress 側はだんまりです。
上記のように mbstring 系の設定はすべてコメントアウト状態で、output_handler もオフにします。
;output_handler = mb_output_handler
;mbstring.http_output = pass
すると、最初で問題なかった時のようにちゃんと応答が返ります。これもググると Wordpress では output_handler
はオフにしろと書かれていますが、理由が書かれた文章は見つけられていません。
はっきりわかりませんが、wp-admin/admin-ajax.php
を見てみると、以下のようになっています。関係しそうなところだけ抜き出します。
/** Load Ajax Handlers for WordPress Core */
require_once( ABSPATH . 'wp-admin/includes/ajax-actions.php' );
@header( 'Content-Type: text/html; charset=' . get_option( 'blog_charset' ) );
ajax 関連のコードが含まれているファイルを require_once してから、さらに header('Content-Type: text/html')
呼び出しています。
require_once しているファイルのコードを追ったりしてみると、wp-include/function.php
内に wp_send_json
という関数があり、そこで header で Content-Type として application/json
を返しています。
function wp_send_json( $response, $status_code = null ) {
@header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ) );
えー、二度呼ばれるやん。でももしかして admin-ajax.php
内で処理が exit して text/html
返してる header のコードまで返らないんじゃ? と思って、軽く printf() デバッグならぬ error_log() デバッグをしてみました。
上記の 2 つの @header 行の前に error_log("application/json");
とか error_log("text/html");
とか入れてみました。で、メディアライブラリにアクセスすると、
[Thu Jan 19 21:22:50 2017] [error] [client a.b.c.d] text/html, referer: http://example.com/wordpress/wp-admin/upload.php
[Thu Jan 19 21:22:50 2017] [error] [client a.b.c.d] application/json, referer: http://example.com/wordpress/wp-admin/upload.php
というように、両方の header
が呼ばれています。先に text/html
の方が呼ばれて、あとで application/json
が呼ばれるようです。
mb_output_handler 経由すると、先に呼ばれた方の Content-Type で返って、経由しないとあとで呼ばれた方の Content-Type が返るのかな。
この検証方法が妥当なのか知りませんが…