質問: PHP7.1、CakePHP3.6、JavascriptでWebアプリケーションを作っています。 よくあるプロフィールの登録画面でプロフィール情報+画像(複数項目あり)をアップロード、登録する処理について、編集時の画像データをどう取り回せばいいか悩んでいます。 テーブル構造は以下となります。 ``` CREATE TABLE `users` ( `id` INT NOT NULL AUTO_INCREMENT, `name` VARCHAR(45) NULL, PRIMARY KEY (`id`)); CREATE TABLE `user_images` ( `id` INT NOT NULL AUTO_INCREMENT, `user_id` INT NOT NULL, `file_name` VARCHAR(255) NOT NULL, PRIMARY KEY (`id`), INDEX `fk_user_idx` (`user_id` ASC), CONSTRAINT `fk_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION); ``` 新規登録時は以下の処理を前提とします。 ``` タグで画像を選択後、Ajaxでサーバにアップロード、一意のファイル名をつけて一時画像フォルダに保存 ↓ 画像URL、ファイル名をクライアントに返して画面側でプレビュー表示 ↓ 登録ボタンクリック → 新規登録処理内で、POSTされたファイル名をもとに、一時画像フォルダから正規画像フォルダのユーザーIDフォルダ 配下にコピーして、user_imagesテーブルに新規ユーザーIDに紐づくファイル名を保存 ``` プロフィール編集時、初期値としてプロフィール情報とプレビューのための画像URL、画像ファイル名をクライアント側に渡します。 画像ファイルが必須登録ではないとすると、画像ファイル編集については以下の3パターンが発生します。 1. 画像はそのままで更新 2. 画像を変更して更新 3. 画像を削除して更新 上記3パターンの処理を条件分岐で網羅させるのも大変なので、私が考えたのは、新規登録処理にある「一時画像フォルダからコピーして保存」という 処理を使い回すことです。具体的には以下の処理になります。 ``` 編集時のプロフィール情報取得時に、ユーザーIDに紐づく画像を正規画像フォルダから一時画像フォルダへコピー ↓ プロフィール情報とプレビューのための画像URL、画像ファイル名をクライアント側に渡す ↓ クライアント側で画像削除や差し替えなど編集作業 ※削除した場合はファイル名をPOSTしないようにする ↓ 更新ボタンクリック → 編集処理内で、まずは正規画像フォルダのユーザーIDフォルダ配下の画像データと、ユーザーIDに紐づくuser_imagesテーブルの データを削除し、新規登録処理と同じようにPOSTされたファイル名をもとに、一時画像フォルダから正規画像フォルダのユーザーIDフォルダ配下にコピー ``` 上記の処理にすると、上記3パターンを網羅できると考えたのですが、編集時のプロフィール情報取得時に画像を一時画像フォルダに コピーする処理が少し野暮ったい気がしました。 もっと簡単な処理や定番のパターンなどをご存知でしたらぜひご教示頂きたく、宜しくお願い致します。 ※画像をAjaxでアップロードする仕様は確定していますので変えられません。 ※画像をDBに保存することは考えていません。
回答: もしかしたら要件を正しく汲み取れていない可能性もあるのですが・・。 定番かどうかは分かりませんが、「一時画像フォルダ」は「テンポラリ」と解釈してもよろしいでしょうか? テンポラリであれば、処理が終了したら自動的に削除されるものになります。 * PHPマニュアル:tmpfile ではなく、テンポラリから移動したご自身で準備されたフォルダのファイルである場合、 そこにファイルが沢山たまっていくことになります。 もし画像を変更する場合はどうするのでしょうか? `削除して同名で設置`か、`新しい名前で保存する` いずれかになると思います。 つまり、一時と正規でミラーリングのような状態となりますが、画像が必ず倍の容量を食い続けることになります。 ユーザープロフィールの画像とのことですが、多少ファイルサイズの上限を制限したとしても ユーザーが増えるたびに画像2枚分のスペースが増えます。 これはサーバー容量圧迫(あともしかしたらサイトの表示速度の遅延)につながる可能性もあります。 (ディレクトリを細かく分けたとしても空ディレクトリの問題とか必ず出てきます) 入力フォームから画像が送られてきたかどうかはPOSTデータを確認すれば分かるので、 下記のような処理フローでいかがでしょうか。 ``` if(一時フォルダに画像がある){ 一時フォルダの画像削除 } if(送信された){ 一時フォルダにアップロード } 確認画面?プレビュー表示 更新ボタン押下 if(一時フォルダに画像がある){ if(正規フォルダに画像がある){ 正規フォルダの元画像削除 } if(!正規フォルダのユーザー用フォルダの存在){ ユーザーフォルダ作成 } 一時フォルダの画像を正規フォルダに移動 } ```