北青山通信 – from aoyama » 覚え書き
タイトルの件、考えてみれば当たり前なのですが、お客さんからの仕様で引っかかりました。ここでいう全角文字は、マルチバイト文字のこと。
フォームに文字を入力する処理で、入力した文字の長さをチェックする処理が必要です。そこで文字長でチェックするか、バイトでチェックするか。
これをCakePHPのバリデーションで用意しているmaxLengthのルールでチェックしたところ、何も考えずに内部コードのバイト長でチェックしていまいます。これをお客様から指摘されました。希望としては、全角文字を2バイトでチェックして欲しいとのこと。
例えば、「あああ」は6バイトではなく9バイトとして判定されます。これは内部のコードがUTF-8だからです。CakePHPのバリデーションで正しく文字数で判定するには、maxLengthの処理をmb_strlen()で変更してあげます。詳細な対応方法は、こちらのサイトをご覧ください。
ここで簡単な実験です。こんなコードと結果です。
<?php
$str = "あああ";
echo(strlen($str)); // 9
echo(mb_strlen($str)); // 9
echo(mb_strlen($str, ‘UTF-8′)); // 3
echo(mb_strlen(mb_convert_encoding($str, ‘SJIS’, ‘UTF-8′), ‘SJIS’)); // 3
echo(strlen(mb_convert_encoding($str, ‘SJIS’, ‘UTF-8′))); // 6
?>
UTF-8のままですと、全角文字は2バイトにはなりません。しかも、正しく文字コードをしてあげないと正しい文字数になりません。
一旦、シフトJISに変換してあげて、mb_stringではないstrlen()で全角文字を2バイトで計算してくれます。
昔の人間ですと、どうしても全角=2バイト、半角=1バイトと考えてしまうのですが、この考え方は古いかもしれませんね。
PHPの関数で用意されているfgetcsv()は、CSVファイルを一行読み込んで、各項目を配列で返してくれます。こんな感じ。
$handle = @fopen("testtest.csv", "r");
$buffer = fgetcsv($handle, 4096);
ただし、CSVファイルに2バイトのデータが含まれていたら、うまく切り分けてくれない。PHPの内部コードはUTF-8で、CSVファイルがシフトJISなら、変なところで切ってくれる。
仕方ないので、手っ取り早く
$handle = @fopen("testtest.csv", "r");
$buffer = split(",", fgets($handle, 4096));
のように変更してあげる。CSVファイルはこちらでプログラムで生成されているので、途中にコンマが紛れてこないだろうということで、とりあえずOKとしておきます。なんだが美しくないなあー。これだと完全なCSVファイルの処理をしていないので、また後で考えなければいけないか・・・。