Storing file upload details in the database provide more flexibility and control over file handling and management. You can easily keep track of who uploaded this file and when.
In this tutorial, I show how you can upload file with validation and save it to the MySQL database in CakePHP 4 project.
Also, show how you can display stored files on the page.

Contents
- Create Table
- Database Configuration
- Create Model
- Create Controller
- Create Template
- Output
- Conclusion
1. Create Table
In the example, I am using files table. It has the following structure –
CREATE TABLE `files` (
`id` int(11) NOT NULL,
`filename` varchar(255) NOT NULL,
`path` varchar(255) NOT NULL
)
2. Database Configuration
- Open
config/app_local.phpfile. - Specify your database configuration details in the
Datasourcesdefault.
'Datasources' => [
'default' => [
'host' => '127.0.0.1',
/*
* CakePHP will use the default DB port based on the driver selected
* MySQL on MAMP uses port 8889, MAMP users will want to uncomment
* the following line and set the port accordingly
*/
//'port' => 'non_standard_port_number',
'username' => 'root',
'password' => 'root',
'database' => 'cakephp4',
/*
* If not using the default 'public' schema with the PostgreSQL driver
* set it here.
*/
//'schema' => 'myapp',
/*
* You can use a DSN string to set the entire configuration
*/
'url' => env('DATABASE_URL', null),
],
/*
* The test connection is used during the test suite.
*/
'test' => [
'host' => 'localhost',
//'port' => 'non_standard_port_number',
'username' => 'my_app',
'password' => 'secret',
'database' => 'test_myapp',
//'schema' => 'myapp',
'url' => env('DATABASE_TEST_URL', 'sqlite://127.0.0.1/tests.sqlite'),
],
],
3. Create Model
- Create
FilesModel.
bin/cake bake model Files
- This will create 2 files –
src/Model/Entity/File.php src/Model/Table/FilesTable.php
src/Model/Entity/File.php
If you don’t want to allow insertion and updating of any field then set it to false.
Completed Code
<?php
declare(strict_types=1);
namespace App\Model\Entity;
use Cake\ORM\Entity;
/**
* Image Entity
*
* @property int $id
* @property string $filename
* @property string $path
*/
class File extends Entity
{
protected $_accessible = [
'filename' => true,
'path' => true,
];
}
src/Model/Table/FilesTable.php
Defined file validation in validationDefault() method. fileel is the element name.
Completed Code
<?php
declare(strict_types=1);
namespace App\Model\Table;
use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;
class FilesTable extends Table
{
public function initialize(array $config): void
{
parent::initialize($config);
$this->setTable('files');
$this->setDisplayField('id');
$this->setPrimaryKey('id');
}
public function validationDefault(Validator $validator): Validator
{
$validator
->scalar('filename')
->maxLength('filename', 255)
->requirePresence('filename', 'create')
->notEmptyFile('filename');
$validator
->scalar('path')
->maxLength('path', 255)
->requirePresence('path', 'create')
->notEmptyString('path');
// File validation
$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;
}
}
4. Create Controller
- Create a
FileuploadController.phpfile insrc/Controller/folder. - Create
FileuploadControllerClass that extendsAppController. - Include
App\Model\Entity\FileEntity and to create a new folder includeCake\Filesystem\Folder. - Create
index()method –- Create
Fileentity instance. - If
<form >is POST then validate the POST data usingpatchEntity(). - Read file element details if it is validated.
- If
$error == 0then assign upload location in$locationvariable and check if upload exists or not. If not exists then create it. - Upload the file by calling
moveTo(). - After upload assign upload path in
$filepath. - Insert a new record in
filestable. Here, pass$filenametofilenameand$filepathtopath. - Fetch all records the
filestable and passfilesListandfileto the template.
- Create
NOTE – The uploaded file will be stored in the
webroot/uploads/folder.
Completed Code
<?php
declare(strict_types=1);
namespace App\Controller;
use App\Model\Entity\File;
use Cake\Filesystem\Folder;
class FileuploadController extends AppController
{
public function index(){
## File entity
$file = new File();
$files = $this->getTableLocator()->get('Files');
if ($this->request->is('post')) {
// Validate the data
$file = $files->patchEntity($file, $this->request->getData());
// File is validated
if(!isset($file->getErrors()['fileel'])){
$attachment = $this->request->getData('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();
if($error == 0){
## Upload location
$location = WWW_ROOT . 'uploads' . DS;
## Check upload location exists or not
$folder = new Folder();
$checkfolder = $folder->inPath($location, true);
if(!$checkfolder){ // Not exists
if (!$folder->create($location)) {
$this->Flash->error('File not uploaded.');
}
}
## Upload file
$targetPath = $location.$filename;
$attachment->moveTo($targetPath);
## Uploaded file path
$filepath = "/uploads/".$filename;
## Insert a record in 'files' table
$insData['filename'] = $filename;
$insData['path'] = $filepath;
$newfile = $files->newEntity($insData);
if ($files->save($newfile)) {
$this->Flash->success('Inserted successfully.');
}else{
$this->Flash->error('Record not inserted.');
}
}else{
$this->Flash->error('File not uploaded.');
}
}
}
// Fetch all records
$query = $files->find()->all();
$filesList = $query->toArray();
// Pass to template
$this->set('filesList', $filesList);
$this->set('file', $file);
}
}
5. Create Template
Create a new Fileupload folder in templates/ folder. Now in the Fileupload folder create index.php file (templates/Fileupload/index.php).
Create a <form >. Set action to fileupload/index. Pass $file as 1st parameter in create(). Here, $file is an entity instance passed from the controller.
Using <table > to list all stored files in the files table. Loop on $filesList Array and check if extension.
If $extension is an image type then create an image element to display otherwise create a link.
Completed Code
<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();
?>
<!-- Files list -->
<table>
<thead>
<tr>
<th>File</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<?php
foreach ($filesList as $file): ?>
<?php
$filename = $file['filename'];
$path = $file['path'];
$extension = pathinfo($filename, PATHINFO_EXTENSION);
?>
<tr>
<td>
<?php
$image_exts = array("jpg","jpeg","png");
if(in_array($extension,$image_exts)){
echo $this->HTML->image($path,['width' => '100px']);
}else{
echo $this->Html->link(
'View file',
$path,
['target' => '_blank']
);
}
?>
</td>
<td><?= $file['filename'] ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
6. Output
7. Conclusion
You have to create a Model and use Entity instance in <form > creation. Upload the file from the controller on submit and insert a new record in the table.
If you don’t want to save to the database after the file upload then you have to create a Modelless form. I have already written a tutorial this topic which you can view here.
If you found this tutorial helpful then don't forget to share.