【PHP・MySQL】データベースに画像を保存・表示する方法 第4回「画像を表示する」
ここまでの記事はこちら
今回はデータベースに保存した画像を取得・表示していきます。
解説
画像を取得する
list.php を開いて、8~11行目を追加します。
images テーブルからcreated_at(作成日時)の新しい順でデータを取得しています。
画像を表示する
取得した画像データ $images を for ルーブを使って表示していきます。
list.php の5・8・11行目のコードを変更します。
8行目
画像の表示は、画像を出力する image.php ファイルを作成して行います。
image.php という名前でファイルを作成して、以下のようにコードを書いてください。
image.php では
<img src="image.php?id=<?= $images[$i]['image_id']; ?>"
で渡された image_id を受け取って、その image_id から画像データを取得します。
12行目で image/jpg, image/png などの Content-type を指定してから画像データを出力します。
11行目
画像の名前とサイズを表示しています。
画像サイズはバイトで保存されているので、キロバイトに変換して小数点第二位まで表示させています。(1KB = 1,000B)
Lightboxの画像
最後に Lightbox 部分も修正しましょう。
list.php の 3・8・10行目のコードを変更します。
動作確認
これで画像表示は完成です!
画像が表示されていること、Lightbox も正しく表示されることを確認してください。
次に行うこと
次回は画像をデータベースから削除できるようにしていきます。
コメント失礼致します。
こちらのサイトを参考にプログラムの勉強をしております。
画像を保存し、表示するプログラムにてpdfを保存して同じように表示することは可能でしょうか。
当サイトをご利用いただきありがとうございます!
全く同じコードで pdf ファイルも保存できます。表示する時だけ img タグではなく iframe タグを使ってみてください。
ありがとうございます!!
無事にリストの方で確認ができました!!
クリックした際に、拡大表示が出来ないのですが、その場合は諦めた方がよろしいでしょうか。
表示できたようで良かったです!
少し無理矢理ですが、このようにコードを変更すれば拡大表示できるようになると思います。(iframeの上にaタグを重ねています。)
<li class=”media mt-5″>
<div style=”position:relative;”>
<iframe src=”image.php?id=<?= $images[$i][‘image_id’]; ?>” width=”300″ height=”200″></iframe>
<a href=”#lightbox” data-toggle=”modal” data-slide-to=”<?= $i; ?>” style=”position:absolute; top:0; left:0; display:inline-block; width:300px; height:200px; z-index:10;”></a>
</div>
<div class=”media-body”>
お試しください。
何度もコメント返信頂き、ありがとうございます!!
「404 File Not Found」のページが表示され、データが読み込めなかったのですが、
もしかしたらlightboxはPDFに対応してないのでしょうか。
iframeタグはブラウザによって上手く表示できない場合がありますが、ChromeではLightboxも表示することができています。
以下の箇所もiframeタグに変更したことをご確認の上、ブラウザを変えてみてください。
<div class=”carousel-item <?php if ($i == 0) echo ‘active’; ?>”>
<iframe src=”image.php?id=<?= $images[$i][‘image_id’]; ?>” class=”d-block w-100″ width=”500″ height=”300″></iframe>
</div>
何度もご回答ありがとうございます。
上記のプログラムで添付画像のようになってしまいます。
Microsoft EdgeやGoogle Chromeで試しましたが、同じ結果となってしまいます。
自分で解決出来ずに申し訳ございません。
iframe タグ部分を
” → "
’ → '
に修正にしてみてください。
該当箇所のスクリーンショットです。
本当にありがとうございます!!
無事に確認することができました!
とんでもなく初歩的なミスにより、
Sara先生には大変ご迷惑をおかけして大変申し訳ありませんでした。
Sara先生の講座を今から受講し、これからもっと勉強して精進したいと思います!
本当にありがとうございました😭
無事に確認できたとのことで安心しました!
まだPHPの記事・講座は少ないですが、少しでもMatsudaさんのお役に立てれば幸いです
久しぶりの質問で失礼いたします。
先日はご丁寧な質問対応ありがとうございました。
PDF拡大を行なって気づいたのですが、
画像にカーソルを合わせなくても、lightboxで指定された範囲をクリックすることで拡大表記が出来ることだったのですが、
カーソルを画像にだけ合わせた時に拡大クリックすることは可能ではないなでしょうか。
>カーソルを画像にだけ合わせた時に拡大クリックすることは可能ではないなでしょうか。
「マウスオーバーしたときにクリックしないで拡大表示する」ということでしょうか?
その場合はjQueryのhoverイベントを使って
とすれば可能かと思います。
表示する画像の指定など細かい調整がかなり必要になると思いますが、modalを開くときは
$('#lightbox').modal('show');
modalを閉じるときは
$('#lightbox').modal('hide');
と書くことができます。
参考になれば幸いです。
コメント失礼致します!
ライトボックスを勉強している者です!
ライトボックスで画像を拡大後に右上に×ボタンをつけて、拡大画像を閉じる機能をつけたいと考えているのですが、それは実装可能でしょうか。
当サイトを見つけて頂きありがとうございます
CSS での調整が必要になると思いますが、data-dismiss="modal" 属性を付けたボタンを用意すれば可能です。
例えば以下のような感じです。
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
<div class="modal-body">
複数の画像ファイルを選択してデータベースに保存することは可能でしょうか。
input タグを以下のようにすると複数の画像を選択できるようになります。
<input type="file" name="image[]" multiple="multiple" required>
あとは for ループなどで一枚ずつ保存してみてください。
コメント失礼します!!
こちらのサイトを参考に勉強させて頂いています。
保存した画像を表示しようとしたところ、画像が表示されたりされなかったりします。
プログラム、DB設定等全てこちらのサイト通りにしております。
こちらの解決方法がありましたらご教授頂きたいです。
当サイトを見つけていただきありがとうございます!
表示されていない「1-9.png」という画像は、データベースには保存できている状態でしょうか?
保存できている場合は「出力時のコードに問題あり」保存できていない場合は「画像に問題あり」と考えられます。
もご確認ください。
(ご質問の際は開発環境もお書き頂くようお願い致します。)
データベース内に追加もできていますし、データ自体もおそらく届いているのに表示ができません。新しい画像も追加し再度試みましたがやはりだめです。現在データベース内には画像データが二つある状態です。
環境としてはxamp vscode だけです。エラーメッセージは出ていません。新しい
先ほど Windows + XAMPP 環境でテストしましたが正しく動作していましたので「image.php が list.php と同じ場所に配置されていること」をご確認ください。
同じ場所に配置しているけど動かないという場合は <img src="./image.php?id= と変更してみてください。
わかりました。一応ファイルは同じ階層にあります!そのカードで試してみますね!返信ありがとうございます。
追記ですが色々試していて、ファイルの中身を出力したりしていたところ、本来画像で出力される所が文字化けして出力されてしまい、ファイルが壊れてしまったのではと予測しました。そこで調べたところ
何やらfile get contentsの関数で受け取るとファイルが壊れると言う記事を発見し、それによるとphpのバージョンによって破損してしまうことがあるようです。
改善のために現在7.3?〜8.1.11にアップデートをして無事更新、apachiも動きますが、次はxamppのmysqlのadminボタンからdatabaseを開いたところ、本来表示されるものが表示されず、要約するとopensll mysqliの拡張機能をインストールしてくれといったエラー文が出るようになってしまいました。調べてみたところphp.iniで;を外すなどとあり試してみましたが改善致しません。
もはやこのブログとは関係ない質問になってしまいましたがこちらの改善方法はご存知ないでしょうか?
また正常に動くxampp内でのphpアップデート方法や、saraさんのおすすめの開発環境教えて頂きたいです。
file_get_contents関数の問題は外部からファイルを取得するときに起きることはありますが、今回のプロジェクトでは問題ない気がします。古いPHPバージョンでも動作確認をしているので、画像ファイルが壊れることもないと思うのですが、、、
あとはPHPファイルの保存形式も確認してみてください。
Visual Studio Codeを使っているとのことなので問題はないと思うのですが、image.phpファイルをエディタで開いた時に右下に表示されるファイル形式が「UTF-8 with BOM」となっていると画像ファイルが開けません。もしなっていたら「UTF-8」形式で保存してみてください。
私の場合、Windowsでの開発環境はXAMPP(v3.3.0)とVisual Studio Codeエディタを使っています。
あまりカスタマイズしてしまうと読者の方との環境が合わなくなってしまうので、XAMPPの設定も保存可能なファイルサイズを変更するmax_allowed_packet値の変更しかしていません。
アップデートは「ファイルのバックアップ→アンインストール→再インストール」という方法で行っています。バックアップを取るのはhtdocsフォルダ・httpd.conf・php.iniあたりのファイルです。XAMPPはPHPだけアップデートすることも可能だったかと思いますが、動かなくなったりエラーだらけになった経験が何度かあるので「アンインストールして再インストール」が一番簡単で確実な方法かと思います。
opensllの問題はおそらく読み込みのパスが間違っていることが原因かと考えられますが、XAMPP自体を再インストールするのが一番簡単で早い解決法かもしれません。
すいません、指摘の通りに直しましたが改善されません。こちらの画像で試してみてほしいです。一応私のコード載せておきますね。
image.php
<?php
require_once ‘functions.php’;
$pdo = connectDB();
$sql = ‘DELETE FROM age_artworks WHERE image_id = :image_id’;
$stmt = $pdo->prepare($sql);
$stmt->bindValue(‘:image_id’, (int)$_GET[‘id’], PDO::PARAM_INT);
$stmt->execute();
header(‘Location:list.php’);
exit();
?>
list.php
<?php
require_once ‘functions.php’;
$pdo = connectDB();
if ($_SERVER[‘REQUEST_METHOD’] != ‘POST’) {
// 画像を取得
$sql = ‘SELECT * FROM age_artworks ORDER BY created_at DESC‘;
$stmt = $pdo->prepare($sql);
$stmt->execute();
$images = $stmt->fetchAll();
// foreach ($images as $value) {
// print_r($value);
// }
// exit();
} else {
// 画像を保存
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’];
$sql = ‘INSERT INTO age_artworks(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” required>
</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” style=“position:fixed;”>
<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>
載せて頂いたのはimage.phpではなくdelete.phpではないでしょうか?
私の環境では頂いた画像を保存できたので、image.phpに問題があるのかもしれません。
http://localhost/ImageTest/image.php?id=1 のように直接アクセスして画像が表示されるかも確認してみてください。
ちょくせつみてみたところこのようになりました
[“tmp_name”]=> string(24) “C:\xampp\tmp\phpC184.tmp” [“error”]=> int(0) DUMPしてみたらどうやらtempにエラーが出ているのでファイルが保存できてないようです。
list.phpにて
var_dump($_FILES[‘image’]);
print_r($http_response_header);
exit();
array(6) { [“name”]=> string(14) “S__8192105.jpg” [“full_path”]=> string(14) “S__8192105.jpg” [“type”]=> string(10) “image/jpeg” [“tmp_name”]=> string(24) “C:\xampp\tmp\php9ABD.tmp” [“error”]=> int(0) [“size”]=> int(316884) } DUMPしてみたらこんな感じです。
すいませんあげなおしです
image.php
<?php
require_once ‘functions.php’;
$pdo = connectDB();
$id = $_GET[‘id’];
$sql = ‘SELECT * FROM age_artworks WHERE image_id = :image_id LIMIT 1‘;
$stmt = $pdo->prepare($sql);
$stmt->bindValue(‘:image_id’, $id, PDO::PARAM_INT);
$stmt->execute();
$image = $stmt->fetchAll();
header(‘Content-type: ‘ . $image[‘image_type’]);
echo $image;
exit();
?>
image.phpの10行目あたり
$image = $stmt->fetchAll();
ではなく
$image = $stmt->fetch();
です。
ここを修正すれば表示されるはずです!
以前と変わらずこの状態です。fetchallはDBのカラムを全要素、配列にいれたくてそうしました。一応戻して直接開いてみましたら表示はされるのですがこのように本来の画像が表示されません。お手上げ状態です。前の質問に挙げた画像が悪いのでしょうか?。。。それかそもそも保存がうまくできてないのでしょうか。
fetchAllはカラムの全要素を入れるのではなく、複数の行(データ)を取得するためのものです。
取得するカラムは $sql = 'SELECT * FROM images… の * の部分で指定します。(* は全カラムを意味します。)
一方fetchは1つの行(データ)を取得します。
image.phpではidから1つの画像(行)を取得するので、fetchAllではなくfetchを使ってください。
また、すもももさんのコードでは echo $image; と取得したデータをそのまま出力していますが、ここで出力するのは画像データだけなので echo $image['image_content']; と書きます。
この2箇所を修正したのが以下のコードです。list.phpは問題なさそうなので、image.phpだけ修正してみて下さい。
<?php
require_once 'functions.php';
$pdo = connectDB();
$id = $_GET['id'];
$sql = 'SELECT * FROM age_artworks WHERE image_id = :image_id LIMIT 1';
$stmt = $pdo->prepare($sql);
$stmt->bindValue(':image_id', $id, PDO::PARAM_INT);
$stmt->execute();
$image = $stmt->fetch();
header('Content-type: ' . $image['image_type']);
echo $image['image_content'];
exit();
?>