質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.77%

PHPでバリデーションを共通化してまとめたい

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 8,661

dog57

score 123

PHPでバリデーションを共通化してまとめたいです。
具体的には下記のコードを

// 名前の未入力チェック
    if (empty($name)) {
        $errors[] = "名前を入力してください。";
    }

    // メールアドレスの未入力チェック
    if (empty($email)) {
        $errors[] = "メールアドレスを入力してください。";
    }

    // パスワードの未入力チェック
    if (empty($password)) {
        $errors[] = "パスワードを入力してください。";
    }

    // 電話番号の未入力チェック
    if (empty($tel)) {
        $errors[] = "電話番号を入力してください。";
    }

    // 都道府県の未入力チェック
    if ($prefectures == "選択") {
        $errors[] = "都道府県を選択してください。";
    }

      //
      // 文字数チェック
      //

      // 名前の文字数チェック
      if (strlen($name) >= 60) {
        $errors[] = "氏名が長すぎます。";
      }

      // パスワード文字数チェック(8文字以上か)
      if (preg_match("/^[a-zA-Z1-9]{1,7}$/", $password)) {
          $errors[] = "パスワードは8文字以上で入力してください。";
      }

      // 電話番号の文字数チェック(10文字 or 11文字)
      if (strlen($tel) >= 1 && strlen($tel) <= 9 && preg_match("/^[0-9]+$/", $tel)) {
          $errors[] = "電話番号は10文字か11文字で入力してください。";
      } elseif (strlen($tel) >= 12 && preg_match("/^[0-9]+$/", $tel)) {
          $errors[] = "電話番号は10文字か11文字で入力してください。";
      }

      //
      // 形式チェック
      //

      // メールアドレス形式チェック
      if (!preg_match("/^([a-zA-Z0-9])+([a-zA-Z0-9\._-])*@([a-zA-Z0-9_-])+([a-zA-Z0-9\._-]+)+$/", $email) && $email !== "") {
          $errors[] = "メールアドレスに間違いがあります。";
      }

      // 電話番号の形式チェック
      if (preg_match("/[-]+/", $tel)) {
          $errors[] = "電話番号はハイフンなしで入力してください。";
      }

      // 電話番号の半角チェック
      if (preg_match("/[a-zA-Z]/", $tel) && $tel !== "") {
          $errors[] = "電話番号は半角数字で入力してください。";
      }



  if (count($errors) >= 1) {
      $_SESSION['errors'] = $errors;

      header("location: registration_form.php");
      exit;

  } else {

    $errors = array();

  }

下記のようにまとめてみました。
まとめたやつは

require_once('./validation.php');
name_validation();


みたいに使っていこうと思っています。
ですが、1個1個メソッドを作るのがとてもめんどうなのですが、
1つ1つメソッドを作る以外に、もっとまとめられる方法はありますか?

validation.php

