CakePHP3で画像データをDBに保存してみた。
その昔、こんな記事を書きました。
tsuralabo.hatenablog.com
画像データのDB登録記事がないことに1年近く経って気がつきました。
これはいけません。
ということで何事もなかったかの如く、記事を書くことにします。
DBへの画像登録というのは、いわゆるバイナリ登録です。
BLOBデータのアレですね。
昔から「BLOB」と聞くとスライム的な何かを想像してしまうのですが、それはどうでもいいです。
きっと過去にプレイしたRPGの何かなんじゃないかと思いますが、それもよくわかりません。
さて。
画像をDB登録する際はフォームヘルパーのFile属性に対して画像を指定して、それをアップロードするのが多いんじゃないかと。
それ以外もあるのかもしれませんが、自分が見たことないだけかもしれません。
とりあえず、View側の画像アップロード部分はこんな感じで作ります。
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12"> <span>画像</span> <div class="input-group"> <span class="input-group-addon"> <i class="glyphicon glyphicon-paperclip"></i> </span> <?php echo $this->Form->file('sample_image_id', [ 'class' => 'form-control', 'type' => 'file', 'div' => false, 'label'=> false ]); ?> </div> </div>
Bootstrap3使ってます。ちょっと怪しい書き方ですが、その辺は生暖かくお願いします。
さて、ここに指定された画像データがsubmitされた時、以下のようにごにょっとすると登録できます。
<?php /** * 画像登録処理(アップロードされた画像をそのまま登録) * @param type $imageFileModel image_filesテーブルのモデル * @param type $imageFile 登録する画像本体 */ public function saveImageFile($imageFileModel, $imageFile) { // 画像情報を取得 $imginfo = getimagesize($imageFile['tmp_name']); // ファイル拡張子に応じて処理 if ($imginfo[2] == IMAGETYPE_JPEG) { // JPEG画像データを生成 $createImage = imagecreatefromjpeg($imageFile['tmp_name']); } else if ($imginfo[2] == IMAGETYPE_PNG) { // PNG画像データを生成 $createImage = imagecreatefrompng($imageFile['tmp_name']); } // 画像データをバッファへバイナリ出力 ob_start(); imagepng($createImage); $imageBinary = ob_get_clean(); // モデル登録用パラメータ生成 $imgFileParam = [ 'content_type' => $imageFile['type'], 'image_data' => $imageBinary ]; // 新規登録用エンティティ生成 $entity = $imageFileModel->newEntity($imgFileParam); // 画像保存処理実行 $result = $imageFileModel->save($entity); // 画像メモリを解放 ImageDestroy($createImage); // データ登録時のIDを返す return $result->id; }
自分のよくやるパターンだと、上記のfunctionをコンポーネントに入れてます。
で、コントローラの方でそのコンポーネント経由でfunction呼び出してます。
「tmp_nameってなんだよ」ってのはview側からsubmitすればわかります。
「pr($this->request->getData());」とかやってみると出てくると思います。
トランザクションに関しては呼び元のコントローラの方でやっているのですが、環境や仕様に合わせて適宜修正して下さい。
一番最後にIDを返していますが、画像登録用テーブルと実テーブルが別ですのでIDを取得して実テーブルにパラメータセットしているためこんな感じになっています。ここも適宜修正して頂けますと。
getimagesize部分は対象画像のデータが色々取れますので、幅とか高さとかその辺の制限があればここで取得を。
でも登録処理する前にバリデーションは別でやりたいんだよ! という方は、上記functionの前にバリデーションを。
箇条書きっぽくなりましたが、以下を参考にして下さい。
<?php // $params['sample_image_id']でFile属性のデータが渡ってくることにします // 拡張子判定の場合 $extension = substr($params['sample_image_id'], strrpos($params['sample_image_id'], '.') + 1); // $extensionに拡張子が入るので判定。 // 判定用のリストを作っておくのもいいかもしれません private $extensionList = ['jpg', 'png']; if (!in_array($extension, $this->extensionList)) { $errorMessage[] = '画像の拡張子が不正です。jpgファイル、またはpngファイルを指定して下さい。'; } // サイズ判定の場合 $fileSize = $params['sample_image_id']['size']; // そもそもアップロードされてるかどうか判定 if ($params['sample_image_id']['error'] == 0) { // アップロードされた } else { // アップロードされてない // $params['sample_image_id']['error']が「4」とかだと思います }
こんな感じで画像データをDBにバイナリ登録したり、バリデーション実行したりするといいんじゃないかと思います。
でも、多分もっといい書き方あると思います。
まず動くことが大事。
動いてから色々ごにょごにょするといいかなと。