PHPとGETで動的プロフィールページ作成!MySQLのJOINをマスターしよう

Webサイト制作において、profile.php?id=1product.php?id=123のように、URLの一部を変えるだけで表示される内容が変わる「動的なページ」は、アプリケーションの核となる機能です。

今回は、GETリクエストで渡されたIDをもとに、データベースから特定の会員情報を表示するプロフィールページの作り方を解説します。

この課題を通じて、複数のテーブルから関連するデータを一度に取得するための強力なSQLコマンド「JOIN」の使い方をマスターしましょう。


目次

1. データベースの設計:テーブルの正規化

まず、データを格納するデータベースのテーブルを準備します。今回は「会員(members)」と「所属クラブ(clubs)」の情報を扱います。

ここで重要なのは、「会員情報」と「クラブ情報」を別々のテーブルに分けて管理することです。なぜなら、もし同じクラブに100人の会員が所属していた場合、100人分のデータに同じクラブ名や活動概要を重複して保存するのは非効率で、修正も大変だからです。

このように、関連するデータごとにテーブルを分割して、重複を減らすことを「正規化」と呼びます。

【テーブル設計】

  1. clubsテーブル: クラブ情報を管理
    • id (主キー, INT, AUTO_INCREMENT)
    • name (クラブ名, VARCHAR)
    • overview (活動概要, TEXT)
  2. membersテーブル: 会員情報を管理
    • id (主キー, INT, AUTO_INCREMENT)
    • name (会員名, VARCHAR)
    • age (年齢, INT)
    • club_id (所属クラブID, INT) ← これが2つのテーブルを繋ぐ鍵

membersテーブルのclub_idカラムに、clubsテーブルのidを保存することで、「どの会員がどのクラブに所属しているか」という関連性を持たせます。


2. SQLのJOIN句でテーブルを結合する

別々のテーブルに保存された会員情報とクラブ情報を一度に取得するには、SQLのJOIN句を使います。JOINは、指定した条件(キー)が一致する行同士を、複数のテーブルから連結してくれる機能です。

JOINを使ったSQLの基本構造】

SELECT
    取得したいカラム名1, 取得したいカラム名2, ...
FROM
    テーブル1
JOIN
    テーブル2 ON テーブル1.関連キー = テーブル2.関連キー
WHERE
    条件;
  • ON members.club_id = clubs.id: これが結合条件です。「membersテーブルのclub_idと、clubsテーブルのidが一致する行を連結してください」という意味になります。

このJOINを使うことで、ID=1の会員の「名前」と、その会員が所属するクラブの「クラブ名」を、たった一度の問い合わせで取得できます。


3. PHPでプロフィールページを実装する

それでは、実際にPHPでプロフィールページを実装していきましょう。1つのファイル(profile.php)に、ID入力フォームとプロフィール表示の両方の機能を持たせます。

【処理の流れ】

  1. URLにidパラメータ(profile.php?id=1など)があるかチェックする。
  2. idがあれば、そのIDを使ってデータベースに問い合わせる。
  3. JOINを使ってmembersテーブルとclubsテーブルから関連データを取得する。
  4. 取得したデータをHTMLに表示する。
  5. idがない場合や、該当するデータが見つからない場合は、その旨をメッセージで表示する。

完成版コード

profile.php

<?php
// ===== 変数の初期化 =====
$member_data = null;
$error_message = '';
$id = '';

// ===== データベース接続情報 =====
$dsn = 'mysql:dbname=php_learning_db;host=localhost;charset=utf8mb4';
$user = 'root';
$password = ''; // XAMPPのデフォルトは空パスワード

// ===== GETリクエストでIDが指定されている場合の処理 =====
if (isset($_GET['id']) && !empty($_GET['id'])) {
    try {
        $id = (int)$_GET['id']; // IDを整数に変換
        $dbh = new PDO($dsn, $user, $password);
        $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

        // JOINを使ったSQL文の準備
        $sql = <<<SQL
            SELECT
                m.name AS member_name,
                m.age,
                c.name AS club_name,
                c.overview
            FROM
                members AS m
            JOIN
                clubs AS c ON m.club_id = c.id
            WHERE
                m.id = :id
            LIMIT 1
        SQL;

        $stmt = $dbh->prepare($sql);
        $stmt->bindValue(':id', $id, PDO::PARAM_INT);
        $stmt->execute();
        
        $member_data = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!$member_data) {
            $error_message = '指定されたIDの会員は見つかりませんでした。';
        }

    } catch (PDOException $e) {
        $error_message = 'データベースエラー: ' . $e->getMessage();
    }
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>会員プロフィール</title>
    <style>
        body { font-family: sans-serif; }
        .container { width: 80%; margin: 20px auto; }
        .profile-table { border-collapse: collapse; width: 100%; margin-top: 20px; }
        .profile-table th, .profile-table td { border: 1px solid #ccc; padding: 10px; }
        .profile-table th { background-color: #f2f2f2; text-align: right; width: 30%; }
        .search-form { background-color: #f9f9f9; padding: 15px; border: 1px solid #ccc; }
        .error { color: #d9534f; }
    </style>
</head>
<body>
    <div class="container">
        <h1>会員プロフィール検索</h1>
        <div class="search-form">
            <p>確認したい会員のIDを入力してください。</p>
            <form action="" method="GET">
                <input type="number" name="id" value="<?php echo htmlspecialchars($id, ENT_QUOTES, 'UTF-8'); ?>">
                <input type="submit" value="プロフィールを確認する">
            </form>
        </div>

        <hr>

        <?php if ($member_data): ?>
            <h2>会員ID: <?php echo htmlspecialchars($id, ENT_QUOTES, 'UTF-8'); ?> のプロフィール</h2>
            <table class="profile-table">
                <tr>
                    <th>お名前</th>
                    <td><?php echo htmlspecialchars($member_data['member_name'], ENT_QUOTES, 'UTF-8'); ?></td>
                </tr>
                <tr>
                    <th>年齢</th>
                    <td><?php echo htmlspecialchars($member_data['age'], ENT_QUOTES, 'UTF-8'); ?></td>
                </tr>
                <tr>
                    <th>所属クラブ</th>
                    <td><?php echo htmlspecialchars($member_data['club_name'], ENT_QUOTES, 'UTF-8'); ?></td>
                </tr>
                <tr>
                    <th>クラブ概要</th>
                    <td><?php echo nl2br(htmlspecialchars($member_data['overview'], ENT_QUOTES, 'UTF-8')); ?></td>
                </tr>
            </table>
        <?php elseif ($error_message): ?>
            <p class="error"><?php echo $error_message; ?></p>
        <?php endif; ?>
    </div>
</body>
</html>

SQL文の中でmembers AS mのようにASを使うと、テーブル名に短い別名を付けることができ、クエリが読みやすくなります。


まとめ

今回は、GETリクエストとデータベースのJOINを組み合わせた、動的なプロフィールページの作り方を学びました。

【重要ポイントの振り返り】

  1. URLのパラメータで表示内容を切り替えるにはGETリクエストが最適。
  2. 関連するデータはテーブルを分割して管理し、外部キーで関連付ける。
  3. 複数のテーブルからデータを一度に取得するには**JOIN句**を使用する。
  4. URLから受け取った値もユーザー入力の一種。必ずプリペアドステートメントで安全に処理する。

このパターンを応用すれば、商品詳細ページや記事ページなど、あらゆる動的ページの基本を実装できます。次のステップとして、全会員を一覧表示し、各会員の名前をクリックするとその人のプロフィールページに飛ぶ、といった連携機能に挑戦してみるのも良いでしょう。

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

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次