Windows版PHPのstrftime()関数が文字化けする問題
Windows版PHP 5.5のstrftime()関数だと文字化けが起こるという問題、『PHP逆引きレシピ 第2版』にも記載されています。
サンプルで説明すると、以下になります。
<?php
function p($str)
{
echo $str, '<br>';
echo strftime($str), '<br>';
echo bin2hex($str), '<br>';
echo bin2hex(strftime($str)), '<hr>';
}
setlocale(LC_ALL, 'C');
p('あ');
期待される結果:
あ
あ
e38182
e38182
実際の結果:
あ
ぁE
e38182
e3818145
この問題、以下でバグ報告してあるのですが、再現できないと言われてしまいました。
https://bugs.php.net/bug.php?id=65371
手許では、PHP 5.5.1、5.5.6(XAMPP for Windows)で問題が生じることを確認しています。
上記の問題が再現しない環境やバグの原因について心当たりのある方は、お知らせいただけるとありがたいです。 上記のバグ報告にコメントしてもらうのが一番助かります。
回避策
(20:32 追記) なんか、VC11のstrftimeの問題なので、PHPではどうしようもないらしいです。
@kenji_s 恐らく VC のバージョンの違いによるものです。PHPの問題ではないので修正は困難だと思います。
VC11 と VC10 で strftime で不正なマルチバイト文字が渡されたときの挙動が違います(VC9 は手元に無かったので不明)。
— ngyuki(えぬじーなんとか) (@ngyuki) 2014, 1月 10
@kenji_s また "e3818145" というシーケンスは "e38182" を MultiByteToWideChar/WideCharToMultiByte で「ANSI → Unicode → ANSI」と変換すると現れます。
— ngyuki(えぬじーなんとか) (@ngyuki) 2014, 1月 10
@kenji_s VC11 の strftime では何故か Unicode(UTF-16)に変換してから (w)strftime するようになっているみたいです。
— ngyuki(えぬじーなんとか) (@ngyuki) 2014, 1月 10
@kenji_s 見た感じロケールがなんであれ Unicode に一旦変換されています。
ロケールは Unicode への変換で変換元のコードページに使われています。"C" なら ANSI コードページから Unicode に変換しようとして前述の通りになります。
— ngyuki(えぬじーなんとか) (@ngyuki) 2014, 1月 10
@kenji_s PHP 側でどうにか出来る問題ではなく、strftime を再実装するぐらいしか解決方法は無いと思います。
— ngyuki(えぬじーなんとか) (@ngyuki) 2014, 1月 10
ということで、ロケールをjapanese
に指定して、以下のような関数(スクリプトの文字エンコーディングがUTF-8の場合)を用意することで回避できることを確認しました。
function strftime_win($str)
{
$str = mb_convert_encoding($str, 'CP932', 'UTF-8');
return mb_convert_encoding(strftime($str), 'UTF-8', 'CP932');
}
Date: 2014/01/10