またどこかでCTOっぽいことやってる人のブログ

フリーランスを経て、またどこかでCTOっぽいことをやってる人が書いてます。何か色々やってます。

CakePHP3でDBに格納した画像データを表示してみた。

2017/09/04 追記
すっかり書いた気でいた画像データ登録記事を追加しました。
本記事と合わせて読んで頂くと、それっぽくできると思います。

tsuralabo.hatenablog.com



画像データはDBにブチ込むタイプです。
サーバにアップロードする方法もありますが、どちらもメリット、デメリットあります。
メリット、デメリットに関してはグーグル先生が詳しいと思います。
案件に応じて柔軟に対応すればいいんじゃないかなと。

さて、いきなり端折ってしまいますが、image_filesというテーブルに画像データが入っていたとします。
いわゆるBLOB型のカラムですね。
テーブル構成はこんな感じで作りました。

CREATE TABLE `image_files` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `content_type` varchar(64) NOT NULL COMMENT 'コンテンツタイプ',
  `image_data` mediumblob NOT NULL COMMENT '画像バイナリデータ',
  `created` datetime DEFAULT NULL COMMENT 'データ作成日',
  `modified` datetime DEFAULT NULL COMMENT 'データ更新日',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='画像格納テーブル'

ここにブチ込んだ画像バイナリデータをController経由で表示します。
Helperでもいいと思いますが、あんまりHelperを使うのが好きではないのでControllerで。

やりたいことはこれだけです。

・プライマリキーであるimage_files.idを指定する。
・image_files.idに合致するバイナリデータのimage_files.image_dataを取得する。
・画面上に表示する。

なんか簡単っぽいです。
というわけで表示用のControllerを書いてみます。

<?php
  namespace App\Controller;
  use Cake\Event\Event;
  use Cake\ORM\TableRegistry;
  
/**
 * ImageFilesController
 */
class ImageFilesController extends AppController {
  
  public $name = 'ImageFiles';
  
  public function beforeFilter(Event $event) {
    parent::beforeFilter($event);
  }
  
  /**
   * 画像データ取得処理
   * IDに合致する画像データを取得して表示
   * @param type $imageId
   * @throws NotFoundException
   */
  public function content($imageId) {
    
    // Viewをレンダリングしない
    $this->autoRender = false;
    
    // image_filesデータをまるっと取得する
    $imageFile = TableRegistry::get('ImageFiles');
    
    // IDに紐付く画像データを取得
    $fileData = $imageFile->get($imageId);
    
    if (empty($fileData)) {
      // 一応エラー処理
      throw new NotFoundException();
    }
    
    // 画像表示
    $this->response->type($fileData->content_type);
    $this->response->body(stream_get_contents($fileData->image_data));
  }
}

ポイントは特にありません。
強いて言えば、レンダリングしない部分だけじゃないかなと。
あとはよくある画像表示処理です。

このコントローラをView側で呼んであげれば画像が表示されると思います。
View側も一応記載しておきます。

<?php
  <img 
     src="<?php echo $this->Url->build(["controller" => "ImageFiles", "action" => "content", 12345]); ?>" 
     class="img-rounded img-responsive" <!-- ここのClass指定はBootstrap3用 -->
     alt="画像12345です" 
  />

上の例だとimage_files.id = 12345の画像を指定しています。
altは適当に記載していますが、実際はちゃんと入れないとグーグル先生がクローリングしてきた時に叱られます。

出来上がったソースを見ると、CakePHP2の頃とほとんど変わりませんでした。
が、とりあえず画像は表示できたのでよしとします。