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

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

ただいまの
回答率

90.98%

  • PHP

    17812questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

  • Laravel 5

    1454questions

    Laravel 5は、PHPフレームワークLaravelの最新バージョンで、2014年11月に発表予定です。ディレクトリ構造がが現行版より大幅に変更されるほか、メソッドインジェクションやFormRequestの利用が可能になります。

Laravel ファイルのアップロードができない

解決済

回答 3

投稿 編集

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

nnahito

score 1598

 はじめに

Laravel初心者です。

 環境

Windows10
Larabel5.5
XAMPP
PHP 7.1.4 (cli)

 質問

Laravel5.5で、Ajax通信を用いたファイルのアップロードができません。
どうやっても、move_uploaded_fileを実行しようとすると、Internet Server Error(500)が返却されてしまいます。
これは何故なのでしょうか?
ご存じの方がいらっしゃいましたら、ご教授いただけると幸いです。

ずっとレガシーコードで書いていたので、フレームワークを触ったことがなく、全然先に進めません……

 コード

表面JavaScrip

<script>

    // ブラウザ上でファイルを展開する挙動を抑止
    function onDragOver(event) {
        console.log('aaa');
        event.preventDefault();
    }

    // Drop領域にドロップしたファイル情報を読み取り
    function onDrop(event) {
        console.log('iii');
        // ブラウザ上でファイルを展開する挙動を抑止
        event.preventDefault();

        // ドロップされたファイルのfilesプロパティを参照
        var files = event.dataTransfer.files;
        if (files.length >= 1) {
            alert(files[0].name + ":" + files[0].size);
            FileUpload(files[0]);
        }
    }

    // ファイルアップロード
    function FileUpload(f) {
        console.log('uuuu');
        var formData = new FormData();
        formData.append('file', f);
        $.ajax({
            type: 'POST',
            dataType : "text",
            contentType: false,
            processData: false,
            url: '/admin/file/upload/',
            data: formData,
            headers: {
                'X-CSRF-TOKEN': '{{ csrf_token() }}'
            }
        }).done(function(json) {
            alert(json);

        }).fail(function(jqXHR, textStatus, errorThrown) {

            console.log(jqXHR);
            alert(textStatus);

        });
    }

    </script>

PHPコントローラー

namespace App\Http\Controllers;

use App\User;
use Request;
use Session;
use App\Http\Controllers\Controller;
use App\Model\Dao\ArticleDao;

class AdminController extends Controller
{
    /**
     * ファイルのアップロード時に通るコントローラー
     *
     * @author Nな人<nnahito>
     * @return view
     */
    public function fileUpload(Request $request) {

        // アップロードファイルが来ているか
        if ( is_uploaded_file($_FILES['file']['tmp_name']) === true ) {

            // 来ていたら、ファイルをアップロードできたか
             if( move_uploaded_file($_FILES['file']['tmp_name'], '/upfiles/'.$_FILES['file']['name']) ){

                 // アップロード成功
                 return response()->json(['status' => 'true']);

             } else {

                 // アップロード失敗
                 return response()->json(['status' => 'false']);

             }

        }

        // そもそもにアップロード失敗
        return response()->json(['status' => 'false']);

    }
}

 修正

ご指摘を受け、PHPのコントローラーを次のように書き直しましたがファイルのアップロードができませんでした……
該当フォルダの権限は777を与えております。

public function fileUpload(Request $request) {

        // ファイルが来ているかのチェック
        if ( $request->hasFile('file') !== true ) {
            return response()->json(['status' => 'false']);
        }

        // 入力ファイルの取得
        $file = $request->file('file');

        // ファイルの保存(戻り値に保存作のパス)
        $path = $request->file('file')->store('upfiles');

        // ファイルが取得できているかのチェック
        if ( $request->file('file')->isValid() !== true ) {
            // 失敗ならエラー
            return response()->json(['status' => 'false']);
        }

        // アップロード成功ならファイルパスも返す
        return response()->json(['status' => 'true', 'path' => $path]);

    }

 参考

  • https://www.erestage.com/develop/drag-and-drop-file-upload/
  • https://qiita.com/zaburo/items/80b94bce19a4a670e465
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • mts10806

    2017/11/14 09:39

    そもそもphpに渡った時点でファイル情報(tmp)はちゃんと想定通りのものが来てるんですかね。

    キャンセル

  • nnahito

    2017/11/14 12:22

    来てますよ

    キャンセル

  • mts10806

    2017/11/14 14:40

    では、どこまで想定通りにきているか(ソース、ファイル実体)を確認した上で質問に追記された方が良いかと思います。

    キャンセル