<?php
require_once('../config/config.php');


 function name_validation() {

    // 名前の未入力チェック
    if (empty($_SESSION['name'])) {
        $errors[] = "名前を入力してください。";
    }

  }

  function email_validation() {

    // メールアドレスの未入力チェック
    if (empty($_SESSION['email'])) {
        $errors[] = "メールアドレスを入力してください。";
    }

  }

  function password_validation() {

    // パスワードの未入力チェック
    if (empty($_SESSION['password'])) {
        $errors[] = "パスワードを入力してください。";
    }

  }

  function tel_validation() {

    // 電話番号の未入力チェック
    if (empty($_SESSION['tel'])) {
        $errors[] = "電話番号を入力してください。";
    }

  }

  function prefectures_validation() {

    // 都道府県の未入力チェック
    if ($_SESSION["prefectures"] == "選択") {
        $errors[] = "都道府県を選択してください。";
    }

  }



        //
        // 文字数チェック
        //

  function name_length_validation() {

    // 名前の文字数チェック
    if (strlen($_SESSION['name']) >= 60) {
      $errors[] = "氏名が長すぎます。";
    }

  }

  function password_length_validation() {

    // パスワード文字数チェック(8文字以上か)
    if (preg_match("/^[a-zA-Z1-9]{1,7}$/", $_SESSION['password'])) {
        $errors[] = "パスワードは8文字以上で入力してください。";
    }

  }

  function tel_length_validation() {

    // 電話番号の文字数チェック(10文字 or 11文字)
    if (strlen($_SESSION['tel']) >= 1 && strlen($_SESSION['tel']) <= 9 && preg_match("/^[0-9]+$/", $_SESSION['tel'])) {
        $errors[] = "電話番号は10文字か11文字で入力してください。";
    } elseif (strlen($_SESSION['tel']) >= 12 && preg_match("/^[0-9]+$/", $_SESSION['tel'])) {
        $errors[] = "電話番号は10文字か11文字で入力してください。";
    }

  }


      //
      // 形式チェック
      //

      function email_format_validation() {

        // メールアドレス形式チェック
        if (!preg_match("/^([a-zA-Z0-9])+([a-zA-Z0-9\._-])*@([a-zA-Z0-9_-])+([a-zA-Z0-9\._-]+)+$/", $_SESSION['email']) && $_SESSION['email'] !== "") {
            $errors[] = "メールアドレスに間違いがあります。";
        }

      }

      function tel_format_validation() {

        // 電話番号の形式チェック
        if (preg_match("/[-]+/", $_SESSION['tel'])) {
            $errors[] = "電話番号はハイフンなしで入力してください。";
        }

      }

      function te_halfSize_validation() {

        // 電話番号の半角チェック
        if (preg_match("/[a-zA-Z]/", $_SESSION['tel']) && $_SESSION['tel'] !== "") {
            $errors[] = "電話番号は半角数字で入力してください。";
        }

      }

イメージ説明

validation.php

<?php
require_once('../config/config.php');

// バリデーションクラス
class Validation {

  // コンストラクタ(construct)
  function check_Validation($input_control = [], $input_data = []) {

    $result = []; //チェック結果配列

    foreach ($input_control as $control_name => $info) {

      // 入力情報が存在するか
      if (array_key_exists($control_name, $input_data)) {

        $value = $input_data[$control_name];
        $rules = explode("|", $info["rule"]); // バリデーションルールの引き出し

        foreach ($rules as $r) { // 指定されたルールをループ

          $rule = explode("-", $r); // ルール設定の切り出し
          $rule_name = $rule[0]; // ルール名
          $rule_setting = $rule[1]; // ルール設定



          switch ($rule_name) {

            // 入力が空の場合
            case "empty":
              if ($this->empty_check($value)) {

                $result[$control_name][] = $info["name"].'を入力してください。';

              }
              break;

              // 最大文字数のチェック
            case "max":
                if ($this->max_check($value, $rule_setting)) {

                  $result[$control_name][] = $info["name"].'は'.$rule_setting.'文字以内で入力してください。';

                }
                break;


          }


        }

      }

    }

    return $result;

  }





// 空のチェック
public function empty_check($value = "") {

  return empty($value);

}

// 入力文字数のチェック
public function max_check($value = "", $max = 60) {

  return mb_strlen($value) > $max;

}


}

registration_confirm.php 一部抜粋

// POST時
if (filter_input(INPUT_SERVER, 'REQUEST_METHOD') == 'POST') {


    $_SESSION["name"] = filter_input(INPUT_POST, 'name');
    $_SESSION["email"] = filter_input(INPUT_POST, 'email');
    $_SESSION["password"] = filter_input(INPUT_POST, 'password');
    $_SESSION["tel"] = filter_input(INPUT_POST, 'tel');
    $_SESSION["prefectures"] = filter_input(INPUT_POST, 'prefectures');
    $_SESSION["hobby"] = filter_input(INPUT_POST, 'hobby', FILTER_DEFAULT,FILTER_REQUIRE_ARRAY);
    $_SESSION["gender"] = filter_input(INPUT_POST, 'gender');
    $_SESSION["contact"] = filter_input(INPUT_POST, 'contact');

    $name  = $_SESSION["name"];
    $email  = $_SESSION["email"];
    $password  = $_SESSION["password"];
    $tel  = $_SESSION["tel"];
    $prefectures  = $_SESSION["prefectures"];
    $hobby  = $_SESSION["hobby"];
    $gender = $_SESSION["gender"];
    $contact  = $_SESSION["contact"];



    // 対象コントロール→バリデーションルール
    $input_control = [

      "name" => [

        "name" => "氏名",
        "rule" => "empty|max-60"

      ],

      "tel" => [

        "name" => "電話番号",
        "rule" => "empty|min-10|-|halfSize"

      ],

      "password" => [

        "name" => "パスワード",
        "rule" => "empty|min-8"

      ],

      //・・・・以下、対象の入力項目とルールを定義

    ];

    $result = new Validation($input_control, $_SESSION);

    if (count($result) > 0) {

      $_SESSION['result'] = $result;
      header("location: registration_form.php");

    } else {

      $result = array();

    }



}




