23

Jqueryを使ってHTML5ドラッグ&ドロップファイルアップロード

LINEで送る
Pocket

今のプロジェクトでドラッグ&ドロップでブラウザファイルアップロードの機能がいる。
検索してみたらたくさん方法が出てきます。その中一番いいと思うのはJqueryを使ってファイルアップロード。
とても勉強になりました、英語のページを翻訳して、ここに転載します。

原文はこちら

これに対してサーバー側のファイル保存について、下記リンクを参照してください。
phpサーバーアップロードファイル保存

*****以下は翻訳内容です*****

jQueryドラッグ&ドロップファイルアップロードの例で、HTML5およびjQuery AJAX APIを使用して、ドラッグ・アンド・ドロップ・ファイル・アップロードを実現する方法について説明しました。
ドラッグ&ドロップはHTML5をサポートするブラウザのみ使えます。
サポートされたブラウザは次のとおりです: IE 10+、Firefox、Chrome、Safari、Opera
live-demo
drag-and-drop-file-upload-jquery

上記のイメージで示されるようにドラッグ&ドロップファイルをアップロードさせるステップに従ってください。

ステップ1、jQueryライブラリをHTMLに引用

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>

ステップ2、divタグをアップロード処理したいの所に追加

<div id="dragandrophandler">ここにドロップしてください。</div>

アップロードのdivタグに下記のようなCSSを適用します。

#dragandrophandler
{
border:2px dotted #0B85A1;
width:500px;
color:#92AAB0;
text-align:left;vertical-align:middle;
padding:10px 10px 10 10px;
margin-bottom:10px;
font-size:200%;
}

ステップ3、jQueryでドラッグ&ドロップイベントをハンドル

var obj = $("#dragandrophandler");
obj.on('dragenter', function (e) 
{
    e.stopPropagation();
    e.preventDefault();
    $(this).css('border', '2px solid #0B85A1');
});
obj.on('dragover', function (e) 
{
     e.stopPropagation();
     e.preventDefault();
});
obj.on('drop', function (e) 
{
 
     $(this).css('border', '2px dotted #0B85A1');
     e.preventDefault();
     var files = e.originalEvent.dataTransfer.files;
 
     //We need to send dropped files to Server
     handleFileUpload(files,obj);
});

ファイルがdivの外でドロップされた場合、ブラウザで開いてしまいます。それを避けるため、documentの「ドロップ」イベントを防ぐ。

$(document).on('dragenter', function (e) 
{
    e.stopPropagation();
    e.preventDefault();
});
$(document).on('dragover', function (e) 
{
  e.stopPropagation();
  e.preventDefault();
  obj.css('border', '2px dotted #0B85A1');
});
$(document).on('drop', function (e) 
{
    e.stopPropagation();
    e.preventDefault();
});

ステップ4、ファイルがドロップされた時に、HTML5のFormData()を使って、ファイルの中身を読み

function handleFileUpload(files,obj)
{
   for (var i = 0; i < files.length; i++) 
   {
        var fd = new FormData();
        fd.append('file', files[i]);
 
        var status = new createStatusbar(obj); //Using this we can set progress.
        status.setFileNameSize(files[i].name,files[i].size);
        sendFileToServer(fd,status);
 
   }
}

ステップ5、jQuery AJAX APIを使って、FormData()をサーバーに送信

function sendFileToServer(formData,status)
{
    var uploadURL ="http://hayageek.com/examples/jquery/drag-drop-file-upload/upload.php"; //Upload URL
    var extraData ={}; //Extra Data.
    var jqXHR=$.ajax({
            xhr: function() {
            var xhrobj = $.ajaxSettings.xhr();
            if (xhrobj.upload) {
                    xhrobj.upload.addEventListener('progress', function(event) {
                        var percent = 0;
                        var position = event.loaded || event.position;
                        var total = event.total;
                        if (event.lengthComputable) {
                            percent = Math.ceil(position / total * 100);
                        }
                        //Set progress
                        status.setProgress(percent);
                    }, false);
                }
            return xhrobj;
        },
        url: uploadURL,
        type: "POST",
        contentType:false,
        processData: false,
        cache: false,
        data: formData,
        success: function(data){
            status.setProgress(100);
 
            //$("#status1").append("File upload Done<br>");           
        }
    }); 
 
    status.setAbort(jqXHR);
}

まとめる

以上ステップのソースを纏めって、ドラッグ&ドロップファイルアップロードのサンプルは下記のようになります。

