[CakePHP] 画像のアップロード&リサイズを簡単にできる ImageBehavior
画像のアップロード&リサイズ処理などは割とよくある処理でかつ面倒なものです。その処理を簡単にやってくれる Imageビヘイビアの紹介です。CakeFest で紹介された Media Plugin が高性能なので、メディアプラグインを使うのがいいのかもしれませんが、以前から Image ビヘイビアに関していつか使い方をまとめようと思っていたので紹介します。
参考サイト:ActAs Image column behavior (Articles) | The Bakery, Everything CakePHP
Baker で紹介されていた Image ビヘイビアです。このビヘイビアはアップロードされた画像をサムネイル作成、リサイズ、複数のバリエーションのサイズの画像を作成してくれます。またモデルを find すると画像のパスを返してくれます。
作成される画像は、webroot/img/[Model Name]/[Model ID]/ 以下に設定した名前でそれぞれの画像を作成してくれます。
インストール
元サイトにソースがありますが、コメント欄でかなりやり取りがあり結構修正しなければなりません。コメント欄以外にも私の方で修正した部分もあります。最終的に使ったソースをアップしておきます。
ImageBehavior – GitHub
DB の準備
まずモデルのカラムにアップロードファイルの mime タイプを入れるカラムを作成します。今回はユーザ名と画像を持つユーザモデルを作成します。
CREATE TABLE `users` ( `id` tinyint(4) NOT NULL auto_increment, `name` varchar(20) NOT NULL, `image` varchar(255) default NULL, `created` datetime NOT NULL, `modified` datetime NOT NULL, PRIMARY KEY (`id`) );
モデル
次にモデルに Image ビヘイビアの設定を入れます。
カラム名の指定
array(‘fields’=>’image’) となっている部分が DB のカラムに指定したカラム名になります。
サムネイルの指定
thumbnail => array(‘create’=>true) とすることにより、thumb_ をプレフィックスにしたファイル名でサムネイル画像が作成されます。サイズはデフォルトで 100×100 です。サイズの指定も可能です。この指定を省略すればサムネイルは作成されません。
リサイズの指定
resize => array(…) で指定したサイズでリサイズします。縦、横のサイズ、アスペクト比を保つか、指定サイズよりも小さい場合拡大するかなどを指定します。省略した場合はリサイズされずにアップロードされます。
その他のサイズの画像作成
その他のサイズの画像を作成したい場合は、version => array( … ) で指定します。
class User extends AppModel { var $name = 'User'; var $actsAs = array( 'Image'=>array( 'fields'=>array( 'image'=>array( 'thumbnail'=>array('create'=>true), 'resize'=>array( 'width'=>'200', 'height'=>'200', 'aspect'=>true, 'allow_enlarge'=>true, ), 'versions'=>array( array( 'prefix'=>'small', 'width'=>'70', 'height'=>'70', 'aspect'=>true, 'allow_enlarge'=>true, ), ) ) ) ) ); }
ビュー
注意する点としてはアップロードするので array(‘enctype’=>’multipart/form-data’) の指定をお忘れなく。
<div class="users form"> <?php echo $form->create('User', array('enctype'=>'multipart/form-data'));?> <fieldset> <legend><?php __('Add User');?></legend> <?php echo $form->input('name'); echo $form->file('image'); ?> </fieldset> <?php echo $form->end('Submit');?>
画像保存ディレクトリ
アップロードした画像は /webroot/img/ 以下にモデル名、モデルのID によってディレクトリが分けられ保存されます。そのため、webroot/img に apache 実行ユーザに書き込み権限を与えておく必要があります。保存形式は
/webroot/img/[Model Name]/[Model ID]/[column_name].[ext]
という感じになります。thumbnail と version で指定したものにはそれぞれプレフィックスが付きます。
上記の設定で、ユーザID が 1 のユーザが hoge.jpg という画像をアップロードすると
/webroot/img/User/1/image.jpg
/webroot/img/User/1/thumb_image.jpg
/webroot/img/User/1/small_image.jpg
と3つのファイルが保存されます。
コントローラ
コントローラでは特に変わったことをする必要はありません。save すれば画像が保存されます。
function add() { if (!empty($this->data)) { $this->User->create(); if ($this->User->save($this->data)) { $this->Session->setFlash(__('The User has been saved', true)); $this->redirect(array('action'=>'index')); } else { $this->Session->setFlash(__('The User could not be saved. Please, try again.', true)); } } }
ユーザモデルのデータを取得すれば、作成した各種画像のパスが取得できます。
$user = $this->User->read(null, $id); debug($user);
Array ( [User] => Array ( [id] => 1 [name] => hoge [image] => Array ( [path] => User/12/image.jpg [thumb] => User/12/thumb_image.jpg [small] => User/12/small_image.jpg ) [created] => 2009-11-13 15:48:02 [modified] => 2009-11-13 16:08:15 ) )
画像のパスは webroot/img ディレクトリからの相対パスなので下記のように Html ヘルパーを使って出力できます。
<?php echo $html->image($user['User']['image']['path']); ?>
その他
アップロード処理なので、モデルできっちりとバリデーション処理はしてください。この辺りも Behavior に組み込めればいいですね。
関連する投稿
19 comments
コメントをどうぞ
Additional comments powered by BackType
[...] [CakePHP] 画像のアップロード&リサイズを簡単にできる ImageBehavior | Sun Limite… [CakePHP] 画像のアップロード&リサイズを簡単にできる ImageBehavior | Sun Limited Mt. [...]
really nice that code i did long time ago still in use
sorry that i comment not in Japanese, but my native is Russian
Hi, skiedr.
Thank you for your comment.
I think ImageBehavior is nice cood, too.
[...] [CakePHP] 画像のアップロード&リサイズを簡単にできる ImageBehavior | Sun Limite… [...]
すいません、質問なんですがこちらのImage ビヘイビアは確認画面を挟むと使えないんでしょうか?
araiさん
コメントありがとうございます。
通常フォームで確認画面を挟めばフォームからの入力内容をどこかに保持しているはずです。Image ビヘイビアを使っても同様です。
matsuuraさん
ご回答ありがとうございます。
自己解決しました!
質問なのですが、
Userが画像情報を保存していて、Postがbelongsto=>array(‘User’)としている状態で、
コントローラー側から$this->Post->find();とした場合、
取り出したUser情報から画像パスは取得出来ませんでした。
アソシエーションされてる側から、ImageBehaviorは動作しないのでしょうか?
原因が分かりました。というか勉強になりました。
afterFindで躓いてました。
アソシエーションが設定されている関連モデルから呼び出されるafterFindはそのモデルで設定されているものだけで、behaviorで設定されたafterFindは呼び出されないようです。
cake/libs/model/datasources/dbo_source.phpの__filterResults()を適当に直したら動作したのですが今後どんな影響が出るか分からない所が怖いですが・・・↓こんな風に弄くりました。
if (isset($model->{$className}) && is_object($model->{$className})) {
$data = $model->{$className}->afterFind(array(array($className => $results[$i][$className])), false);
}
↓↓
if (isset($model->{$className}) && is_object($model->{$className})) {
$data = array(array($className => $results[$i][$className]));
$return = $model->{$className}->Behaviors->trigger($model->{$className}, ‘afterFind’, array($data, false), array(‘modParams’ => true));
if ($return !== true) {
$data = $return;
}
$data = $model->{$className}->afterFind($data, false);
if (!isset($data[0][$className])) {
unset($results[$i][$className]);
}
}
ということで一応報告でした。
bubbkis さん、情報ありがとうございました。時間あるときに試してみます!
mimetypeを限定したいんですけど、例えば:JPGとPNGしかアップロードできないように、アップできなかったら、Flashmessageでエラーを表示したいし、どうカスタマズすればよろしいですかね。
bubbkis さん
hasMany で取得できない件、対応できました。
感謝感謝です。
[...] http://blog.syuhari.jp/archives/1905 記事でimageBehaviorというのを知り、早速使っていました。 [...]
上の方法で変更した場合に、i18nの変換が、hasManyの場合されないようになってしまいました。
また、belongsToの場合は上の変更では取得できないようです。
影響がありそうですので、ご注意ください。
とって私はこうすればいいとかまではわかりませんが。。
このあたりを参考に
http://d.hatena.ne.jp/okomeworld/20110131/1296440459
true);
$results = $this->Behaviors->trigger($this,’afterFind’,$params,$options);
}
return $results;
}
}
?>
連投もうしわけないです。
コードが変になってました。
上記URLのコードに
return $results;
を追記しただけです。
[...] 画像の投稿はImageBehavior というものを使っています。画像サイズの変更など簡単にできて便利ですが、削除した際に削除前の画像がそのまま表示されてしまいました。これはブラウザにキャッシュされたものが表示されているようです。 [...]
[...] ●?[CakePHP] 画像のアップロード&リサイズを簡単にできる ImageBehavior [...]
CakePHP2.1(現時点)だと
ife(a,b,c) -> a?b:c
uses(‘folder’) -> App::uses(‘Folder’, ‘Utility’)
uses(‘file’) -> App::uses(‘File’, ‘Utility’)
への修正と、
afterFind() の第2引数の’&’を削除する必要があるようです。
むしろ、function() の引数から ‘&’ を全て取っ払った方が悪さをしないかと思いました。