How to upload a file using jQuery AJAX in CodeIgniter 4

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 dataimport 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.CSRFTokenNameapp.CSRFCookieNameapp.CSRFExpire, and app.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 in app/Controllers/ folder.
  • Open the file.
  • Create 2 methods –
    • index() – Load index view.
    • fileUpload() – This method is used to handle the AJAX request.

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

View 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.



Comments