CakePHP

複数ファイルをアップロードできるjQueryのプラグイン「Uploadify」をCakePHPで使ってみる

2015/09/10

前回に続き、ファイルをまとめてアップロードする jQuery のプラグイン「Uploadify」の使い方。
今回はCakePHPでの設置の方法を晒してみたいと思います。

「Uploadify」の設置

【設置構成】

上記構成で説明します。
前回のアップロードフォルダは「uploads」でしたが、今回は media とします。
ちなみに、 media は medium の複数形ですので、覚えておくと良いことがあるかも。

DBへの書き込みも行うので、適当にこのようなSQLでテーブル作成。
[sql]
CREATE TABLE IF NOT EXISTS media (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
created DATETIME NOT NULL, -- 登録日時
modified DATETIME NOT NULL, -- 編集日時
pic_large VARCHAR(255) default NULL, -- 等倍画像
pic_middle VARCHAR(255) default NULL, -- 中サイズ用画像
pic_small VARCHAR(255) default NULL, -- 小サイズ画像
pic_mobile VARCHAR(255) default NULL, -- 携帯用画像
alt VARCHAR(255) default NULL, -- alt
title VARCHAR(255) default NULL, -- 代替テキスト
caption VARCHAR(255) default NULL, -- キャプション
description VARCHAR(255) default NULL, -- 説明
width INT default NULL, -- 幅px
height INT default NULL, -- 縦px
path VARCHAR(255) default NULL, -- 絶対パス
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
[/sql]

view

アップロードフォーム(/app/views/upform.ctp)

レイアウトかヘッダ辺りで jQuery と uploadify を読み込んで下さい。

[php]
<?php
echo '<p class="upform">SELECT FILES ボタンを押し、ファイルを選択して下さい。<br />複数の画像を選択することも可能です。</p>';

echo $form->create('Medium', aa('type','post', 'action','upload'));
echo '<div id="queue" style="background-color: #505050; height: 200px; margin-bottom: 10px; padding:10px; overflow: auto; width: 400px;"></div>';
echo $form->file('Medium.upload_file', aa('id','file_upload'));
echo $form->end(null);

$timestamp = time();
?>
<script type="text/javascript">
<!--
$(document).ready(function() {
$('#file_upload').uploadify({
'formData' : {
'timestamp' : '<?php echo $timestamp;?>',
'token' : '<?php echo md5('unique_salt' . $timestamp);?>'
},
'debug' : false,
'uploader' : '/media/upload',
'swf' : '/js/uploadify/uploadify.swf',
'auto' : true,
'queueID' : 'queue',
'fileTypeDesc' : 'Image Files',
'fileTypeExts' : '*.gif; *.jpg; *.png',
});
});
-->
</script>
[/php]

controller

アップロードフォーム用アクション : upform

単に表示するだけです。

[php]
function upform()
{
// htmlタイトル
$this->set('title_for_layout', 'メディアアップロード');
}
[/php]

アップロード用アクション

uploadify.php を元に作成しています。

途中にあるパスはapp.php で以下のように設定しています。
PIC_PATH_MEDIA
define('PIC_PATH_MEDIA', WWW_ROOT . 'media/img/'); // WEBルートから

PIC_DIR_PATH_MEDIA
define('PIC_DIR_PATH_MEDIA', "/" . "media/img/"); // 絶対パス

PIC_WIDTH_MIDDLE
PIC_WIDTH_SMALL
PIC_WIDTH_MOBILE には、保存する画像のピクセルサイズを指定しています。

[php]
function upload()
{
// レイアウトは使用しない。
$this->layout = null;
$this->autoLayout = false;

// アップロード情報がないなら終了
if ( empty($_FILES) ) {
exit();
}

// 画像をアップするパス(WWW_ROOTからのパス)
$path = $path = PIC_PATH_MEDIA;

$verifyToken = md5('unique_salt' . $_POST['timestamp']);

$microtime = (microtime()*1000000);

if ( !empty($_FILES) && $_POST['token'] == $verifyToken ) {

//
$name = $_FILES['Filedata']['name'];
$tempFile = $_FILES['Filedata']['tmp_name'];

// Validate the file type
$fileTypes = array('jpg','jpeg','gif','png'); // File extensions
$fileParts = pathinfo($_FILES['Filedata']['name']);

// ファイル名がアルファベットのみかをチェック
if ( preg_match("/^([a-zA-Z0-9\.\-\_])*$/u", $name) == false ) {
$saveFileName = date("Ymd_His", time()); // 日時で
}
else {
if ( preg_match("/\.jpg$/ui", $name) == true ) {
$ret = explode('.jpg', $name);
}
elseif ( preg_match("/\.gif$/ui", $name) == true ) {
$ret = explode('.gif', $name);
}
elseif ( preg_match("/\.png$/ui", $name) == true ) {
$ret = explode('.png', $name);
}
$saveFileName = $ret[0]; // 拡張子を除いたそのまま
}

// フォルダ内を検索し、同名ファイルがあれば、保存ファイル名をタイムスタンプとする
if ( is_file(PIC_PATH_MEDIA . $name) == true ) {
$saveFileName = date("Ymd_His", time()); // 日時で
}

// マイクロ秒をファイル名に付加
$saveFileName = $saveFileName . $microtime;

if ( in_array($fileParts['extension'],$fileTypes) ) {

// アップロード処理(戻り値:ファイル名)
$pic_large = $this->CompImageUpload->copyUploadFilenameNotChange($name, $tempFile, $path, $saveFileName, 1); // 縦横そのまま
$pic_middle = $this->CompImageUpload->sizeChangeUploadFilenameNotChange($name, $tempFile, $path, $saveFileName, PIC_WIDTH_MIDDLE, 1, "middle");
$pic_small = $this->CompImageUpload->sizeChangeUploadFilenameNotChange($name, $tempFile, $path, $saveFileName, PIC_WIDTH_SMALL, 1, "small");
$pic_mobile = $this->CompImageUpload->sizeChangeUploadFilenameNotChange($name, $tempFile, $path, $saveFileName, PIC_WIDTH_MOBILE, 1, "mobile");

//echo '1';

if ( ($pic_large === false) || ($pic_middle === false) || ($pic_small === false) || ($pic_mobile === false) ) {
$error_message = '画像ファイルが正しくないか、ファイルサイズがオーバーしています。';
$this->makeErrorMessage($error_message);
$this->list();
$this->render('list');
return;
}

// 拡張子を除いたファイル名作成
if ( preg_match("/\.jpg$/ui", $pic_large) == true ) {
$fname = explode('.jpg', $pic_large);
}
elseif ( preg_match("/\.gif$/ui", $pic_large) == true ) {
$fname = explode('.gif', $pic_large);
}
elseif ( preg_match("/\.png$/ui", $pic_large) == true ) {
$fname = explode('.png', $pic_large);
}

//------------------------------------------------------------
// media テーブルここから
//------------------------------------------------------------
// トランザクション開始
$this->Medium->begin();

// ID初期化
$this->Medium->id = NULL;

// 登録データ成形
$save_media_datas = array(
'Medium' => array(
'pic_large' => $pic_large,
'pic_middle' => $pic_middle,
'pic_small' => $pic_small,
'pic_mobile' => $pic_mobile,
'alt' => $fname[0],
'title' => null,
'caption' => null,
'description' => null,
'path' => PIC_DIR_PATH_MEDIA,
)
);

// DB登録実行
if ( !$this->Medium->save($save_media_datas, 0) ) {
$this->Medium->rollback(); // RollBack

if ( $this->Medium->getDbo()->error !== null ) {
$message = "メディア登録エラー\n";
$message .= "[SQL ErrorCode] " . $this->Medium->getDbo()->error . "\n";
}

// エラーログ作成
$this->_log('メディア登録エラー', __LINE__);

// 失敗したらフォームに戻る
$this->list();
$this->render('list');
return;
}
//------------------------------------------------------------
// media テーブルここまで
//------------------------------------------------------------

// 確定(Commit)
$this->Medium->commit();

} else {
echo 'Invalid file type.';
}
}
}
[/php]

CakePHPなので、「$_POST」とか「$_FILES」を「$this->data」で受けたかったのですが、うまく取得できなかったので、「$_POST」「$_FILES」形式で取得しています。

アップロードの処理は独自で作成したコンポーネントを使用しています。
やってることは、tmpデータを指定されたファイル名でサイズそのままと、サイズを変えてコピーするだけです。
戻り値はそれぞれ、ファイルネームを返しています。
要望があればまたそちらも公開したいと思います。

戻ってきたら、DBにインサートしているだけ。その辺りは問題ないと思います。

model

Medium.php

最後にモデル。
特にアップロードに関して処理していませんので、以下のように。

[php]
<?php
class Medium extends AppModel
{
var $name = 'Medium';
}
?>
[/php]

と、早足ですが、とりあえずはこれで toogie の環境(ウェブサーバと Windows7 に作ったローカル環境)で走っています。
動かないって方は、まずは通常の PHP で動くかどうかを試してから、CakePHP にとりかかるのがよろしいかと思います。

ちなみにこの CakePHP 版を作るのに toogie は2日掛けてしまいました(苦笑

何かのお役に立てれば幸いです。

[tgAmazonItemLookup asin="4150309930" related="1"]

-CakePHP
-, , , , , ,