mb_strlenとかで挙動が変だったのでメモ(php.iniの設定(マルチバイトまわり)とか)
- 2009年3月21日 18時31分
- [PHP]
プログラムをちょこちょこ書いていると、よく動きがおかしくなって解決に時間を費やしてしまいます。
mbstring.internal_encoding = EUC-JPになっていたせいでUTF-8なアプリの日本語入力が効かなかったりとか。
mb_strlenも、あれ?と思う動きをしてしまいます。プログラムの動きがおかしいときは、大抵自分の書いたコードが間違えているのですけれども(多分)。
んで、mb_strlenです。文字数の判定で使ったところ、実際の文字数と数値が違ってしまいました。試しに以下のようなスクリプトを書いて実験してみます。
<?php
$post_mb_strlen = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['submit']))
{
if (isset($_POST['mb_strlen']))
{
$post_mb_strlen = $_POST['mb_strlen'];
$echo_post_mb_strlen_1 = mb_strlen($post_mb_strlen);
$echo_post_mb_strlen_2 = mb_strlen($post_mb_strlen, 'utf8');
}
}
?><!DOCTYPE html>
<head>
<meta charset=utf-8">
<title>mb_strlenテスト</title>
</head>
<body>
<h1>mb_strlenテスト</h1>
<ul>
<?php
if (! empty($echo_post_mb_strlen_1))
{
echo '<li>第2パラメータ設定なし : ' . $echo_post_mb_strlen_1 . '</li>';
}
if (! empty($echo_post_mb_strlen_2))
{
echo '<li>第2パラメータ設定あり : ' . $echo_post_mb_strlen_2 . '</li>';
}
?>
</ul>
<form action="./" method="post">
<p><input type="text" name="mb_strlen" value="<?=$post_mb_strlen?>"></p>
<p><input type="submit" name="submit"></p>
</form>
</body>
</html>
※公開サーバで検証しないようにお願いします。
「abcde」をPOSTすると、以下の結果が出力されました。
第2パラメータ設定なし : 5 第2パラメータ設定あり : 5
次に「あいうえお」をPOSTすると、以下の結果が出力されました。
第2パラメータ設定なし : 15 第2パラメータ設定あり : 5
マニュアルのmb_strlenの項には以下のように書いてあります。
int mb_strlen ( string $str [, string $encoding] )
文字列の長さを取得します。
- str
長さを調べたい文字列。
- encoding
encodingパラメータには文字エンコーディングを指定します。省略した場合は、内部文字エンコーディングを使用します。
ああ、なるほどー、encodingパラメータを指定していないからだな、と考えてしまうと、その場その場で文字コードに悩まされることになります。Webで調べてみると、encodingパラメータは必ず指定せよ、と教えるページもあるのですが、それ以前に、.htaccessとかスクリプトでPHPの設定をあらかじめ変更しておくのがトラブルが少ないのではないかと思います。
前述の実験では、php.iniの記述が以下のようになっていました。
output_buffering = Off
;default_charset =
;mbstring.language =
;mbstring.internal_encoding =
mbstring.http_input = pass
mbstring.http_output = pass
mbstring.encoding_translation = Off
mbstring.detect_order = Off
;mbstring.substitute_character =
PHPの設定としては、mbstring.language = EUC-JPのように設定してあるよりは、ほぼ何も設定していないこのようにしてあるのが、実際のところ、文字化けなどのトラブルの原因を突き止めるのに有用かなと思います。
これを.htaccessやスクリプトで例えば以下のように変更してみます。
- .htaccess
-
php_value mbstring.internal_encoding UTF-8 - スクリプト
-
ini_set('mbstring.internal_encoding', 'UTF-8');
そうすると、出力は以下のようになりました。
「abcde」をPOSTすると、以下の結果が出力されました。
第2パラメータ設定なし : 5 第2パラメータ設定あり : 5
次に「あいうえお」をPOSTすると、以下の結果が出力されました。
第2パラメータ設定なし : 5 第2パラメータ設定あり : 5
encodingパラメータを指定しなくても、文字数が正しくカウントされています。
んで、php.iniの他の項目は変える必要があるのかないのか疑問に思ってくるので、各項目について調べてみることにします。
output_buffering-
デフォルトは
"0"。このディレクティブを ‘On’ と設定することにより、全てのファイルに 関して出力バッファリングを有効にすることができます。 特定の大きさにバッファの大きさを制限したい場合、このディレクティブの 値として ‘On’ の代わりに最大バイト数(例:output_buffering=4096) を使用することができます。 PHP 4.3.5 以降、PHP-CLI ではこのディレクティブが常に Off となります。
これはデフォルトのままでいいんじゃないの?
default_charset-
デフォルトは
""。4.0.0 以降、PHP は、デフォルトで常にContent-type:ヘッダで character encodingを出力するようになっています。charsetの送信 を無効にするには、これを空にしてください。
ということなので、これもデフォルトのままで。つか、文字コード決め打ちするとメールとか大丈夫なの? と思ってしまうので、
header()とか使えばいいんじゃないの? mbstring.language-
デフォルトは
"neutral"。mbstring で使用される言語設定(NLS)のデフォルト値。 この設定は mbstring.internal_encoding を定義するため、 php.ini の中で mbstring.internal_encoding は、 mbstring.language の後に置く必要があることに注意してください。
これが
"neutral"でも上のスクリプトでは何も問題ないのですが……。というのも、PHP入門書とかでは'Japanese'にせよ、と書いてあるのです。試しに
mbstring.internal_encodingをコメントアウトして、これを'Japanese'にしてみると(ini_set('mbstring.language', 'Japanese');)、mbstring.internal_encodingはISO-8859-1になって、第2パラメータ設定なしのmb_strlenは正しくカウントされません。ということで、
mbstring.languageのセットは必要ないっぽい。 mbstring.internal_encoding-
デフォルトは
NULL。内部文字エンコーディングのデフォルト値を定義します。
これのみ、今回設定を変更しました。設定を変更しないとISO-8859-1になってしまいましたので。マルチバイト関数を使わないなら無視する感じ。
mbstring.http_input-
デフォルトは
"pass"。HTTP 入力文字エンコーディングのデフォルト値を定義します。
これこのままで問題あるの? って思うと何も問題ないのでこのまま
"pass"で。 mbstring.http_output-
デフォルトは
"pass"。HTTP 出力文字エンコーディングのデフォルト値を定義します。
これも
mbstring.http_inputと同様、このまま"pass"で。 mbstring.encoding_translation-
デフォルトは
"0"。入力される HTTP クエリに関して、 文字エンコーディング検出および内部文字エンコーディングへの変換を行う 透過的な文字エンコーディングフィルタを有効にします。
変換なんてされるとややこしいので、このまま
"0"で。 mbstring.detect_order-
デフォルトは
NULL。文字コード検出のデフォルト値を定義します。
echo implode(', ', mb_detect_order())で確認するとASCII, UTF-8となる。なんか怪しいので、UTF-8, ASCIIにしておく。 mbstring.substitute_character-
デフォルトは
NULL。無効な文字を代替する文字を定義します。
あんまり重要じゃないっぽいのでデフォルトのままでいいのかな。ちなみにデフォルトは
NULLだけれどもmb_substitute_character()とかmb_get_info()で調べると63が入ってる。
という感じで、スクリプトでは以下のように設定してみます。
ini_set('output_buffaring', '0');
ini_set('default_charset', '');
ini_set('mbstring.language', 'neutral');
ini_set('mbstring.internal_encoding', 'UTF-8');
ini_set('mbstring.http_input', 'pass');
ini_set('mbstring.http_output', 'pass');
mb_detect_order('UTF-8, ASCII');
ini_set('mbstring.substitute_character', '63');
mbstring.encoding_translationはPHP_INI_PERDIRで、スクリプトでは設定できないので、.htaccessとかで設定。
php_flag mbstring.encoding_translation 0
ini_set('mbstring.http_input', 'pass');が効かないけれども、出力された後だからかな?
あ、あと、mbstring.func_overloadもあったなぁ。


2008-2010 maaguu.
コメントを残す