1. Perl
  2. モジュール
  3. here

Validator::Custom - HTML入力データのバリデーション

Validator::Customは、HTMLフォームのバリデーションを手伝うためのPerlのモジュールです。値のチェックとフィルタリング、エラーメッセージの扱いを簡潔に記述できます。使い方は、きわめて簡単で、複雑なバリデーションの組み合わせにも、柔軟に対応できます。

名前

Validator::Custom - HTMLフォームのバリデーション、簡潔でよい柔軟性を持つ

使い方

  use Validator::Custom;
  my $vc = Validator::Custom->new;
  
  # 入力データ
  my $id = 1;
  my $name = 'Ken Suzuki';
  my $price = ' 19.23 ';
  my $favorite = ['001', '002'];
  
  # バリデーションオブジェクトの作成
  my $validation = $vc->validation;
  
  # 「ID」が整数であることをチェック
  if (!$vc->check($id, 'int')) {
    # 失敗時のメッセージを追加
    $validation->add_failed(id => 'id must be integer');
  }
  
  # 「名前」に長さがあることをのチェック
  if (!(length $name)) {
    $validation->add_failed(name => 'name must have length');
  }
  # 「名前」の長さが30より小さいことをチェック
  elsif (!(length $name < 30)) {
    $validation->add_failed(name => 'name is too long');
  }
  
  # 左右の空白を取り除くために「価格」をフィルタリング
  $price = $vc->filter($price, 'trim');

  # 「価格」が、小数部が2桁以内の数値であることをチェック
  if (!$vc->check($price, , 'number', {decimal_part_max => 2})) {
    # Set default value if validation fail
    $price = 20.25;
  }
  
  # 「お気に入り」のそれぞれの値を、「trim」フィルター関数を使ってフィルタリング
  $favorite = $vc->filter_each($favorite, 'trim');
  
  # 「お気に入り」が少なくともひとつの値を持つことをチェック
  if (@$favorite == 0) {
    $validation->add_failed(favorite => 'favorite must be selected more than one');
  }
  # 「お気に入り」が「001」「002」「003」のうちのどれかひとつであることをチェック
  elsif (!($vc->check_each($favorite, 'in',  ['001', '002', '003']))) {
    $validation->add_failed(favorite => 'favorite is invalid');
  }
  
  # バリデーションの結果が正しいかをチェック
  if ($validation->is_valid) {
    # ...
  }
  else {
    
    # どのパラメーターが失敗したのかをチェック
    unless ($validation->is_valid('name')) {
      # ...
    }
    
    # 失敗したすべてのパラメーターの名前を取得
    my $failed = $validation->failed;

    # 失敗したひとつのパラメーターのメッセージを取得
    my $name_message = $validation->message('name');
    
    # 失敗したすべてのパラメーターのメッセージを取得
    my $messages = $validation->messages;
    
    # 失敗したすべてのパラメーターの名前とメッセージをハッシュのリファレンスとして取得
    my $messages_h = $validation->messages_to_hash;
  }

=====

解説

Validator::CustomはHTMLフォームのバリデータで、簡潔さとよい柔軟性を備えています。

特徴は以下のようになっています。

  • いくつかのチェック関数がデフォルトで利用できます。ascii_graphic,int, number, inなど。
  • いくつかのフィルター関数がデフォルトで利用できます。trim, remove_blankなど。
  • あなた自身のチェック関数とフィルター関数を追加することができます。
  • 簡潔なバリデーションオブジェクト利用できます。失敗したパラメーターの名前とメッセージを順序を保って保存できます。

ガイド

1. 基礎

1. 新しいValidator::Customオブジェクトを作成

まず最初にnewメソッドを使って、Validator::Customオブジェクトを作成します。

  use Validator::Custom;
  my $vc = Validator::Custom->new;

2.バリデーションのための入力データの準備

次に、入力データを準備します。

  my $id = 1;
  my $name = 'Ken Suzuki';
  my $price = ' 19.23 ';
  my $favorite = ['001', '002'];

3. バリデーションオブジェクトの作成

次に、validationメソッドを使って、新しいバリデーションオブジェクトを作成します。

  my $validation = $vc->validation;

これは、

失敗したパラメーター名とメッセージを保存するための、Validator::Custom::Validationオブジェクトです。

4. 入力データの検証

  # 「ID」が整数であることをチェック
  if (!$vc->check($id, 'int')) {
    # 失敗時のメッセージを追加
    $validation->add_failed(id => 'id must be integer');
  }

