CakePHP MediaPlugin + Plupload 複数ファイルの同時アップロード

追記 2011-08-01
CakePHPのプラグイン化してみました
https://junichi11.com/?p=1406

複数のファイルを同時にアップロード

多くのファイルをアップロードしたい場合は、ファイルを何度も選択するのが大変。

何かいいものはないかと探していたところ、

PluploadというjQueryのプラグインを見つけた。
Pluploadでは下図のように複数のファイルを一度に選択することができる。

ダウンロード:http://www.plupload.com/

Pluploadの仕組み

Pluploadは以下のような仕組みになっている。

  1. 非同期で選択したファイルを複数に分割(chunkというもの)して送信する。
  2. 全ての送信が完了。
  3. 送信したファイル情報をPOSTで送信する。
    送信したファイルの情報はPluploadのサイトを参照。
    サーバー側には上図のような情報がファイル数分送られてくる。

 CakePHPでの処理

  1. 送信されてきたファイルを処理するメソッドを作成する。
    メソッドの中身はDLしたpluploadのファイルの中に、ファイルを処理するプログラムファイルがあるのでそれをそのまま使う。
  2. POSTされてきた情報をもとに、ファイルのUPロード処理を行う。
    (MediaPluginを使用する。)

MediaPluginのインストールは下記を参照
http://d.hatena.ne.jp/slywalker/20090730/1248916519
http://www.zontheworld.com/blog/archives/111
PHPで作る携帯サイト デベロッパーズガイド」秀和システム 滝下真玄著

ここではPHPで作る携帯サイト デベロッパーズガイドを参考にMediaPluginをインストールしています。

通常Pictureの部分はAttachementとして作成されているかもしれません。

app/controllers/photos_controller.php

class PhotosController extends AppController {
    public $name = 'Photos';
public $uses = array('Photo', 'Picture');

public $components = array('RequestHandler');
    //  …

function plupload(){
// plupload/examples/upload.phpの中身をコピペ
}

    function add(){

/*....................................................
* POST
* uploader_0_tmpname
* uploader_0_name
* uploader_0_status
* ...
....................................................*/
if(!empty($this->data)){
        $plupload = null;
$cnt = 0;
$tmpdir = ini_get('upload_tmp_dir');
foreach($_POST as $key => $value){
if($key == 'uploader_count'){
$cnt = $value;
}
$split = explode('_', $key);

if(in_array('tmpname', $split) || in_array('name', $split)){
$plupload[$split[1]][$split[2]] = $value;
}

}
foreach($plupload as $file){
@rename($tmpdir.DS.$file['tmpname'], $tmpdir.DS.$file['name']);
}

for($i = 0; $i<count($plupload); $i++){
$this->data['Picture'][$i]['title'] = '';
$this->data['Picture'][$i]['description'] = '';
$this->data['Picture'][$i]['model'] = 'Photos';
$this->data['Picture'][$i]['file'] = $tmpdir.DS.$plupload[$i]['name'];
        }

        if($this->Photos->saveAll($this->data, array('validate' => 'first'))){
$this->flash('データを追加しました', 'index',3);
foreach($plupload as $file){
@unlink($tmpdir.DS.$file['name']);
}
return;
}else{
$this->flash('失敗', 'add');
foreach($plupload as $file){
@unlink($tmpdir.DS.$file['name']);
}
        }
        }
}

    function beforeFilter(){
        if ($this->RequestHandler->isFlash()) {
            $this->Auth->allow('add');
        }
    }

}


/app/models/photos.php

class Photo extends AppModel {
var $name = 'Photo';

//アソシエーション設定
var $hasMany = array(
'Picture' => array(
'className' => 'Picture',
'foreignKey' => 'foreign_key',
'conditions' => array('Picture.model' => 'Photo'),
'dependent' => true,
),
);
}

最初に上手くいかなかったのが、下記の部分。
送られてくる情報が通常のファイルを送信する場合と違うから、
[‘file’]の部分をどうしていいのかわからなかった。

    $this->data['Picture'][$i]['file'] = $tmpdir.DS.$plupload[$i]['name'];

mediapluginのgitのwikiをみると解決。

MediaPluginの転送方法は3つある

[‘file’]の部分は以下の指定が可能。
pluploadでアップした場合2番目の使い方をする。

HTML formタグによるHTTP POST配列を使う

array(
'name' => 'hoge.jpg',
'type' => 'image/jgeg',
'tmp_name' => '/tmp/3242ljl',
'error' => 0,
'size' => 3524
)

ファイルへの絶対パスを使う

Ex : ‘/var/www/tmp/hoge.jpg’

URLを指定する

Ex : ‘http://www.cakephp.org/imgs/hoge.png’

/app/views/photos/add.ctp


<!-- Thirdparty intialization scripts, needed for the Google Gears and BrowserPlus runtimes -->
<?php echo $javascript->link('plupload/gears_init.js');?>
<script type="text/javascript" src="<a href="http://bp.yahooapis.com/2.4.21/browserplus-min.js%22%3E%3C/script">http://bp.yahooapis.com/2.4.21/browserplus-min.js"></script</a>>

<!-- Load plupload and all it's runtimes and finally the jQuery queue widget -->
<?php echo $javascript->link('plupload/plupload.full.min.js');?>
<?php echo $javascript->link('plupload/jquery.plupload.queue.min.js');?>
<script type="text/javascript">
// Convert divs to queue widgets when the DOM is ready
$(function() {
$("#uploader").pluploadQueue({
// General settings
runtimes : 'gears,flash,silverlight,browserplus,html5',
url : '<?php echo $html->webroot('/photos/plupload')?>',
max_file_size : '3mb',
chunk_size : '1mb',
unique_names : true,

// Resize images on clientside if we can
//resize : {width : 640, height : 480, quality : 100},

// Specify what files to browse for
filters : [
{title : "Image files", extensions : "jpg,gif,png"},
{title : "Zip files", extensions : "zip"}
],

// Flash settings
flash_swf_url : '<?php echo $html->webroot('/js/plupload/');?>plupload.flash.swf',

// Silverlight settings
silverlight_xap_url : '<?php echo $html->webroot('/js/plupload/');?>plupload.silverlight.xap'
});

// Client side form validation
$('form').submit(function(e) {
var uploader = $('#uploader').pluploadQueue();

// Validate number of uploaded files
if (uploader.total.uploaded == 0) {
// Files in queue upload them first
if (uploader.files.length > 0) {
// When all files are uploaded submit form
uploader.bind('UploadProgress', function() {
if (uploader.total.uploaded == uploader.files.length)
$('form').submit();
});

uploader.start();
} else
alert('You must at least upload one file.');

e.preventDefault();
}
});
});
</script>
<h2>写真の追加</h2>
Add files をクリックしてファイルを追加してください。<br />
ファイルを選択するときに複数のファイルを選択することができます。<br />
Google Gears をインストールしていれば、ファイルをドラッグ&ドロップで追加できます。
<?php echo $form->create('Photo', array('type' => 'file', 'action' => 'add', 'class' => 'plupload')); ?>
<span id="plupload">
<div id="uploader">
<p>You browser doesn't have Flash, Silverlight, Gears, BrowserPlus or HTML5 support.</p>
</div>
<br style="clear: both" />
</span>
<?php echo $form->end('追加'); ?>

実際に作ったものと名前等を変えているので、調整しないと動かないかもしれません。

もっといい作り方があるかもしれませんが、

参考までに。。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください