PHPによる入力データの検証(データバリデーション)

カテゴリ:PHP編

PHP+MySQLによる簡単なブログサイトの構築ではデータベース連携に主眼を置いて解説したため、入力データの検証(データバリデーション)は省略しましたが、この記事ではデータバリデーションを提供するクラスの作成について解説していきます。 クラスとして実装する理由は、データバリデーションは通常、同じバリデーション処理を複数のページ(記事登録・記事編集ページなど)で実施するためです。

バリデーションクラスの作成

クラス名は DataValidation とします。

まず、ブログの登録時にはタイトル、本文、カテゴリーの入力があるため、$title、$text、$categoryを引数に取るバリデーションメソッドを作成します。 また、エラーメッセージを格納するためのインスタンス変数 $errorMsg を作成し、各バリデーションチェックメソッドに抵触した場合にエラーメッセージを保存するようにします。

例)

class DataValidation {

    $errorMsg = "";

    function validForArticleParams($title, $text, $category) {

        //空文字のチェック
        if ($title == "" || $text == "" || $category == "") {
            $this->errorMsg = "入力されていない項目があります。";
            return false;
        }

        //入力値の型のチェック
        if (!is_string($title)  || !is_string($text) || !is_string($category)) {
            $this->errorMsg = "入力値が不正な項目があります。";
            return false;
        }

        //入力値のサイズのチェク
        if ($title > 100 || $text > 50000 || $category > 50) {
            $this->errorMsg = "入力値のサイズが制限を超えている項目があります。";
            return false;
        }

        return true;

    }

}

また、ブログの更新時にはタイトル、本文、カテゴリーに加えてIDの入力もあるため、$idも引数に取る以下のバリデーションメソッドも作成します。

    function validForArticleParamsWithId($id, $title, $text, $category) {


        //空文字のチェック
        if ($id == "") {
            $this->errorMsg = "IDがありません。";
            return false;
        }

        //入力値の型のチェック
        if (!is_int($id)) {
            $this->errorMsg = "IDの型が不正です。";
            return false;
        }

        //入力値のサイズのチェク
        if ($id > 1000000) {
            $this->errorMsg = "IDのサイズが制限を超えています。";
            return false;
        }

        //ID以外のバリデーションを実施
        if($this->validForArticleParams($title, $text, $category)) {
            return false;
        };

        return true;

    }

最後にエラーメッセージ取得用のメソッド getErrorMsg() を追加し、最終的に DataValidation クラスは以下のようになります。

class DataValidation {

    private $errorMsg = "";

    function validForArticleParams($title, $text, $category) {

        //空文字のチェック
        if ($title == "" || $text == "" || $category == "") {
            $this->errorMsg = "入力されていない項目があります。";
            return false;
        }

        //入力値の型のチェック
        if (!is_string($title)  || !is_string($text) || !is_string($category)) {
            $this->errorMsg = "入力値が不正な項目があります。";
            return false;
        }

        //入力値のサイズのチェク
        if ($title > 100 || $text > 50000 || $category > 50) {
            $this->errorMsg = "入力値のサイズが制限を超えている項目があります。";
            return false;
        }

        return true;

    }

    function validForArticleParamsWithId($id, $title, $text, $category) {


        //空文字のチェック
        if ($id == "") {
            $this->errorMsg = "IDがありません。";
            return false;
        }

        //入力値の型のチェック
        if (!is_int($id)) {
            $this->errorMsg = "IDの型が不正です。";
            return false;
        }

        //入力値のサイズのチェク
        if ($id > 1000000) {
            $this->errorMsg = "IDのサイズが制限を超えています。";
            return false;
        }

        //ID以外のバリデーションを実施
        if($this->validForArticleParams($title, $text, $category)) {
            return false;
        };

        return true;

    }

    //エラーメッセージの取得用メソッド
    function getErrorMsg() {
        return $this->errorMsg;
    }

}

使い方

DataValidation クラスは以下のように使用します。

//クラスの読み込み
include("DataValidation.php");

//インスタンス化
$dv = new DataValidation();

//バリデーションチェック
if ($dv->validForArticleParams($title, $text, $category)) {
    //バリデーション成功時の処理
} else {
    //バリデーション失敗時の処理
    echo $dv->getErrorMsg(); //エラーメッセージを表示
}

実際の実装例

では、PHP+MySQLによる簡単なブログサイトの構築で作成したブログ記事登録用ページ article_add.php とブログ記事編集用ページ article_modify.php に実際にバリデーションクラスを実装してみましょう。 以下のようになります。

article_add.php