値が、整数であることをチェックするためにintチェック関数を使用することができます。intチェック関数はデフォルトのチェック関数です。チェック関数はcheckメソッドを通して、利用することができます。

チェックが成功しなかった場合は、失敗したパラメーターの名前とメッセージを、Validator::Custom::Validationクラスのadd_failedメソッドを使って追加することができます。

  # 左右の空白を取り除くために「価格」をフィルタリング
  $price = $vc->filter($price, 'trim');

左右のスペースを削除するために、trimフィルター関数を使うことができます。

  # 「お気に入り」のそれぞれの値を、「trim」フィルター関数を使ってフィルタリング
  $favorite = $vc->filter_each($favorite, 'trim');

「お気に入り」のそれぞれの値をフィルターするために、filter_eachメソッドを使うことができます。

  # 「お気に入り」が少なくともひとつの値を持つことをチェック
  if (@$favorite == 0) {
    $validation->add_failed(favorite => 'favorite must be selected more than one');
  }
  # 「お気に入り」が「001」「002」「003」のうちのどれかひとつであることをチェック
  elsif (!($vc->check_each($favorite, 'in',  ['001', '002', '003']))) {
    $validation->add_failed(favorite => 'favorite is invalid');
  }

「お気に入り」のそれぞれの値をチェックするために、check_eachメソッドを使うことができます。

デフォルトのチェック関数とフィルター関数を知りたい場合は、「チェック関数」と「フィルター関数」の項目を見て下さい。

2 バリデーションオブジェクトの扱い

すべての入力データが正しいことをチェックするにはis_validメソッドを使用します。

  # バリデーションの結果が正しいことを確認する
  if ($validation->is_valid) {
    # 成功
  }
  else {
    # 失敗
  }

もし、ひとつの入力データが正しいかどうかをチェックしたい場合は、is_validメソッドをパラメーターつきで使ってください。

  # どのパラメーターが失敗したかを確認
  unless ($validation->is_valid('name')) {
    # ...
  }

failedメソッドを使って、バリデーションに失敗したすべてのパラメーターの名前を取得できます。

  # バリデーションに失敗したすべてのパラメーターの名前を取得
  my $failed = $validation->failed;

messageメソッドを使って、バリデーションに失敗したパラメーターのメッセージを取得できます。

  # バリデーションに失敗したパラメーターのメッセージを取得
  my $name_message = $validation->message('name');

messagesメソッドを使って、バリデーションに失敗したすべてのパラメーターのメッセージを取得できます。

  # バリデーションに失敗したすべてのパラメーターのメッセージを取得
  my $messages = $validation->messages;

messages_to_hashメソッドを使って、バリデーションに失敗したすべてのパラメーターの名前とメッセージを、ハッシュリファレンス形式で取得できます。

  # 失敗したすべてのパラメーターの名前とメッセージをハッシュのリファレンスとして取得
  my $messages_h = $validation->messages_to_hash;

Validator::Custom::Validationも参考にしてください。

3 発展的な技術

1. チェック関数の追加

必要であれば、add_checkメソッドを使って、自分自身でチェック関数を追加できます。

  $vc->add_check(
    telephone => sub {
      my ($vc, $value, $arg) = @_;
      
      my $is_valid;
      if ($value =~ /^[\d-]+$/) {
        $is_valid = 1;
      }
      return $is_valid;
    }
  );

チェック関数は、みっつの引数をとります。最初の引数は、Validator::Customオブジェクト、二つ目の引数は、チェックするための値、三つ目の引数は、チェック関数への引数。

チェック関数は、戻り値として真か偽の値を返す必要があります。

2. フィルター関数の追加

必要であれば、add_filterメソッドを使って、自分自身でフィルター関数を追加できます。

  $vc->add_filter(
    to_upper_case => sub {
      my ($vc, $value, $arg) = @_;
      
      my $new_$value = uc $value;
                  
      return $new_value;
    }
  );

フィルター関数は、みっつの引数をとります。最初の引数は、Validator::Customオブジェクト、二つ目の引数は、フィルタリングするための値、三つ目の引数は、フィルター関数への引数。

フィルター関数は、フィルタリングの結果を返却する必要があります。

チェック関数

Validator::Customは、次のデフォルトのチェック関数を持ちます。すべてのチェック関数はcheckメソッドを使って呼び出すことができます。

int

  my $value = 19;
  my $is_valid = $vc->check($value, 'int');

整数値かどうかをチェックする。

正しい値の例

  "-10"
  "234"

不正な値の例

  "10.11"
  "abc"

