@ PHP

CRUD:レコードの登録

入力値を元にデータベースに登録する

add.php で入力された内容を登録処理するためのソースコードを以下に示します。

ここでは、ユーザー入力の検証関数を定義した validate.php と、特殊文字を HTML エンティティに変換する関数を定義した functions.php を外部ファイルとして作成します。

add.php

<?php

require_once("dbconnect.php");
require_once("functions.php");
require_once('validate.php');

if (isset($_POST["add"])) {
    if (!$err) {
        try {

        $sql = <<<SQL
INSERT INTO products (name, price, description, created) VALUES(:name, :price, :description, :created)
SQL;

            $sth = $dbh->prepare($sql);

            $sth->bindValue(':name', $_POST ['name']);
            $sth->bindValue(':price', $_POST ['price']);
            $sth->bindValue(':description', $_POST ['description']);
            $sth->bindValue(':created', $created);

            $rows = $sth->execute();

            if ($rows) {
                header('location:index.php');
                exit();
            }
        } catch (PDOException $e) {
            exit('ERR! : ' . $e->getMessage());
        } finally {
            $dbh = null;
        }
    }
}
?>
<!DOCTYPE html>
<html lang="ja">

<head>
  <title>PHP PDO CRUD</title>
  <link rel="stylesheet" href="styles.css">
</head>

<body>

  <main class="container">
    <h1>Add product</h1>
    <form action="" method="post">
      <fieldset>
        <div>
          <label>Product name: </label><br>
          <input type="text" name="name" value="<?= h($_POST['name']) ?>" placeholder="Enter name">
        </div>
<?php
if ($err['name']) {
    echo h($err['name']);
}
?>
        <div>
          <label>Price: </label><br>
          <input type="text" name="price" value="<?= h($_POST['price']) ?>" placeholder="Enter price">
        </div>
<?php
if ($err['price']) {
    echo h($err['price']);
}
?>
        <div>
          <label>Description: </label><br>
          <textarea name="description" rows="2" placeholder="Enter description"><?= h($_POST['description']) ?></textarea>
        </div>
<?php
if ($err['description']) {
    echo h($err['description']);
}
?>
        <div>
          <label>Created: </label><br>
          <input type="date" name="created" required>
        </div>
        <div>
          <input type="submit" name="add" value="Add">
        </div>
      </fieldset>
    </form>
</main>
</body>

</html>

functions.php

<?php
function h($str, string $charset = 'UTF-8'): string
{
    return htmlspecialchars($str, ENT_QUOTES | ENT_HTML5, $charset);
}

validate.php

<?php

function min_length($str, $len)
{
    if (mb_strlen($str) <= $len) {
        return true;
    } else {
        return false;
    }
}

function max_length($str, $len)
{
    if (mb_strlen($str) >= $len) {
        return true;
    } else {
        return false;
    }
}

if (isset($_POST["update"])) {
    $err = [];
    if (!$_POST['name']) {
        $err['name'] = 'Name is missing.';
    }
    if (!$_POST['price']) {
        $err['price'] = 'Price is not entered.';
    }
    if (!$_POST['description']) {
        $err['description'] = 'Description is not entered.';
    } elseif (max_length($_POST['description'], 10)) {
        $err['description'] = 'Must be 10 characters or less.';
    }
}

if (isset($_POST["add"])) {
    $err = [];
    if (!$_POST['name']) {
        $err['name'] = 'Name is missing.';
    }
    if (!$_POST['price']) {
        $err['price'] = 'Price is not entered.';
    }
    if (!$_POST['description']) {
        $err['description'] = 'Description is not entered.';
    } elseif (max_length($_POST['description'], 10)) {
        $err['description'] = 'Must be 10 characters or less.';
    }
}

styles.css

@charset "utf-8";
* {
  box-sizing: border-box;
}

body,
input,
textarea {
  color: #000;
  font-family: '游ゴシック', YuGothic, 'ヒラギノ角ゴ Pro W3', 'Hiragino Kaku Gothic Pro', 'メイリオ', Meiryo, 'MS Pゴシック', Verdana, sans-serif;
  font-size: 1rem;
  font-weight: normal;
  font-style: normal;
  line-height: 1.8rem;
  word-break: keep-all;
}

