Home > PHP

PHPのフォーム入力のヴァリデイト

2010.04.01 20:19
 PHPの正規表現に続いてここではかなり具体的な文字列の検証方法を紹介します。とはいってもなかなか完全...には至らないのですがある程度フィルタリングできるといったところです。ここではフォーム送信データなどのヴァリデイトをする際の正規表現ということを考えています。テキスト上の完全マッチということではありません。(テキスト上の(例えば)住所にマッチする正規表現は理論上不可能なのです。)


日本の名前を検証する

 これまた定義が面倒なのですが、日本で一番長い姓は、左衛門三郎(サエモンサブロウ)さんと勘解由小路(カデノコウジ)さんだそうです。名前は太郎喜左衛門将時能(タロウキザエモンノショウトキヨリ)さんだそうでいずれも実在。つまり姓が5文字、名前は9文字が最長ということになります。また最短では姓が一文字(林さんとか)で名前も一文字です。(私も名前が一文字です。)日本の名前を定義すると、
  • 漢字、ひらがな、カタカナで構成されている
  • 姓は最短で1文字、最長で5文字
  • 名は最短で1文字、最長で9文字
ということになります。これらを正規表現で表すと、
姓の場合
$str = 'オムニオ';
$re = preg_match("/^[一-龠あ-んア-ンーヽヾ]{1,5}+$/u",$str);
名の場合
$str = '太郎';
$re = preg_match("/^[一-龠あ-んア-ンーヽヾ]{1,9}+$/u",$str);
です。いすれも条件を外すと為になり、上記の条件内だと正を返します。

日本の名前のフリガナ(カタカナ)を検証する

 上記の日本語の名前の定義の通りでフリガナ(カタカナ)を検証する際には、最も長い姓のフリガナは8文字、最も長い名前のフリガナは16文字ということになります。最も短い姓と名の文字数は共に2文字ということになっています。それらをまとめると、
  • フリガナはカタカナで構成されている
  • 姓は最短で2文字、最長で8文字
  • 名は最短で2文字、最長で16文字
これらを正規表現で表すと、
姓(セイ)の場合
$str = 'オムニオ';
$re = preg_match("/^[ア-ンーヽヾ]{2,8}+$/u",$str);
名(ナ)の場合
$str = 'タロウ';
$re = preg_match("/^[ア-ンーヽヾ]{2,16}+$/u",$str);
です。preg_mactchなのでずれも条件が満たされている場合は正を、フリガナにカタカナ以外の文字が入っていたり文字数を越えてしまうと為を返します。

郵便番号にマッチする

 最も最良の方法は日本郵政が配布している郵便番号データベースをダウンロードしてその中から郵便番号を検索することです。しかしそこまでしなくてもいいだろうということでここではあくまでも正規表現で検証してみたいと思います。定義としては単純に最初の3桁と下の4桁という具合でよろしいかと思います。
 フォームデータの構成の仕方にもよりますが、ここではあくまでも、
-
というフォームデータを解析するという感じで正規表現を考えます。入力される文字は半角数字であることが前提となります。
前の3桁の場合
$str = "123";
$re = preg_match("/^\d{3}/",$str);
後の4桁の場合
$str = "123";
$re = preg_match("/^\d{4}/",$str);

住所にマッチする

 住所にマッチするというのは理論上不可能です。ですのであくまでも住所がある程度入力されたかどうかを検証する以外に方法はありません。ですのであくまでもできる範囲で...ということでの正規表現です。通常住所を入力する際には都道府県などはプルダウンメニューで選択させる方法をとります。この方が間違いが少ないからです。しかしそれから下の住所となると各市町村名とプルダウンで選択させるというのはかなり不可能に近い荒技なので手動で入力してもらうのが常だと思います。
 定義としては、漢字、ひらがな、カタカナ、数字による番地、という日本語のすべての文字を殆ど無形式で用いるのでそれらの文字の文字数制限が精一杯です。アパートやマンション名などはアルファベットを使用している可能性もあります。日本で一番長い住所は、「(京都府)京都市上京区智恵光院通り芦山寺上る西入る西社町(番地が続く)」です。京都府を抜いても24文字+番地ということなので34文字、あるいは35文字ぐらいが最も長い住所ということになりそうです。また最も短い住所は(東京都)北区赤羽(番地が続く)です。番地を入れても14文字から16文字ぐらいが最短の住所となりそうです。
 住所は略して書いたり(1-23-45とか...)、略さないで1丁目23番地45号とか書いたりといろいろですので、結局はひどいいたずら入力を制御するといった形しか不可能です。ですので、
  • 漢字、ひらがな、カタカナ、半角数字(または全角数字)、アルファベットを含んだ
  • 4文字以上40文字以下