もし値の範囲のチェックも行いたいのであれば、次のように書くことができます。

  my $is_valid =  $vc->check($value, 'int') && $value > 0;

number

  my $is_valid = $vc->check($value, 'number');

値が数値であるかどうかをチェックします。数値というのは、整数と小数を意味します。

正しい値の例:

  '1'
  '123'
  '123.456'
  '-1'
  '-100'
  '-100.789'

不正な値の例:

  'a';
  '1.a';
  'a.1';

decimal_part_maxオプションを使って、小数部の最大桁数を指定することもできます。

  my $is_valid = $vc->check($value, 'number', {decimal_part_max => 3});

正しい値の例:

  '123'
  '123.456'
  '-100.789'

不正な値の例:

  '123.4567'
  '-100.7891'

ascii_graphic

  my $is_valid = $vc->check($value, 'ascii');

値がAsciiのグラフィック文字(16進の「21-7e」)であるかをチェックします。一般的には、パスワードの文字をチェックするために利用します。

正しい値の例:

  "Ken!@-"

不正な値の例:

  "aa aa"
  "\taaa"

in

  my $value = '001';
  my $is_valid = $vc->check($value, 'in', ['001', '002', '003']);

値が、与えられた複数の値のうちのひとつであるかどうかをチェックします。

正しい値の例:

  '001'
  '002'
  '003'

不正な値の例:

  '004'
  '005'

フィルター関数

Validator::Customは次のデフォルトのフィルター関数を持っています。すべてのフィルター関数はy C method.

trim

  my $new_value = $vc->filter($value, 'trim');

前後の空白を取り除きます。[ \t\n\r\f]というASCIIの空白文字だけではなく、ユニコードの空白文字も取り除くことに注意してください。

フィルタリングの例:

  入力: '   Ken  '
  出力: 'Ken'

remove_blank

  my $new_values = $vc->filter($values, 'remove_blank');

空文字と未定義の文字を配列のリファレンスから取り除きます。

フィルタリングの例:

  入力: [1, 2, '', undef, 4]
  出力: [1, 2, 4]

メソッド

Validator::CustomはObject::Simpleのすべてのメソッドを継承しており、次の新しいメソッドを実装しています。

new

  my $vc = Validator::Custom->new;

新しいValidator::Customオブジェクトを生成します。

add_check

  $vc->add_check(int => sub { ... });

チェック関数を追加します。

サンプル:

  $vc->add_check(
    int => sub {
      my ($vc, $value, $arg) = @_;
      
      my $is_valid = $value =~ /^\-?[\d]+$/;
      
      return $is_valid;
    }
  );

チェック関数は、みっつの引数をとります。最初の引数は、Validator::Customオブジェクト、二つ目の引数は、チェックするための値、三つ目の引数は、チェック関数への引数。チェック関数は、戻り値として真か偽の値を返す必要があります。

add_filter

  $vc->add_filter(trim => sub { ... });

フィルター関数を追加します。

サンプル:

  $vc->add_filter(
    trim => sub {
      my ($vc, $value, $arg) = @_;
      
      $value =~ s/^\s+//;
      $value =~ s/\s+$//;
      
      return $value;
    }
  );

フィルター関数は、みっつの引数をとります。最初の引数は、Validator::Customオブジェクト、二つ目の引数は、フィルタリングするための値、三つ目の引数は、フィルター関数への引数。

フィルター関数は、フィルタリングの結果を返却する必要があります。

check

  my $is_valid = $vc->check($value, 'int');
  my $is_valid = $vc->check($value, 'int', $arg);

チェック関数を実行します。

第一引数は、チェックをする値です。第二引数は、チェック関数の名前です。第三引数は、チェック関数の引数です。

check_each

  my $is_valid = $vc->check_each($values, 'int');
  my $is_valid = $vc->check_each($values, 'int', $arg);

チェック関数を配列のリファレンスのすべての要素に対して実行します。ひとつ以上の値が不正であれば、check_eachメソッドは偽の値を返却します。

第一引数は、チェックをする値です。これは、配列のリファレンスである必要があります。第二引数は、チェック関数の名前です。第三引数は、チェック関数の引数です。

filter

  my $new_value = $vc->filter($value, 'trim');
  my $new_value = $vc->filter($value, 'trim', $arg);

フィルター関数を実行します。

第一引数は、フィルタリングを行う値です。第二引数は、フィルター関数の名前です。第三引数は、フィルター関数の引数です。