<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<style>
#dragandrophandler
{
border:2px dotted #0B85A1;
width:500px;
color:#92AAB0;
text-align:left;vertical-align:middle;
padding:10px 10px 10 10px;
margin-bottom:10px;
font-size:200%;
}
.progressBar {
    width: 200px;
    height: 22px;
    border: 1px solid #ddd;
    border-radius: 5px; 
    overflow: hidden;
    display:inline-block;
    margin:0px 10px 5px 5px;
    vertical-align:top;
}
 
.progressBar div {
    height: 100%;
    color: #fff;
    text-align: right;
    line-height: 22px; /* same as #progressBar height if we want text middle aligned */
    width: 0;
    background-color: #0ba1b5; border-radius: 3px; 
}
.statusbar
{
    border-top:1px solid #A9CCD1;
    min-height:25px;
    width:700px;
    padding:10px 10px 0px 10px;
    vertical-align:top;
}
.statusbar:nth-child(odd){
    background:#EBEFF0;
}
.filename
{
display:inline-block;
vertical-align:top;
width:250px;
}
.filesize
{
display:inline-block;
vertical-align:top;
color:#30693D;
width:100px;
margin-left:10px;
margin-right:5px;
}
.abort{
    background-color:#A8352F;
    -moz-border-radius:4px;
    -webkit-border-radius:4px;
    border-radius:4px;display:inline-block;
    color:#fff;
    font-family:arial;font-size:13px;font-weight:normal;
    padding:4px 15px;
    cursor:pointer;
    vertical-align:top
    }
</style>
</head>
 
<body>
<div id="dragandrophandler">ここにドロップしてください。</div>
<br><br>
<div id="status1"></div>
<script>
function sendFileToServer(formData,status)
{
    var uploadURL ="http://hayageek.com/examples/jquery/drag-drop-file-upload/upload.php"; //Upload URL
    var extraData ={}; //Extra Data.
    var jqXHR=$.ajax({
            xhr: function() {
            var xhrobj = $.ajaxSettings.xhr();
            if (xhrobj.upload) {
                    xhrobj.upload.addEventListener('progress', function(event) {
                        var percent = 0;
                        var position = event.loaded || event.position;
                        var total = event.total;
                        if (event.lengthComputable) {
                            percent = Math.ceil(position / total * 100);
                        }
                        //Set progress
                        status.setProgress(percent);
                    }, false);
                }
            return xhrobj;
        },
    url: uploadURL,
    type: "POST",
    contentType:false,
    processData: false,
        cache: false,
        data: formData,
        success: function(data){
            status.setProgress(100);
 
            $("#status1").append("File upload Done<br>");         
        }
    }); 
 
    status.setAbort(jqXHR);
}
 
var rowCount=0;
function createStatusbar(obj)
{
     rowCount++;
     var row="odd";
     if(rowCount %2 ==0) row ="even";
     this.statusbar = $("<div class='statusbar "+row+"'></div>");
     this.filename = $("<div class='filename'></div>").appendTo(this.statusbar);
     this.size = $("<div class='filesize'></div>").appendTo(this.statusbar);
     this.progressBar = $("<div class='progressBar'><div></div></div>").appendTo(this.statusbar);
     this.abort = $("<div class='abort'>Abort</div>").appendTo(this.statusbar);
     obj.after(this.statusbar);
 
    this.setFileNameSize = function(name,size)
    {
        var sizeStr="";
        var sizeKB = size/1024;
        if(parseInt(sizeKB) > 1024)
        {
            var sizeMB = sizeKB/1024;
            sizeStr = sizeMB.toFixed(2)+" MB";
        }
        else
        {
            sizeStr = sizeKB.toFixed(2)+" KB";
        }
 
        this.filename.html(name);
        this.size.html(sizeStr);
    }
    this.setProgress = function(progress)
    {       
        var progressBarWidth =progress*this.progressBar.width()/ 100;  
        this.progressBar.find('div').animate({ width: progressBarWidth }, 10).html(progress + "% ");
        if(parseInt(progress) >= 100)
        {
            this.abort.hide();
        }
    }
    this.setAbort = function(jqxhr)
    {
        var sb = this.statusbar;
        this.abort.click(function()
        {
            jqxhr.abort();
            sb.hide();
        });
    }
}
function handleFileUpload(files,obj)
{
   for (var i = 0; i < files.length; i++) 
   {
        var fd = new FormData();
        fd.append('file', files[i]);
 
        var status = new createStatusbar(obj); //Using this we can set progress.
        status.setFileNameSize(files[i].name,files[i].size);
        sendFileToServer(fd,status);
 
   }
}
$(document).ready(function()
{
var obj = $("#dragandrophandler");
obj.on('dragenter', function (e) 
{
    e.stopPropagation();
    e.preventDefault();
    $(this).css('border', '2px solid #0B85A1');
});
obj.on('dragover', function (e) 
{
     e.stopPropagation();
     e.preventDefault();
});
obj.on('drop', function (e) 
{
 
     $(this).css('border', '2px dotted #0B85A1');
     e.preventDefault();
     var files = e.originalEvent.dataTransfer.files;
 
     //We need to send dropped files to Server
     handleFileUpload(files,obj);
});
$(document).on('dragenter', function (e) 
{
    e.stopPropagation();
    e.preventDefault();
});
$(document).on('dragover', function (e) 
{
  e.stopPropagation();
  e.preventDefault();
  obj.css('border', '2px dotted #0B85A1');
});
$(document).on('drop', function (e) 
{
    e.stopPropagation();
    e.preventDefault();
});
 
});
</script>
</body>
</html>
LINEで送る
Pocket

