TS!mb_strlen関数が返してくる文字数が狂ってる - PHP
PHPのmb_strlen関数は、シングルバイト文字の一文字もマルチバイト文字の一文字も、同じ1個として文字の長さを返してくれる便利な関数です。
PHP: mb_strlen - Manual
ところが開発中、mb_strlen関数が返してくる文字数が狂ってるがゆえに入力値のチェックが正常に動作しない不具合が発生してしまいました。
具体的にどう修正したか
今回は、CodeIglinerのForm Validationクラスを魔改…流用して自環境のバリデーションとして使用しておりました。
例えば最大文字数のチェックは以下の通り
<?php public function max_length($str, $val) { if (preg_match("/[^0-9]/", $val)) { return FALSE; } if (function_exists('mb_strlen')) { return (mb_strlen($str) > $val) ? FALSE : TRUE; } return (strlen($str) > $val) ? FALSE : TRUE; } ?>
$strに$_POSTから取得した入力値、$valに最大文字数が入ります。
入力チェックに使用しているmb_strlenを使っている関数は他にも多々あり、そのため一つ一つmb_strlenに引数を与えるのではなく、$_POSTから受け取った入力値を各関数に渡す前に、内部エンコーディングと同じEUC-JPに変換する方法を選択しました。
<?php if(is_string($postval) ){ $detect_array = array( 'ASCII','UTF-8','UTF-16','EUC-JP','CP51932','SJIS','JIS' ); $postval= mb_convert_encoding($postdata, 'EUC-JP', mb_detect_encoding($postdata, $detect_array, true)); if(mb_detect_encoding($postdata, $detect_array, true) !== 'EUC-JP'){ $postdata = mb_convert_encoding($postdata, 'EUC-JP', mb_detect_encoding($postdata, $detect_array, true)); } } $result = $this->$rule($postdata, $param); ?>
$result = $this->$rule($postdata, $param); が、実際に入力チェックをする個々の関数を呼び出している箇所です。
$this->form_validation->set_rules('username', 'ユーザー名', 'max_length[5]');
と指定すると
function max_length($postdata, 5) が呼ばれます。
そういった入力チェック関数が呼ばれる直前で、POSTデータが文字列であればEUC-JPにしてます。
これで入力値の文字数が指定値を超えたらFALSEを返してくれるようになりました。
ちなみに何で文字エンコーディングに差がでてしまったかというと、EUC-JPの環境でAjax(UTF-8)で値を受け取っていたからです。