php-db07:データベースを使った掲示板で作成した掲示板に、画像がアップロードできる機能を追加してみましょう。データベース掲示板の作成は下記のサイトを参照してください。
Webtraining - Webトレは、 初心...


PHPとデータベースを使った掲示板 | Webtraining - Webトレは、 初心者から実務までのWeb学習トレーニング
完成イメージ この章では、php-basic10 で作成した「テキストファイルに保存するミニ掲示板」を、MySQLのデータベースに保存する構成へとリファクタリングします。これによ...
フォルダ構成とファイル名
- 作成フォルダ:
php-uploadimage - 作成ファイル:
bbs.php - 使用CSSファイル(任意):
style.cssは任意で作成 - /
upload画像を格納するためのフォルダの作成
データベーステーブルの作成
アップロード付のテーブルを新規で作成しておきましょう。データベースはtestdbです
CREATE TABLE bbs_upload (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
comment TEXT NOT NULL,
image VARCHAR(255) DEFAULT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
完成イメージ

アップロード掲示板+DBのコード
<?php
session_start();
// DB接続
$dsn = 'mysql:host=localhost;dbname=testdb;charset=utf8mb4';
$user = 'root';
$password = '';
function h($str)
{
return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}
try {
$pdo = new PDO($dsn, $user, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$errors = [];
$rows = [];
$maxComment = 100; // 最大文字数を定数的に定義
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = trim($_POST['name'] ?? '');
$comment = trim($_POST['comment'] ?? '');
$imageName = null;
// 画像がアップロードされたら保存
if (!empty($_FILES['image']['name'])) {
// サイズチェック(2MB超ならエラー)
if ($_FILES['image']['size'] > 2 * 1024 * 1024) {
$errors[] = '画像は2MB以下にしてください。';
} else {
$ext = strtolower(pathinfo($_FILES['image']['name'], PATHINFO_EXTENSION));
if (in_array($ext, ['jpg', 'jpeg', 'png', 'gif'])) {
$imageName = uniqid() . '.' . $ext;
if (!move_uploaded_file($_FILES['image']['tmp_name'], __DIR__ . '/upload/' . $imageName)) {
$errors[] = '画像のアップロードに失敗しました。';
}
} else {
$errors[] = '画像は jpg, jpeg, png, gif のいずれかを選択してください。';
}
}
}
// バリデーションチェック
if ($name === '') {
$errors[] = '名前を入力してください。';
}
if ($comment === '') {
$errors[] = 'コメントを入力してください。';
} elseif (mb_strlen($comment) > $maxComment) {
$errors[] = "コメントは {$maxComment} 文字以内で入力してください。";
}
// バリデーションを通過した場合のみ登録
if (empty($errors)) {
$stmt = $pdo->prepare("INSERT INTO bbs_upload (name, comment, image) VALUES (?, ?, ?)");
$stmt->execute([$name, $comment, $imageName]);
$_SESSION['flash_msg'] = "投稿しました!";
header("Location: " . $_SERVER['PHP_SELF']);
exit;
}
}
// 一覧表示
$stmt = $pdo->query("SELECT * FROM bbs_upload ORDER BY id DESC");
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
echo "DBエラー:" . $e->getMessage();
exit;
}
?>
<!DOCTYPE html>
<html lang="ja">
<link rel="stylesheet" href="style.css">
<head>
<meta charset="UTF-8">
<title>データベース版掲示板</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header class="header">
<h1>掲示板+画像のアップロード付</h1>
</header>
<main class="content">
<!-- メッセージ -->
<?php if (!empty($_SESSION['flash_msg'])): ?>
<p><strong><?= h($_SESSION['flash_msg']) ?></strong></p>
<?php unset($_SESSION['flash_msg']); ?>
<?php endif; ?>
<!-- 入力フォーム -->
<section class="new-post">
<h2>新規投稿</h2>
<form method="post" enctype="multipart/form-data">
<p><label for="name">名前</label>
<input type="text" name="name" id="name" required>
</p>
<p>
<label for="come">コメント(最大<?= h($maxComment) ?>文字)</label>
<textarea name="comment" id="come" required maxlength="<?= h($maxComment) ?>"></textarea>
</p>
<p>
<label>画像
<input type="file" name="image" accept=".jpg,.jpeg,.png,.gif">
</label>
</p>
<button type="submit">投稿する</button>
</form>
</section>
<!-- エラーメッセージ -->
<section>
<?php if (!empty($errors)): ?>
<ul class="error">
<?php foreach ($errors as $e): ?>
<li><?= h($e) ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</section>
<section>
<h2>投稿一覧(新しい順)</h2>
<?php if (empty($rows)): ?>
<p>まだ投稿はありません。</p>
<?php else: ?>
<?php foreach ($rows as $row): ?>
<article>
<strong><?= h($row['name']) ?></strong>
<time>(<?= h($row['created_at']) ?>)</time>
<p><?= nl2br(h($row['comment'])) ?></p>
<?php if (!empty($row['image'])): ?>
<p><img src="upload/<?= h($row['image']) ?>" alt="" width="200"></p>
<?php endif; ?>
</article>
<?php endforeach; ?>
<?php endif; ?>
</section>
</main>
</body>
</html>
プログラムの追加構成と解説
フォームに enctype とファイル選択を追加
<form method="post" enctype="multipart/form-data">
...
<p>
<label>画像
<input type="file" name="image" accept=".jpg,.jpeg,.png,.gif">
</label>
</p>
</form>
enctype="multipart/form-data"
ファイルをアップロードするときは必須の設定です。accept属性
選べるファイルの種類を制限(jpg, png, gif のみ)
画像アップロード処理を追加
この処理では、アップロードされた画像を安全に保存するために
サイズチェック・拡張子チェックを行い、保存時には重複しないファイル名を作っています。
__DIR__ を使って絶対パスで保存しているので、スクリプトの場所が変わっても正しく動作します。
// 画像がアップロードされたら保存
if (!empty($_FILES['image']['name'])) {
// サイズチェック(2MB超ならエラー)
if ($_FILES['image']['size'] > 2 * 1024 * 1024) {
$errors[] = '画像は2MB以下にしてください。';
} else {
$ext = strtolower(pathinfo($_FILES['image']['name'], PATHINFO_EXTENSION));
if (in_array($ext, ['jpg', 'jpeg', 'png', 'gif'])) {
$imageName = uniqid() . '.' . $ext;
if (!move_uploaded_file($_FILES['image']['tmp_name'], __DIR__ . '/upload/' . $imageName)) {
$errors[] = '画像のアップロードに失敗しました。';
}
} else {
$errors[] = '画像は jpg, jpeg, png, gif のいずれかを選択してください。';
}
}
}
画像アップロード処理の流れ
- アップロードされたか確認
$_FILES['image']['name']が空でなければ、画像が選択されていると判断。 - サイズチェック
$_FILES['image']['size']が 2MB以下か確認。超えていればエラーを追加。 - 拡張子の取得とチェック
pathinfo()でファイル名から拡張子を取り出し、strtolower()で小文字に変換して比較。in_array(探す値, 配列)で、拡張子が['jpg','jpeg','png','gif']のどれかかをチェック。 - 保存用のファイル名を作成
uniqid()で一意のファイル名を作り、重複や上書きを防止。 - ファイルを移動して保存
move_uploaded_file()を使い、サーバー内の/upload/フォルダに移動。__DIR__は「このファイルのあるディレクトリ」を表す定数
→ 相対パスではなく絶対パスで保存するので安全。
データベースにファイル名を保存
$stmt = $pdo->prepare("INSERT INTO bbs_upload (name, comment, image) VALUES (?, ?, ?)");
$stmt->execute([$name, $comment, $imageName]);
- 画像ファイル名を一緒にINSERT
- 画像がなければ
NULLが入る
一覧表示で画像を出力
<?php if (!empty($row['image'])): ?>
<p><img src="upload/<?= h($row['image']) ?>" alt="" width="200"></p>
<?php endif; ?>
- 画像があるときだけ
<img>を表示 - 表示サイズを固定(ここでは横幅200px)
ステップアップしてみよう!
アップロードフォルダの存在をチェックして自動作成
$uploadDir = __DIR__ . '/upload/';
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0777, true);
}
→ フォルダが存在しない場合に自動で作る。
ファイルサイズの制限
if ($_FILES['image']['size'] > 2 * 1024 * 1024) { // 2MB
$errors[] = "画像サイズは2MB以下にしてください。";
}
→ サーバーに大きすぎるファイルが送られないようにする。
ファイルサイズの制限
if ($_FILES['image']['size'] > 2 * 1024 * 1024) { // 2MB
$errors[] = "画像サイズは2MB以下にしてください。";
}
→ サーバーに大きすぎるファイルが送られないようにする。