管理者

23 Comments

  1. ドラッグ&ドロップでのファイルのアップロードのについていのわかりやすいサイトの説明、ありがとうございます。
    試してみまして、ブラウザではアップロードできるのですが、サーバーにそのファイルを保存するのには、どうすればよろしいのでしょうか?もし、お時間があれば教えて頂ければありがたいです。よろしくどうぞ。

    • ZIROさん
      こんにちは。管理人のKAIです。

      サーバーにアップロードされたファイルの保存、基本にはサーバー側にファイルのコンテンツを受け取ってサーバーのフォルダに保存する。(←_←あたりまえですねへへ)
      言語によって実装方法が違いますが、この基本ルールは変わらないと思います。
      phpサンプルを説明したいと思います。詳しい説明するため、下記ページを作成しました、ご参照ください。
      http://www.it-view.net/php-file-upload-server-save-296.html
      お役に立てれば幸いです。

  2. お世話になります。

    ドラッグ&ドロップの機能の実装をいましておりましてとても参考になりました。

    こちらで4質問することではないのかもしれませんが、ドラッグ&ドロップされたエクセルファイルをphpで配列に格納し、CSVで出力するという機能を実装したいのですが、(PHPExcelを使い配列にする部分はできている)こちらのコードを利用して、サーバーに上げるのではなく、受け取ったファイルをphpに渡すにはどうすればよいでしょうか?

    お手隙の時にでもご教授いただければ幸いです。
    以上、宜しくお願い致します。

    • SHINODAさん

      返事が遅くなってすみません。

      この問題もう解決されたかもしれませんが、
      http://www.it-view.net/php-file-upload-server-save-296.htmlにも書いてます、
      $_FILES[“file”][“tmp_name”]でアップロードされたファイルをサーバーで受け取ることが可能です。
      そして、PHPExcelのloadメソッドを使えばファイルの内容を読み取れます。

      PS:パラメータ名“file”は、フォームのHTMLタグ

      <input type="file" name="パラメータ名">

      で 指定された名称です。

  3. お世話になります。

    ドラッグ&ドロップの実装はできたのですが、8MB辺りを境にファイルサイズが大きなものが保存されないのですが、制限等あるのでしょうか?

    また、フォルダごとアップロードする事は可能でしょうか?

    • ファイルサイズがサーバの制限設定によります。
      例えばphpの場合、php.iniに下記の設定でファイルサイズが制限されます
      1.メモリ使用量の上限(memory_limit)
      2.POSTデータの最大サイズ(post_max_size)
      3.1ファイルあたりの最大アップロードサイズ(upload_max_filesize)

      フォルダのアップロードが出来ないです。

      • ありがとうございます。

        サーバー側の設定を確認するのを忘れていました。
        見直した所、デフォルトの8Mになっていましたので修正し対応できました。

        やはりフォルダ単位は無理なようですね。

  4. 分かりやすいアップロード方法ありがとうございます。
    17時にLIVEDEMOで、サンプル的にアップロードさせていただきましたが、誤って重要なファイルをアップロードしてしまいました。
    申し訳ありませんが、削除していただけないでしょうか
    よろしくお願いいたします

    • Mantenkunさん

      安心してください。
      デモですので、アップロードされたファイルはサーバに保存しないの仕組みになっています。

  5. お世話になります。
    とても分かりやすい説明があり感謝です。

    アップロード先ディレクトリを毎回変化させたいのですが、可能でしょうか?
    cgiで新着記事を書く(+記事noのディレクトリを作成)→作ったディレクトリにアップするための専用ページをcgi側から出す(こちらのページのまとめるの部分に変数($no)を組み込む)→作ったディレクトリに画像をアップ、としたいです。
    その為、上記のhtmlファイルから紹介して頂いている「phpファイルアップロードサーバー保存」のphpファイルにディレクトリ情報を送りたいのですが、どのように記述したらよいでしょうか?

    よろしくお願いします。

  6. 追記
    html81行目を
    var uploadURL =”upload.php?no=10″;
    として、phpの4行目を
    “files/$_get[‘no’]/”

    “files/$_post[‘no’]/”
    としてみましたがアップ(保存)してくれませんでした。
    この程度の知識しかなく申し訳ないです。

    • html172行目に
      fd.append(‘no’,’10’)を追加、渡したいデータをFormDataでサーバに渡します。
      サーバで$_POST["no"]で取れます。

      サーバの書き方もちょっと問題がありますね。
      “files/$_get[‘no’]/”のように””に入れると全部文字列になっちゃうので、"files/" . $_POST["no"] . "/"にしてください。

      ディレクトリがないと保存できないので、ディレクトリを作成しましょう。

      if (!file_exists("files/" . $_POST["no"])){ 
          mkdir ("files/" . $_POST["no"]); 
          echo 'make directory success.';
      } else {
          echo 'directory is already exsist.';
      }
  7. 素早い回答ありがとうございます!!

    無事に組み込むことが出来ました。
    ディレクトリ作成の方はcgiの情報を保存する時に作成するようにしてみました。

    ありがとうございました。

    余談ですが…
    現状では、ファイルをアップした時にhtml側に記載されている「File upload Done」が表記されるのですが、これをphp側に書かれているような「○○(ファイル名)をアップロードしました。」とする事は出来るのでしょうか?

    • >php側に書かれているような「○○(ファイル名)をアップロードしました。」とする事は出来るのでしょうか?
      出来ますよ。
      html107行のdataがサーバから返したデータです。
      このサンプルの場合、データがphpのecho後のメッセージです。
      なので、$("#status1").append(data);でサーバのメッセージが表示されます。

      • 余談にまで素早い返答ありがとうございます。
        無事「○○(ファイル名)をアップロードしました。」の表記に変更出来ました。
        ありがとうございました。

  8. 初めまして。
    初心者なもので、わかりやすいこちらのサイト、大変ありがたく拝見させていただいております。

    突然で大変失礼ながら質問をさせていただきたいのですが、htmlからpython、flaskへデータを受け渡ししたいのですが可能でしょうか。

    こちらに掲載いただいているD&Dを使用させて頂いたのですが、inputを使用しない場合の書き方がわからずご教示いただければと思い質問させていただきました。(現在はinputを使用しファイル選択をしてアップロードしています。)

    全くの初心者で必要な情報が欠けていたり、見当違いなことを申しておりましたら申し訳ございません。
    どうぞ、よろしくお願いいたします。

    以下、現在の内容です。(…はタブです)
    .py
    @app.route(階層/methods=[“GET “,”POST “])
    def upload():
    if request method == “POST”
    …print(“post”)
    …upload_files = request.files.getlist(“up_file”)

    .html

    submit

    • 何度もすみません。
      うまくコメントが反映されないみたいで、申し訳ありません。

      .html
      〈form method=”post” action=”階層” target=”_blank”〉
      〈input type=”file” name=”up_file” enctype=”multiple” 〉
      〈button type=”submit” submit /button〉

    • pythonはもちろん使えます。
      flaskを使った場合request.files['file']でアップロードしたファイルを受け取れると思います。

      • お世話になります。
        早急なご返信ありがとうございます。

        一般的はファイル参照の場合はhtml側でinputにnameで名前(up_file)を定義しpythonと対応させておりますが、今回ご教示頂いているD&Dではinputを使用しておりませんが、その辺りはどのように関連付けているのでしょうか。html側はformとsubmitのみでしょうか。

        度々初歩的な事ばかり恐れ入ります。
        ご教示いただければ幸いです。

        • クライアントのソースはサンプルのまま使っていいです。
          formとinputの代わりに、jarascriptでフォームデータを作成しています。

          var fd = new FormData();
          fd.append('file', files[i]);
          

          ※サンプルのAjaxのURLをFormのPost先URLに変更してください。

          • ご丁寧にありがとうございます。

            どうやら根本的なことを誤っておりました。
            ドロップすると随時アップされるのですね。認識不足ですみません。

            複数ファイルを一括でアップすることも可能なのでしょうか。

            何度も何度も申し訳ございません。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です