エス技研

WordPress、CakePHP、PHP、baserCMSなどの Web系システムを中心に情報を提供します!


CakePHP3でファイルのアップロード処理を自作・解説付き・その1

      2017/11/26

CakePHP3でファイルのアップロード処理を作る

 
CakePHPでは、下記の GitHubに公開されているファイルアップロードプラグインがよく利用されているそうです。
 
https://github.com/josegonzalez/cakephp-upload/blob/master/README.md#requirements
 
ですが、このプラグインでは、アップロードしたファイルのサムネイルを作成するのですが、その際に GDライブラリか、Imagickライブラリを使います。
そのため、GD、Imagickのいずれかが利用でいないとこのプラグインを利用できないのですが、レンタルサーバの場合は、ライブラリを自由にインストールできない場合もあろうかと考え、まずは、アップロード処理を自作してみることにしました。
 
 

画像アップロードを行う画面の前提

 
一般的な CMSを想定し、ニュース登録の画面を作成します。
その中に、画像の登録を行う項目があることを想定しています。
 
 
テーブルは下記を想定し、必要なプログラムは、bake allで生成しているものとして話を始めます。
 

 
 
フォームの画面は下記のようなイメージです。
CakePHP3でファイルのアップロード処理を自作・解説付き・その1
 
 

テンプレートファイルの変更

 
ファイルのアップロードをするには、まず、formタグを修正する必要があります。
 
CakePHP3の Formヘルパーの使い方は「CakePHP3のForm Helperの使い方のまとめ」で解説をしていますので、詳しくはそちらを参照してください。
 
 

add.ctp、edit.ctpを変更

 
アップロードする画像を入力する画面となるテンプレートの変更を行います。
対象ファイルは、以下の 2ファイルです。
 
/src/template/news/add.ctp
/src/template/news/edit.ctp
 
修正箇所は以下の通りです。
Formタグでファイルのアップロードを扱えるようにします。
 

 
 
inputタグのタイプを fileに変更します。
 

 
 

アップロードされる画像の確認

 
入力フォームを修正しただけで、画像をアップロードすることはできます。
 
実際にアップロードしたファイルを、コントローラー側では下記の様に記述することで受け取っていることを確認することができます。
 
/src/controller/NewsController.php
 

 
これにより、ログファイルには下記の情報が出力されます。
ログファイルへの出力する方法の解説は「CakePHP3ログファイルへの出力・$this->log()、独自ログへの出力方法の解説」を参照してください。
 

 
入力フォームに追加したファイルの入力項目「file_name」から送信された値が取得できていることが確認できます。
 
ただ、この状態では、送信された画像ファイルは、「tmp_name」の値にあるように「C:\xampp\tmp\php37DC.tmp」という一時ファイルとして生成されますが、その後の処理でそのファイルも削除されてしまいます。
 
そのため、この一時ファイルを希望する場所に移すための処理を記述します。
加えて、ファイルがアップロードされていない場合や、ファイルサイズが大きい場合、想定しているファイル種類でない場合などのチェックも行います。
 
 


 

コントローラーの変更

 
ファイルアップロードの処理を作成するにあたって、必要になる処理をコントローラーに追記します。
 
対象となるコントローラーファイルは、下記になります。
/src/controller/NewsController.php
 
 

必要なクラスをロードする処理

 
ファイルアップロードの処理に必要となるクラスをロードする処理、下記の内容を追記します。
 

 
Folder、Fileクラスに関しては下記が参考になります。
 https://book.cakephp.org/3.0/ja/core-libraries/file-folder.html
 
「RuntimeException」クラスに関しては下記が参考になります。
 http://waterada.ldblog.jp/archives/20000008.html
 
 

ファイルアップロードの処理の追記

 
下記の 4~12行目を追加します。
「add()」「edit()」アクションに追加します。
 

 
5行目で、アップロードするファイルを保存するフォルダのパスを指定します。
6行目で、アップロードするファイルの容量の最大値を指定します。
 
そして、8行目で自作のファイルアップロード関数「file_upload()」に、ファイルの入力項目の値「$this->request->data['file_name']」と、5行目、6行目で指定した値を引数として渡して、関数を実行します。
(今回は、同一コントローラー内の関数としてアップロード処理を作っていますが、アップロード処理はコンポーネントとして作成する方がいいでしょうね。)
 
 
5行目では、アップロードするファイルを保存するパスを指定しています。
このパスの指定では、「WWW_ROOT」という定数を使って指定していますが、各種フォルダの位置を示す定数に関しては「CakePHP3でDocumentRootやtmp、webroot、logsなどのフォルダへのパスの定数」にまとめましたので参考にしてみてください。
 