//
// Twig
//

// Composerで作成されたautoload.phpを読み込む
require_once ('../vendor/autoload.php');
// Twig_Loader_Filesystem と Twig instance の生成を読み込む
require_once('../config/twig.php');


// render
echo $twig->render('registration_confirm.html', array (

   'name' => $name,
   'email' => $email,
   'password' => $password,
   'tel' => $tel,
   'prefectures' => $prefectures,
   'hobby' => $hobby,
   'gender' => $gender,
   'contact' => $contact,

   'result' => $result,
   'string' => $string,


   )
);

・registaration_form.php (登録フォーム) 一部抜粋

上の確認フォームからエラーメッセージをリダイレクトで受け取っています。

順番は registration_form.php → registration_confirm.php 
registration_confirm.php  でエラーがあれば registration_form.php にリダイレクト

// エラーメッセージ
if (isset($_SESSION['result'])) {

  if (count(array($_SESSION['result'])) >= 1) {

    $result = $_SESSION['result'];

  }
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

+3

個別にしすぎているので汎用性が低く、今の状態でも「まとめた」とは言えません。
空のバリデーションは1つにできますし、最大文字数もまとめられます。
電話番号チェックなどはわけるのではなく1つにできそうです。

それぞれのコントロールに対してバリデーションルールをつけてそのルールに基づいてチェックしてはどうでしょうか。
あとはルールを追加していけばいいだけなので、入力項目個別に作るよりは様々な用途に使えて、メソッド追加も最小限に済むと思います。

というわけで、私ならクラス化します。

※ざっと作ったので動作検証ほとんどできてませんが・・・。

バリデーション呼び出し側

require_once('./validation.php');

//対象コントロール→バリデーションルール
$input_control=[
 "name"=>[
          "name"=>"氏名",
          "rule"=>"empty|max-50"
         ],
 "empty"=>[
          "name"=>"電話番号",
          "rule"=>"empty|tel"
         ],
 "password"=>[
          "name"=>"パスワード",
          "rule"=>"password"
         ],

・・・・以下、対象の入力項目とルールを定義
];

$result = new Validation($input_control,$_SESSION);

if(count($result) > 0){
  //エラーがある場合の処理

}else{
  //エラーがない場合の処理
}

バリデーション(validation.php)

//バリデーションクラス
class Validation{
  //コンストラクタ
  function Validation($input_control = [],$input_data = []){
     $result = [];//チェック結果配列
     foreach($input_control as $control_name=>$info){
        //入力情報が存在するか
        if(array_key_exists($control_name,$input_data)){
             $value = $input_data[$control_name];
             $rules = explode("|",$info["rule"]);//バリデーションルールの引き出し
             foreach($rules as $r){ //指定されたルールをループ
               $rule = explode("-",$r); //ルール設定の切り出し
               $rule_name = $rule[0]; //ルール名
               $rule_setting = $rule[1]; //ルール設定
               switch($rule_name){
                  //入力空の場合
                  case "empty":
                      if($this->empty_check($value)){
                         $result[$control_name][] = $info["name"].'を入力してください。';
                      }
                      break;
                 //最大文字数のチェック
                  case "max":
                      if($this->max_check($value,$rule_setting){
                         $result[$control_name][] = $info["name"].'は'.$rule_setting.'文字以内で入力してください。';
                      }
                      break;

           ・・・・以下、バリデーションルールを追加
               }

             }
        }
     }

     return $result;
  }

  //空のチェック
  private function empty_check($value = ""){
      return empty($value);
  }
  //入力文字数のチェック
  private function max_check($value = "",$max = 50){
      return mb_strlen($value) > $max;
  }

 ・・・以下、バリデーションチェック処理を追加
}

パスワードとかは入力必須ではないということはないと思いますので、そういう場合は「パスワードチェック」に空かどうかも含ませるというのもありです。

エラーメッセージなども設定で持ってそこから取得するようにすればswitchすらも不要にできる可能性があります(そこは発想とやり方次第ですね)
いずれにしてもバリデーションルールが増えればメソッドも増えます。

追記:
filter_var()という関数があるのでこちらを使うとメールアドレスのチェックなどはかなり楽です(自身のチェックしたい内容全て網羅しているとは限りませんが・・・)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/03/09 20:02

    ソースコードをご提示ください。エラーメッセージだけではわかりません。

    キャンセル

  • 2018/03/09 20:26 編集

    エラーメッセージそのまま調べてもらえればわかりますが、オブジェクト(今回はValidation)の扱いがどこかで間違っているのではと思いますが。何かでint型にしようとしているような記述があるのではないでしょうか。

    キャンセル

  • 2018/03/11 09:52

    質問欄の画像の下にコードを追記いたしました。

    キャンセル

checkベストアンサー

+2

私なら、どっかのフレームワークからコード持ってきます。
大抵のフレームワークなら、このあたりの実装はしっかりねられているので。

特殊なチェックはコールバック関数で渡す感じの実装しとけば、大体対応できると思います。

余談
「共通化してまとめたい」って質問ですが、「もう少し見通しを良くする」って方向でコード書くと、自然と共通化されます。読みやすいコードを書くように意識すると良いですよ。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+2

汎用性を前提に場合分けをしてelseifでつないでいけばよいでしょう

<?PHP
$list=[
  "name"=>[
    "kanji"=>"名前",
    "required"=>true,
    "max_length"=>3,
    ],
  "email"=>[
    "kanji"=>"メールアドレス",
    "required"=>true,
    "min_length"=>5,
    ],
  "password"=>[
    "kanji"=>"パスワード",
    "required"=>true,
    "min_length"=>8,
    "max_length"=>10,
    ],
  "tel"=>[
    "kanji"=>"電話",
    "required"=>true,
    "pattern"=>"/^[0-9]+$/",
    ],
  ];
$errors=[];
array_walk($list,function($x,$y) use(&$errors){
  $v=filter_input(INPUT_GET,$y);
  if(is_null($v)){
    return false;
  }elseif(empty($v) and isset($x["required"]) and $x["required"]){
    $errors[]=$x["kanji"]."は必須";
  }elseif(isset($x["min_length"]) and isset($x["max_length"])){
    $errors[]=$x["kanji"]."の長さは".$x["min_length"]."文字以上".$x["max_length"]."文字以下";
  }elseif(isset($x["min_length"]) and $x["min_length"]> mb_strlen($v)){
    $errors[]=$x["kanji"]."の長さは".$x["min_length"]."文字以上";
  }elseif(isset($x["max_length"]) and $x["max_length"]< mb_strlen($v)){
    $errors[]=$x["kanji"]."の長さは".$x["max_length"]."文字以下";
  }elseif(isset($x["pattern"]) and !preg_match($x["pattern"],$v)){
    $errors[]=$x["kanji"]."は使用できない文字が含まれている";
  }
});
if(count($errors)>0) print_r($errors);
?>
<form>
<input type="text" name="name" placeholder="名前"><br>
<input type="text" name="email" placeholder="メールアドレス"><br>
<input type="text" name="password" placeholder="パスワード"><br>
<input type="text" name="tel" placeholder="電話"><br>
<input type="submit" value="go">
</form>

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.77%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る