How to upload a file using jQuery AJAX in CodeIgniter 4
With AJAX you can perform an action on the server without refreshing the whole page.
You can use it to fetch data, import file data, upload files, etc.
In this tutorial, I am using it to upload a file and display a preview if the file is an image otherwise display a link in the CodeIgniter 4 project.
I have enabled CSRF token in the CodeIgniter project.
1. Enable CSRF
- Open
.env
file. - Remove # from the start of the
app.CSRFProtection
,app.CSRFTokenName
,app.CSRFCookieName
,app.CSRFExpire
, andapp.CSRFRegenerate
. - I update the
app.CSRFTokenName
value with'csrf_hash_name'
. With this name read CSRF hash. You can update it with any other value.
app.CSRFProtection = true app.CSRFTokenName = 'csrf_hash_name' app.CSRFCookieName = 'csrf_cookie_name' app.CSRFExpire = 7200 app.CSRFRegenerate = true # app.CSRFExcludeURIs = []
- Open
app/Config/Filters.php
file. - Uncomment in
'csrf'
in'before'
if commented.
// Always applied before every request public $globals = [ 'before' => [ //'honeypot' 'csrf', ], 'after' => [ 'toolbar', //'honeypot' ], ];
2. Route
- Open
app/Config/Routes.php
file. - Define 2 routes –
- / – Display file upload view.
- users/fileUpload – It is used to upload a file.
Completed Code
$routes->get('/', 'UsersController::index'); $routes->post('users/fileUpload', 'UsersController::fileUpload');
3. Controller
- Create
UsersController.php
file inapp/Controllers/
folder. - Open the file.
- Create 2 methods –
- index() – Load
index
view. - fileUpload() – This method is used to handle the AJAX request.
- index() – Load
Assign new CSRF token to $data['token']
.
Set file validation –
'file' => 'uploaded[file]|max_size[file,1024]|ext_in[file,jpeg,jpg,docx,pdf],'
If the file is not validated then assign 0
to $data['success']
and validation response to $data['error']
.
If the file is validated then read the file name and extension and upload the file to the "public/uploads"
location. Assign 1
to $data['success']
, 'Uploaded Successfully!'
to $data['message']
, file path to $data['filepath']
, and file extension to $data['extension']
.
If the file is not uploaded then assign 2
to $data['success']
and 'File not uploaded.'
message to $data['message']
.
Return $data
Array in JSON format.
Completed Code
<?php namespace App\Controllers; use App\Models\Users; class UsersController extends BaseController{ public function index(){ return view('index'); } public function fileUpload(){ $data = array(); // Read new token and assign to $data['token'] $data['token'] = csrf_hash(); ## Validation $validation = \Config\Services::validation(); $input = $validation->setRules([ 'file' => 'uploaded[file]|max_size[file,1024]|ext_in[file,jpeg,jpg,docx,pdf],' ]); if ($validation->withRequest($this->request)->run() == FALSE){ $data['success'] = 0; $data['error'] = $validation->getError('file');// Error response }else{ if($file = $this->request->getFile('file')) { if ($file->isValid() && ! $file->hasMoved()) { // Get file name and extension $name = $file->getName(); $ext = $file->getClientExtension(); // Get random file name $newName = $file->getRandomName(); // Store file in public/uploads/ folder $file->move('../public/uploads', $newName); // File path to display preview $filepath = base_url()."/uploads/".$newName; // Response $data['success'] = 1; $data['message'] = 'Uploaded Successfully!'; $data['filepath'] = $filepath; $data['extension'] = $ext; }else{ // Response $data['success'] = 2; $data['message'] = 'File not uploaded.'; } }else{ // Response $data['success'] = 2; $data['message'] = 'File not uploaded.'; } } return $this->response->setJSON($data); } }
4. View
Create index.php
file in app/Views/
.
Create a hidden element to store CSRF token name specified in .env
file in the name
attribute and store CSRF hash in the value
attribute.
<input type="hidden" class="txt_csrfname" name="<?= csrf_token() ?>" value="<?= csrf_hash() ?>" />
Display AJAX response message in <div id="responseMsg">
using jQuery.
Created <img >
and <a >
element in <div id="filepreview">
to display a file preview according to the file extension using jQuery.
Create <form method="post" action="<?=site_url('users/fileUpload')?>" enctype="multipart/form-data">
. In the form add a file element and a button. Display error in <div id="err_file">
if not validated using jQuery.
Script
On the button click read CSRF Token name and hash from the hidden field and assign it to the csrfName
and csrfHash
.
Check if a file is selected or not. If not selected then alert("Please select a file.");
otherwise, pass selected file using FormData object. Also, pass CSRF with FormData.
Send AJAX POST request to "<?=site_url('users/fileUpload')?>"
where pass FormData Object as data.
On successful callback update CSRF token by assigning response.token
to '.txt_csrfname'
.
If response.success == 1
means file successfully uploaded. Display the response message and preview the file according to the file extension.
If response.success == 2
means file is not uploaded. Display the response message.
If response.success
does not equal 1 or 2 means the file is not validated. Display the error message.
Completed Code
<!DOCTYPE html> <html> <head> <title>How to upload a file using jQuery AJAX in CodeIgniter 4</title> <link rel="stylesheet" type="text/css" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> <style type="text/css"> .displaynone{ display: none; } </style> </head> <body> <div class="container"> <!-- CSRF token --> <input type="hidden" class="txt_csrfname" name="<?= csrf_token() ?>" value="<?= csrf_hash() ?>" /> <div class="row"> <div class="col-md-12"> <!-- Response message --> <div class="alert displaynone" id="responseMsg"></div> <!-- File preview --> <div id="filepreview" class="displaynone" > <img src="" class="displaynone" with="200px" height="200px"><br> <a href="#" class="displaynone" >Click Here..</a> </div> <!-- File upload form --> <form method="post" action="<?=site_url('users/fileUpload')?>" enctype="multipart/form-data"> <div class="form-group"> <label for="file">File:</label> <input type="file" class="form-control" id="file" name="file" /> <!-- Error --> <div class='alert alert-danger mt-2 d-none' id="err_file"></div> </div> <input type="button" class="btn btn-success" id="submit" value="Upload"> </form> </div> </div> </div> <!-- Script --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script type="text/javascript"> $(document).ready(function(){ $('#submit').click(function(){ // CSRF Hash var csrfName = $('.txt_csrfname').attr('name'); // CSRF Token name var csrfHash = $('.txt_csrfname').val(); // CSRF hash // Get the selected file var files = $('#file')[0].files; if(files.length > 0){ var fd = new FormData(); // Append data fd.append('file',files[0]); fd.append([csrfName],csrfHash); // Hide alert $('#responseMsg').hide(); // AJAX request $.ajax({ url: "<?=site_url('users/fileUpload')?>", method: 'post', data: fd, contentType: false, processData: false, dataType: 'json', success: function(response){ // Update CSRF hash $('.txt_csrfname').val(response.token); // Hide error container $('#err_file').removeClass('d-block'); $('#err_file').addClass('d-none'); if(response.success == 1){ // Uploaded successfully // Response message $('#responseMsg').removeClass("alert-danger"); $('#responseMsg').addClass("alert-success"); $('#responseMsg').html(response.message); $('#responseMsg').show(); // File preview $('#filepreview').show(); $('#filepreview img,#filepreview a').hide(); if(response.extension == 'jpg' || response.extension == 'jpeg'){ $('#filepreview img').attr('src',response.filepath); $('#filepreview img').show(); }else{ $('#filepreview a').attr('href',response.filepath).show(); $('#filepreview a').show(); } }else if(response.success == 2){ // File not uploaded // Response message $('#responseMsg').removeClass("alert-success"); $('#responseMsg').addClass("alert-danger"); $('#responseMsg').html(response.message); $('#responseMsg').show(); }else{ // Display Error $('#err_file').text(response.error); $('#err_file').removeClass('d-none'); $('#err_file').addClass('d-block'); } }, error: function(response){ console.log("error : " + JSON.stringify(response) ); } }); }else{ alert("Please select a file."); } }); }); </script> </body> </html>
5. Output
6. Conclusion
Pass selected file using FormData Object to upload in AJAX request.
If you don’t want to display file preview after file upload then you don’t have to send file path from the Controller. Remove the file preview <div >
and update the jQuery script.