CakePHP2 DropZone.jsでのファイルアップロードの実装について
受付中
回答 1
投稿
- 評価
- クリップ 0
- VIEW 2,639
前提・実現したいこと
CakePHP2とDropZone.jpでドラッグ&ドロップによるファイルアップロードを実現したいです。
CakePHPのバージョンは2.8.3です。
発生している問題・エラーメッセージ
https://teratail.com/questions/31031
こちらを参考に作成し、レスポンスも200が返ってきていますが、
ファイルがアップロードされません。
アップロードディレクトリのパーミッションは777に変更しています。
ご教授のほどよろしくお願いいたします。
該当のソースコード
/app/View/UpFiles/index.ctp
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<?php
echo $this->Html->css('dropzone');
echo $this->Html->script('dropzone');
?>
<script>
$(function(){
Dropzone.autoDiscover = false;
Dropzone.options.myAwesomeDropzone = {
paramName : "file", // input fileの名前
parallelUploads:1, // 1度に何ファイルずつアップロードするか
addRemoveLinks: true,
acceptedFiles:'image/*', // 画像だけアップロードしたい場合
maxFiles:10, // 1度にアップロード出来るファイルの数
maxFilesize:0.5, // 1つのファイルの最大サイズ(1=1M)
dictFileTooBig: "ファイルが大きすぎます。 ({{filesize}}MiB). 最大サイズ: {{maxFilesize}}</script>
<div id="my-awesome-dropzone" class="dropzone"></div>
/app/Controller/UpFilesController.php
<?php
App::uses('AppController', 'Controller');
class UpFilesController extends AppController {
public $uses = array('UpFile');
public function index()
{
}
public function upload()
{
$file = $this->request['file'];
$ds = DIRECTORY_SEPARATOR;
$storeFolder = 'uploads';
if(!empty($file))
{
$tempFile = $file['tmp_name'];
$targetPath = WWW_ROOT . 'uploads' . $ds;
$targetFile = $targetPath.$file['name'];
move_uploaded_file($tempFile, $targetFile);
}
}
}
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
0
$file = $this->request['file'];
となってますが、CakePHP2ではpostデータは$this->request->dataの中に入ってくるので、やるなら
$file = $this->request->data['file'];
といった感じでは?
upload()アクションに
$this->log($this->request->data); というのを追加して、ログファイルでどんな形式でデータが返ってくるか確認したほうが良いですよ?
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.20%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2016/06/21 14:47
ご指摘いただいた点を修正し、ログ出力処理を記述したところ、出力されませんでした。
そこで、index()でもログを吐くようにすると、
画面を開いた時と画像をドラッグ&ドロップした時の2回出力されました。
/app/Config/routes.phpを確認すると以下のような記述をしており、
コメントアウトすることで、upload()アクションは呼び出せました。
```PHP
Router::connect('/UpFiles/*', array('controller' => 'UpFiles', 'action' => 'index'));
```
しかし、$this->request->dataの中身は空でした。
```
2016-06-21 13:52:36 Debug: Array
(
)
```
dropzone.jsでファイルをアップロードしてるであろう処理に
console.log(file);を入れて出力してみました。
```JavaScript
Dropzone.prototype.uploadFiles = function(files) {
var file, formData, handleError, headerName, headerValue, headers, i, input, inputName, inputType, key, method, option, progressObj, response, updateProgress, url, value, xhr, _i, _j, _k, _l, _len, _len1, _len2, _len3, _m, _ref, _ref1, _ref2, _ref3, _ref4, _ref5;
xhr = new XMLHttpRequest();
for (_i = 0, _len = files.length; _i < _len; _i++) {
file = files[_i];
file.xhr = xhr;
}
method = resolveOption(this.options.method, files);
url = resolveOption(this.options.url, files);
xhr.open(method, url, true);
xhr.withCredentials = !!this.options.withCredentials;
response = null;
handleError = (function(_this) {
return function() {
var _j, _len1, _results;
_results = [];
for (_j = 0, _len1 = files.length; _j < _len1; _j++) {
file = files[_j];
_results.push(_this._errorProcessing(files, response || _this.options.dictResponseError.replace("{{statusCode}}", xhr.status), xhr));
}
return _results;
};
})(this);
updateProgress = (function(_this) {
return function(e) {
var allFilesFinished, progress, _j, _k, _l, _len1, _len2, _len3, _results;
if (e != null) {
progress = 100 * e.loaded / e.total;
for (_j = 0, _len1 = files.length; _j < _len1; _j++) {
file = files[_j];
file.upload = {
progress: progress,
total: e.total,
bytesSent: e.loaded
};
}
} else {
allFilesFinished = true;
progress = 100;
for (_k = 0, _len2 = files.length; _k < _len2; _k++) {
file = files[_k];
if (!(file.upload.progress === 100 && file.upload.bytesSent === file.upload.total)) {
allFilesFinished = false;
}
file.upload.progress = progress;
file.upload.bytesSent = file.upload.total;
}
if (allFilesFinished) {
return;
}
}
_results = [];
for (_l = 0, _len3 = files.length; _l < _len3; _l++) {
file = files[_l];
console.log(file);
_results.push(_this.emit("uploadprogress", file, progress, file.upload.bytesSent));
}
return _results;
};
})(this);
```
ログのスクリーンショットが以下になります。
http://www.fastpic.jp/viewer.php?file=0646917844.png
responseのところに「Undefined index: file [<b>APP/Controller/UpFilesController.php</b>, line <b>17</b>]」の記述があるのが気になりました。
CakePHPを使わずにDropZoneでのアップロードも試したのですが、
こちらではうまくアップロードでき、responseの中は空でした。
お手数をおかけいたしますが、ご教授のほどよろしくお願いいたします。
2016/06/21 14:50
見づらくなってしまい、申し訳ございません。
よろしくお願いいたします。
2016/06/22 13:12 編集
routes.phpの設定は明らかに変ですね。何か見えないとこで余計なことをしているような気がします。
問題を切り分ける必要がありそうなので、一度、cakeではなく、素のPHP(フレームワーク無しで)でどういうレスポンスが返ってくるかなどの、動きを確認されるてみたほうがいいかもしれません。
2016/06/22 17:39
indexアクションで表示されるHTMLは意図通りでした。
素のPHPとCakeでのレスポンスの違いは、XMLHttpRequestの「response」と「responseTxt」の中身で
Cakeでは、$this->request->data['file']のインデックスである「file」が定義されていない旨のHTML文が入っています。
なぜうまくデータが渡っていないのか、素のPHPとCakeそれぞれの場合で、
dropzone.jsの中をもう少し追いかけてみたいと思います。
念のためresponseのHTMLの概要を記述します。
------------------------------------------------------------------------------------------
◆見出し
Notice (8): Undefined index: file [APP/Controller/UpFilesController.php, line 17]
◆<span class="code-highlight">
uploadアクションに書かれている以下の2行が出力されています。
$this->log($this->request->data, LOG_DEBUG);
$file = $this->request->data['file'];
◆<pre class="stack-trace">
UpFilesController::upload() - APP/Controller/UpFilesController.php, line 17
ReflectionMethod::invokeArgs() - [internal], line ??
Controller::invokeAction() - CORE/Cake/Controller/Controller.php, line 491
Dispatcher::_invoke() - CORE/Cake/Routing/Dispatcher.php, line 193
Dispatcher::dispatch() - CORE/Cake/Routing/Dispatcher.php, line 167
[main] - APP/webroot/index.php, line 111
------------------------------------------------------------------------------------------
2016/06/23 11:37
こちらを参考に、POSTデータにhogeのカラムを追加して
ログを確認したところ、hogeの値は出力されました。
dropzone.jsの処理を自分なりに追いかけてみましたが、
どのタイミングでfileの中身をconsole.logで出力しても
responseには既にfileが定義されていないエラーが入っておりました。
ちなみに、index.ctpのhogeを設定している箇所にconsole.logを入れても同様でした。
myDropzone.on("sending", function(file,xhr,formData) {
console.log(file);
formData.append("hoge", hogeParam);
});
------------------------------------------------------------------------------------------
<script>
$(function(){
// 何かの値をPostしたいなら
var hogeParam = "hoge";
// おまじない
Dropzone.autoDiscover = false;
Dropzone.options.myAwesomeDropzone = {
paramName : "file", // input fileの名前
parallelUploads:1, // 1度に何ファイルずつアップロードするか
addRemoveLinks: true,
acceptedFiles:'image/*', // 画像だけアップロードしたい場合
maxFiles:10, // 1度にアップロード出来るファイルの数
maxFilesize:0.5, // 1つのファイルの最大サイズ(1=1M)
dictFileTooBig: "ファイルが大きすぎます。 ({{filesize}}MiB). 最大サイズ: {{maxFilesize}}MiB.",
dictInvalidFileType: "画像ファイル以外です。",
dictMaxFilesExceeded: "一度にアップロード出来るのは10ファイルまでです。",
};
// urlは実際に画像をアップロードさせるURLパスを入れる
var myDropzone = new Dropzone("div#my-awesome-dropzone",{url:"<?php echo $this->Html->url(array('controller' =>'UpFiles','action' => 'upload')); ?>"});
// 何か値をpostしたい場合
myDropzone.on("sending", function(file,xhr,formData) {
formData.append("hoge", hogeParam);
});
});
</script>
------------------------------------------------------------------------------------------