ドラッグ&ドロップでファイルアップロード

「HTML5とJavascriptによるドラッグ&ドロップ操作でファイルなどをサーバにアップロードするコード」です。いざ作ろうと思って調べてみると古い情報ばかりでどうにもこうにもアレだったので、わりと最近のFirefox、Safari、IE、Chromeで動くようなものを作ってここに置いときます。

index.html

<html>
<head>
<meta charset="UTF-8">
<style type="text/css">
#droparea {
 background-color: #ddd;
 border: dashed 4px #bbb;
 border-radius: 20px 20px 20px 20px;
 width: 400px;
 padding: 20px;
 font-family: Century Gothic;
 font-size: 36px;
 text-align: center;
 color: #bbb;
}
#droparea.dropover {
 background-color: #eee;
 border: dashed 4px #ccc;
 color: #ccc;
}
</style>
<script type="text/javascript">
window.onload = function( ) {
 var msg = document.getElementById( 'message' );  var darea = document.getElementById( 'droparea' );
 darea.addEventListener( 'drop', function( event ) {   var dt = event.dataTransfer;   var files = dt.files;
  var fd = new FormData( );   var xhr= new XMLHttpRequest( );
  event.preventDefault( );   hideDropping( );
  fd.append( "a", "This is A" );   fd.append( "b", "This is B" );   for ( var i = 0, len = files.length; i < len; i++ ) {    fd.append( 'file[]', files[ i ] );   }
  xhr.open( "POST", encodeURI( "upload.php" ) );   xhr.upload.onprogress = function( evt ) {    msg.innerHTML = Math.floor( (evt.loaded / evt.total ) * 100 ) + '%';   }
  xhr.upload.onloadend = function( evt ) {    msg.innerHTML = '100% Successfull';    setTimeout( function ( ) { msg.innerHTML = '&nbsp'; }, 5000 );   }
  xhr.onreadystatechange = function ( evt ) {    if ( xhr.readyState == 4 ) {     if ( xhr.status == 200 ) {      if ( xhr.responseText.length > 1 ) {       msg.innerHTML = xhr.responseText;       setTimeout( function ( ) { msg.innerHTML = '&nbsp'; }, 7000 );      }     } else {      msg.innerHTML = "can't access to the server";      setTimeout( function ( ) { msg.innerHTML = '&nbsp'; }, 7000 );     }    }   };
  xhr.send( fd );
 } );
 darea.addEventListener( 'dragover', function( evt ) {   evt.preventDefault( );   evt.dataTransfer.dropEffect = 'copy';   showDropping( );  } );
 darea.addEventListener( 'dragleave', function( evt ) {   hideDropping( );  } );
 function showDropping( ) {   darea.classList.add( 'dropover' );  }
 function hideDropping( ) {   darea.classList.remove( 'dropover' );  }
}; </script> </head> <body>
<div id="droparea" effectAllowed="move"> Drop files here!<br> <span id="message">&nbsp;</span> </div>
</body> </html>

update.php


<?php
 //print $_POST[ "a" ]."<br>\n";  //print $_POST[ "b" ]."<br>\n";
 $uploaddir = '/path to directory/';
 foreach ( $_FILES[ "file" ][ "error" ] as $key => $value ) {   $file_name = basename( $_FILES["file"]["name"][$key] );   $file_type = $_FILES["file"]["type"][$key];   $file_size = $_FILES["file"]["size"][$key];   $file_temp = $_FILES["file"]["tmp_name"][$key];
  if ( $file_size > 10000000 ) {    print "err:data size > 10MB";    return;   }
  //print $file_name." ".$file_type." ".$file_size." ".$file_temp."<br>\n";
  $status = "error";
  if( is_uploaded_file( $file_temp ) )    $status = move_uploaded_file( $file_temp, $uploaddir.$file_name ) ? 'success': 'error';
  //print $status."<br>\n";  }
?>

ファイルサイズのチェックを upload.phpの中で行っていますが、index.htmlのなかでやったほうがいいですよね。エラーメッセージの表示テストのため、あえてこうしてあります。

(少し書きかえれば)ファイルタイプを調べてアップロードできるファイルとできないファイルを判別するとか、選択したテキストをドラッグ&ドロップで送信することもできるようになります。

実行の様子:

Firefoxで index.htmlを表示しているところです。線種を dashedにして borderの角を丸くすると、角がつぶれるのが超絶気になります。IEではきれいに点々のままコーナーが丸くなるんですけど。

HTML5 Javascript File Drag & Drop

デスクトップからファイルをドラッグしてきます。1つでも複数でもOKです。ドロップ領域に入ると領域がハイライト表示になります。

HTML5 Javascript File Drag & Drop

ファイルをドロップするとサーバへの送信が始まります。データ送信の進捗がパーセント表示されます。ファイル各々の進捗ではなく、”全体”の進捗です。

HTML5 Javascript File Drag & Drop

送信がおわり、サーバのほうでエラーなく処理されていれば↓のようになります。スペルミスしていて、ただしくは"Successful"(笑)

HTML5 Javascript File Drag & Drop

update.phpでファイルサイズ制限を 100kバイトに変更してファイルをアップしてみた結果。このスクリプトでは100kバイト以上のファイルに行きあたった時点で処理終了するようになっています。

HTML5 Javascript ファイル アップロード ドラッグ ドロップ

 

 

修正

xhr.send の場所をハンドラの後に移動しました。もとは xhr.openの直後に書いてたんですが、そうするとonprogressのハンドラが実行されず。以前は動いたんですけどねー。