[PHPのはじめ方] Part25: 簡単な掲示板アプリの作成

はじめに

これまでのステップで、PHPの基本的な文法、フォーム処理、データベース操作などを学んできました。いよいよ実践編です! このステップでは、学んだ知識を総動員して、簡単な掲示板アプリを作成します。

この掲示板アプリでは、以下の機能を実現します。

  • 名前とメッセージを投稿できるフォーム
  • 投稿された名前とメッセージを一覧表示する機能

シンプルな機能ですが、Webアプリケーション開発の基本要素が詰まっています。さっそく挑戦してみましょう!

1. データベースの準備

まずは、投稿されたメッセージを保存するためのデータベースとテーブルを準備します。phpMyAdminなどのツールを使って、新しいデータベース(例: `php_bbs`)を作成し、その中に以下の構造を持つテーブル(例: `posts`)を作成しましょう。

カラム名データ型制約説明
idINTUNSIGNED AUTO_INCREMENT PRIMARY KEY投稿ID (自動採番)
nameVARCHAR(50)NOT NULL投稿者名
messageTEXTNOT NULLメッセージ本文
created_atTIMESTAMPDEFAULT CURRENT_TIMESTAMP投稿日時

SQLでテーブルを作成する場合は、以下のようになります。

CREATE TABLE posts ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL, message TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
); 

2. データベース接続設定

次に、PHPからデータベースに接続するための設定ファイルを作成します。config.php という名前でファイルを作成し、以下のようにデータベース接続情報を記述します。(実際の接続情報に合わせてください)

<?php
define('DB_HOST', 'localhost'); // データベースサーバーのホスト名
define('DB_NAME', 'php_bbs'); // データベース名
define('DB_USER', 'your_db_username'); // データベースユーザー名
define('DB_PASS', 'your_db_password'); // データベースパスワード
// データベース接続オプション
$options = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // エラーモードを例外に設定 PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // フェッチモードを連想配列に設定 PDO::ATTR_EMULATE_PREPARES => false, // プリペアドステートメントのエミュレーションを無効化
];
// データソース名 (DSN)
$dsn = "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8mb4";
try { // PDOインスタンスの作成 $pdo = new PDO($dsn, DB_USER, DB_PASS, $options);
} catch (PDOException $e) { // 接続エラー時の処理 die("データベース接続に失敗しました: " . $e->getMessage());
}
?> 

このファイルは、データベース操作が必要な他のPHPファイルから読み込んで使用します。

3. 掲示板のメインファイル作成 (index.php)

いよいよ掲示板のメインとなるファイル `index.php` を作成します。このファイルは、投稿フォームの表示、投稿処理、投稿一覧の表示を担当します。

3.1. ファイルの基本構造と設定ファイルの読み込み

<!DOCTYPE html>
<html lang="ja">
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>簡単掲示板</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@1.0.0/css/bulma.min.css"> <!-- Bulma CSS -->
</head>
<body> <section class="section"> <div class="container"> <h1 class="title"> 簡単掲示板</h1> <?php // データベース接続設定ファイルを読み込む require_once 'config.php'; // エラーメッセージ格納用変数 $errors = []; // 成功メッセージ格納用変数 $success_message = ''; // --- ここに投稿処理を記述 --- // --- ここに投稿一覧表示処理を記述 --- ?> <!-- 投稿フォーム --> <div class="box mt-5"> <h2 class="subtitle is-5">メッセージを投稿する</h2> <?php // エラーメッセージの表示 if (!empty($errors)): ?> <div class="notification is-danger is-light"> <ul> <?php foreach ($errors as $error): ?> <li><?php echo htmlspecialchars($error, ENT_QUOTES, 'UTF-8'); ?></li> <?php endforeach; ?> </ul> </div> <?php endif; ?> <?php // 成功メッセージの表示 if (!empty($success_message)): ?> <div class="notification is-success is-light"> <?php echo htmlspecialchars($success_message, ENT_QUOTES, 'UTF-8'); ?> </div> <?php endif; ?> <form action="index.php" method="post"> <div class="field"> <label class="label" for="name">お名前</label> <div class="control"> <input class="input" type="text" id="name" name="name" required> </div> </div> <div class="field"> <label class="label" for="message">メッセージ</label> <div class="control"> <textarea class="textarea" id="message" name="message" rows="3" required></textarea> </div> </div> <div class="field"> <div class="control"> <button class="button is-primary" type="submit">投稿する</button> </div> </div> </form> </div> <!-- /投稿フォーム --> <!-- 投稿一覧 --> <div class="mt-5"> <h2 class="subtitle is-5">投稿一覧</h2> <div id="post-list"> <!-- ここに投稿一覧が表示される --> </div> </div> <!-- /投稿一覧 --> </div> </section>
</body>
</html> 

まずはHTML部分と、設定ファイルの読み込み、メッセージ表示用の変数を準備します。フォームの `action` 属性は `index.php`(自分自身)、`method` 属性は `post` に設定します。

3.2. 投稿処理の実装 (POSTリクエストの処理)

