File APIを使ったドラッグ&ドロップとプログレスバー

植物新しいWEBサービスでファイルアップロードを実装することに。できれば複数ファイルをドラッグ&ドロップできるようなイマドキなの。この分野はライブラリの開発も盛んに行われており、

  • Uploadify
  • Plupload
  • jQuery File Upload

などを試してみるが、痒い所に手が届かず自作することに。

一つのファイルをアップするだけならinputのtype=fileで一発なんだけど、ドラッグ&ドロップとなると難易度も上がる。実現方法としてHTML5のFile APIという機能を使うと比較的楽に作れる。しかし対応はモダンブラウザのみでIE8も未対応。mixiでもこの方式を採用している。

もう一つFlashを利用する方法があるが、その開発はコストに見合わない。幸いにもサイトのターゲットにIE使いは少なそうなので、IEの複数ファイルアップロードには対応しないことに。

 

実装の道筋

先人の知恵を拝借する作業の始まり。まずは、

HTML5の Drag and Drop API と File API を使ってファイルアップロードを実装する – しばやん雑記

を参考に作り始め。しばやん雑記のおかげで一応シンプルなバージョンの完成。次はアップロード中の進捗のプログレスバー表示。

POSTのアップロード中に転送完了分のサイズを取得するには、現在3つの方法がある。

Flashは使いたくないしPHPは5.3.3から変えたくなかったのでAPCを使うことに。次に参考にさせて頂いたサイト

cl.pocari.org – APC と jQuery を利用してファイルアップロードの進行状況を表示する

まずはSakuraのVPSにAPCをインスコ。これは一瞬で終了。apcの設定でrfc1867をonに。他はすべてデフォルトで。

#yum -y install php-pecl-apc
#vim /etc/php.d/apc.ini
apc.rfc1867 = Off → On
#service httpd restart

これでサクッといけると思えたんだけど、ここで最大の山場が。

 

APC_UPLOAD_PROGRESSの宣言位置

進捗の取得手段は、ファイルをアップする時にhiddenでAPC_UPLOAD_PROGRESSにキーを渡して同時にアップし、別のアクセスから、このキーのアップロードどれくらい進んでる?って1秒間隔くらいで聞いてあげる。

しかし今回はフォームじゃなくてFile APIのオブジェクトをajaxでアップするから、ちょっと勝手が違ってhiddenとかない。具体的にはこんな感じのJS。

var fd = new FormData();
fd.append('APC_UPLOAD_PROGRESS','progress_key');
fd.append('files',file);
$.ajax({
    url: 'hoge',
    type: 'POST',
    data: fd,
    processData: false,
    contentType: false
});

ここでAPC_UPLOAD_PROGRESSをappendする順番をfileの前に記述しないと進捗は表示されない。これで3時間くらい潰す。

php.netのapc.rfc1867に答えがありました。

APC_UPLOAD_PROGRESS で指定した hidden フィールドが file フィールドよりも前にこなければならないことに注意しましょう。 そうしないと、アップロードの進捗処理が正しく動作しません。

以上で File APIを使った複数ファイルのドラッグ&ドロップアップロードwith進捗プログレスバー表示が何とか形になりました。