Logicky Blog

Logickyの開発ブログです

cakePHP1.3 - 画像のアップロードの研究

cakePHP1.3で画像をアップロードできるようにします。 参考にするサイトはツチノコラボです。

研究用にUptestsコントローラーをつくりました。
Uptestsコントローラーのindexアクションにアップロード処理をつくります。ちなみに、今回はデータベースにファイルを保存するのではなく、フォルダに格納します。最終的には、ファイル名をデータベースで管理できるようにしたいと思います。

Viewの設定

まずViewにformをつくります。index.ctpを下記のように作成しました。

<h1>Update Test</h1>

<?php
    $options = array(
        'action'=>'index',
        'type'=>'file'
    );
    echo $form->create('Uptest', $options);
?>
<?php echo $form->file('file_name') ?>
<?php echo $form->submit('送信'); ?>
<?php echo $form->end(); ?>

画面イメージは下記のようになります。

ちなみに、作成されるHTMLソースは下記のようになります。

<h1>Update Test</h1>

<form action=&quot;/cake/uptests&quot; id=&quot;UptestIndexForm&quot; enctype=&quot;multipart/form-data&quot; method=&quot;post&quot; accept-charset=&quot;utf-8&quot;>
<div style=&quot;display:none;&quot;><input type=&quot;hidden&quot; name=&quot;_method&quot; value=&quot;POST&quot; /></div>
<input type=&quot;file&quot; name=&quot;data[Uptest][file_name]&quot; id=&quot;UptestFileName&quot; /><br />
<div class=&quot;submit&quot;><input type=&quot;submit&quot; value=&quot;送信&quot; /></div>
</form>


Controllerの設定

次にUptestsコントローラーをつくります。下記コードでファイルのアップロードは出来るようになります。

<?php
Configure::write('upload.path', 'img/upload');

class UptestsController extends AppController{
    public $name = 'Uptests';
    public $uses = array();
    public $layout = 'uptests';

    //画像アップロード
    public function index(){
        //データチェック
        if (empty($this->data)) return;
        if(!(is_uploaded_file($this->data['Uptest']['file_name']['tmp_name']))) return;

        //アップロードするファイルの場所
        $uploaddir = Configure::read('upload.path');
        $uploadfile = $uploaddir.DS.basename($this->data['Uptest']['file_name']['name']);

        // 同じ名前のファイルがすでに存在すれば、別名に変える
        $info = pathinfo($uploadfile);
        $i = 1;
        while(file_exists($uploadfile)){
            $i++;
            $file_name = basename($info['basename'],'.'.$info['extension']).
                '_'.$i.'.'.$info['extension'];
            $uploadfile = $info['dirname'].DS.$file_name;
            $this->data['Uptest']['file_name']['name'] = $file_name;
        }

        //画像をテンポラリーの場所から、正式な置き場所へ移動
        if (move_uploaded_file($this->data['Uptest']['file_name']['tmp_name'], $uploadfile)){
            chmod($uploadfile, 0666);
        }else {
            $this->Session->setFlash(&quot;ファイルのアップロードに失敗しました。&quot;);
        }
    }
}
?>

一番上の行の、Configure::write('upload.path', 'img/upload');というのは、upload.pathにimg/uploadと設定している様です。Configureメソッドは、ここに説明が書いてあります。
upload.pathは、ファイルをアップロードするパスのことで、app/webrootフォルダを基準にしたパスになります。よって、app/webroot/img/uploadにファイルをアップロードすると設定していることになります。ちなみに、uploadフォルダは、このコードですと事前に作成しておく必要がありますし、フォルダの権限設定も書き込み可能にしておく必要があります。

これで、フォームでファイルを選択して送信ボタンを押すと、ファイル名の重複を回避しながら、uploadフォルダにファイルが保存できるようになりました。

アップデートファイルのチェック

次に、ファイル名、ファイルのサイズ、拡張子をチェックして、条件に合うファイルのみアップロードするようにします。