<html>
<?php
//title、text、cateoryパラメータがPOSTメソッドで送られてきたら登録と判断
if (isset ($_POST['title']) && isset ($_POST['text']) && isset ($_POST['category']) ) {
    $title = $_POST['title'];
    $text = $_POST['text'];
    $category = $_POST['category'];

    include("DataValidation.php");
    $dv = new DataValidation();

    //バリデーション
    if ($dv->validForArticleParams($title, $text, $category)) {
    
        //データベース接続
        $dsn = "mysql:host=localhost;dbname=blog";
        $username = "root";
        $password = "pass";
        $db = new PDO($dsn, $username, $password);
        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

        //category_listテーブルに同名のカテゴリーが存在しなければカテゴリーを登録
        try {
            $res = $db->query("SELECT COUNT(*) FROM category_list WHERE category = '" . $category . "'");
            if ($res->fetchColumn() == 0) {
                $statement = $db->prepare("INSERT INTO category_list (category) VALUES (:category)");
                $statement->bindValue(':category', $category, PDO::PARAM_STR);
                $statement->execute();
                $statement = null;
                echo "カテゴリーを追加しました。";
            }
        }
        catch (Exception $error) {
            echo "カテゴリーの登録失敗:" . $error->getMessage();
        }

        //記事を登録
        try {
            $statement = $db->prepare("INSERT INTO blog (title, text, date, category_id) VALUES (:title, :text, NOW(), (SELECT id FROM category_list WHERE category = :category))");
            $statement->bindValue(':title', $title, PDO::PARAM_STR);
            $statement->bindValue(':text', $text, PDO::PARAM_STR);
            $statement->bindValue(':category', $category, PDO::PARAM_STR);
            $statement->execute();
            $statement = null;
            echo "記事を追加しました。";
            }
        catch (Exception $error) {
            echo "記事の登録失敗:" . $error->getMessage();
        }
    } else {
        //バリデーション失敗
        echo $dv->getErrorMsg();
    }
} else { ?>
    <!-- 記事の登録フォーム -->
    <form name="artible_add" action="article_add.php" method="post">
        <p>カテゴリ:<input name="category" type="text">
        <p>タイトル:<input name="title" type="text">
        <p>本文:<br><textarea name="text" cols="50" rows="10"></textarea>
        <p><input type="submit" value="登録">
    </form>
<?php } ?>
</html>

article_modify.php

<html>
<?php
//データベース接続
$dsn = "mysql:host=localhost;dbname=blog";
$username = "root";
$password = "pass";
$db = new PDO($dsn, $username, $password);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

//id、title、text、cateoryパラメータがPOSTメソッドで送られてきたら更新と判断
if (isset ($_POST['id']) && isset ($_POST['title']) && isset ($_POST['text']) && isset ($_POST['category'])) {
    $id = $_POST['id'];
    $title = $_POST['title'];
    $text = $_POST['text'];
    $category = $_POST['category'];

    include("DataValidation.php");
    $dv = new DataValidation();

    //バリデーション
    if ($dv->validForArticleParams($title, $text, $category, $id)) {

        //category_listテーブルに同名のカテゴリーが存在しなければカテゴリーを登録
        try {
            $res = $db->query("SELECT COUNT(*) FROM category_list WHERE category = '" . $category . "'");
            if ($res->fetchColumn() == 0) {
                $statement = $db->prepare("INSERT INTO category_list (category) VALUES (:category)");
                $statement->bindValue(':category', $category, PDO::PARAM_STR);
                $statement->execute();
                $statement = null;
                echo "カテゴリーを追加しました。";
            }
        }
        catch (Exception $error) {
            echo "カテゴリーの登録失敗:" . $error->getMessage();
        }

        //記事を更新
        try {
            $statement = $db->prepare("UPDATE blog SET title = :title, text = :text, category_id = (SELECT id FROM category_list WHERE category = :category) WHERE id = :id");
            $statement->bindValue(':title', $title, PDO::PARAM_STR);
            $statement->bindValue(':text', $text, PDO::PARAM_STR);
            $statement->bindValue(':category', $category, PDO::PARAM_STR);
            $statement->bindValue(':id', $id, PDO::PARAM_INT);
            $statement->execute();
            $statement = null;
            echo "記事を更新しました。";
            }
        catch (Exception $error) {
            echo "記事の更新失敗:" . $error->getMessage();
        }
    } else {
        //バリデーション失敗
        echo $dv->getErrorMsg();
    }
} else //idパラメータがGETメソッドで送られてきたら、該当idの記事データを取得してフォームに表示
if (isset ($_GET['id'])) {
    $id = $_GET['id'];
    $statement = $db->prepare("SELECT id, (SELECT category FROM category_list WHERE category_id = id) AS category, title, text, date FROM blog WHERE id = :id");
    $statement->bindValue(':id', $id, PDO::PARAM_INT);
    $statement->execute();
    $row = $statement->fetch();
?>
<!-- 記事の更新フォーム -->
<form name="article_modify" action="article_modify.php" method="post">
    <p>記事ID:<?php echo $row['id']; ?>
    <p>カテゴリ:<input name="category" type="text" value="<?php echo $row['category']; ?>">
    <p>タイトル:<input name="title" type="text" value="<?php echo $row['title']; ?>">
    <p>本文:<br><textarea name="text" cols="50" rows="10"><?php echo $row['text']; ?></textarea>
    <input name="id" type="hidden" value="<?php echo $row['id']; ?>">
    <p><input type="submit" value="更新">
</form>
<?php } ?>
</html>

以上、PHPによる入力データの検証(データバリデーション)の解説でした。

公開日時:2020年06月12日 08:05:05
最終更新日時:2022年02月06日 20:36:35

なお、レンタルサーバー選びで迷ったらこちらの記事で主要レンタルサーバーのプランと料金を比較していますので、是非参考にしてみてください。

PHP編に戻る

このページのトップに戻る