目次
はじめに
前回のオブジェクト指向プログラミングに続き、今回はPHPでのデータベース操作について解説します。主にMySQLを例に、データベースへの接続、基本的なCRUD操作(Create, Read, Update, Delete)、そして安全なデータ処理について学んでいきます。
データベース接続
PDOを使用した接続
<?php
try {
$pdo = new PDO(
"mysql:host=localhost;dbname=sample_db;charset=utf8mb4",
"username",
"password",
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]
);
echo "データベースに接続しました\n";
} catch (PDOException $e) {
die("接続エラー: " . $e->getMessage());
}
基本的なCRUD操作
CREATE(データの作成)
// プリペアドステートメントを使用した安全なデータ挿入
function createUser($pdo, $name, $email, $age) {
$sql = "INSERT INTO users (name, email, age) VALUES (:name, :email, :age)";
try {
$stmt = $pdo->prepare($sql);
$stmt->execute([
':name' => $name,
':email' => $email,
':age' => $age
]);
return $pdo->lastInsertId();
} catch (PDOException $e) {
error_log($e->getMessage());
throw new Exception("ユーザー作成に失敗しました");
}
}
READ(データの読み取り)
// 全ユーザーの取得
function getAllUsers($pdo) {
$sql = "SELECT * FROM users";
try {
$stmt = $pdo->query($sql);
return $stmt->fetchAll();
} catch (PDOException $e) {
error_log($e->getMessage());
throw new Exception("ユーザー情報の取得に失敗しました");
}
}
// 特定のユーザーの取得
function getUserById($pdo, $id) {
$sql = "SELECT * FROM users WHERE id = :id";
try {
$stmt = $pdo->prepare($sql);
$stmt->execute([':id' => $id]);
return $stmt->fetch();
} catch (PDOException $e) {
error_log($e->getMessage());
throw new Exception("ユーザー情報の取得に失敗しました");
}
}
UPDATE(データの更新)
function updateUser($pdo, $id, $name, $email, $age) {
$sql = "UPDATE users SET name = :name, email = :email, age = :age
WHERE id = :id";
try {
$stmt = $pdo->prepare($sql);
return $stmt->execute([
':id' => $id,
':name' => $name,
':email' => $email,
':age' => $age
]);
} catch (PDOException $e) {
error_log($e->getMessage());
throw new Exception("ユーザー情報の更新に失敗しました");
}
}
DELETE(データの削除)
function deleteUser($pdo, $id) {
$sql = "DELETE FROM users WHERE id = :id";
try {
$stmt = $pdo->prepare($sql);
return $stmt->execute([':id' => $id]);
} catch (PDOException $e) {
error_log($e->getMessage());
throw new Exception("ユーザーの削除に失敗しました");
}
}
実践的な例:ブログシステム
<?php
class BlogDatabase {
private $pdo;
public function __construct(PDO $pdo) {
$this->pdo = $pdo;
}
// 記事の作成
public function createPost(string $title, string $content, int $authorId): int {
$sql = "INSERT INTO posts (title, content, author_id, created_at)
VALUES (:title, :content, :author_id, NOW())";
$stmt = $this->pdo->prepare($sql);
$stmt->execute([
':title' => $title,
':content' => $content,
':author_id' => $authorId
]);
return $this->pdo->lastInsertId();
}
// 記事の取得(ページネーション付き)
public function getPosts(int $page = 1, int $perPage = 10): array {
$offset = ($page - 1) * $perPage;
$sql = "SELECT p.*, u.name as author_name
FROM posts p
JOIN users u ON p.author_id = u.id
ORDER BY p.created_at DESC
LIMIT :limit OFFSET :offset";
$stmt = $this->pdo->prepare($sql);
$stmt->bindValue(':limit', $perPage, PDO::PARAM_INT);
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
return $stmt->fetchAll();
}
// 記事の検索
public function searchPosts(string $keyword): array {
$sql = "SELECT p.*, u.name as author_name
FROM posts p
JOIN users u ON p.author_id = u.id
WHERE p.title LIKE :keyword
OR p.content LIKE :keyword";
$stmt = $this->pdo->prepare($sql);
$stmt->execute([':keyword' => "%{$keyword}%"]);
return $stmt->fetchAll();
}
}
セキュリティとベストプラクティス
1. SQLインジェクション対策
// 悪い例(絶対に使用しないでください)
$sql = "SELECT * FROM users WHERE name = '$name'";
// 良い例(プリペアドステートメントを使用)
$sql = "SELECT * FROM users WHERE name = :name";
$stmt = $pdo->prepare($sql);
$stmt->execute([':name' => $name]);
2.トランザクション処理
function transferMoney($pdo, $fromAccount, $toAccount, $amount) {
try {
$pdo->beginTransaction();
// 送金元から引き落とし
$sql1 = "UPDATE accounts SET balance = balance - :amount
WHERE id = :from AND balance >= :amount";
$stmt1 = $pdo->prepare($sql1);
$result1 = $stmt1->execute([
':amount' => $amount,
':from' => $fromAccount
]);
if ($stmt1->rowCount() === 0) {
throw new Exception("残高不足です");
}
// 送金先に入金
$sql2 = "UPDATE accounts SET balance = balance + :amount
WHERE id = :to";
$stmt2 = $pdo->prepare($sql2);
$result2 = $stmt2->execute([
':amount' => $amount,
':to' => $toAccount
]);
$pdo->commit();
return true;
} catch (Exception $e) {
$pdo->rollBack();
throw $e;
}
}
3.エラー処理とログ
function logDatabaseError($error, $context = []) {
$logMessage = date('Y-m-d H:i:s') . " | " . $error->getMessage();
if (!empty($context)) {
$logMessage .= " | Context: " . json_encode($context);
}
error_log($logMessage, 3, "database_errors.log");
}
パフォーマンス最適化
インデックスの使用
CREATE INDEX idx_email ON users(email);
CREATE INDEX idx_created_at ON posts(created_at);
クエリの最適化
// 必要なカラムのみを選択
$sql = "SELECT id, name, email FROM users";
// JOINの適切な使用
$sql = "SELECT p.*, COUNT(c.id) as comment_count
FROM posts p
LEFT JOIN comments c ON p.id = c.post_id
GROUP BY p.id";
まとめ
本日はPHPでのデータベース操作について学びました。PDOを使用した安全なデータベース操作、CRUD操作の基本、そしてセキュリティとパフォーマンスの最適化について解説しました。
練習問題
- 以下の機能を持つ簡単な商品管理システムを作成してください:
- 商品の登録、表示、更新、削除
- カテゴリー別の商品一覧表示
- 在庫数の管理
- ユーザー認証システムを作成してください:
- ユーザー登録機能
- ログイン/ログアウト機能
- パスワードのハッシュ化
- セッション管理
次回は、PHPでのセッション管理とセキュリティについて解説していきます。お楽しみに!
コメント