ドキュメントルートのパスや、「tmp」フォルダへのパスなどが規定されています。
 
 

ファイルアップロードの処理の関数本体

 
実際にファイルアップロードを行う本体の関数処理です。
 

 
 
各処理について解説します。
 
4~10行目。
ファイルを保存するフォルダとして指定する「$dir」の値が正しいかどうかをチェックしています。
「$dir」が空でないことと、「file_exists()」関数を使ってのフォルダの存在をチェックしています。
 
13~15行目。
アップロードするファイル項目が未定義であったり、複数のファイルが送信されてきたり、破損攻撃をするなど、不正な処理を受け付けた場合に無効にするための処理が記述されています。
 
18~30行目。
アップロードされたファイルのチェックを行います。
ファイルがない場合や、送信できるファイルの容量を超えている場合などのエラーチェックを行います。
 
33行目。
「tmp」フォルダにアップロードされたファイルの情報をチェックするため、file()オブジェクトを呼び出します。
 
36~38行目。
33行目の File()オブジェクトからファイルのサイズを取得し、引数で受け取ったサイズより小さいことをチェックします。
「$file[‘size’]」でもファイルサイズは取得できますが、File()オブジェクトの情報の方を信用していますので、そちらで処理をしています。
 
41~47行目。
File()オブジェクトから MIMEタイプを取得し、想定しているファイルタイプの中に存在するか否かをチェックするとともに、拡張子を取得します。
 
50行目、51行目
保存するファイル名を生成しています。
51行目は「$file[“tmp_name”]」を基にして、sha1_file()関数でファイル名を生成しています。
50行目は「$file[“name”]」としていまして、入力があったファイル名をそのまま使用する場合を想定しています。
 
ここは、どちらかを指定することを想定していますが、50行目の元のファイル名を使用する場合は、下記の不具合につながる可能性についての理解が必要です。
 ファイル名が重複する可能性
 全角文字(日本語)が文字化けする可能性
 
54~56行目
ファイル移動の処理本体です。
関数の引数として受け取ったフォルダ「$dir」に、「move_uploaded_file()」関数を使ってファイルを移動させることで、所定の場所にファイルが保存されたことになります。
 
ここまでいろいろな処理をしていますが、51行目までの処理は全てが入力チェックですので、入力チェックがなくていいならば、54行目のみでも OKです。
(入力チェックをしないのは現実的ではありませんが。)
 
59行目。
コメントアウトにしていますが、ここまで来たら正常に処理が終了したことになります。 
50行目、51行目で生成するファイル名を戻して処理終了です。
 
 
このファイルのアップロード処理に関しては、下記の処理を参考にしています。
https://secure.php.net/features.file-upload
 
「The following code cannot cause any errors absolutely.(次のコードはエラーを絶対に引き起こしません。)」と書いてありましたので、それを利用しました。
 
ただ、「move_uploaded_file()」関数は、正常にファイル移動ができない場合は、「false」を返すとともに、Warningを出力するため、CakePHP3ではそこで止まってしまいます。
 
そのため「@move_uploaded_file()」とすることで Warningを出さないように対処しています。
 
 

CakePHP3でファイルアップロードのまとめ

 
CakePHP3でファイルをアップロードするための処理を自作してみました。
 
ですが、この処理ではレコードを新規登録する際にファイルをアップロードする時には問題なく実行できるものの、レコードを更新する場合の画像の取り扱いや、ファイルだけを削除したい場合などの対処が十分ではないため実運用に使うにはもう少し処理を追加する必要があります。
 
それについては、下記に改めて記事を書きましたので、そちらを参照してください。
 CakePHP3で画像・ファイルのアップロード処理を自作・解説付き・その2
 
また、ファイルを保存する場所を指定するパス、および、画像を表示する際のドキュメントルートからのパスを取得する処理については、下記に記事を書いていますのであわせて参考にしてください。
 CakePHP3でDocumentRootやtmp、webroot、logsなどのフォルダへのパスの定数
 CakePHP3でDocumentRootやwebroot、imgフォルダのURLやドメイン、パスを取得
 
 

CakePHP3の関連記事

