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

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

ただいまの
回答率

87.78%

mysql,phpで画像投稿機能を実現したい

受付中

回答 3

投稿

  • 評価
  • クリップ 1
  • VIEW 1,086

score 4

前提・実現したいこと

プログラミング初心者です。
MySQLとphpを使用して、画像・動画投稿機能を作成しようとしています。
画像(png,jpeg,gif)、動画(mp4)をアップロードするとmediatest.phpのhtmlのフォームの下に表示されるようにしたいです。

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

エラーメッセージはなく、画像を選択し「アップロード」を押しても何も表示されない状態です。

該当のソースコード

<?php
//mediatest.php
//データベース接続
  $dsn='';
  $user='';
  $password='';
  $pdo=new PDO($dsn, $user, $password, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING));

$sql="CREATE TABLE IF NOT EXISTS mediatest"
 ."(" 
 ."id INT AUTO_INCREMENT PRIMARY KEY," 
 ."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"
 .");";

$sql ='SHOW CREATE TABLE mediatest';
    $result = $pdo -> query($sql);
    foreach ($result as $row){
        echo $row[1];
    }
    echo "<hr>";

try{
        //ファイルアップロードがあったとき
        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=\"mediatest.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 mediatest(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="mediatest.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 mediatest WEHRE id;";
    $stmt = $pdo->prepare($sql);
    $results = $stmt->fetchAll(PDO::FETCH_ASSOC);
    foreach($results as $row){
        echo $row["id"]."<br/>";
        //動画と画像で場合分け
        echo $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/>";
     }
    ?>

</body>
</html>
<?php
//import_media.php
    //データベース接続
  $dsn='';
  $user='';
  $password='';
  $pdo=new PDO($dsn, $user, $password, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING));
$sql="CREATE TABLE IF NOT EXISTS mediatest"
 ."(" 
 ."id INT AUTO_INCREMENT PRIMARY KEY," 
 ."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"
 .");";



if(isset($_GET["target"]) && $_GET["target"] !== ""){
        $target = $_GET["target"];
    }
    else{
        header("Location: mediatest.php");
    }
    $MIMETypes = array(
        'png' => 'image/png',
        'jpeg' => 'image/jpeg',
        'gif' => 'image/gif',
        'mp4' => 'video/mp4'
    );
    try {

        $sql = "SELECT * FROM mediatest 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());
    }
?>

試したこと

対応しているファイル以外をアップロードしたときは、「非対応ファイルです」というメッセージが表示され、正しく処理されているようでした。
また、echoでどこまで表示されるか試したところ、mediatest.phpの
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
の下までは表示され、foreach以降は表示されなくなりました。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • m.ts10806

    2019/10/30 06:24

    $resultsには何が入ってましたか?

    キャンセル

  • hina4646

    2019/10/30 10:36

    プログラミングインターンの一環で、インターン先からの具体的な教えもなく全然わからない状態で作っていて申し訳ないのですが、私は勝手に$resultにはfetchAllで取ってきたテーブルの中身が入ってると思っていました。

    キャンセル

  • Y.H.

    2019/10/30 13:08

    > 私は勝手に$resultにはfetchAllで取ってきたテーブルの中身が入ってると思っていました。
    で、実際は何が入ってましたか?

    キャンセル

回答 3

+2

まえがき

ファイルアップロードは非常に危険な機能です。
コードのすべてを理解しなければ使ってはいけないモノなので、ツギハギで作らないでください。
以下に、入口となる記事をリンクしておきます。

ファイルアップロードの例外処理はこれぐらいしないと気が済まない

回答

コードの詳細は追ってませんが、流し読みで以下が引っかかりました。

$sql = "SELECT * FROM mediatest WEHRE id;";
$stmt = $pdo->prepare($sql);
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);

実行している箇所がありません。
変数の推移を確認すると良いです。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/10/30 07:48

    where id だけで何をとる想定なのかもちと謎ですね。ツギハギという指摘も当然。

    キャンセル

  • 2019/10/30 07:54

    あぁ、そっちは流し読んじゃってましたw
    多分他にもあると思う^^;

    キャンセル

  • 2019/10/30 10:43

    そうなんですね…私も何を示しているのか分からない部分が多くあり、自分でもツギハギだなと思っていました。まずは示してくださったリンクを読んでみたいと思います。ありがとうございます。

    キャンセル

  • 2019/10/30 10:48

    ついでにアドバイスをしておくと「理解できないコードを使うな」です。
    参考にしたりすることはあっても動くのは自分の手元です。把握できてないものがあるのはブラックボックス化してしまい「なんか知らないけど動いている」からの大事故に繋がりかねません。何かあっても自分で対応できませんし、他人に丸投げすることになり余計にわからない部分が増えていきます。
    であれば自分で管理把握できる範囲の小さいコードを作ってそこから広げていきましょう。王道はありませんので少しずつやっていくしかありません

    キャンセル

+2

「アップロード」を押しても何も表示されない状態

エラーを表示しないようになっているからです。
mediatest.phpの先頭を以下のようにini_set()を2行追加しエラーが表示されるようにしましょう。

<?php
ini_set('display_errors', 1 );
ini_set('error_reporting', E_ALL);

質問に記載のソースコードでは、エラーや警告が出ると思います。
まずはエラーや警告を良く読んでこれらが出ないように修正してください。
エラーや警告はここがこんな風に違いますよと教えてくれているものです。

たぶん、質問するより早い解決ができると思います。
もし、それでも解らないことがあった場合は具体的にその部分を質問されると良いでしょう。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/10/30 10:37

    ありがとうございます。教えていただいたコードを追記し実行して、自分でも正しく実行されない原因をもう一度探してみたいと思います。

    キャンセル

  • 2019/10/30 11:05

    すみません、教えていただいたコードを追記し再度ファイルをアップロードしたのですが、何も表示されませんでした。

    キャンセル

  • 2019/10/30 11:45

    あぁ、 sqlを実行していない($stmt -> execute(); がない)からエラーにならないのか。。。

    キャンセル

+1

データベース内にアップロードされたファイルをバイナリー保存かけるようなコードに読み取れますが、
一般には、アップロードされたファイルをリネームして、
公開ディレクトリ上に整理してファイルをコピーして保存し、
保存したファイルのファイル名とパス名をデータベース上に保持するものだと思います。
特に数十KBなどでは収まらない昨今の画像ファイル、音声ファイル、動画ファイルを、
リクエストを受けるたびにデータベース内から引っ張り出すよりも、
サーバーに掛かる負担が低減されると思います。

PHP: move_uploaded_file - Manual
を使ってやる方法として、例えばこちらの事例などどうでしょうか。

\[PHP\]ファイルアップロードサンプル(PHP → DB → HTML) - Qiita

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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

関連した質問

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