cakePHP 2.x 画像アップロードプラグイン“upload”の使い方

Shunsuke Sawada

cakePHPで画像アップロードといえばMedia Pluginだったのでしょうが、GitHubを見てみるとなんだか開発は中止したそうなので、これから作るウェブに組み込むのはちょっと微妙かなと思い他を探してみました。

条件としてこんな感じ。
・cakePHP 2.x 対応
・複数のモデルに対して複数の画像が関連付けられる
・サムネイルを作ってくれる
・MIMEタイプを制限できる
  
いくつか見つかりましたが、海外のフォーラムとかで評判がよさそうな"upload"を使ってみることに。
↓こんな記事があったので、気になってましたが、イロイロ考えてやめました。画像系って一回組み込むと変えたくないからちょっと慎重になる。
CakePHPの超便利なファイルアップロードプラグイン、FileBinderプラグインの使い方をまとめてみた。
  
↓今回つかったのはこちら↓
josegonzalez / upload

こんな条件

cakePHP 2.2
モデル:UserとMenu
UserとMenuには複数画像を登録したい
2013/3/27追記
UserとMenuのテーブル構成に追加する要素はありません。

インストール

ダウンロードしたフォルダをapp/Plugin/に設置。
名前は"Upload"とする。
  
ひとまず読み込む
app/Config/bootstrap.php

1
CakePlugin::load('Upload');

attachmentsテーブルを作る

画像専用のテーブルです。

1
2
3
4
5
6
7
8
9
10
11
12
CREATE table attachments (
    "id" int(10) unsigned NOT NULL auto_increment,
    "model" varchar(20) NOT NULL,
    "foreign_key" int(11) NOT NULL,
    "photo_user" varchar(255) NOT NULL,
    "photo_menu" varchar(255) NOT NULL,
    "dir" varchar(255) DEFAULT NULL,
    "type" varchar(255) DEFAULT NULL,
    "size" int(11) DEFAULT 0,
    "active" tinyint(1) DEFAULT 1,
    PRIMARY KEY ("id")
);

Attachmentモデルを作る

$actsAsの設定もします。

php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php
class Attachment extends AppModel {

    public $actsAs = array(
        'Upload.Upload' => array(
            'photo_user' => array(
                'thumbnailSizes' => array(
                    'thumb150' => '150x150',
                    'thumb80' => '80x80',
                ),
                'thumbnailMethod' => 'php',
                'fields' => array('dir' => 'dir', 'type' => 'type', 'size' => 'size'),
                'mimetypes' => array('image/jpeg', 'image/gif', 'image/png'),
                'extensions' => array('jpg', 'jpeg', 'JPG', 'JPEG', 'gif', 'GIF', 'png', 'PNG'),
                'maxSize' => 2097152, //2MB
            ),
            'photo_menu' => array(
                'thumbnailSizes' => array(
                    'thumb' => '100x100'
                ),
                'thumbnailMethod' => 'php',
                'fields' => array('dir' => 'dir', 'type' => 'type', 'size' => 'size')
            ),
        ),
    );


    public $belongsTo = array(
        'User' => array(
            'className' => 'User',
            'foreignKey' => 'foreign_key',
        ),

        'Menu' => array(
            'className' => 'Menu',
            'foreignKey' => 'foreign_key',
        ),
    );
}
?>

  
photo_userphoto_menuの設定をしています。
  
thumbnailSizes
'thumb150' => '150x150'みたいに書くとそのサイズのサムネイルを自動で生成してくれます。

thumbnailMethod
サムネイルの画像リサイズに使うメソッドを選択します。
デフォルトではimagickになっているので、ここではGDにしました。GDの場合は'php'と書きます。

fields
画像の情報を入れるフォールドを指定できます。ここでは変えていません。

mimetypes
MIMEタイプを制限。

extensions
アップロードする拡張子を制限。

maxSize
アップロードする画像のデータサイズを制限。
  
$belongsToでアソシエーションの設定もする必要があります。

反対側からもアソシエーション

Userモデル

php
1
2
3
4
5
6
7
8
9
10
11
12
<?php
class User extends AppModel {
    public $hasMany = array(
        'Image' => array(
            'className' => 'Attachment',
            'foreignKey' => 'foreign_key',
            'conditions' => array(
                'Attachment.model' => 'User',
            ),
        ),
    );
}

Menuモデル

php
1
2
3
4
5
6
7
8
9
10
11
12
<?php
class Menu extends AppModel {
    public $hasMany = array(
        'Image' => array(
            'className' => 'Attachment',
            'foreignKey' => 'foreign_key',
            'conditions' => array(
                'Attachment.model' => 'Menu',
            ),
        ),
    );
}

ビューを作る

ここではusers/add.ctpだけ書きます。
typeをfileにしないと動きません。単純だけど忘れがちでハマります。

php
1
2
3
4
5
6
7
8
9
10
<?php echo $this->Form->create('User', array('type' => 'file')); ?>
<!-- nameフィールドもあると仮定します。 -->
<?php echo $this->Form->input('Image.0.name', array('type' => 'file')); ?>
<!-- インデックス0をつけてモデル名を指定してあげるのがポイント -->
<?php echo $this->Form->hidden('Image.0.model', array('value'=>'Person'));?>
<!-- ファイルを選択するボタン -->
<?php echo $this->Form->input('Image.0.photo_person', array('type' => 'file')); ?>
<!-- 送信ボタン -->
<?php echo $this->Form->submit('Send');?>
<?php echo $this->Form->end()  ?>

これで動くはず。
アプロードされた画像はUserに紐付いているので、$this->User->find()とかでくっついてきます。
あ、コントローラで画像を保存する時にはsaveではなくてsaveAllを使うこと。
でないと保存されません。

画像以外にも対応している

別に画像じゃなくたってもアップロードできる。PDFとか映像データも。
スバラっしい!

2013/3/27追記
コントローラーで
$this->User->saveAll($this->request->data);
とすればAttachmentテーブルに保存されると思います。

$this->request->dataの中身はこんな感じになっていると、うまくいくかと。

php
1
2
3
4
5
6
7
8
9
10
11
12
    'Image' => array(
        (int) 0 => array(
            'photo_user' => array(
                'name' => 'アップロードする画像の名前.png',
                'type' => 'image/png',
                'tmp_name' => '/var/tmp/xxxxx',
                'error' => (int) 0,
                'size' => (int) 8237
            ),
            'model' => 'User'
        )
    )
35
Shunsuke Sawada

おすすめの記事

CakePHP 2.x JSヘルパーでajax通信(ajax helperは使わない)
20
Rails4でQiita投稿ボタンをつくった
18
紙のデザイナーがウェブ開発できるようになるまでに必要なこと
451