HTML5 + jQueryで複数ファイルのアップロード時、プログレスバーを表示

HTML5 + jQueryで複数ファイルのアップロードを試してみました。
CodeIgniter 3 + HTML5 FileAPI + jQueryで複数ファイルのアップロード

アップロードの進捗を表示するプログレスバーを表示してみます。

progress



HTML5で、プログレスバーを表示するタグが追加されました。
これを使用して進捗表示してみます。

今回もCodeIgniter 3と組み合わせて使用してみます。


・application/views/fileupload.php


  1. <html>
  2. <head>
  3.     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  4.     <title>ファイルアップロード</title>
  5.     <script src="//code.jquery.com/jquery-2.2.3.min.js" integrity="sha256-a23g1Nt4dtEYOj7bR+vTu7+T8VP13humZFBJNIYoEJo=" crossorigin="anonymous"></script>
  6.     <script>
  7. <!--
  8. $(function(){
  9.     
  10.     // ファイルのアップロード処理
  11.     var uploadFiles = function(files) {
  12.         // FormDataオブジェクトを用意
  13.         var fd = new FormData();
  14.         
  15.         // ファイルの個数を取得
  16.         var filesLength = files.length;
  17.         // ファイル情報を追加
  18.         for (var i = 0; i < filesLength; i++) {
  19.             console.log(files[i]["name"]);
  20.             fd.append("files[]", files[i]);
  21.         }
  22.         // Ajaxでアップロード処理をするファイルへ内容渡す
  23.         $.ajax({
  24.             url: 'fileupload/upload',
  25.             type: 'POST',
  26.             data: fd,
  27.             processData: false,
  28.             contentType: false,
  29.             xhr : function(){
  30.                 var XHR = $.ajaxSettings.xhr();
  31.                 XHR.upload.addEventListener('progress',function(e){
  32.                     var progre = parseInt(e.loaded/e.total * 100);
  33.                     $('#prog').val(progre);
  34.                     $('#pv').html(progre);
  35.                 });
  36.                 return XHR;
  37.             }
  38.             
  39.             
  40.         }).done(function(data) {
  41.             console.log(data);
  42.             
  43.         }).fail(function(data) {
  44.             console.log(data.responseText);
  45.         });
  46.     };
  47.     
  48.     // ファイルドロップ時の処理
  49.     $('#drag-area').on('drop', function(e){
  50.         // デフォルトの挙動を停止
  51.         e.preventDefault();
  52.         // ファイル情報を取得
  53.         var files = e.originalEvent.dataTransfer.files;
  54.         uploadFiles(files);
  55.     
  56.     
  57.     // デフォルトの挙動を停止 これがないと、ブラウザーによりファイルが開かれる
  58.     }).on('dragenter', function(){
  59.         return false;
  60.     }).on('dragover', function(){
  61.         return false;
  62.     });
  63.     
  64.     
  65.     // ボタンを押した時の処理
  66.     $('#btn').on('click', function() {
  67.         // ダミーボタンとinput[type="file"]を連動
  68.         $('#file_selecter').click();
  69.     });
  70.     $('#file_selecter').on('change', function(){
  71.         // ファイル情報を取得
  72.         var files = this.files;
  73.         uploadFiles(files);
  74.     });
  75. });
  76. -->
  77. </script>
  78. </head>
  79. <body>
  80. <div id="drag-area" style="border-style: dashed;background-color: #042943; color: #ffffff;">
  81. <p>アップロードするファイルをドロップ</p>
  82. <p>または</p>
  83. <div class="btn-group">
  84.     <input id="file_selecter" type="file" multiple="multiple" style="display:none;" name="files"/>
  85.     <button id="btn">ファイルを選択</button>
  86. </div>
  87. </div>
  88. <progress value="0" id="prog" max=100></progress>(<span id="pv" style="color:#00b200">0</span>%)
  89. </body>
  90. </html>




コントローラー側は前回と同様です。

・application/controllers/Fileupload.php


  1. <?php
  2. class Fileupload extends CI_Controller {
  3.     
  4.     // アップロード用の画面を表示
  5.     public function index() {
  6.         $this->load->view('fileupload');
  7.     }
  8.     // 画像アップロード
  9.     public function upload() {
  10.         
  11.         $count = count($_FILES['files']['tmp_name']);
  12.         
  13.         for ($i = 0 ; $i < $count ; $i ++ ) {
  14.             
  15.             $tmp_name = $_FILES["files"]["tmp_name"][$i];
  16.             if (!is_uploaded_file($tmp_name)) {
  17.                 continue;
  18.             }
  19.         
  20.             move_uploaded_file($tmp_name, FCPATH.$_FILES["files"]["name"][$i]);
  21.         }
  22.                 
  23.         // 保存結果を返信
  24.         $this->output
  25.             ->set_content_type('application/json')
  26.             ->set_output(json_encode(['result' => $count]));
  27.         
  28.     }
  29. }




初期表示

690_01.png


ファイルを選択すると、プログレスバーに進捗が表示されました。

690_02.png




PHP Warning: Maximum number of allowable file uploads




複数ファイルをまとめて1回でPOSTするため、
選択したファイルの総容量が大きくなるとサーバー側のPOST値の上限を
あっさり超えてしまいます。
また、phpのデフォルトでは1回のPOSTでアップロードできるファイル数は20個までです。