filter_each

  my $new_values = $vc->filter_each($values, 'trim');
  my $new_values = $vc->filter_each($values, 'trim', $arg);

フィルター関数を配列のリファレンスのすべての要素に対して実行します。

第一引数は、フィルタリングを行う値です。これは、配列のリファレンスである必要があります。第二引数は、フィルター関数の名前です。第三引数は、フィルター関数の引数です。

サンプル

バリデーションを行ういくつかのサンプルを紹介します。

パスワードのチェック:

  my $password = 'abc';
  my $password2 = 'abc';
  
  my $validation = $vc->validation;
  
  if (!length $password) {
    $validation->add_failed(password => 'password must have length');
  }
  elsif (!$vc->check($password, 'ascii')) {
    $validation->add_failed(password => 'password contains invalid characters');
  }
  elsif ($password ne $password2) {
    $validation->add_failed(password => "two passwords don't match");
  }
  
  if ($validation->is_valid) {
    # ...
  }
  else {
    # ...
  }

チェックボックス、少なくとも一つが選択されている。特定の値。

  my $favorite = ['001', '002'];

  my $validation = $vc->validation;
  
  if (@$favorite == 0) {

    $validation->add_failed(favorite => 'favorite must be selected at least 1');
  }
  elsif (!$vc->check($favorite, 'in', ['001', '002', '003'])) {
    $validation->add_failed(favorite => 'favorite have invalid value');
  }
  
  if ($validtion->is_valid) {
    # ...
  }
  else {
    # ...
  }

日付の文字列をTime::Pieceオブジェクトに変換:

  my $date = '2014/05/16';
  
  my $validation = $vc->validation;
  
  my $date_tp;
  if (!length $datetime) {
    $validation->add_failed(date => 'date must have length');
  }
  else {
    eval { $date_tp = Time::Piece->strptime($date, '%Y/%m/%d') };
    if (!$date_tp) {
      $validation->add_failed(date => 'date value is invalid');
    }
  }

日付時刻の文字列をTime::Pieceオブジェクトに変換:

  my $datetime = '2014/05/16 12:30:40';
  
  my $validation = $vc->validation;
  
  my $datetime_tp;
  if (!length $datetime) {
    $validation->add_failed(datetime => 'datetime must have length');
  }
  else {
    eval { $datetime_tp = Time::Piece->strptime($datetime, '%Y/%m/%d %H:%M:%S') };
    if (!$datetime_tp) {
      $validation->add_failed(datetime => 'datetime value is invalid');
    }
  }

(参考)eval

FAQ

まだValidator::Customの0.xxのバージョンを使用しています。ドキュメントを見たいのですが。

Validator::Custom::Document::Version0を見てください。これは「Validator::Custom 0.xx」の完全なドキュメントです。

バージョン1.xxで気をつけなければならない点は何ですか。

  • in_array制約関数はinチェック関数にリネームされています。
  • trimフィルター関数は、[ \t\n\r\f]だけでなく、ユニコード文字列も削除するようになりました。
  • decimal制約関数はnumberチェック関数にリネームされ、簡易化されています。
  • date_to_timepiece制約関数はもう存在しません。代替の方法については、「サンプル」の「日付の文字列をTime::Pieceオブジェクトに変換」を参照してください。
  • datetime_to_timepiece制約関数はもう存在しません。代替の方法については、「サンプル」の「日付時刻の文字列をTime::Pieceオブジェクトに変換」を参照してください。

バージョン0.xxの制約関数に対応するチェック関数をどのように作成すればよいですか

いくつかのサンプルを見せます。

space

  $vc->add_check(space => sub {
    my ($vc, $value, $arg) = @_;
    return defined $value && $value =~ '^[ \t\n\r\f]*$' ? 1 : 0;
  });

