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.phpfile insrc/Form/folder. CreateFormfolder if it does not exist. - Create
UploadfileFormclass.
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.phpfile insrc/Controller/folder. - Create
FileuploadControllerClass 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.