新しい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
- APCというPHPアクセラレータの機能のひとつ
- PHP5.4の新機能
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進捗プログレスバー表示が何とか形になりました。