というのが日本の住所の十分条件になりそうです。正規表現で表す必要もむしろなくなってくる...というものなので、あえて文字数の制限だけにします。
$str = "千代田区1-1";
$length = mb_strlen ($str, "UTF-8");
if ($length >= 4 && $length <= 40) {
    print $length."\n";
} else {
    print "Error!\n";
}

電話番号にマッチ

 電話番号もハイフンで区切って入力してもらう場合は半角数字が何桁であるのかを検証すれば済むのですが、ここでは電話番号をハイフン付きでフルで書き込んでもらうことを前提にします。
$str = '03-1111-1111';
$re = preg_match("/0\d{1,5}-\d{0,4}-\d{4}/",$str);

Emailアドレスにマッチする

 多数のサイトで解説されているように完全なEmailアドレスを正規表現で表すことは不可能なので便宜的に「殆どの確率で合っている」メールアドレスの正規表現ということになります。
$str = 'omnioo_mail@gmail.com';
$re = preg_match("/^([a-zA-Z0-9])+([a-zA-Z0-9\._-])*@([a-zA-Z0-9_-])+([a-zA-Z0-9\._-]+)+$/", $str);

ユーザー名にマッチする

 システムのユーザー名(Ubuntuの場合ですが)で使用できる文字種は半角英数字(アルファベットは小文字のみ)とハイフンのみです。アンダーハイフンは残念ながら使用できません。文字数の制限は特にありませんが長すぎるユーザー名も短すぎるユーザー名もよくないので常識的な範疇でユーザー名を定義します。通常使われるユーザーアカウントは3文字以上16文字以下ぐらいが適当だと思います。
  • 半角英数字(小文字のみ)とハイフンで、
  • 3文字以上、16文字以下
という設定で登録を可能にします。
$str = "a345678901234561";
$re = preg_match("/^[a-z]{1,}[0-9a-z-]{1,}[0-9a-z]{1,}+$/",$str);
$length = mb_strlen ($str, "UTF-8");
if ($length < 3 || $length > 16) {
    $re = 0;
}
 ユーザー名となるとちょっと常識的におかしな感じになるのが、「-username」とか「username-」とかいう文字列です。また「-0023user」というのも読みづらくてあんまりいいとは言えません。そういうわけで最初の頭文字はアルファベットから始めるようにします。その後中程にハイフンや数字を使い、最後の文字ではハイフンを禁止しています。

パスワードを検証する

 パスワードの文字種としては半角英数字と半角記号などを利用できますが、ここではパスワードの設定の推奨例としてアルファベットのa〜z、A〜Z、0〜9とハイフン、アンダーハイフンを使用してパスワードを作成してもらうようにします。!"#$%&'()~=~|{`}*+_?><\^-[@]:;\/.,は使用可能(らしい)ですが、ここでは使用できないようにします。というのはすぐに忘れてしまう可能性もありますし、:'@[]{}辺りの記号はコマンド類に使用する文字なので送信データとして受け取るのはちょっとイヤな感じがしないでもないからです。ですから、ここでは、
  • 半角英数字のアルファベットのa〜z、A〜Z、0〜9とハイフン、アンダーハイフン
  • 文字数は4文字以上32文字以下
で設定してもらうようにします。
$str = "8sujhy-97dUjWS_YTR5S";
$re = preg_match("/[0-9A-Za-z_-]/",$str);
$length = mb_strlen ($str, "UTF-8");
if ($length < 4 || $length > 32) {
    $re = 0;
}
 また単純なパスワードは非常に危険なので、あらかじめ複雑なパスワードを設定するように促すというシステムも必要かもしれません。推奨例としては、大文字のアルファベット、小文字のアルファベット、数字が程よいバランスで含まれていることと、単語や名前、または連続した1文字や予想されやすいパスワードを弾くというのも大切です。

 余談ですが、フォーム入力において最も広義な文字列の正規表現というのはどういうものになるでしょうか?つまりXSSなどを防止しつつも任意の常識的な文字列を受け付けるという正規表現です。勿論危険な文字列はあるルーチンをもってサニタイズすることに変わりはありませんが、テキストフィールドなどの単語や短い文字列を要求する際には、
preg_match("/^[一-龠あ-んア-ンA-Za-z0-9-_ーヽヾ]{1,20}+$/u",$str)
のような正規表現になります。勿論文字列の長さはここでは20になっていますが便宜書き換えてください。この正規表現は、漢字・ひらがな・カタカナすべて、半角英数すべて、ハイフン、アンダーハイフンとなっています。通常の常識的な文字列にアスタリスクやその他の半角記号などが使われるとは思えないので、この正規表現で十分だと思います。
 textareaのようなフリーな入力スペースでは半角記号が使われる可能性は十分にあり、HTMLタグなどが使用できる使用できないなどの複雑な操作が必要となってきます。これは正規表現だけでは扱うには複雑過ぎるので複数の関数で制御する必要があります。
 






プロフィール



  • Name :: 山上オサム ♂(39)
  • Hobby :: 武術
  • Work :: Web Designer