今日あったトラブルなんですがこんな感じのコードです。
<?php
require "vendor/autoload.php";
class StringTest extends \PHPUnit_Framework_TestCase
{
/**
* @test
*/
public function 文字数が50文字以上の場合は50文字で切ることができる()
{
$str = "犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬";
$actual = mb_substr($str,0,50);
$this->assertEquals(50, mb_strlen($actual),'文字数が正しくない');
}
}
まあこれはテスト通るんですが、実は出力してみるとおかしくなるんですよね。
<?php
$str = "犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬";
echo mb_substr($str,0,50)."\n";
これの出力結果が以下の通りです
$php test.php
犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬�
文字がぶっ壊れてしまいましたね。
で、phpマニュアルにると、mb_substrの4番目の引数にエンコーディングの設定があります。
デフォルト値がmb_internal_encoding()
となっていたので、mb_internal_encodingの値を確認してみましょう。
$ php -i | grep mbstring.internal_encoding
mbstring.internal_encoding => no value => no value
どうやらno value
になっていたのが原因みたいです。
UTF-8として認識されていなかったのぽいので、文字がぶっ壊れたと思います。
試しにecho mb_internal_encoding()
;ってやってみたらISO-8859-1
って出てきました。
これmacな環境だからですかね?
コメントで教えていただきましたが、どうやらOS依存ではなくて、PHP5.5だとデフォルトがISO-8859-1
になるようです。
対応策
まあどの環境でもUTF-8でコードを書いてたならUTF-8で動くようにしなきゃいけませんよね。
考えられる対応策は3つありますね。
- 毎回引数に文字コードを明示的にしていする
- スクリプトの中で
mb_internal_encoding()
を指定する - php.iniで設定
大体こんな感じだと思います。
まあこの辺はプロジェクトとかスクリプトが使われる状況によって変わって来ると思います。
まあiniで設定するのが一番良さそうですが、どうなんすかね。
とりあえず今回は引数指定で、修正してみました。
<?php
$str = "犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬";
echo mb_substr($str,0,50,'utf-8')."\n";
しかしmb_strlenはなぜ50文字って取得できたのか。。。
まあmb_strlenもエンコード指定してなかったからですね。これがmb_strlenだけにutf-8指定してたらちゃんとエラーになりますね。
<?php
require "vendor/autoload.php";
class StringTest extends \PHPUnit_Framework_TestCase
{
/**
* @test
*/
public function 文字数が50文字以上の場合は50文字で切ることができる()
{
$str = "犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬犬";
$actual = mb_substr($str,0,50);
$this->assertEquals(50, mb_strlen($actual,'UTF-8'),'文字数が正しくない');
}
}
まとめ
mb_~系のメソッドは大体文字コードの指定があるのでちゃんとinternal_encodingエンコーディングを設定しましょう。もしくは引数を必ず書きましょう。