webプロダクトいんふぉ

webの気になった情報を発信中!!

ファイルアップロードをドラッグ&ドロップでも可能にする

ファイルアップロードするには?

フロント側のHTMLもしくはPHPファイルにフォームの記述をします。

<form action="" method="post" enctype="multipart/form-data">
  <input type="file" value="ファイルを選択" name="image">
  <input type="value" value="送信">
</form>

画像を扱う場合にはenctype部分が必須になります。他にもinputタグにaccept属性を指定することにより、画像の形式をpng、jpgのみ受け付けるようにすることなどもできますが、今回は必要最低限で説明していきます。

次に画像ファイルを受け取る裏側を書いていきます。詳しくは説明しないんですが、1行目のif文で画像データが問題なく送られているかチェックします。問題がなければ4・5行目でアップロードしたファイル名と拡張子を取得します
ex)test.png→$filename=test、$extension=png

$tmp_pathでアップロード画像が仮で置かれているパスを取得します。

$file_dir_pathでアップロードした画像をどこに置くかを選択。今回は同階層のuploadフォルダに格納するようにする。

$uniq_nameは同じファイル名でアップロードした場合は上書きされて古い画像が消えてしまうのを避けるために格納する際にユニークな名前をつけて画像が上書きされるのを避けます。

入れ子になった最初のif文でPOSTでアップロードされたファイルか確認。次のif文でアップロードされたファイルを新しい位置に移動する。

移動できたら、パーミッション(アクセス権限)を設定。所有者は読み書きOK、それ以外は読み込みだけOK

if (!isset($_FILES['image']['error']) || !is_int($_FILES['image']['error'])){
  echo "ファイルアップロードエラー";
} else {
  $file_name = $_FILES['image']['name'];
  $extension = pathinfo($file_name, PATHINFO_EXTENSION); //拡張子取得
  $tmp_path = $_FILES['image']['tmp_name'];
  $file_dir_path = "upload/";
  $uniq_name = date("YmdHis").md5(uniqid(microtime(),1)).session_id() . "." . $extension;

  if (is_uploaded_file($tmp_path)) {
    if(move_uploaded_file( $tmp_path, $file_dir_path . $uniq_name)) {
      chmod($file_dir_path . $uniq_name, 0644);
    } else {
      echo "Error:アップロードできませんでした。";
    }
  }
}

これで必要最低限のシステムはできました。

ファイルアップロードをドラッグ&ドロップでも可能にするには?

今回のゴールは下記のようなドラッグ&ドロップでもアップロードを可能にするシステムです。

f:id:front-end-engineer:20160708150321p:plain

簡単な話ではありますが、上記で作ったシステムとjsを使えば実装できます。

jQueryは使わずに生のjsで書いてみます。その前に、フロント部分の記述を少し変更します。

cssは各々で調整してください。

<form action="" method="post" enctype="multipart/form-data">
  <div id="drag-drop-area">
    <div class="drag-drop-inside">
      <p class="drag-drop-info">ここにファイルをドロップ</p>
      <p>または</p>
      <input type="file" value="ファイルを選択" name="image">
      <p class="drag-drop-buttons"><input id="fileInput" type="file" value="ファイルを選択" name="image"></p>
      <input type="value" value="送信">
    </div>
  </div>
</form>

fileAreaでドラッグ&ドロップの有効範囲を設定。fileInputにfile属性のinputタグを代入しておく。

dragoverイベントはドラッグしている要素がドロップ領域にある間に発生

dragleaveイベントはドラッグしている要素がドロップ領域から出たときに発生

dropイベントはドラッグしている要素がドロップ領域にドロップされたときに発生

その他にもドラッグ&ドロップのイベントはあります。もっと知りたい方は下記のリンクを参考にしてください。
https://app.codegrid.net/entry/dnd-api-1

files変数にドロップされた画像のデータ情報が入り、そのデータをfileInputに渡しているだけです。

これで完成です。

※ドロップした時点でアップロードしたい際には、changeイベントを使えば可能です

var fileArea = document.getElementById('drag-drop-area');
var fileInput = document.getElementById('fileInput');


fileArea.addEventListener('dragover', function(evt){
  evt.preventDefault();
  fileArea.classList.add('dragover');
});

fileArea.addEventListener('dragleave', function(evt){
    evt.preventDefault();
    fileArea.classList.remove('dragover');
});
fileArea.addEventListener('drop', function(evt){
    evt.preventDefault();
    fileArea.classList.remove('dragenter');
    var files = evt.dataTransfer.files;
    fileInput.files = files;
});