QuickForm を使用すると、クライアント側およびサーバ側での検証が簡単にできます。 正規表現を使用した検証も可能ですし、検証用に作成した独自の関数やメソッドを使用することもできます。 自分で作成した検証規則を、お望みの要素あるいはグループに対して適用することができるのです。 この節では、検証を容易に行うために QuickForm が提供しているさまざまな機能について説明します。
QuickForm は、必須要素に値が入力されているかどうかをフォーム送信時に調べることができます。 この機能は、あらゆる型の要素あるいはグループに対して使用できます。 整数の 0 は未入力とはみなされません。
<?php
require_once 'HTML/QuickForm.php';
$form = new HTML_QuickForm('myform', 'post');
$form->addElement('text', 'email', 'メールアドレス:');
$form->addElement('submit', 'submit', '送信');
// 検証規則
$form->addRule('email', 'メールアドレスは必須です', 'required');
// 検証
if ($form->validate()) {
$form->freeze();
}
$form->display();
?>
空の要素の検証要素が空の場合、
required
以外の検証規則は適用されません。 つまり、空の要素が無効となるのは、その要素が必須である場合のみです。
アップロードの必須チェックfile 要素に対しては
required
規則は動作しません。uploadedfile
を使用してください。
HTML_QuickForm::validate() メソッドによって、 設定された規則がその順に処理されます。規則が満たされなかった場合、 その要素に対応するエラーメッセージが表示され、入力フォームがもう一度表示されます。 テンプレートを使用することで、エラーメッセージを表示する場所を設定することが可能です。 検証規則を設定する順番は重要です。というのも、実際に表示されるメッセージがそれによって決まるからです。
QuickForm によって、クライアント側でのフォームの検証に必要な javascript を生成することができます。 この機能は、あらゆる型の要素あるいはグループに対して使用できます。 クライアント側で javascript が off になっている場合は、 サーバ側の検証が常に実行されます。
<?php
$form->addRule('email', 'E-Mail is required', 'required', null, 'client');
?>
パラメータ
'client'
を設定すると、javascript が自動的に生成されます。
QuickForm では、フォームの検証によく使用されるいくつかの規則を組み込みで提供しています。
中には、追加のパラメータ $format
を
addRule() /
addGroupRule()
に渡す必要があるものもあります。
名前 | 説明 | $format パラメータ |
---|---|---|
required |
値が空ではありません | |
maxlength |
値は決して指定した文字数を超えません | 文字の数を表す整数値 |
minlength |
値は少なくとも指定した文字数以上なければなりません | 文字の数を表す整数値 |
rangelength |
値の最小文字数と最大文字数を指定します | array(最小文字数, 最大文字数) |
regex |
値が正規表現にマッチしなければなりません | 調べる正規表現を表す文字列 |
email |
値が email アドレスとして正しい形式でなければなりません | checkdnsrr() によるドメインチェックを追加で行うかどうかをしていする boolean 値 |
lettersonly |
値が文字のみで構成されていなければなりません | |
alphanumeric |
値が文字と数字のみで構成されていなければなりません | |
numeric |
値が数値でなければなりません | |
nopunctuation |
値に記号を含んではいけません | |
nonzero |
値は先頭が 0 でない数値でなければなりません | |
compare |
この規則では、2 つのフォームフィールドの値を比較することができます。 「『パスワード (もう一度入力してください)』の内容が『パスワード』と一致しなければならない」 といった類の規則を表すために使用します。 addRule() の最初のパラメータとして、比較する要素名を配列で渡さなければならないことに注意しましょう。 | 行う比較の内容を表す文字列
|
callback |
この規則では外部の関数/メソッドを使用して検証を行なうことができます。 フォーマットパラメータとしてコールバックを明示的に渡すか、 あるいは暗黙的に registerRule() で登録します。 | callback として使用する関数あるいはメソッド |
ファイルアップロード用の検証規則 | ||
uploadedfile |
ファイルをアップロードしなければなりません | |
maxfilesize |
ファイルの大きさが指定したバイト数を超えてはいけません | ファイルの最大サイズを表す整数値 |
mimetype |
ファイルの MIME 型が正しくなければなりません | 有効な MIME 型を表す文字列、あるいは複数の MIME 型の配列 |
filename |
ファイル名が、指定した正規表現にマッチしなければなりません | 調べる正規表現を表す文字列 |
ファイルアップロードの規則についてこれらの規則は
HTML/QuickForm/file.php
で定義されており、file
型の要素がフォームに追加された際に自動的に登録されます。 これらの規則がサーバ側でのみ動作するのは当然のことです。
組み込みの規則の使用法は、パッケージに含まれる
rules-builtin.php
で網羅しています。
rules-custom.php
では、独自の規則クラスの使用法および
callback
型の規則の使用方法を説明しています。
ここでは、数値が最大値と最小値の間にあることを調べるために
NumericRange クラスが含まれています。
リリース 3.2 以降、組み込みの検証規則はすべて HTML_QuickForm_Rule クラスのサブクラスとなります。独自のサブクラスを作成し、validate() および getValidationScript() の両メソッドを実装することも可能です。 実際の例は、ソースを参照ください。
もっと複雑な検証が必要な場合、QuickForm では独自の関数を使用して 要素やグループの検証を行うことが可能です。また、クラスのメソッドをコールすることもできます。 この場合hあ、PEAR の Validate パッケージやその他のクラスが使用できます。 独自の関数を使用したい場合には、以下の 2 つの選択肢があります。
registerRule()
を使用して関数を登録します。$type
には
'callback'
を使用し、新しい規則名を
$ruleName
で指定します。その後
addRule()
を使用する際に、この名前を他の組み込み規則と同じように使用できます。
addRule()
で callback
型の規則を追加し、関数の名前を
$format
に渡します。こちらのほうがタイプ数が少なくなりますが、
検証用の関数に追加のデータを渡すことができなくなります。
Email の検証関数
<?php
/**
* email アドレスを検証します
*
* @param string $email 検証する Email アドレス
* @param boolean $domainCheck ドメインの存在をチェックするかどうか
*/
function checkEmail($email, $domainCheck = false)
{
if (preg_match('/^[a-zA-Z0-9\._-]+\@(\[?)[a-zA-Z0-9\-\.]+'.
'\.([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/', $email)) {
if ($domainCheck && function_exists('checkdnsrr')) {
list (, $domain) = explode('@', $email);
if (checkdnsrr($domain, 'MX') || checkdnsrr($domain, 'A')) {
return true;
}
return false;
}
return true;
}
return false;
}
$form->registerRule('checkmail', 'callback', 'checkEmail');
$form->addRule('email', 'Email が不正です', 'checkmail', true);
?>
HTML_QuickForm::addRule() で、関数に渡す追加のパラメータを指定することができます。 ここでは、TRUE を渡すことで関数内での DNS チェックを有効にしています。
メソッドを使用する場合は、そのメソッドが存在するクラスを指定しなければなりません。 規則を登録する際に以下のような構文を使用します。
<?php
// checkEmail メソッドが Validate クラス内に存在します。
$form->registerRule('checkmail', 'callback', 'checkEmail', 'Validate');
?>
フォームを検証する際に javascript の関数を使用することもできます。 PHP 関数と同じ名前をつけ、boolean を返すようにし、
'client'
パラメータを指定します。
要素グループについてもその他の要素と同じ方法で検証することができます。 あるいはより複雑な検証方法を使用することも可能です。グループ全体を検証するには、 単に HTML_QuickForm::addRule() を使用します。 グループの各要素の値が、配列として検証関数に渡されます。
HTML_QuickForm::addGroupRule() メソッドを使用すると、 より複雑な検証規則を適用することができます。これは、グループ内の要素ごとに検証を行うことができます。 また、グループ内の要素のうち何個が検証規則を満たせばそのグループを有効とみなすかを指定することもできます。
複雑なグループの検証
<?php
// グループ
$id[] = &HTML_QuickForm::createElement('text', 'username', 'ユーザ名');
$id[] = &HTML_QuickForm::createElement('text', 'code', 'コード');
$form->addGroup($id, 'id', 'あなたの ID:', '-');
// 要素ごとの検証規則
$rule['username'][] = array('ユーザ名は必須です', 'required');
$rule['username'][] = array('ユーザ名には文字のみが使用できます', 'lettersonly');
$rule['username'][] = array('ユーザ名の長さは 5 文字から 8 文字までです', 'rangelength', array(5, 8));
$rule['code'][] = array('コードは必須です', 'required');
$rule['code'][] = array('コードには数字のみが使用できます', 'regex', '/^\d+$/');
$rule['code'][] = array('コードの長さは 5 桁です', 'rangelength', array(5, 5));
$form->addGroupRule('id', $rule);
?>
この例では、グループ内の要素についての検証規則を設定しています。 要素名を使用する代わりに、(作成された順番によって決まる) グループ内のインデックスを使用することもできます。 そのほうが検証の速度が速くなるでしょう。
次の例では、同じグループに対して 2 つの要素のうち少なくとも一方が入力されているかどうかのみを検証します。
これを実現するには、howmany
パラメータを使用して、
そこに 1 を設定します。
<?php
$form->addGroupRule('id', '少なくとも 1 つの要素を入力してください', 'required', null, 1);
?>
これまで見てきたとおり、QuickForm を使用すると、要素やグループの検証がとても簡単になります。 毎度毎度同じようなコードで値が異なるだけという検証コードを書く必要がなくなるのです。 必須要素の確認もしてくれますし、javascript のコードも自動で生成してくれます。 また独自の関数や正規表現を使用して独自の検証を行えるという柔軟性もあります。 さあ、そろそろ試してみませんか ...?
<?php
$form->addRule('element', 'この要素は必須です', 'required');
?>
のような規則をフォームに追加した場合、例えば空白 1 文字のみといった入力でも 検証を通過してしまいます。 これは、この検証規則が単に文字が入力されているかどうかだけを確認しているだけであり、 空白文字もこの規則を満たしているからです。
正規表現を使用して独自の規則を作ればこの問題は回避できますが、 もっと簡単な解決法もあります。たいていの場合、入力内容の前後の空白は意味のないものであり、 検証作業の前に組み込みの trim() 関数を使用してこの空白を取り除くことができます。そのためには以下のようにします。
<?php
$form->applyFilter('element', 'trim');
?>
フィルタは再帰的に適用されます。つまり、配列の全要素に対して順次 trim() が適用されるということです。 applyFilter() メソッドに対する引数として、あらゆる callback を渡すことが可能です。
ユーザの入力を「サニタイズ」し、無効な値を無視したい場合にはフィルタを使用します。