これらの制約を加味して、プログラムを修正してみました。


  1. <html>
  2. <head>
  3.     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  4.     <title>ファイルアップロード</title>
  5.     <script src="//code.jquery.com/jquery-2.2.3.min.js" integrity="sha256-a23g1Nt4dtEYOj7bR+vTu7+T8VP13humZFBJNIYoEJo=" crossorigin="anonymous"></script>
  6.     <script>
  7. <!--
  8. $(function(){
  9.     
  10.     // フォームデータのアップロード処理
  11.     var uploadFormData = function(fd, totalBytes, tasks, index) {
  12.         
  13.         var xhr_func = function(){
  14.             var XHR = $.ajaxSettings.xhr();
  15.             XHR.upload.addEventListener('progress',function(e){
  16.                 tasks[index] = e.loaded;
  17.                 
  18.                 var upload = 0;
  19.                 tasks.forEach(function(bytes) {
  20.                     upload += bytes;
  21.                 });
  22.                 
  23.                 var progre = parseInt(upload/totalBytes * 100);
  24.                 
  25.                 $('#prog').val(progre);
  26.                 $('#pv').html(progre);
  27.             });
  28.             return XHR;
  29.         };
  30.         
  31.         
  32.         // Ajaxでアップロード処理をするファイルへ内容渡す
  33.         $.ajax({
  34.             url: 'fileupload/upload',
  35.             type: 'POST',
  36.             data: fd,
  37.             processData: false,
  38.             contentType: false,
  39.             xhr : xhr_func
  40.             
  41.         }).done(function(data) {
  42.             console.log(data);
  43.             
  44.         }).fail(function(data) {
  45.             console.log(data.responseText);
  46.         });
  47.         
  48.     };
  49.     
  50.     
  51.     // ファイルのアップロード処理
  52.     var uploadFiles = function(files) {
  53.         
  54.         // ファイルの個数を取得
  55.         var filesLength = files.length;
  56.         
  57.         // 選択されたファイルの総容量を取得
  58.         var totalBytes = 0;
  59.         for (var i = 0; i < filesLength; i++) {
  60.             totalBytes += files[i].size;
  61.         }
  62.         console.log(totalBytes);
  63.         
  64.         var fd = new FormData();
  65.         var fdBytes = 0;
  66.         var fdCount = 0;
  67.         var tasks = [];
  68.         for (var i = 0; i < filesLength; i++) {
  69.             // 指定バイト数を超えないかチェック
  70.             var currentBytes = files[i].size;
  71.             if (((fdBytes + currentBytes) >= 8000000) || (fdCount >= 20)) {
  72.                 // 超えたらアップロード実行
  73.                 tasks.push(0);
  74.                 uploadFormData(fd, totalBytes, tasks, tasks.length - 1);
  75.                 fd = new FormData();
  76.                 fdBytes = 0;
  77.                 fdCount = 0;
  78.             }
  79.             
  80.             fdBytes += currentBytes;
  81.             fdCount += 1;
  82.             fd.append("files[]", files[i]);
  83.         }
  84.         
  85.         if (fdCount > 0) {
  86.             tasks.push(0);
  87.             uploadFormData(fd, totalBytes, tasks, tasks.length - 1);
  88.         }
  89.     };
  90.     
  91.     // ファイルドロップ時の処理
  92.     $('#drag-area').on('drop', function(e){
  93.         // デフォルトの挙動を停止
  94.         e.preventDefault();
  95.         // ファイル情報を取得
  96.         var files = e.originalEvent.dataTransfer.files;
  97.         uploadFiles(files);
  98.     
  99.     
  100.     // デフォルトの挙動を停止 これがないと、ブラウザーによりファイルが開かれる
  101.     }).on('dragenter', function(){
  102.         return false;
  103.     }).on('dragover', function(){
  104.         return false;
  105.     });
  106.     
  107.     
  108.     // ボタンを押した時の処理
  109.     $('#btn').on('click', function() {
  110.         // ダミーボタンとinput[type="file"]を連動
  111.         $('#file_selecter').click();
  112.     });
  113.     $('#file_selecter').on('change', function(){
  114.         // ファイル情報を取得
  115.         var files = this.files;
  116.         uploadFiles(files);
  117.     });
  118. });
  119. -->
  120. </script>
  121. </head>
  122. <body>
  123. <div id="drag-area" style="border-style: dashed;background-color: #042943; color: #ffffff;">
  124. <p>アップロードするファイルをドロップ</p>
  125. <p>または</p>
  126. <div class="btn-group">
  127.     <input id="file_selecter" type="file" multiple="multiple" style="display:none;" name="files"/>
  128.     <button id="btn">ファイルを選択</button>
  129. </div>
  130. </div>
  131. <progress value="0" id="prog" max=100></progress>(<span id="pv" style="color:#00b200">0</span>%)
  132. </body>
  133. </html>




これで100ファイルまとめて選択してもアップロードできるようになりました。

ただ、1ファイルで8MB以上だとエラーになります。
これに関しては別の対策を考えてみます。


【参考URL】

$.ajaxファイルアップロードでプログレスバーを表示する。

HTML5 進捗状況を表示するプログレスバーを使ってみる

JavaScript で File API を使用してファイルを読み取る

関連記事

コメント

管理人のみ閲覧できます

このコメントは管理人のみ閲覧できます

プロフィール

Author:symfo
blog形式だと探しにくいので、まとめサイト作成中です。
https://symfo.web.fc2.com/

PR

検索フォーム

月別アーカイブ