フォームからデータが送信された (POSTリクエストが来た) 場合の処理を記述します。場所は `// — ここに投稿処理を記述 —` の部分です。

 // --- ここに投稿処理を記述 --- if ($_SERVER['REQUEST_METHOD'] === 'POST') { // フォームからのデータを取得し、サニタイズ $name = isset($_POST['name']) ? trim($_POST['name']) : ''; $message = isset($_POST['message']) ? trim($_POST['message']) : ''; // 簡単なバリデーション if ($name === '') { $errors[] = 'お名前を入力してください。'; } elseif (mb_strlen($name) > 50) { $errors[] = 'お名前は50文字以内で入力してください。'; } if ($message === '') { $errors[] = 'メッセージを入力してください。'; } // エラーがない場合のみデータベースに挿入 if (empty($errors)) { try { // プリペアドステートメントを使用して安全にデータを挿入 $sql = "INSERT INTO posts (name, message) VALUES (:name, :message)"; $stmt = $pdo->prepare($sql); $stmt->bindParam(':name', $name, PDO::PARAM_STR); $stmt->bindParam(':message', $message, PDO::PARAM_STR); // SQLを実行 if ($stmt->execute()) { $success_message = 'メッセージを投稿しました!'; // フォームの再送信を防ぐためにリダイレクト(任意) // header('Location: index.php'); // exit; } else { $errors[] = '投稿に失敗しました。もう一度お試しください。'; } } catch (PDOException $e) { $errors[] = 'データベースエラー: ' . $e->getMessage(); // 本番環境では詳細なエラーメッセージをユーザーに見せないように注意 // error_log('PDO Error: ' . $e->getMessage()); // エラーログに記録 // $errors[] = 'データベースエラーが発生しました。'; } } } // --- 投稿処理 ここまで --- 

POSTリクエストかどうかを確認し、送信されたデータを `$_POST` スーパーグローバル変数から取得します。`trim()` で前後の空白を除去し、簡単なバリデーション(空チェック、文字数チェック)を行います。

エラーがなければ、PDOを使ってデータベースにデータを挿入します。SQLインジェクション対策として、必ずプリペアドステートメント (`prepare`, `bindParam`, `execute`) を使用しましょう。

投稿成功時には成功メッセージを設定します。コメントアウトされている `header()` 関数を使うと、投稿後にページをリダイレクトさせ、ブラウザの更新ボタンによる意図しない再投稿(二重投稿)を防ぐことができます(今回はシンプルにするためリダイレクトは行いません)。

3.3. 投稿一覧表示処理の実装

次に、データベースから投稿データを取得し、一覧表示する処理を記述します。場所は `// — ここに投稿一覧表示処理を記述 —` の部分です。

 // --- ここに投稿一覧表示処理を記述 --- try { // postsテーブルからデータを新しい順に取得 $sql_select = "SELECT name, message, created_at FROM posts ORDER BY created_at DESC"; $stmt_select = $pdo->query($sql_select); // クエリを実行 $posts = $stmt_select->fetchAll(); // 結果をすべて取得 } catch (PDOException $e) { // エラー発生時はエラーメッセージを表示して処理を中断 echo '<div class="notification is-danger">投稿の読み込みに失敗しました: ' . htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8') . '</div>'; $posts = []; // エラー時は空の配列にする // ここで処理を中断する場合は exit; などを使用 } // --- 投稿一覧表示処理 ここまで --- 

`SELECT` 文で `posts` テーブルから必要なカラム (`name`, `message`, `created_at`) を取得します。`ORDER BY created_at DESC` で新しい投稿が上に表示されるように並び替えます。 取得したデータは `$posts` 配列に格納します。

最後に、取得した投稿データをHTMLとして表示する部分(`<div id=”post-list”>` の中)を修正します。

 <!-- 投稿一覧 --> <div class="mt-5"> <h2 class="subtitle is-5">投稿一覧</h2> <div id="post-list"> <?php if (empty($posts)): ?> <p>まだ投稿はありません。</p> <?php else: ?> <?php foreach ($posts as $post): ?> <article class="message is-info mb-4"> <div class="message-header"> <p> <strong><?php echo htmlspecialchars($post['name'], ENT_QUOTES, 'UTF-8'); ?></strong> <small class="ml-2">(<?php echo htmlspecialchars($post['created_at'], ENT_QUOTES, 'UTF-8'); ?>)</small> </p> </div> <div class="message-body"> <?php echo nl2br(htmlspecialchars($post['message'], ENT_QUOTES, 'UTF-8')); ?> </div> </article> <?php endforeach; ?> <?php endif; ?> </div> </div> <!-- /投稿一覧 --> 

`$posts` 配列を `foreach` でループし、各投稿を表示します。ここで重要なのは、ユーザーが入力した内容(名前やメッセージ)をHTMLに出力する際に、必ず `htmlspecialchars()` 関数を使ってXSS(クロスサイトスクリプティング)対策を行うことです。これにより、悪意のあるHTMLタグやJavaScriptコードが埋め込まれるのを防ぎます。

また、メッセージ本文は改行がそのまま表示されるように `nl2br()` 関数も併用しています。

4. 実行してみよう!

これで、`config.php` と `index.php` の2つのファイルが完成しました。これらのファイルをWebサーバー(XAMPPやMAMPのhtdocs/wwwディレクトリなど)に配置し、Webブラウザから `index.php` にアクセスしてみてください。

フォームが表示され、名前とメッセージを入力して投稿すると、下に一覧表示されるはずです。

まとめと次のステップ

お疲れ様でした!簡単な掲示板アプリを作成することで、PHPによるWebアプリケーション開発の一連の流れを体験できましたね。

  • HTMLフォームの作成
  • POSTデータの受け取りと処理
  • データベースへの接続と操作 (PDO, プリペアドステートメント)
  • データベースからのデータ取得と表示
  • 基本的なセキュリティ対策 (XSS対策, SQLインジェクション対策)

これらの要素は、より複雑なWebアプリケーションを開発する上での基礎となります。

今回作成した掲示板は非常にシンプルですが、ここからさらに機能を拡張していくことができます。例えば…

  • 投稿の編集・削除機能
  • パスワードによる投稿の保護
  • ページネーション(投稿が多い場合にページを分ける)
  • 画像のアップロード機能

次のステップでは、ログイン機能の実装に挑戦してみましょう!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です