table {
  width: 100%;
  margin: 20px 0;
}

table,
tr,
th,
td {
  border: solid 1px #EEE;
  border-collapse: collapse;
  padding: 5px 10px;
}

.container {
  max-width: 960px;
  margin: 0 auto;
  background: #fff;
  padding: 40px;
  box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.4);
  border-radius: 3px;
}


/* form */

fieldset {
  margin: 0;
  padding: 10px 0;
  border: transparent;
}

input[type="text"],
textarea {
  border: 0;
  padding: 5px 15px;
  font-size: 1rem;
  color: #000;
  border: solid 1px #ccc;
  margin: 0 0 10px;
  width: 100%;
  border-radius: 4px;
}

input[type="date"] {
  border: 0;
  padding: 5px 15px;
  font-size: 1rem;
  color: #000;
  border: solid 1px #ccc;
  margin: 0 0 10px;
  border-radius: 4px;
}

input[type="text"]:focus,
input[type="password"]:focus,
textarea:focus {
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 5px rgba(102, 175, 233, .6);
}

input[type=submit] {
  padding: 5px 15px;
  margin: 20px 0 0;
  background: #337ab7;
  color: #fff;
  border: 0 none;
  cursor: pointer;
  -webkit-border-radius: 4px;
  border-radius: 4px;
}

add.php を少し詳しく見ていきます。

プレイスフォルダと bindValue()

データベースに発行する一連の命令を管理するのは、PDOStatement オブジェクトの役割です。
PDOStatement オブジェクトは、 PDO オブジェクト $dbh から prepare() メソッドを呼び出すことで、取得できます。
prepare() は、データベースに対して発行したい SQL 命令を指定します。

次に示すソースコードでは「products というテーブルの name、price、created というフィールドに、それぞれ指定された値をセットしようとしている」わけです。

INSERT 文に含まれる 「:name」という記述は、プレイスフォルダを表します。プレイスフォルダとは、パラメータの置き場のことで、実行時に動的に任意のパラメータを引き渡すことができます。

bindValue() は、プレイスフォルダに値をセットします。

たとええば、「 $stmt->bindValue(‘:name’, $_POST [‘name’]); 」であれば、プレイスフォルダ「:name」に対して $_POST[‘name’] で受け取った値をセットしています。

これで SQL 命令を発行するための準備ができました。あとは、excute() によってデータベースに命令を送信 / 実行されます。

example.php

$sql = <<<SQL
INSERT INTO products (name, price, created) VALUES(:name, :price, :created)
SQL;

    $sth = $dbh->prepare($sql);

    $sth->bindValue(':name', $_POST ['name']);
    $sth->bindValue(':price', $_POST ['price']);
    $sth->bindValue(':created', $created);

    $rows = $sth->execute();

名前なしパラメータ

「?」という形式でプレイスフォルダを指定することもできます。これを名前なしパラメータと呼びます。
名前なしパラメータで書き換えると次のようになります。

example.php

$sql = <<<SQL
INSERT INTO products ( name, price, description, created ) VALUES(?, ?, ?, ?)
SQL;

    $sth = $dbh->prepare($sql);

    $sth->bindValue(1, $_POST['name'], PDO::PARAM_STR);
    $sth->bindValue(2, $_POST['price'], PDO::PARAM_INT);
    $sth->bindValue(3, $_POST['description'], PDO::PARAM_STR);
    $sth->bindValue(4, $_POST['created'], PDO::PARAM_STR);

    $rows = $sth->execute();

名前なしパラメータでは、bindValue() の第1引数に(パラメータの代わりに)インデックス番号を指定します。インデックス番号は 1 から始まります。

PDO::PARAM_INT は SQL INTEGER データ型を表し、PDO::PARAM_STR は SQL CHAR, VARCHAR, または他の文字列データ型を表す定義済の定数です。これにより、パラメータに対して明示的なデータ型を指定することができます。