http_url

  $vc->add_check(http_url => sub {
    my ($vc, $value, $arg) = @_;
    return defined $value && $value =~ /^s?https?:\/\/[-_.!~*'()a-zA-Z0-9;\/?:\@&=+\$,%#]+$/ ? 1 : 0;
  });

decimal

  $vc->add_check(decimal => sub {
    my ($vc, $value, $arg) = @_;

    return undef unless defined $value;
    
    my $digits_tmp = $arg;
    
    # Digit
    my $digits;
    if (defined $digits_tmp) {
      if (ref $digits_tmp eq 'ARRAY') {
        $digits = $digits_tmp;
      }
      else {
        $digits = [$digits_tmp, undef];
      }
    }
    else {
      $digits = [undef, undef];
    }
    
    # Regex
    my $re;
    if (defined $digits->[0] && defined $digits->[1]) {
      $re = qr/^[0-9]{1,$digits->[0]}(\.[0-9]{0,$digits->[1]})?$/;
    }
    elsif (defined $digits->[0]) {
      $re = qr/^[0-9]{1,$digits->[0]}(\.[0-9]*)?$/;
    }
    elsif (defined $digits->[1]) {
      $re = qr/^[0-9]+(\.[0-9]{0,$digits->[1]})?$/;
    }
    else {
      $re = qr/^[0-9]+(\.[0-9]*)?$/;
    }
    
    # Check value
    if ($value =~ /$re/) {
      return 1;
    }
    else {
      return 0;
    }
  }

バージョン0.xxの制約関数に対応するフィルター関数をどのように作成すればよいですか

いくつかのサンプルを見せます。

trim_collapse

  $vc->add_filter(trim_collapse => sub {
    my ($vc, $value, $arg) = @_;
    
    return undef unless defined $value;
    
    $value =~ s/[ \t\n\r\f]+/ /g;
    $value =~ s/^[ \t\n\r\f]*(.*?)[ \t\n\r\f]*$/$1/ms;

    return $value;
  });

trim_lead

  $vc->add_filter(trim_lead => sub {
    my ($vc, $value, $arg) = @_;
    
    return undef unless defined $value;

    $value =~ s/^[ \t\n\r\f]+(.*)$/$1/ms;

    return $value;
  });

trim_trail

  $vc->add_filter(trim_trail => sub {
    my ($vc, $value, $arg) = @_;
    
    return undef unless defined $value;

    $value =~ s/^(.*?)[ \t\n\r\f]+$/$1/ms;

    return $value;
  });

trim_uni

  $vc->add_filter(trim_uni => sub {
    my ($vc, $value, $arg) = @_;
    
    return undef unless defined $value;

    $value =~ s/^\s*(.*?)\s*$/$1/ms;

    return $value;
  });

trim_uni_collapse

  $vc->add_filter(trim_uni_collapse => sub {
    my ($vc, $value, $arg) = @_;

    return undef unless defined $value;
    
    $value =~ s/\s+/ /g;
    $value =~ s/^\s*(.*?)\s*$/$1/ms;

    return $value;
  });

trim_uni_lead

  $vc->add_filter(trim_uni_lead => sub {
    my ($vc, $value, $arg) = @_;
    
    return undef unless defined $value;
    
    $value =~ s/^\s+(.*)$/$1/ms;
    
    return $value;
  });

trim_uni_trail

  $vc->add_filter(trim_uni_trail => sub {
    my ($vc, $value, $arg) = @_;
    
    return undef unless defined $value;

    $value =~ s/^(.*?)\s+$/$1/ms;

    return $value;
  });

著者

木本裕紀(kimoto.yuki@gmail.com)

[http://github.com/yuki-kimoto/Validator-Custom]

Validator::Customのチェック関数のサンプル

「ひらがな」や「かたかな」、メールアドレスのチェックなどの、チェック関数のサンプルはこちらにあります。

Validator::Custom 1.0 以前におけるドキュメント

Validator::Custom 1.0 以前におけるドキュメントは、こちらにあります。

チェック関数のサンプル

Validator::Customにおけるバリデーシのためのチェック関数のサンプルをいくつか紹介します。

ひらがなとカタカナ

ひらがなとカタカナであることを判定するには以下のような制約関数を登録します。

# ひらがな
$vc->add_check(
  hiragana => sub {
    my ($vc, $value) = @_;
    my $is_valid = $value =~ /^\p{InHiragana}+$/;
    return $is_valid;
  }
);

# カタカナ
$vc->add_check(
  katakana => sub {
    my ($vc, $value) = @_;
    my $is_valid = $value =~ /^\p{InKatakana}+$/
    return $is_valid;
  }
);

メールのバリデーション

メールのバリデーションは、デフォルトのチェック関数としては準備されていません。必要であればEmail::Valid::Looseをインストールしてから、チェック関数を登録して使うのがよいでしょう。

use Email::Valid::Loose;

$vc->add_check(
  email => sub {
    my ($vc, $value) = @_;
    return Email::Valid::Loose->address($value);
  }
);

業務に役立つPerl

Perlテキスト処理のエッセンス

PerlでポータブルなLinuxファイル管理入門

ITエンジニアの求人情報など

 ITエンジニアの求人情報・Webサービス・ソフトウェア・スクールなどの情報。

システム開発のお問い合わせ