質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.49%

PHPを使用したDB内の画像を表示ができない

受付中

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 540

score 4

前提・実現したいこと

PHPを使用してDBに画像と動画のバイナリデータを格納し、再度出力するまでの動作を行いたいです。

発生している問題・エラーメッセージ

画像の格納までは行えたのですが、出力で進めなくなりました。
小さな画像アイコンのみ表示されている状態です。((パスの指定がうまく出来ていないのでしょうか…?

$stmt -> bindValue(":target", $target, PDO::PARAM_STR);

header("Content-Type: ".$MIMETypes[$row["extension"]]);


以上のコード部分でエラーが発生しています。
ちなみに出力できていない画像のsrcはfnameの値が入っている状態でした。
>src=input_media?target=fnameの値

該当のソースコード

storage.php

<?php
    try{
        $user = "root";
        $pass = "root";
        $pdo = new PDO("mysql:host=127.0.0.1;dbname=mediatest;charset=utf8", $user, $pass);

        //ファイルアップロード
        if (isset($_FILES['upfile']['error']) && is_int($_FILES['upfile']['error']) && $_FILES["upfile"]["name"] !== ""){
            //エラーチェック
            switch ($_FILES['upfile']['error']) {
                case UPLOAD_ERR_OK: // OK
                    break;
                case UPLOAD_ERR_NO_FILE:   // 未選択
                    throw new RuntimeException('ファイルが選択されていません', 400);
                case UPLOAD_ERR_INI_SIZE:  // php.ini定義の最大サイズ超過
                    throw new RuntimeException('ファイルサイズが大きすぎます', 400);
                default:
                    throw new RuntimeException('その他のエラーが発生しました', 500);
            }

            //画像・動画をバイナリデータに変換
            $raw_data = file_get_contents($_FILES['upfile']['tmp_name']);

            //拡張子を確認&統一
            $tmp = pathinfo($_FILES["upfile"]["name"]);
            $extension = $tmp["extension"];
            if($extension === "jpg" || $extension === "jpeg" || $extension === "JPG" || $extension === "JPEG"){
                $extension = "jpeg";
            }
            elseif($extension === "png" || $extension === "PNG"){
                $extension = "png";
            }
            elseif($extension === "gif" || $extension === "GIF"){
                $extension = "gif";
            }
            elseif($extension === "mp4" || $extension === "MP4"){
                $extension = "mp4";
            }
            else{
                echo "非対応ファイル<br/>";
                echo ("<a href=\"storage.php\">戻る</a><br/>");
                exit(1);
            }

            //DBに格納するファイルネーム設定
            //サーバー側の一時的なファイルネームと取得時刻を結合した文字列にsha256をかける.
            $date = getdate();
            $fname = $_FILES["upfile"]["tmp_name"].$date["year"].$date["mon"].$date["mday"].$date["hours"].$date["minutes"].$date["seconds"];
            $fname = hash("sha256", $fname);

            //画像・動画をDBに格納.
            $sql = "INSERT INTO media(fname, extension, raw_data) VALUES (:fname, :extension, :raw_data);";
            $stmt = $pdo->prepare($sql);
            $stmt -> bindValue(":fname",$fname, PDO::PARAM_STR);
            $stmt -> bindValue(":extension",$extension, PDO::PARAM_STR);
            $stmt -> bindValue(":raw_data",$raw_data, PDO::PARAM_STR);
            $stmt -> execute();

        }

    }
    catch(PDOException $e){
        echo("<p>500 Inertnal Server Error</p>");
        exit($e->getMessage());
    }
?>

<!DOCTYPE HTML>

<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>media</title>
</head>

<body>
    <form action="storage.php" enctype="multipart/form-data" method="post">
        <label>画像/動画アップロード</label>
        <input type="file" name="upfile">
        <br>
        ※画像はjpeg方式,png方式,gif方式に対応しています.動画はmp4方式のみ対応しています.<br>
        <input type="submit" value="アップロード">
    </form>

    <?php
    //DBから取得して表示する.
    $sql = "SELECT * FROM media ORDER BY id;";
    $stmt = $pdo->prepare($sql);
    $stmt -> execute();
    while ($row = $stmt -> fetch(PDO::FETCH_ASSOC)){
        echo ($row["id"]."<br/>");
        //動画と画像で場合分け
        $target = $row["fname"];
        if($row["extension"] == "mp4"){
            echo ("<video src=\"import_media.php?target=$target\" width=\"426\" height=\"240\" controls></video>");
        }
        elseif($row["extension"] == "jpeg" || $row["extension"] == "png" || $row["extension"] == "gif"){
            echo ("<img src='import_media.php?target=$target'>");
        }
        echo ("<br/><br/>");
    }
    ?>
</body>
</html>

テーブル構造

CREATE TABLE 
`mediatest`.`media` ( `id` INT NOT NULL AUTO_INCREMENT , 
`fname` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL , 
`extension` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL , 
`raw_data` LONGBLOB NOT NULL , PRIMARY KEY (`id`)) ENGINE = InnoDB;

input_media.php

<?php
    if(isset($_GET["target"]) && $_GET["target"] !== ""){
        $target = $_GET["target"];
    }
    else{
        header("Location: storage.php");
    }
    $MIMETypes = array(
        'png' => 'image/png',
        'jpeg' => 'image/jpeg',
        'gif' => 'image/gif',
        'mp4' => 'video/mp4'
    );
    try {
        $user = "root";
        $pass = "root";
        $pdo = new PDO("mysql:host=127.0.0.1;dbname=mediatest;charset=utf8", $user, $pass);
        $sql = "SELECT * FROM media WHERE fname = :target;";
        $stmt = $pdo->prepare($sql);
        $stmt -> bindValue(":target", $target, PDO::PARAM_STR);
        $stmt -> execute();
        $row = $stmt -> fetch(PDO::FETCH_ASSOC);
        header("Content-Type: ".$MIMETypes[$row["extension"]]);
        echo ($row["raw_data"]);
    }
    catch (PDOException $e) {
        echo("<p>500 Inertnal Server Error</p>");
        exit($e->getMessage());
    }
?>

補足情報(FW/ツールのバージョンなど)

実行環境は
php7.3.14
Cloud9
MySQL5.5.62

DBへの接続にはPDOを使用しています。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • m.ts10806

    2020/02/28 15:24

    出ているエラーをそのままコピペでご提示ください

    キャンセル

  • mmm02

    2020/02/28 15:50

    [Fri Feb 28 06:48:05 2020] PHP Notice: Undefined variable: target in /home/ec2-user/environment/OpusApp/input_media.php on line 20
    [Fri Feb 28 06:48:05 2020] PHP Notice: Undefined index: in /home/ec2-user/environment/OpusApp/input_media.php on line 23

    ご協力ありがとうございます。

    キャンセル

  • 退会済みユーザー

    退会済みユーザー

    2020/02/28 16:01

    アップロードされたファイルをバイナリーデータとしてDBに格納しようとしている? どのBLOB型を使っているのかな? けど、PDO::PARAM_LOB 使ってないね、だいじょうぶ? そして仮に格納できたとしてどうやって表示しようとしている? バイナリーデータをBASE64エンコードしてHTML内に直接展開するの? どうやったら表示できるかも知らずにコードを書いていたりする?

    キャンセル

  • m.ts10806

    2020/02/28 16:30

    line XXとエラーありますがそれぞれコードのどこにあたるかコメント入れてください。
    コードを省略されているからかと思いますが、エラーと行数がマッチしません

    キャンセル

回答 2

+2

どうしてもDBにバイナリーデータ的にファイルの中身を格納して管理したいのであれば、
画像などの表示用に出力する方法は下記が参考になるかと。

画像をエンコードして、HTML出力の中に入れ込むことが出来て、
画像表示のためにHTML表示と別なHTTPリクエストを受けずにHTML出力に組み込めるっていうこと。

画像をBase64でHTMLファイルに直接埋め込む方法 | design Edge
DBに保存したバイナリデータをブラウザで表示する - フロントエンドエンジニアの覚え書き

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

ざっとしか見てないので多分他にも問題はあると思いますが

//storage.php
            echo ("<img src='input_media.php?id=11'>");


targetを指定していないのに

//input_media.php
      $target = $_GET["target"];

を取得しようとしているのでstorage.phpに常にリダイレクトされてしまっているように見えます。

  1. まずはinput_media.php単体にブラウザでアクセスして画像を表示できるようにして、その際の正しいURLを把握する
  2. storage.php内でecho ("<img src='input_media.php?id=11'>");している部分をブラウザの開発者ツールで確認して、1で把握したURLになるように修正する

という感じで修正すれば直せると思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/02/28 15:56

    storage.phpのecho文が間違っていますね…。
    echo ("<img src='import_media.php?target=$target'>");に修正してみました。

    そのうえで表示された画像の保持するsrcを開発者ツールで参照してみたところ
    以下の通りの指定になっていました。
    import_media.php?target=e47a5fe8a7810d000896fcf9d12d8791cb475e2da3d3159ae50017ed5c7698ce

    素人質問で申し訳ないですが、ご協力ありがとうございます。

    キャンセル

  • 2020/02/28 16:10 編集

    $targetでは無く多分$row["id"]だと思いますが、回答欄でデバッグをするつもりはありませんので、(作業依頼はteratailで禁止されているので)
    回答の通りの順で切り分けてみてください。

    var_dump($row);
    等で、$rowにどういった値が入っているか確認できます

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.49%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る