[ステップアップ! CakePHP]画像をデータベースに保存する

No Photo

イメージ

iPad、すでに3,000円以上のアプリを買ってるtanakaです。GoodReader初めて使いましたが便利ですね!

CakePHP連載6回目。今回はアップロードされた画像をデータベースに保存する方法を紹介します。

実はあんまりCakePHPとは関係ないですが、CakePHPのおかげで実装が容易になる部分もありますので紹介します。

画像格納用テーブル

まずは画像を保存するためのテーブルを用意します。

CREATE TABLE `images` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `filename` varchar(60) NOT NULL,
  `contents` mediumblob NOT NULL,
  PRIMARY KEY (`id`)
);

filenameは、URL中のファイル名として使います。(URLにidを使う場合は不要)contentsが、画像ファイルの中身を入れるカラムです。

大きめなデータを保存するにはtext型かblob型を使います。ここではblob型のひとつmediumblob型を選びます。mediumblob型を選ぶのは、単なるblob型だと約60キロバイトまでしか保存できず、mediumblob型は約16メガバイトまで保存できるためです。16メガバイトなら、たいていの場合、画像を保存するには十分です。

アップロード用フォーム views/images/index.ctp

まずは、ImagesControllerから解説といきたいところですが、単にフォームを表示するだけでいいので、テンプレートをまず紹介します。

<?php e($form->create(null, array('type'=>'file', 'action'=>'add')));?>
<?php e($session->flash());?>
<?php e($form->file('image'));?>
<?php e($form->submit('画像を追加'));?>
<?php e($form->end());?>

<h2>追加した画像</h2>
<ul>
<?php foreach ($images as $image) { ?>
    <li><?php e($html->link("/images/contents/{$image['Image']['filename']}"));?></li>
<?php } ?>
</ul>

上にアップロード用フォームがあります。ファイルアップロードできるよう'type'=>'file'と記述する以外は普通のフォームです。

下には追加された画像にアクセス出来るよう一覧を表示します。

アップロード〜保存処理 ImagesController::add() (images_controller.php)

フォームからのアップロードはaddアクションで処理します。

<?php
class ImagesController extends AppController {
    // ... 中略
    /**
     * 画像を登録する
     */
    function add(){
        $limit = 1024 * 1024;

        // 画像の容量チェック
        if ($this->data['Image']['image']['size'] > $limit){
            $this->Session->setFlash('1MB以内の画像が登録可能です。');
            $this->redirect('index');
        }
        // アップロードされた画像か
        if (!is_uploaded_file($this->data['Image']['image']['tmp_name'])){
            $this->Session->setFlash('アップロードされた画像ではありません。');
            $this->redirect('index');
        }
        // 保存
        $image = array(
            'Image' => array(
                'filename' => md5(microtime()) . '.jpg',
                'contents' => file_get_contents($this->data['Image']['image']['tmp_name']),
            )
        );
        $this->Image->save($image);
        $this->Session->setFlash('画像をアップロードしました。');
        $this->redirect('index');
    }
    // ... 中略
}

まずは、入力を検査します。あまり大きなファイルをアップロードしてもらいたくないので、1メガバイトに制限します。また、本当にアップロードされたファイルなのかもチェックします。

こういったチェックはモデルのカスタムバリデーションメソッドで記述すれば、コントローラのロジックがすっきりするのでオススメです。

検査が終わったら、データベースに保存しましょう。ファイル名は一意になるようにして、画像の中身はfile_get_contentsでバイナリ列を取得して保存します。

データベース内の画像データを表示する

最後に、データベースに保存した画像を表示します。

    function contents($filename) {
        $this->layout = false;
        $image = $this->Image->findByFilename($filename);
        if (empty($image)) {
            $this->cakeError('error404');
        }
        header('Content-type: image/jpeg');
        echo $image['Image']['contents'];
    }

ファイル名形式の文字列を$filenameで受け取り、データを取り出します。次に余計なものが表示されないよう、$this->layoutを無効にします。

ブラウザにJPEG画像として扱ってもらうようにヘッダを送出し、画像をレンダリングします。

コントローラのコード全体

フォームのテンプレートは上記の通りですので、最後にコントローラのコードを載せます。

<?php
class ImagesController extends AppController {
    var $uses = array('Image');
    function index(){
        $images = $this->Image->find('all');
        $this->set(compact('images'));
    }

    /**
     * 画像を登録する
     */
    function add(){
        $limit = 1024 * 1024;
        debug($this->data);

        // 画像の容量チェック
        if ($this->data['Image']['image']['size'] > $limit){
            $this->Session->setFlash('1MB以内の画像が登録可能です。');
            $this->redirect('index');
        }
        // アップロードされた画像か
        if (!is_uploaded_file($this->data['Image']['image']['tmp_name'])){
            $this->Session->setFlash('アップロードされた画像ではありません。');
            $this->redirect('index');
        }
        // 保存
        $image = array(
            'Image' => array(
                'filename' => md5(microtime()) . '.jpg',
                'contents' => file_get_contents($this->data['Image']['image']['tmp_name']),
            )
        );
        $this->Image->save($image);
        $this->Session->setFlash('画像をアップロードしました。');
        $this->redirect('index');
    }

    function contents($filename) {
        $this->layout = false;
        $image = $this->Image->findByFilename($filename);
        if (empty($image)) {
            $this->cakeError('error404');
        }
        header('Content-type: image/jpeg');
        echo $image['Image']['contents'];
    }
}

まとめ

画像のアップロードからデータベースへの保存、画像表示までの流れを紹介しました。

  • このエントリーをはてなブックマークに追加

この記事を読んだ人にオススメ