PHPとデータベース - INSERT
ナビゲーションに移動
検索に移動
概要
DATETIME型
SQLインジェクション対策のため、必ず、プリペアドステートメントを使用する。
これは、パフォーマンスの向上にも寄与する。
タイムゾーンの設定
// PHPのタイムゾーン設定
date_default_timezone_set('Asia/Tokyo');
// データベース接続の設定
$dsn = 'mysql:host=<ホスト名またはIPアドレス>;dbname=<データベース名>;charset=utf8mb4';
$username = 'username';
$password = 'password';
try {
$pdo = new PDO($dsn, $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]);
$pdo->exec("SET time_zone = '+09:00'"); // MySQLのタイムゾーン設定
}
catch (PDOException $e) {
echo "エラー: " . $e->getMessage();
}
NOW関数の使用
MySQLのNOW
関数を使用して現在時刻を挿入する。
サーバ側の時刻が使用されるため、最も正確である。
なお、タイムゾーンはMySQLの設定に依存することに注意する。
// データベース接続の設定
$dsn = 'mysql:host=<ホスト名またはIPアドレス>;dbname=<データベース名>;charset=utf8mb4';
$username = 'username';
$password = 'password';
try {
$pdo = new PDO($dsn, $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]);
// 現在時刻をMySQLのNOW関数で挿入
// MySQLのカラムがDATETIME型の必要がある
$sql = "INSERT INTO events (event_name, created_at) VALUES (:name, NOW())";
$stmt = $pdo->prepare($sql);
$stmt->execute([':name' => 'イベント1']);
}
catch (PDOException $e) {
echo "エラー: " . $e->getMessage();
}
DateTimeオブジェクトの使用
PHPのDateTimeクラスを使用して日時を管理する。
また、formatメソッドでMySQLが理解できる形式に変換する。
これは、より柔軟な日時の操作が可能である。
// データベース接続の設定
$dsn = 'mysql:host=<ホスト名またはIPアドレス>;dbname=<データベース名>;charset=utf8mb4';
$username = 'username';
$password = 'password';
try {
$pdo = new PDO($dsn, $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]);
// PHPのDateTimeオブジェクトを使用
$sql = "INSERT INTO events (event_name, created_at) VALUES (:name, :datetime)";
$stmt = $pdo->prepare($sql2);
$datetime = new DateTime();
$stmt2->execute([':name' => 'イベント',
':datetime' => $datetime->format('Y-m-d H:i:s')
]);
}
catch (PDOException $e) {
echo "エラー : " . $e->getMessage();
}
文字列での直接指定
特定の日時を文字列として指定する。
ただし、フォーマットはYYYY-MM-DD HH:MM:SS形式である必要がある。
また、入力値の検証が重要となる。
// データベース接続の設定
$dsn = 'mysql:host=<ホスト名またはIPアドレス>;dbname=<データベース名>;charset=utf8mb4';
$username = 'username';
$password = 'password';
try {
$pdo = new PDO($dsn, $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]);
// 特定の日時を文字列で指定
$sql = "INSERT INTO events (event_name, created_at) VALUES (:name, :datetime)";
$stmt = $pdo->prepare($sql);
$specificDate = '2024-12-31 23:59:59';
$stmt->execute([':name' => 'イベント3',
':datetime' => $specificDate]);
}
catch (PDOException $e) {
echo "エラー : " . $e->getMessage();
}
明示的な型指定
PDO::bindValueメソッドを使用してパラメータの型を明示的に指定する。
これは、より厳密な型チェックが可能となる。
PDO::PARAM_STRを使用してSTRING型として扱う必要がある。
// データベース接続の設定
$dsn = 'mysql:host=<ホスト名またはIPアドレス>;dbname=<データベース名>;charset=utf8mb4';
$username = 'username';
$password = 'password';
try {
$pdo = new PDO($dsn, $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]);
// バインドパラメータの型を明示的に指定
$sql = "INSERT INTO events (event_name, created_at) VALUES (:name, :datetime)";
$stmt = $pdo->prepare($sql);
$datetime = new DateTime('+1 week');
$stmt->bindValue(':name', 'イベント', PDO::PARAM_STR);
$stmt->bindValue(':datetime', $datetime->format('Y-m-d H:i:s'), PDO::PARAM_STR);
$stmt->execute();
}
catch (PDOException $e) {
echo "エラー: " . $e->getMessage();
}
複数のレコードの一括挿入
配列を使用して、繰り返し文で複数のレコードを効率的に挿入する。
これは、メモリ効率が良い。
// データベース接続の設定
$dsn = 'mysql:host=<ホスト名またはIPアドレス>;dbname=<データベース名>;charset=utf8mb4';
$username = 'username';
$password = 'password';
try {
$pdo = new PDO($dsn, $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]);
// 複数のレコードの一括挿入
$sql = "INSERT INTO events (event_name, created_at) VALUES (?, ?)";
$stmt = $pdo->prepare($sql5);
$events = [
['イベント5', '2024-01-01 00:00:00'],
['イベント6', '2024-01-02 00:00:00'],
];
foreach ($events as $event) {
$stmt->execute($event);
}
}
catch (PDOException $e) {
echo "エラー: " . $e->getMessage();
}
トランザクションを使用した安全な挿入
// データベース接続の設定
$dsn = 'mysql:host=<ホスト名またはIPアドレス>;dbname=<データベース名>;charset=utf8mb4';
$username = 'username';
$password = 'password';
try {
$pdo = new PDO($dsn, $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]);
// トランザクションを使用した安全な挿入
$pdo->beginTransaction();
try {
$sql = "INSERT INTO events (event_name, created_at) VALUES (:name, :datetime)";
$stmt = $pdo->prepare($sql6);
$datetime = new DateTime();
$stmt->execute([':name' => 'トランザクションイベント',
':datetime' => $datetime->format('Y-m-d H:i:s')]);
$pdo->commit();
}
catch (Exception $e) {
$pdo->rollBack();
throw $e;
}
}
catch (PDOException $e) {
echo "エラー: " . $e->getMessage();
}
日付のバリデーション
DateTime::createFromFormatメソッドを使用した日付バリデーションにおいて、以下に示す検証を組み合わせることにより、堅牢な日付バリデーションが実現できる。
必ず、タイムゾーンを考慮する必要がある。
DateTimeクラスの書式指定子
- Y
- 4桁の年 (例: 2024)
- m
- 2桁の月 (01-12)
- d
- 2桁の日 (01-31)
- H
- 24時間形式の時 (00-23)
- i
- 分 (00-59)
- s
- 秒 (00-59)
常にタイムゾーンを明示的に設定する。
date_default_timezone_set('Asia/Tokyo');
// 使用例 1
try {
$datetime = DateTime::createFromFormat('Y-m-d H:i:s', $dateString);
$errors = DateTime::getLastErrors(); // 戻り値は連想配列となることに注意
if ($errors['warning_count'] > 0 || $errors['error_count'] > 0) {
// エラーがある場合
}
}
catch (Exception $e) {
// エラー処理
log_error($e->getMessage());
return false;
}
// 正常に処理ができた場合は、処理を以下に記述...
// ...略
// 使用例 2
try {
$date = new DateTime($dateString);
if ($date === false) {
throw new Exception("無効な日付フォーマットです");
}
}
catch (Exception $e) {
// エラー処理
log_error($e->getMessage());
return false;
}
また、日付の範囲をチェックする必要もある。
$minDate = new DateTime('2000-01-01');
$maxDate = new DateTime('2099-12-31');
if ($date >= $minDate && $date <= $maxDate) {
// 有効な範囲の場合
}
ユーザ入力が伴う場合は、XSS攻撃の可能性があるため、正規化が必要となる。
$date = trim($dateString);
$date = filter_var($date, FILTER_SANITIZE_STRING);