どこにもエラー報告が見当たらなかったので。デフォルトでも発生する、大きいバグと思われる。問題詳細から解決方法まで記録用に。
環境:Windows 10
64bit Windows版 XAMPP7.4.1(PHP 7.4.1, Apache 2.4.41, MariaDB 10.4.11, PHP 7.4.1, phpMyAdmin 5.0.1, OpenSSL 1.1.1, XAMPP Control Panel 3.2.4, Webalizer 2.23-04, Mercury Mail Transport System 4.63, FileZilla FTP Server 0.9.41, Tomcat 7.0.99 (with mod_proxy_ajp as connector), Strawberry Perl 5.16.3.1 Portable)をインストールした。
起動前に若干設定ファイルを変更した。タイムアウトの延長や、前バージョンの設定の引継ぎなど。今回の問題に関わるような変更はしていない。
「外観の設定」で「言語 - Language」を「日本語 - Japanese」にし、phpMyAdminの「状態」(http://localhost/phpmyadmin/server_status.php)を開いたときに、
Fatal error: Uncaught TypeError: mb_detect_encoding() expects parameter 1 to be string, bool given in C:\xampp\phpMyAdmin\libraries\classes\Util.php:1620 Stack trace: #0 C:\xampp\phpMyAdmin\libraries\classes\Util.php(1620): mb_detect_encoding(false, 'UTF-8', true) #1 C:\xampp\phpMyAdmin\libraries\classes\Controllers\Server\Status\StatusController.php(51): PhpMyAdmin\Util::localisedDate(1580669987) #2 C:\xampp\phpMyAdmin\server_status.php(35): PhpMyAdmin\Controllers\Server\Status\StatusController->index(Object(PhpMyAdmin\ReplicationGui)) #3 {main} thrown in C:\xampp\phpMyAdmin\libraries\classes\Util.php on line 1620
と表示され、閲覧できない。
当該ソース(C:\xampp\phpMyAdmin\libraries\classes\Util.php)はこちら。
/* Fill in AM/PM */
$hours = (int) date('H', (int) $timestamp);
if ($hours >= 12) {
$am_pm = _pgettext('AM/PM indication in time', 'PM');
} else {
$am_pm = _pgettext('AM/PM indication in time', 'AM');
}
$date = preg_replace('@%[pP]@', $am_pm, $date);
$ret = strftime($date, (int) $timestamp);
// Some OSes such as Win8.1 Traditional Chinese version did not produce UTF-8
// output here. See https://github.com/phpmyadmin/phpmyadmin/issues/10598
if (mb_detect_encoding($ret, 'UTF-8', true) != 'UTF-8') {
$ret = date('Y-m-d H:i:s', (int) $timestamp);
}
これはphpMyAdminを構成するコアな部分で、もちろん一切コードは変更していない。
このバグは言語が日本語の時だけ発生する。他の言語では発生しないため、発見が遅れている可能性が高い。
該当ソースのユーザー定義関数localisedDate()
の中で発生している。直接的には、1617行目のstrftime()がfalseを返していることが原因。php.netによれば
エラー / 例外
出力内容は元となった C ライブラリに依存するため、サポートしていない変換指定子もあります。 Windows では、対応していない変換指定子を渡すと 5 つの E_WARNING メッセージが出て FALSE を返します。 その他のオペレーティングシステムでは特に E_WARNING メッセージは出ず、 変換指定子が (変換されずに) そのまま出力されます。
とあり、Windows依存のバグ。
先ほどのコードでは、strftime()の第一引数に、$date
の中身として%Y 年 2 月 %d 日 %H:%M
が渡されている。これ自体は仕様通りで問題が無いように見える。
しかし、strftimeを処理する際に、依存するWindowsのCライブラリでは、文字列を一度Shift-JISに変換している。つまり、UTF-8→SJIS→UTF-8の変換が行われている。ここで、漢字の「月」の字が文字化けを起こし、不正なマルチバイト文字と認識され、strftime()がfalseを吐いている、というのが真相である。
実際に、UTF-8→Shift-JIS→UTF-8変換を行うと、「%Y 年 2 � %d 日 %H:%M」となる。
また、$date
フォーマット文字列において漢字の「月」を削除すればこのバグは発生しなくなる。
要するに、このバグはOS依存の関数を用いるコードのほうに問題がある。strftime()ではなくdate()に書き換えるべきである。
とりあえず日本語ユーザーができる仮対応としては、C:\xampp\phpMyAdmin\libraries\classes\Util.phpの1617行目を「$ret = strftime('%Y-%B-%d %H:%M', (int) $timestamp);」に書き換えることで閲覧できるようになる。
Fatal Errorが出るのは相当だと思うので、もし他の方が同じバグに遭遇したら是非プロジェクトに熱いissueを送ってほしい。私はやり方がよくわからないので原因究明で終わりにします。
【追記】
だらさんに報告して頂きました、ありがとうございます。
https://github.com/phpmyadmin/phpmyadmin/issues/15830
Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?
コメント