ドラッグ&ドロップで複数画像をアップロードする

2017-05-23

今更感が有りますしあちこちで紹介されていますが、とある案件で画像アップロードが必要になり、昔ながらの画像選択ボタンをと考えていたのですが、SNS等の利用経験があると画像はドラッグドロップで複数枚をいっぺんにアップロード出来るものだと知ってらっしゃる方も多く・・・プラグイン等も公開されてはいるのですが、企業の基幹システム系等、機密性を重視するプログラムではあまり使いたくは有りませんので、自作する事にしました。

ちなみに、FileAPI非搭載のブラウザは動作しません。まぁIE9以下ですが・・・そろそろIE10以上前提で書きたいですね・・・IE7で表示がおかしい!バグだ!っと指摘される事が未だにままあるので(泣

ドラッグ&ドロップで画像をアップロードする

サンプル

先ずはドラッグドロップで即画像をアップロードする簡単なサンプルです。

 

画像をドラッグする場所へ、ondragoverとondropイベントをセットします。

<div id="iamgeArea" ondragover="dragover(event)" ondrop="drop(event)">ファイルをドラッグアンドドロップ</div>

 

ブラウザへ画像をドロップすると画像が表示されてしまいますので、それぞれのfunctionには下記のように記述し、画像表示しないようにします。

function dragover(e) {
    e.preventDefault();
}

 

ドロップするとevent.dataTransfer.filesに画像の情報が配列でセットされていますので、forで回してアップロード処理を行います。

function drop(e) {
  e.preventDefault();
  var files = e.dataTransfer.files;
  for (var i=0; i<files.length; i++) {
    //画像じゃない場合はスルー
    if (!files[i] || files[i].type.indexOf('image/') < 0) {
      continue;
    }
    //アップロード処理へ
    FileUpload(files[i]);
  }
}

ファイル情報はコンソールで見ると以下のようなもの

 

あとは同期通信でPHPに渡し、アップロード処理を行います。

function FileUpload(fd) {
    var formData = new FormData();
    formData.append('image', fd);
    $.ajax({
      async: true,
      type: 'POST',
      contentType: false,
      processData: false,
      url: 'ImageUp_1.php',
      data: formData,
      dataType :'xml'
    }).done(function(xml){
      var mes  = $(xml).find("mes").text();
      var file = $(xml).find("file").text();
      var flag = $(xml).find("flag").text();
      if(flag == 1){
        $('#imagebox').append('<img src="upload/'+file+'">');
      }
    });
}

PHPは以下のような簡単なもの

<?php

$flag         = false;
$path         = 'upload/';
$_filedata    = $_FILES['image'];
$ext          = substr($_filedata['name'],-3);
$ext          = strtolower($ext);
$size         = $_filedata['size'];
$fname_origin = str_replace(".".$ext,"",$_filedata['name']);
$filename     = time().'_'.$fname_origin;

if($size < 5000000){
	$new_upload_file  = $path . $filename . "." . $ext;
	if (move_uploaded_file($_filedata['tmp_name'], './' . $new_upload_file)) {
		$mes     = 'UPロードが完了しました';
		$flag    = true;
	} else {
		$mes = 'アップロードエラー';
	}
}else{
	$mes = 'サイズが大きすぎます。';
}

header("Content-type: application/xml");
echo '<?xml version="1.0" encoding="UTF-8" ?> ' . "\n";
?>
<rss>
  <item xml:space="preserve">
      <mes><?php echo $mes; ?></mes>
      <file><?php echo $filename.'.'.$ext; ?></file>
      <flag><?php echo $flag; ?></flag>
  </item>
</rss>

実際はファイル形式をチェックしたりリサイズしたり等様々な事をPHPで行いますが、要はアップロードしてファイル名を返してあげるだけの単純なものです。

 

プログレスバーを表示して格好良くアップロード

どうせなら画像アップロード状態を示すプログレスバーを表示して格好よくしてみます。

サンプル

アップロード時のAjaxにXHRを設定し、XMLHttpRequestUploadからアップロードプロセスを得ます。progressの数値をパーセンテージとしてspanの長さをアニメーションさせています。光回線ですとよほど大きな画像じゃなければ一瞬で終わってしまいますが。

 

アップロード前に画像をプレビューさせる

画像はアップロードしなくとも、どのファイルを選択したかプレビューする事が出来ます。

サンプル

 

ファイルをドロップした際にFileReaderで画像をプレビューします。

function drop(e) {
  e.preventDefault();
  files = e.dataTransfer.files;
  $('#prevbox ul li').remove();
  for (var i=0; i<files.length; i++) {
    if (!files[i] || files[i].type.indexOf('image/') < 0) {
      continue;
    }
    var fileReader = new FileReader();
    fileReader.onload = function( event ) {
      var loadedImageUri = event.target.result;
      $("<li><img src='"+loadedImageUri+"'></li>").appendTo("#prevbox ul");
    };
    fileReader.readAsDataURL( files[i] );
  }
  $("#prevbox").after('<button type="button" class="btn btn-success" id="btn" onclick="Upload()">Upload</button>');
}

ファイルのURLはevent.target.resultで取り出せますので、それをIMGタグで表示するだけ。

あとはボタンを押したらアップロード処理を実行ですね。

実際はもっと小綺麗にCSSを書き、プレビューからアップロードしたい画像を選択させたりなどUIを凝りますが、基本的な事を押さえておけば応用が効きますので。