File uploads are a common feature in web applications. It allows users to upload and share files, such as images, videos, and documents.
CakePHP 4 already has built-in File handling classes to handle file uploads.
In this tutorial, I show how you can upload file with validation and display its preview after upload in CakePHP 4.
In the example, I am using the Modelless form for creating an upload form.
Table of Content
1. Create UploadfileForm Form
- Create
UploadfileForm.php
file insrc/Form/
folder. CreateForm
folder if it does not exist. - Create
UploadfileForm
class.
Create 3 methods –
- _buildSchema() – Define HTML form schema data. I am not defining
<form >
element from here. - validationDefault() – This method will handle form validation. Specifically, focus on the
fileel
, which represents the file input element. Set it as required and establish rules for file type and file size.
- _execute() – From this method upload the selected file.
Assign file instance to $attachment
. Read file details and assign them to the variables.
If $error == 0
then check if uploads
folder exists in webroot
or not. If not exists then create it.
Upload the file and return true
.
NOTE – Uploaded file will be stored in
webroot/uploads/
folder.
<?php namespace App\Form; use Cake\Form\Form; use Cake\Form\Schema; use Cake\Validation\Validator; use Cake\Filesystem\Folder; class UploadfileForm extends Form { protected function _buildSchema(Schema $schema): Schema { return $schema; } public function validationDefault(Validator $validator): Validator { $validator ->notEmptyFile('fileel') ->add('fileel', [ 'mimeType' => [ 'rule' => ['mimeType',['image/jpg','image/png','image/jpeg','application/pdf']], 'message' => 'File type must be .jpg,.jpeg,.png,.pdf', ], 'fileSize' => [ 'rule' => ['fileSize','<', '2MB'], 'message' => 'File size must be less than 2MB', ] ]); return $validator; } protected function _execute(array $data): bool { $attachment = $data['fileel']; // File details $filename = $attachment->getClientFilename(); $type = $attachment->getClientMediaType(); $size = $attachment->getSize(); $extension = pathinfo($filename, PATHINFO_EXTENSION); $tmpName = $attachment->getStream()->getMetadata('uri'); $error = $attachment->getError(); // Upload file if($error == 0){ $location = WWW_ROOT . 'uploads' . DS; $folder = new Folder(); $checkfolder = $folder->inPath($location, true); if(!$checkfolder){ // Not exists if (!$folder->create($location)) { return false; } } $targetPath = $location.$filename; $attachment->moveTo($targetPath); return true; }else{ return false; } } }
2. Create Controller
- Create a
FileuploadController.php
file insrc/Controller/
folder. - Create
FileuploadController
Class that extendsAppController
. - Include
App\Form\UploadfileForm
.
Here, create 1 method –
- index() – Create an instance of
UploadfileForm()
.
Check if the <form>
is submitted using the POST method. If the form is submitted, then call $uploadfile->execute()
and pass the POST data. If this function returns true
, then proceed to read data from the file input element for preview.
Assign $filepath
to $filedetails['filepath']
and $extension
to $filedetails['extension']
.
Finally, set both filedetails
and uploadfile
for further processing.
<?php declare(strict_types=1); namespace App\Controller; use App\Form\UploadfileForm; class FileuploadController extends AppController { public function index(){ $uploadfile = new UploadfileForm(); $filedetails = array(); if ($this->request->is('post')) { if ($uploadfile->execute($this->request->getData())) { // Read file for preview $attachment = $this->request->getData('fileel'); $filename = $attachment->getClientFilename(); $extension = pathinfo($filename, PATHINFO_EXTENSION); $filepath = "/uploads/".$filename; $extension = $extension; $filedetails['filepath'] = $filepath; $filedetails['extension'] = $extension; $this->Flash->success('File uploaded successfully.'); } else { $this->Flash->error('File not uploaded.'); } } $this->set('filedetails', $filedetails); $this->set('uploadfile', $uploadfile); } }
3. Create Template
Create a new Fileupload
folder in templates/
folder. Now in the Fileupload
folder create index.php
file.
Create a <form >
set its action to fileupload/index
. Pass $uploadfile
as 1st parameter in create()
. Here, $uploadfile
is an instance of UploadfileForm
Class it is set from the controller.
In the <form >
create a file element and a submit button.
To display a preview check if $filedetails
Array is empty or not.
If not empty then check $filedetails['extension']
extension value. If the extension is image type then create <img >
element to display file otherwise create <a >
tag to create view link.
<div class="row"> <div class="col-6"> <?php // Upload form echo $this->Form->create($uploadfile,array('url'=>['controller' => 'fileupload','action' => 'index'],"enctype" => "multipart/form-data" )); echo $this->Form->control('fileel',['label' => 'Select file','type' => 'file','class' => 'form-control','required' => true]); echo $this->Form->button('Submit'); echo $this->Form->end(); ?> <?php // Preview file if(count($filedetails) > 0){ $image_exts = array("jpg","jpeg","png"); if(in_array($filedetails['extension'],$image_exts)){ echo $this->HTML->image($filedetails['filepath']); }else{ echo $this->Html->link( 'View file', $filedetails['filepath'], ['target' => '_blank'] ); } } ?> </div> </div>
4. Output
http://localhost:8765/fileupload
5. Conclusion
If you also want to save the file to the database then you don’t need to create a Modelless Form class. You need to pass ORM Entity in form and handle it in the controller.
You can view this tutorial if you want to save file to a database.
If you found this tutorial helpful then don't forget to share.