質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.04%

CakePHP3でアップロードした画像の差し替えがうまくできない

受付中

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,629

score 23

下記URLのサイトをもとに、画像アップロードの実装をおこなっております。
https://blog.s-giken.net/325.html

画像のアップロード、削除までは、実装できましたが、
編集を行う際、画像の差し替えを行った場合に、新たにアップロードした画像が
DBに反映されません。同様に、指定したディレクトリにも画像が格納されません。
編集を実行してもエラーメッセージなどは表示されず、保存されたというメッセージが出力されます。

丸3日ほど、色々と修正を試みましたが、解消はされませんでした。
CakePHPにお詳しい方のお力をお借りしたく存じます。
宜しくお願い致します。

DBデーブル

CREATE TABLE `news` (
  `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `title_date` date NOT NULL,
  `title` varchar(255) NOT NULL,
  `body` text,
  `file_name` text,
  `created` datetime NOT NULL,
  `modified` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;


edit.ctp

<?php
$this->assign('title','Edit Post');
 ?>

 <h1>編集画面</h1>
 <?= $this->Html->link('戻る',['action'=>'index'],['class'=>['pull-right','fs12']]); ?>

 <?= $this->Form->create($news); ?>
<?= $this->Form->textarea('title_date'); ?>
<?= $this->Form->textarea('title'); ?>
<?= $this->Form->textarea('body'); ?>
<!--画像の修正-->
<?php
//image」の有無をチェックすることで、ファイルがアップロードされているか否かをチェック
if($news->file_name){

    echo $this->Html->image("/upload_img/".str_replace('\\','/',$news->file_name));

    echo $this->Form->input("file_before",["type"=>"hidden",
                                            "value"=>$news->file_name]);
    echo $this->Form->input("delete",["type"=>"submit",
                                      "name"=>"file_delete",
                                      "value"=>"delete"]);

}?>

 <?=$this->Form->control('file_name1',["type"=>"file"]);?>
 <?= $this->Form->button('submit'); ?>
 <?= $this->Form->end(); ?>


NewsController.php

<?php
namespace App\Controller;

use App\Controller\AppController;
use Cake\Filesystem\Folder;
use Cake\Filesystem\File;
use RuntimeException;

class NewsController extends AppController
{
    public function index()
    {
        $news = $this->paginate($this->News);

        $this->set(compact('news'));

    }
////編集//////////////////////////////////////////////////////////////////////
            public function edit($id = null)
            {

            //変数newsの中に、DBから取得したデータを入れる
            $news = $this->News->get($id, [
            'contain' => []
        ]);
        //PATCH 一部分を更新したい場合。POST 新規に追加する場合。 PUT 丸ごと更新する場合。
        //リクエストがPATCH、POST、PUT である時の処理
        if ($this->request->is(['patch', 'post', 'put'])) {
            //patchEntityこれは、データの更新するときに使用する。具体的には、更新処理。
            //patchEntity 複数のレコードのデータを一括して更新してくれる
            //テーブルnewsのデータを取得
            $news = $this->News->patchEntity($news, $this->request->getData());

            //アップロードするファイルを保存するフォルダを指定
            $dir = realpath(WWW_ROOT . "/upload_img");


            // deleteボタンがクリックされたか、いかなの判定
            if($this->request->getData('file_delete')){
                try {

                    //フォルダを作成して、そこに差し替えまえのファイルを移動させる
                    $del_file = new File($dir . "/". $this->request->getData('file_before'));
                    // ファイル削除処理実行 Fileクラスで削除処理対象のファイルを指定して削除を実行
                    if($del_file->delete()) {
                        $news['file_name'] = "";
                    } else {
                        //削除できなかった時の処理
                        $news['file_name'] = $this->request->getData('file_before');
                        throw new RuntimeException('ファイルの削除ができませんでした.');
                    }
                  //エラー処理  
                } catch (RuntimeException $e){
                    $this->Flash->error(__($e->getMessage()));
                }
            } else {
                //submitボタンを押した時の処理。
                // ファイルが入力されたとき、ファイルをアップロードする
                if ($this->request->getData('file_name.name')) {
                    $limitFileSize = 10240 * 10240;
                                //アップロードするファイルを保存するフォルダを指定
            $dir = realpath(WWW_ROOT . "/upload_img");


            try {

            //ファイルの入力項目の値「$this->request->data['file_name']」と指定した値を引数として渡して、関数を実行
                $news['file_name'] = $this->file_upload($this->request->getData('file_name1'), $dir, $limitFileSize);
            } catch (RuntimeException $e){
                $this->Flash->error(__('ファイルのアップロードができませんでした.'));
                $this->Flash->error(__($e->getMessage()));
            }
                    catch (RuntimeException $e){
                        // アップロード失敗の時、既登録ファイルがある場合はそれを保持
                        if ($this->request->getData('file_before')){
                            $news['file_name'] = $this->request->getData('file_before');
                        }
                        $this->Flash->error(__('ファイルのアップロードができませんでした.'));
                        $this->Flash->error(__($e->getMessage()));
                    }
                } else {
                    // ファイルは入力されていないけど登録されているファイルがあるとき
                    if ($this->request->getData('file_before')){
                        $news['file_name'] = $this->request->getData('file_before');
                    }
                }
            }

            if ($this->News->save($news)) {
                $this->Flash->success(__('The news has been saved.'));

                if($this->request-> getData('file_delete')){
                    $this->set(compact('news'));
                    return $this->redirect(['action' => 'edit', $id]);
                } else {
                    return $this->redirect(['action' => 'index']);
                }
            }
            $this->Flash->error(__('The news could not be saved. Please, try again.'));
        }
        $this->set(compact('news'));
        $this->set('_serialize', ['news']);
    }
/////////////////////////////////////////////////////////////////////////////
 ////実際にファイルアップロードを行う処理///////////////////////////////////

 public function file_upload ($file = null,$dir = null, $limitFileSize = 10240 * 10240){
        try {
            // ファイルを保存するフォルダ $dirの値のチェック
            if ($dir){
                if(!file_exists($dir)){
                    throw new RuntimeException('指定のディレクトリがありません。');
                }
            } else {
                throw new RuntimeException('ディレクトリの指定がありません。');
            }

            // 未定義、複数ファイル、破損攻撃のいずれかの場合は無効処理
            if (!isset($file['error']) || is_array($file['error'])){
                throw new RuntimeException('Invalid parameters.');
            }

            // エラーのチェック
            switch ($file['error']) {
                case 0:
                    break;
                case UPLOAD_ERR_OK:
                    break;
                case UPLOAD_ERR_NO_FILE:
                    throw new RuntimeException('No file sent.');
                case UPLOAD_ERR_INI_SIZE:
                case UPLOAD_ERR_FORM_SIZE:
                    throw new RuntimeException('Exceeded filesize limit.');
                default:
                    throw new RuntimeException('Unknown errors.');
            }

            // ファイル情報取得
            $fileInfo = new File($file["tmp_name"]);

            // ファイルサイズのチェック
            if ($fileInfo->size() > $limitFileSize) {
                throw new RuntimeException('Exceeded filesize limit.');
            }

            // ファイルタイプのチェックし、拡張子を取得
            if (false === $ext = array_search($fileInfo->mime(),
                                              ['jpg' => 'image/jpeg',
                                               'png' => 'image/png',
                                               'gif' => 'image/gif',],
                                              true)){
                throw new RuntimeException('Invalid file format.');
            }

            // ファイル名の生成
            //そのままのファイル名を使用            $uploadFile = $file["name"] . "." . $ext;
            $uploadFile = sha1_file($file["tmp_name"]) . "." . $ext;

            // ファイルの移動


            if (!@move_uploaded_file($file["tmp_name"], $dir . "/" . $uploadFile)){
                throw new RuntimeException('アップロードしたファイルの移動ができませんでした');

            }


            // 処理を抜けたら正常終了
//            echo 'File is uploaded successfully.';

        } catch (RuntimeException $e) {
            throw $e;
        }
        return $uploadFile;
    }



/////////////////////////////////////////////////////////////////////////////
    }


NewsTabele.php

<?php
namespace App\Model\Table;

//クラスをまえもって呼び出しておく
use Cake\ORM\Table;
//画像拡張子を指定するためのバリデーションを使えるようにする
use Cake\Validation\Validator;

$validator = new Validator();

class NewsTable extends Table
{
    //初期化しておく
    public function initialize(array $config)
    {
        $this->setTable('news');
        $this->primaryKey('id'); 
        $this->setDisplayField('dir');                              
        //$this->addBehavior('Timestamp');       
    }
}

情報

phpバージョン:7.2.19
cakePHPバージョン:3.7.8
画像格納先:webroot/upload_img/
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • m.ts10806

    2019/08/06 15:28

    コードあまり見てませんが、編集時、ファイル以外のカラムは正しく更新されているのでしょうか。またアップロードするファイルは、別の名前をつけてもできてませんか?
    アップロード処理は正しく通っているのでしょうか

    キャンセル

  • jam912sh

    2019/08/06 15:33 編集

    mts10806様
    ご返答有難うございます。
    >編集時、ファイル以外のカラムは正しく更新されている
    ファイル以外のカラムは正しく更新可能でございます。

    >アップロードするファイルは、別の名前をつけてもできてませんか
    はい、アップロードできない状態でございます。

    >アップロード処理は正しく通っているのでしょうか
    はい、アップロード処理は問題ないかと存じます。画像の差し替え動作に問題があるかと存じます。

    宜しくお願い致します。

    キャンセル

  • m.ts10806

    2019/08/06 15:49

    もう1点確認です。
    「フォルダを作成して、そこに差し替えまえのファイルを移動させる」
    はできているということでよろしいですか?

    キャンセル

  • jam912sh

    2019/08/06 15:56

    mts10806様
    ご確認頂き有難うございます。
    >フォルダを作成して、そこに差し替えまえのファイルを移動させる
    こちらの処理、うまく出来ていないようでございます。
    削除処理は問題なくできているようでございます。
    宜しくお願い致します。

    キャンセル

回答 1

0

formが

 <?=$this->Form->control('file_name1',["type"=>"file"]);?>

で定義されているなら下記は

if ($this->request->getData('file_name.name')) {
ではなく
if ($this->request->getData('file_name1')) {
では?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/08/06 17:13

    というかファイルアップロードできてないならsaveさせてはダメだと思います。
    失敗した時点でエラーとして返さないと

    キャンセル

  • 2019/08/06 17:28

    ごもっともで御座いますね。
    ご指摘箇所、修正し、今一度動作確認致します。
    ちなみに、全部フラッシュエラーを並べますと以下で御座います。

    1つ目「ファイルのアップロードができませんでした.」
    2つ目「Invalid parameters.」
    3つ目「The news has been saved.」

    今日はこれから、席を外しまして、、進捗が悪いので、大目玉を喰らいに行ってまいります。
    また明日調査致します!
    お忙しい中、ご教示頂きまして、有難うございました。大変参考になりました。

    キャンセル

  • 2019/08/06 17:39

    > Invalid parameters.
    直接原因はこれですね。
    ちゃんとfile_upload()内でそのメッセージ返してるようですし、
    その変をデバッグしてみてください。たぶんあとはデバッグで解決できます。

    ちなみに3つ目は先ほども言いましたがエラーではないですね。
    コードを読むと分かりますが「$this->Flash->success()」でセットされていますし。

    (自分で質問しているのに他人のコードのような話し方されてますが、どこまでこのコードを把握できているのでしょうか。かなり不安です。)

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.04%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る