回答 3

+1

Laravelでのファイルアップロード方法はこれです。
https://readouble.com/laravel/5.5/ja/requests.html#files
素のPHPでのやり方とかは全部忘れたほうがいいです。
とはいえ正常にアップできてるかの確認とファイルの保存なのでやることは同じです。

まずJSを使わず普通のファイルアップロードから試したほうがいいです。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/11/13 23:24

    ご回答ありがとございます。
    早速、変更したところエラーは出なくなりました。

    しかし、アップロードのパスは取得できるのですが、実際にファイルがアップロードできておりません。
    こちら、$request->photo->store('');メソッドはどこからの相対パスになるのでしょうか?
    publicフォルダでしょうか?

    また、
    > 素のPHPでのやり方とかは全部忘れたほうがいい
    これは何故でしょうか?

    キャンセル

  • 2017/11/14 09:15

    横からの意見になってしまいますが…

    >> 素のPHPでのやり方とかは全部忘れたほうがいい
    > これは何故でしょうか?
    Laravel独自の書き方で書いている箇所と、素のPHPの書き方で書いている箇所が混在すると、かなり問題になるからです。例えばなんらかの処理Aを書こうとしたとき、素のPHPでは本当にAのことしかやらないですが、Laravelの書き方で書くと、Aのセキュリティ向上やアクセス効率向上の為に必要なことBもやってくれている、という可能性があるからです。そして、なんらかの処理Cをするとき、Aの処理を素のPHPでやっていた場合、本来あるはずのBの処理が抜けていてバグになるからです。

    あと、storeメソッドで保存される先はlaravelプロジェクトフォルダ/storage以下です。ただし、設定でストレージの場所をアマゾンS3等に変えていた場合、クラウド上のストレージに保存されます。

    キャンセル

  • 2017/11/14 22:33

    ご返信ありがとうございます。

    > Laravel独自の書き方で書いている箇所と、素のPHPの書き方で書いている箇所が混在すると、かなり問題になるからです。
    なるほどそういうことだったのですね。
    ありがとうございます。

    > あと、storeメソッドで保存される先はlaravelプロジェクトフォルダ/storage以下です。
    こちら知識不足でした。
    すべてpublicフォルダ配下に行くものだと思っておりました。

    キャンセル

checkベストアンサー

0

Laravelのファイルアップロードの補足としては、公式ドキュメント翻訳の以下の箇所になります。
Laravel 5.5 ファイルストレージ ファイルアップロード
保存場所は、config/filesystems.phpの設定により決まります。
画像保存の場合は、以下のライブラリも使いやすいかと思います。
spatie/laravel-medialibrary
Getting started with Laravel Medialibrary