CakePHPのpostlinkで生成した削除リンクをクリックしても処理が実行されない対処法
CakePHP4のCSS、JavaScript、画像のブラウザへのキャッシュをコントロールする
CakePHP3でレコードを保存(追加、更新、Insert、Update)する複数の方法を紹介
CakePHP3でモデルなしフォームからCSVをアップロードしレコードを更新する方法解説
CakePHP3でPHP Simple HTML DOM Parserを使ってスクレイピングする方法
CakePHP3のInsert On Duplicate Key Update(upsert)構文を解説・バルク処理も
CakePHP3の1対多での連携を中間テーブルを使った多対多の連携に変更するときの手順
CakePHP3でデフォルトのソート条件を設定してユーザの選択肢たソート条件を有効にする方法
CakePHP3で Ajaxを使う方法の解説。3.6以降対応。Successとthenの両方を解説。
CakePHP3でパンくずの指定は HTMLヘルパーを使って指定する方法を解説
 
その他の「CakePHP3」に関する記事一覧
 
 

 - CakePHP 3.x 4.x 5.x

GoogleAdwords

GoogleAdwords

最後までお読みいただきましてありがとうございます。
この記事が参考になったと思いましたらソーシャルメディアで共有していただけると嬉しいです!

Message

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

下記の空欄を埋めてください。 * Time limit is exhausted. Please reload CAPTCHA.

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

※入力いただいたコメントは管理者の承認後に掲載されます。

  関連記事

CakePHP4のFrozenDateで1ヵ月前、先月、今月1日、来月末の日付などを算出する方法
CakePHP4のFrozenDateで1ヵ月前、先月、今月1日、来月末の日付などを算出する方法

CakePHPには「FrozenDate」の日付を扱う関数が用意されている。これを利用して、1ヶ月後、月末日、月初日、5日後などを指定して日付を取得できる。それを解説。

CakePHP3のCakeDC/Usersのバリデーションのカスタマイズ方法解説
CakePHP3のCakeDC/Usersのバリデーションのカスタマイズ方法解説

CakeDC謹製Usersプラグインの紹介。Usersのカスタマイズとして入力項目のバリデーションの変更を、プラグインのファイルは触らずオーバーライドにより実装する方法を解説する。

CakePHP3で他のテーブルのマスタテーブルからセレクトボックス(プルダウンリスト)を作る
CakePHP3で他のテーブルのマスタテーブルからセレクトボックス(プルダウンリスト)を作る

他のテーブルのマスタのレコードからプルダウンリストを作成し、選択できるようにするサンプルプログラムと解説。ORMの設定によりデータベースの値を取得し、配列を作成し optionsに与える。

CakePHP4、5の認証処理で認証が通らない際の確認方法と確認箇所の紹介
CakePHP4、5の認証処理で認証が通らない際の確認方法と確認箇所の紹介

CakePHP4、5系の認証処理でログイン認証が通らない場合の確認方法、確認箇所を解説。ログ出力し、ステータスを確認するが、ステータスの内容も紹介。それはそのままusernameを変更する際のポイントでもある。

CakePHP 2.3 コマンドラインからPHPのシェル実行の方法解説

CakePHP 2.3でコマンドラインから CakePHPで記述した処理を実行する方法を解説します。

CakePHPで Auto Incrementを外すと Duplicate entry '0' for keyのエラーが出るかも
CakePHPで Auto Incrementを外すと Duplicate entry ‘0’ for keyのエラーが出るかも

CakePHPでAuto Incrementの設定を変更したときに「Duplicate entry ‘0’ for key」のエラーが出た。原因はModel内で IDを編集する処理の追加を忘れていたからだった。

Windows環境の XAMPPを利用して CakePHPの開発する際の注意点
Windows環境の XAMPPを利用して CakePHPの開発する際の注意点

WindowsベースにXAMPPで環境を構築しCakePHP4を利用したWebシステムを構築する際は、大文字と小文字の違いを意識する必要がある。LinuxベースのWebサーバに移動させたときに不具合で動作しないこともある。

MySQL、CakePHP 2.3で「tinyint(1)」の Boolean型の動作を再確認

MySQL+CakePHPの環境で「tinyint(1)」を利用する際の動作を検証。「tinyint(1)」の Boolean型について CakePHPでは自動処理が実施されていることを確認しました。

CakePHPで同一テーブル内の値を比較する条件でレコードを取得する方法
CakePHPで同一テーブル内の値を比較する条件でレコードを取得する方法

CakePHPの同一テーブルにある項目の値を比較し条件に合致するレコードを取得する方法を解説。[”項目名”=>”値”]ではなく[”項目名 = 項目名”]と書くところがポイント。

CakePHP3チュートリアルで日付と時刻のDateTimeでエラーが出たときの対処方法
CakePHP3チュートリアルで日付と時刻のDateTimeでエラーが出たときの対処方法

CakePHP3のブックマークチュートリアルには記載ミスもあり、そのまま動かない個所もある。CakePHP3では namespaceを使うようになったので、classを呼び出すときに¥を追加する必要が!