【PHP・MySQL】データベースに画像を保存・表示する方法 第7回「ファイルサイズのチェック」

Sara
ここまでの記事はこちら
サイズが大きすぎる画像を保存できてしまうと、サーバーに負担がかかってしまいます。
前回の形式チェックと同じように画像ファイルのサイズチェックも入れておきましょう。

ファイルのサイズチェックを入れる方法
第6回「形式チェック」が完了している状態から始めます。
今回は 1MB までのファイルでチェックを入れてみましょう。
前回形式チェックを入れた箇所にコードを追加します。(10~14行目)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* 省略 */ | |
if (!empty($_FILES['image']['name'])) { | |
$name = $_FILES['image']['name']; | |
$type = $_FILES['image']['type']; | |
$content = file_get_contents($_FILES['image']['tmp_name']); | |
$size = $_FILES['image']['size']; | |
// 画像のサイズ・形式チェック | |
$maxFileSize = 1048576; | |
$validFileTypes = ['image/png', 'image/jpeg']; | |
if ($size > $maxFileSize || !in_array($type, $validFileTypes)) { | |
$err_msg = '* jpg, jpeg, png 形式で 1 MB までの画像を選択してください。'; | |
} | |
if ($err_msg == '') { |
10行目
$maxFileSize = 1048576;
$_FILES[‘image’][‘size’]; で取得した画像サイズの単位は Byte(バイト)です。

1 MB = 1024 KB = 1048576 Byte
なので $maxFileSize = 1048576; としています。
12行目
if ($size > $maxFileSize || !in_array($type, $validFileTypes)) {
形式チェックと一緒にサイズの判定も入れています。
「画像サイズが $maxFileSize を超えている」または「形式が $validFileTypes に含まれていない」場合にエラーメッセージを表示します。
コードの修正
エラーメッセージを表示すると、左側に表示されるはずの登録済み画像が消えてしまいます。

登録済みの画像が常に表示されるようにコードを修正します。(1~13行目)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
require_once('functions.php'); | |
$pdo = connectDB(); | |
$err_msg = ''; | |
// 画像を取得 | |
$sql = 'SELECT * FROM images ORDER BY created_at DESC'; | |
$stmt = $pdo->prepare($sql); | |
$stmt->execute(); | |
$images = $stmt->fetchAll(); | |
if ($_SERVER['REQUEST_METHOD'] == 'POST') { | |
// 画像を保存 | |
if (!empty($_FILES['image']['name'])) { | |
$name = $_FILES['image']['name']; | |
$type = $_FILES['image']['type']; |
完成
以下のように動いていれば完成です。
ここまでのコード
- list.php
-
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
<?php require_once('functions.php'); $pdo = connectDB(); $err_msg = ''; // 画像を取得 $sql = 'SELECT * FROM images ORDER BY created_at DESC'; $stmt = $pdo->prepare($sql); $stmt->execute(); $images = $stmt->fetchAll(); if ($_SERVER['REQUEST_METHOD'] == 'POST') { // 画像を保存 if (!empty($_FILES['image']['name'])) { $name = $_FILES['image']['name']; $type = $_FILES['image']['type']; $content = file_get_contents($_FILES['image']['tmp_name']); $size = $_FILES['image']['size']; // 画像のサイズ・形式チェック $maxFileSize = 1048576; $validFileTypes = ['image/png', 'image/jpeg']; if ($size > $maxFileSize || !in_array($type, $validFileTypes)) { $err_msg = '* jpg, jpeg, png 形式で 1 MB までの画像を選択してください。'; } if ($err_msg == '') { $sql = 'INSERT INTO images(image_name, image_type, image_content, image_size, created_at) VALUES (:image_name, :image_type, :image_content, :image_size, now())'; $stmt = $pdo->prepare($sql); $stmt->bindValue(':image_name', $name, PDO::PARAM_STR); $stmt->bindValue(':image_type', $type, PDO::PARAM_STR); $stmt->bindValue(':image_content', $content, PDO::PARAM_STR); $stmt->bindValue(':image_size', $size, PDO::PARAM_INT); $stmt->execute(); header('Location:list.php'); exit(); } } } ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>Image Test</title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous"> </head> <body> <div class="container mt-5"> <div class="row"> <div class="col-md-8 border-right"> <ul class="list-unstyled"> <?php for($i = 0; $i < count($images); $i++): ?> <li class="media mt-5"> <a href="#lightbox" data-toggle="modal" data-slide-to="<?= $i; ?>"> <img src="image.php?id=<?= $images[$i]['image_id']; ?>" width="100" height="auto" class="mr-3"> </a> <div class="media-body"> <h5><?= $images[$i]['image_name']; ?> (<?= number_format($images[$i]['image_size']/1000, 2); ?> KB)</h5> <a href="javascript:void(0);" onclick="var ok = confirm('削除しますか?'); if (ok) location.href='delete.php?id=<?= $images[$i]['image_id']; ?>'"><i class="far fa-trash-alt"></i> 削除</a> </div> </li> <?php endfor; ?> </ul> </div> <div class="col-md-4 pt-4 pl-4"> <form method="post" enctype="multipart/form-data"> <div class="form-group"> <label>画像を選択</label> <input type="file" name="image" accept=".jpg,.jpeg,.png" required> <?php if ($err_msg != ''): ?> <div class="invalid-feedback d-block"><?= $err_msg; ?></div> <?php endif; ?> </div> <button type="submit" class="btn btn-primary">保存</button> </form> </div> </div> </div> <div class="modal carousel slide" id="lightbox" tabindex="-1" role="dialog" data-ride="carousel"> <div class="modal-dialog modal-dialog-centered" role="document"> <div class="modal-content"> <div class="modal-body"> <ol class="carousel-indicators"> <?php for ($i = 0; $i < count($images); $i++): ?> <li data-target="#lightbox" data-slide-to="<?= $i; ?>" <?php if ($i == 0) echo 'class="active"'; ?>></li> <?php endfor; ?> </ol> <div class="carousel-inner"> <?php for ($i = 0; $i < count($images); $i++): ?> <div class="carousel-item <?php if ($i == 0) echo 'active'; ?>"> <img src="image.php?id=<?= $images[$i]['image_id']; ?>" class="d-block w-100"> </div> <?php endfor; ?> </div> <a class="carousel-control-prev" href="#lightbox" role="button" data-slide="prev"> <span class="carousel-control-prev-icon" aria-hidden="true"></span> <span class="sr-only">Previous</span> </a> <a class="carousel-control-next" href="#lightbox" role="button" data-slide="next"> <span class="carousel-control-next-icon" aria-hidden="true"></span> <span class="sr-only">Next</span> </a> </div> </div> </div> </div> <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script> </body> </html>
Q
ABOUT ME

書籍やオンライン講座でプログラミングを勉強してフリーランスのプログラマーになりました。
このサイトでは「わかりやすく・シンプル」をモットーに、プログラミングの基礎からアプリ開発まで紹介します。
独学でプログラミングを勉強をしている方、基礎は勉強したけれど次に何をすれば良いか分からない...という方のお役に立てるサイトを目指しています。
主な使用言語:Java / Kotlin / PHP
>> 詳しいプロフィール
>> お問い合わせ
>> 書籍を出版しました!
このサイトでは「わかりやすく・シンプル」をモットーに、プログラミングの基礎からアプリ開発まで紹介します。
独学でプログラミングを勉強をしている方、基礎は勉強したけれど次に何をすれば良いか分からない...という方のお役に立てるサイトを目指しています。
主な使用言語:Java / Kotlin / PHP
>> 詳しいプロフィール
>> お問い合わせ
>> 書籍を出版しました!
COMMENT
投稿いただいたコメントは管理者の承認後に表示されます。
コードやエラーに関するご質問の場合は、以下の3点
をできるだけ具体的に必ず書いてください。
当サイトを見つけていただきありがとうございます!
任意のタイトルはデータベースに保存したいのでしょうか?あるいは、表示する時に何か特定のワードを使えれば良いのでしょうか?
また「スーパーグローバル変数にPOSTでecho」という部分についても、もう少し詳しく教えて頂ければと思います。
画像添付して頂いて大丈夫です!
相澤さんが書かれている
<input type="text" name="image_name" value="">
は合っていると思います。
「for文の中に$_POST['image_name']」に問題がありそうで、登録と出力のコードが混在しているような気がします。
$_POSTは「フォームからPOST送信されたデータを受け取るもの」です。
for文の中で行うのは「データベースから取り出したデータを表示すること」です。
このあたりが少し曖昧になってしまっているのかなと思うので、以下の2点を確認してみてください。
1. imagesテーブルに名前は登録できていますか?
登録できていない場合は
$name = $_FILES['image']['name'];
を
$name = $_POST['image_name'];
のように変更しているかご確認ください。
2. データベースに保存できているが取り出せない場合
Warning: Undefined array key "" in C:\xampp\htdocs\ImageTest\list.ph
は「配列にキーがありません」というメッセージなので、image_name というスペルを正しく書いているか、コード全体をチェックしてみてください。
input に入力した名前がデータベースに保存できていることが前提になりますが
<?php echo $_POST[‘image_name ‘]; ?>
は
<?php echo $images[$i][‘image_name’]; ?>
ではないでしょうか??
先ほども書きましたが
$_POST → フォームからPOST送信されたデータを受け取る
for文の中 → データベースから取り出したデータを表示する
です。
表示できたとのこと良かったです!
何かの課題の場合は出題者さんにお問い合わせ頂いた方が良いのかなと思いますが、ブログ内容に沿っている内容であればお気軽にご相談ください!