機能の基盤になっているものはflysystemライブラリで、Laravelでの初期サポート形式以外にも必要に応じてSftp等も使えます。
thephpleague/flysystem

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/11/14 22:42

    ご回答ありがとうございます。

    ファイルは/storageフォルダまで上げることができたのですが、これは結局ユーザに表示できません。
    こちらどのようにしてユーザに画像を表示するのでしょうか。

    キャンセル

  • 2017/11/14 22:46

    失礼いたしました。
    画像は、URLをルートからアップロードしたパスに変更すると普通に表示できました。

    キャンセル

  • 2017/11/14 22:48

    disksをpublicとして、Storageフォルダにデータをアップロードした後は、
    以下のコマンドで、storage/app/publicから公開ディレクトリのpublic/storageにシンボリックリンクを貼るコマンドがあるので活用できると思います。
    ```
    php artisan storage:link
    ```
    [Laravel 5.5 ファイルストレージ パブリックディスク](https://readouble.com/laravel/5.5/ja/filesystem.html#file-uploads#the-public-disk)

    キャンセル

  • 2017/11/14 22:49

    ではなかったです……envいじって、アップロード先を変更してました

    キャンセル

  • 2017/11/14 22:50

    なるほど!そういうことができるのですね!!
    ありがとうございます!

    キャンセル

0

修正例について書いていきます。
この手の質問の場合は、viewsroutesの内容も提示して頂けるとありがたいです。

まずviewsは下記の様にしました。(抜粋)javascriptから呼ばれるURLをurl: '{{ route('fileUpload') }}に変更しています。

        <div id="file_upload_section">
            <div id="drop" style="width:380px; height:100px; padding:10px; border:3px solid;" ondragover="onDragOver(event)" ondrop="onDrop(event)">
                ファイルをドラッグアンドドロップしてください。
            </div>
        </div>
    </body>

    <script src="{{ asset('js/jquery-3.1.1.min.js') }}"></script>

    <script>
        // ブラウザ上でファイルを展開する挙動を抑止
        function onDragOver(event) {
            console.log('aaa');
            event.preventDefault();
        }

        // Drop領域にドロップしたファイル情報を読み取り
        function onDrop(event) {
            console.log('iii');
            // ブラウザ上でファイルを展開する挙動を抑止
            event.preventDefault();

            // ドロップされたファイルのfilesプロパティを参照
            var files = event.dataTransfer.files;
            if (files.length >= 1) {
                alert(files[0].name + ":" + files[0].size);
                FileUpload(files[0]);
            }
        }

        // ファイルアップロード
        function FileUpload(f) {
            console.log('uuuu');
            var formData = new FormData();
            formData.append('file', f);
            $.ajax({
                type: 'POST',
                dataType : "text",
                contentType: false,
                processData: false,
                url: '{{ route('fileUpload') }}',//ここを変更
                data: formData,
                headers: {
                    'X-CSRF-TOKEN': '{{ csrf_token() }}'
                }
            }).done(function(json) {
                alert(json);

            }).fail(function(jqXHR, textStatus, errorThrown) {

                console.log(jqXHR);
                alert(textStatus);

            });
        }
    </script>

で、定義しているrouteはこちらです。api.phpを修正しています。

Route::Post('/admin/file/upload/','AdminController@fileUpload')->name('fileUpload');

Controllerは、このままでも動きます。強いて言うなら

        // 入力ファイルの取得
        $file = $request->file('file');
        // ファイルの保存(戻り値に保存作のパス)
        $path = $request->file('file')->store('upfiles');


        // 入力ファイルの取得
        $file = $request->file('file');
        // ファイルの保存(戻り値に保存作のパス)
        $path = $file->store('upfiles');


とか

        // 入力ファイルの取得
        //$file = $request->file('file');いらない
        // ファイルの保存(戻り値に保存作のパス)
        $path = $request->file('file')->store('upfiles');


の方が良さげですが…余談なので放っておいてもいいです。

これによりアップロードファイルは、app/upfiles配下に格納されるはずです。

如何でしょうか?

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/11/14 22:39

    ご回答ありがとうございます。

    > viewsとroutesの内容も提示して頂けるとありがたいです
    失礼いたしました。
    Controllerまでデータの通信を確認していたので省略してしまいました。
    また、「toreメソッドで保存される先はlaravelプロジェクトフォルダ/storage以下」ということも知らず、アップロードに失敗していると勘違いしておりました。

    また、丁寧なサンプルコードをありがとうございます。
    今のところ、問題なくweb.phpでのアクセスで動いておりますが、こちらapi.phpの方がよろしいのでしょうか?
    また、/strageに上がったファイルは表面で表示させることができないのでしょうか?

    キャンセル

  • 2017/11/14 22:46

    失礼いたしました。
    画像は、URLをルートからアップロードしたパスに変更すると普通に表示できました。

    キャンセル

  • 2017/11/14 22:49

    ではなかったです……envいじって、アップロード先を変更してました

    キャンセル

  • 2017/11/15 09:24

    解決したようなので余談になりますが…

    >api.phpの方がよろしいのでしょうか?
    Ajaxで通信していたので、何となくAPIで組んでたのかな?という推測です。こだわらなくても良いとは思います。個人的にはWebページに関するルーティングはweb.phpでAjaxでデータを取ってくる処理などにはapi.phpを使っています。

    キャンセル

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

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

関連した質問

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

  • PHP

    17812questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

  • Laravel 5

    1454questions

    Laravel 5は、PHPフレームワークLaravelの最新バージョンで、2014年11月に発表予定です。ディレクトリ構造がが現行版より大幅に変更されるほか、メソッドインジェクションやFormRequestの利用が可能になります。