引き続きCRUD処理の開発を進めていきましょう。次はカテゴリー作成処理を実装します。

ここでは以下の手順にしたがってプログラムを作成します。

  1. カテゴリー一覧画面の修正 - index.php
  2. カテゴリー作成画面の作成 - create.php
  3. カテゴリー作成処理の実装 - store.php

1. カテゴリー一覧画面の修正 - index.php

index.php ファイルのHTMLコードにカテゴリー作成画面へのリンクを追加します。

...省略
<body>
  <h3>Categories - Index</h3>
  <hr>
  <table border="1">
    <tr>
      <th>ID</th>
      <th>TITLE</th>
    </tr>
    <?php foreach ($categories as $category) { ?>
    <tr>
      <td><?= htmlspecialchars($category["id"]) ?></td>
      <td><?= htmlspecialchars($category["title"]) ?></td>
    </tr>
    <?php } ?>
  </table>
  <hr>
  <a href="create.php">CREATE</a>
</body>
</html>

カテゴリー作成画面の作成 - create.php

続いてカテゴリー作成画面を表示する create.php ファイルを作成します。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>PHP DB</title>
</head>
<body>
  <h3>Categories - Create</h3>
  <hr>
  <form action="store.php" method="post">
    ID: <input type="number" name="id"><br>
    TITLE: <input type="text" name="title"><br>
    <button type="submit">STORE</button>
  </form>
  <hr>
  <a href="index.php">BACK</a>
</body>
</html>

作成したプログラムについて見ていきましょう。

create.php ファイルはカテゴリーを作成する画面です。form タグを使って入力フォームを定義しています。

  <form action="store.php" method="post">
    ID: <input type="number" name="id"><br>
    TITLE: <input type="text" name="title"><br>
    <button type="submit">STORE</button>
  </form>

この入力フォームを使ってユーザは IDTITLE の2つの項目を入力します。そのあと STORE ボタンをクリックすると次に作成する store.php ファイルにリクエストが送信されます。

3. カテゴリー作成処理の実装 - store.php

さいごにカテゴリー作成画面から送信されるリクエストを処理する store.php ファイルを作成します。

<?php
$id = (string)filter_input(INPUT_POST, "id");
if ($id === "") {
    error_log("Validate: id is required.");
    header("Location: error.php");
    exit();
}
if (filter_var($id, FILTER_VALIDATE_INT) === false) {
    error_log("Validate: id is not int.");
    header("Location: error.php");
    exit();
}

$title = (string)filter_input(INPUT_POST, "title");
if ($title === "") {
    error_log("Validate: title is required.");
    header("Location: error.php");
    exit();
}
if (mb_strlen($title) > 255) {
    error_log("Validate: title length > 255");
    header("Location: error.php");
    exit();
}

try {
    $dsn = "mysql:host=localhost;dbname=eldb;charset=utf8mb4";
    $username = "root";
    $password = "admin";
    $options = [
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_EMULATE_PREPARES => false
    ];
    $pdo = new PDO($dsn, $username, $password);

    $sql = "insert into categories (id, title) values (:id, :title)";
    $ps = $pdo->prepare($sql);
    $ps->bindValue(":id", $id, PDO::PARAM_INT);
    $ps->bindValue(":title", $title, PDO::PARAM_STR);
    $ps->execute();

    header("Location: index.php");
} catch (PDOException $e) {
    error_log("PDOException: " . $e->getMessage());
    header("Location: error.php");
}

プログラムが少し長くなりましたが、先頭から順に見ていきましょう。

このプログラムでは先頭部分で以下の仕様に従って入力チェックを実装しています。

項目名 パラメータ名 入力チェック
カテゴリーID id 必須、整数型
タイトル title 必須、最大255文字まで
<?php
$id = (string)filter_input(INPUT_POST, "id");
if ($id === "") {
    error_log("Validate: id is required.");
    header("Location: error.php");
    exit();
}
if (filter_var($id, FILTER_VALIDATE_INT) === false) {
    error_log("Validate: id is not int.");
    header("Location: error.php");
    exit();
}

上記のコードではリクエストパラメータからカテゴリーID( "id" )を取得して、必須チェックと整数型チェックを実装しています。ここでは入力チェックに違反する場合はエラー画面にリダイレクトするように実装しています。

リクエストパラメータが整数型かどうかをチェックするために filter_var 関数を使用しています。filter_var 関数は第2引数に FILTER_VALIDATE_INT 定数を指定することで、第1引数に指定した変数が整数型かどうかを検証できます。

タイトル( "title" )についての入力チェックも同様です。

$title = (string)filter_input(INPUT_POST, "title");
if ($title === "") {
    error_log("Validate: title is required.");
    header("Location: error.php");
    exit();
}
if (mb_strlen($title) > 255) {
    error_log("Validate: title length > 255");
    header("Location: error.php");
    exit();
}

ここでも入力チェックに違反する場合はエラー画面にリダイレクトするように実装しています。

ここではデータベースとのプログラミングに重点を置くため、入力チェックの実装を簡易な実装としています。実際のシステム開発においては、入力チェックに違反する場合は、入力元画面に遷移して入力エラーメッセージを表示するなど、細かな処理を実装することが多いです。

プログラムの後半部分を見てみましょう。

try {
    $dsn = "mysql:host=localhost;dbname=eldb;charset=utf8mb4";
    $username = "root";
    $password = "admin";
    $options = [
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_EMULATE_PREPARES => false
    ];
    $pdo = new PDO($dsn, $username, $password);

    $sql = "insert into categories (id, title) values (:id, :title)";
    $ps = $pdo->prepare($sql);
    $ps->bindValue(":id", $id, PDO::PARAM_INT);
    $ps->bindValue(":title", $title, PDO::PARAM_STR);
    $ps->execute();

    header("Location: index.php");
} catch (PDOException $e) {
    error_log("PDOException: " . $e->getMessage());
    header("Location: error.php");
}

ここではまずPDOインスタンスを生成してMySQLデータベースに接続しています。それからプリペアドステートメント を定義して、リクエストパラメータをプレースホルダにバインドし、insert 文を実行しています。

insert 文の実行が終わったら、header 関数を使って index.php にリダイレクトするように実装しています。

データベースとのやりとりで例外が発生した場合は catch ブロックの処理が実行されます。ここでは error_log 関数を使ってエラーログを出力して、エラー画面にリダイレクトするように実装しています。

動作確認

それではビルトインWebサーバを起動して、ブラウザから実行結果を確認してみましょう。

コマンドラインからビルトインWebサーバを起動します。

$ php -S localhost:8080

ブラウザから以下のURLにアクセスします。

https://〜.vfs.cloud9.ap-northeast-1.amazonaws.com/categories/index.php

上記のようにカテゴリー一覧画面が表示されることを確認します。表示された画面の下部にある CREATE リンクをクリックしてカテゴリー作成画面( create.php )が表示されることを確認します。

それから任意のデータを入力して新規カテゴリーレコードが作成されることを確認しましょう。

それから STORE ボタンをクリックします。

上記のようにカテゴリー一覧画面にリダイレクトされると、作成したカテゴリーレコードを確認できるでしょう。

ターミナルからMySQLに接続すると categories テーブルに新規レコードが作成されていることを確認できます。