MENU

PHPの基本から応用まで – 初心者向けチュートリアルシリーズ(第5回:データベース操作)

目次

はじめに

前回のオブジェクト指向プログラミングに続き、今回は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操作の基本、そしてセキュリティとパフォーマンスの最適化について解説しました。

練習問題

  1. 以下の機能を持つ簡単な商品管理システムを作成してください:
    • 商品の登録、表示、更新、削除
    • カテゴリー別の商品一覧表示
    • 在庫数の管理
  2. ユーザー認証システムを作成してください:
    • ユーザー登録機能
    • ログイン/ログアウト機能
    • パスワードのハッシュ化
    • セッション管理

次回は、PHPでのセッション管理とセキュリティについて解説していきます。お楽しみに!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次