PHPで複数ファイルのアップロードをなるべくスマートにやる方法はないかなぁと探し回ってたどり着いたのが、コレ。
自分的にはベストな解答です、たぶん。
詳しい使い方は「Ajax風にファイルをアップロードするjQueryプラグイン「Uploadify」の使い方」が超詳しいので、こちらを参照のこと。
以下は自分的にポイントとなったところ。
- 既存のPHPシステム(例えば、EC-CUBEなど)とはできるだけ独立した形にしたかったので、少し工夫した。
- 呼出し部分は小さいので、display:none で本体のHTMLに組み込む。例えば、こんな感じ。
$(document).ready(function() {
$("#uploadify").uploadify({
'uploader' : '<!--{$TPL_DIR}-->js/uploadify/uploadify.swf',
'script' : '<!--{$TPL_DIR}-->js/uploadify/uploadify.php?rand_no=<!--{$rndNo}-->',
'cancelImg' : '<!--{$TPL_DIR}-->js/uploadify/cancel.png',
'folder' : '<!--{$smarty.const.IMAGE_TEMP_URL}-->',
'queueID' : 'fileQueue',
'auto' : false,
'buttonText' : 'Select Files...',
'multi' : true
});
});
<div>
<p style="margin:0">画像ファイルを選択して、Uploadしてください。</p>
<div></div>
<div style="float:right"><a href="fnModeSubmit('upload_image','image_key','sub_image'); tb_remove();">Close Window</a></p></div>
<p><a href="$('#uploadify').uploadifyUpload();">Upload Files</a> <a href="jQuery('#uploadify').uploadifyClearQueue()">Cancel All Uploads</a></p>
</div>
ちょっと見慣れない細工コードが入っているのは無視無視。たったこれだけでアップローダ定義完了。
- 特殊なことをしている点は、複数の人が同時にこのアップローダを使った場合、同じテンポラリ・フォルダを使うことになるので、ファイル管理用のランダム文字列を持たせたこと。(ほんとは rand()だとかぶる危険性もあるんだけど、今回は管理画面からのアップロードということで、せいぜい10人未満の同時使用しかないだろうから、そこには目を瞑った)
- それと、#uploadブロックは通常非表示で、Thickboxのモーダル・ウィンドウで上がってくるようにしている。
<a href="#TB_inline?height=430&width=405&inlineId=upload&modal=true" title="Uploadify" class="thickbox">Uploadify</a>
こうすると本体のHTMLを汚さなくて済むからいいよね。で、Close Windowのとき、fnModeSubmit()といういままでアップロードボタンに割りつけていた関数を呼んでフックをかけると。
- サーバ側もいたってシンプル。
if (!empty($_FILES)) {
$tempFile = $_FILES['Filedata']['tmp_name'];
$targetPath = str_replace('//','/', $_SERVER['DOCUMENT_ROOT'] . $_REQUEST['folder'] . '/');
$targetFile = $targetPath . $_FILES['Filedata']['name'];
move_uploaded_file($tempFile,$targetFile);
$_FILES['Filedata']['tmp_name'] = $targetFile;
$fp = fopen($targetPath.$_REQUEST['rand_no'], "a");
fputs($fp, serialize($_FILES['Filedata'])."\n");
fclose($fp);
echo "1";
}
複数ファイルをまとめてアップロードすると、この PHPが回数分呼ばれることになる。
やってることは、渡されたファイルをフォルダに移して、なんのファイルを移したかファイルに記録しておくだけ。
このときのファイル名に例のランダム文字列を使ってる。
- あとは、この $_FILES がシリアライズされたファイルを読んで、あたかも $_FILESで入ってきたように振舞ってやれば OK。
$no = 0;
$buf = @file(IMAGE_TEMP_DIR . $this->rndNo);
if ($buf) {
foreach ($buf as $e) {
$no++;
$key = "sub_image".$no;
$_FILES[$key] = unserialize($e);
$this->arrErr[$key] = $this->objUpFile->makeTempFile($key, IMAGE_RENAME);
}
@unlink(IMAGE_TEMP_DIR . $this->rndNo);
unset($_POST['rand_no']);
unset($this->rndNo);
}
EC-CUBEのコードにがっつり入り込んでいるのでわかりにくいけど、シリアライズされたファイルを読んで、アンシリアライズしたものを $_FILESにセットして、処理を継続しているだけ。終わったら、後始末しておく。
こんな感じで活用させていただいてます。ありがとう、Uploadify。