ファイル名は半角英数字(英語は小文字のみ)とアンダーバーで30文字以内をルールにします。

if(!preg_match('/^[a-z0-9_]{1,30}$/',$this->data['Uptest']['file_name']['name'])) return;


ファイルのサイズは、$this->data['Uptest']['file_name']['size']に入っていますので、これをチェックするロジックを作ればOKです。

if($this->data['Uptest']['file_name']['size']>500000) return;


拡張子は、$this->data['Uptest']['file_name']['type']に入っていますので、これをチェックするロジックを作ればOKです。拡張子は、jpg,png,gifのみOKにします。

if($this->data['Uptest']['file_name']['type'] != 'image/jpeg' &amp;&amp;
    $this->data['Uptest']['file_name']['type'] != 'image/png' &amp;&amp;
    $this->data['Uptest']['file_name']['type'] != 'image/gif') return;


まとめ

あとは、データベースでファイル名を管理すればいいのですが、テストの為にユーザテーブル作るのめんどくさいのでやめましょう。ユーザテーブルがあったとして、イメージカラムつくって格納すればいいだけだし、例えばイメージを3つまで登録できるようにするのであれば、カラム3つ作ればよいです。アップデート前に3つすでに登録されているか確認して登録済みであればエラーを出すか、どれかと入れ替えるか確認する画面を表示したりすればいいかと存じます。

最後にまとめのコードを記載して終了します。

↓ビュー

<h1>Update Test</h1>

<?php
    $options = array(
        'action'=>'index',
        'type'=>'file'
    );
    echo $form->create('Uptest', $options);
?>
<?php echo $form->file('file_name') ?>
<?php echo $form->submit('送信'); ?>
<?php echo $form->end(); ?>

<?php if(!empty($err)) echo $err;?>

↓コントローラー

<?php
Configure::write('upload.path', 'img/upload');

class UptestsController extends AppController{
    public $name = 'Uptests';
    public $uses = array();
    public $layout = 'uptests';

    //画像アップロード
    public function index(){
        //データチェック
        if (empty($this->data)) return;
        if(!(is_uploaded_file($this->data['Uptest']['file_name']['tmp_name']))) return;

        //ファイル名チェック
        if(!preg_match('/^[a-z0-9_]{1,30}$/',$this->data['Uptest']['file_name']['name'])){
            $this->set('err','ファイル名は半角小文字英数字とアンダーバーで30文字以内にしてください。');
            return;
        }

        //ファイルサイズチェック
        if($this->data['Uptest']['file_name']['size']>500000){
            $this->set('err','ファイルサイズは500KB未満にしてください。');
            return;
        }

        //拡張子チェック
        if($this->data['Uptest']['file_name']['type'] != 'image/jpeg' &amp;&amp;
           $this->data['Uptest']['file_name']['type'] != 'image/png'  &amp;&amp;
           $this->data['Uptest']['file_name']['type'] != 'image/gif'){
                $this->set('err','ファイルはJPG,PNG,GIFのいずれかにしてください。');
                return;
        }

        //アップロードするファイルの場所
        $uploaddir = Configure::read('upload.path');
        $uploadfile = $uploaddir.DS.basename($this->data['Uptest']['file_name']['name']);

        // 同じ名前のファイルがすでに存在すれば、別名に変える
        $info = pathinfo($uploadfile);
        $i = 1;
        while(file_exists($uploadfile)){
            $i++;
            $file_name = basename($info['basename'],'.'.$info['extension']).
                '_'.$i.'.'.$info['extension'];
            $uploadfile = $info['dirname'].DS.$file_name;
            $this->data['Uptest']['file_name']['name'] = $file_name;
        }

        //画像をテンポラリーの場所から、正式な置き場所へ移動
        if (move_uploaded_file($this->data['Uptest']['file_name']['tmp_name'], $uploadfile)){
            chmod($uploadfile, 0666);
        }else {
            $this->set('err','ファイルのアップロードに失敗しました。');
        }
    }

}
?>