Skip to content

Instantly share code, notes, and snippets.

@tenforward
Last active January 19, 2017 12:34
Show Gist options
  • Save tenforward/e0db10ada68be8214f5e3488c641bf88 to your computer and use it in GitHub Desktop.
Save tenforward/e0db10ada68be8214f5e3488c641bf88 to your computer and use it in GitHub Desktop.

Wordpress と output_handler と mbstring の悩ましい関係

発端

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 が返るのかな。

この検証方法が妥当なのか知りませんが…

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment