Codeigniter Multiple Files Upload

I am going to show you how to upload multiple files using PHP based Codeigniter framework. There is file upload class, in Codeigniter, which permits you to upload the file or files. This class also permits you to set various preferences such as destination where the file will be uploaded, restriction on file types, restriction on file size, whether a file name should be encrypted or not, maximum length of the file name etc.

I am going to use jQuery library to perform AJAX technique for uploading multiple files. Here I will show attach more button to select more files using jQuery. You can also delete the selected files using the delete button given next to each selected file except the file one. I am going to save the uploaded files into a directory and uploaded files’ paths into the MySQL database table.

You need to perform the following steps in order to upload files:

  • A form with input type file is required so that user can select the file using the browse button
  • When the form is submitted, the file is validated to make sure that the file is uploaded against the preferences you set
  • Once the file is uploaded successfully to the specified destination, the success message is shown
  • The output in the browser

Prerequisites

PHP 7.4.3, Apache HTTP Server 2.4, CodeIgniter 3.1.11, MySQL 8.0.17 – 8.0.22, jQuery 3.5.1 – 3.6.0

MySQL Table

I am going to create a table called files under roytuts database in MySQL server to save the uploaded files paths.

CREATE TABLE `files` (
  `file_id` int unsigned NOT NULL AUTO_INCREMENT,
  `file_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `file_orig_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `file_path` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `upload_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`file_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Project Directory

You need to create a project root directory called codeigniter-multiple-files-upload the Apache server’s htdocs folder.

Now move all the directories and files from CodeIgniter framework into codeigniter-multiple-files-upload directory.

I may not mention the project root directory in subsequent sections and I will assume that I am talking with respect to the project root directory.

Autoload Configuration

You need some configurations, such as, auto-loading for helpers to avoid loading every time you need to use.

Modify application/config/autoload.php file for auto-loading libraries and helper functions.

This one time auto-loading gives flexibility to uniformly use the helpers and libraries anywhere throughout the application without loading repeatedly.

$autoload['libraries'] = array('database');
$autoload['helper'] = array('url');

Database Configurations

Now I will configure database connection into application/config/database.php file. Please make sure to change values according to your database settings.

$db['default'] = array(
	'dsn'	=> '',
	'hostname' => 'localhost',
	'username' => 'root',
	'password' => 'root',
	'database' => 'roytuts',
        ...
	'char_set' => 'utf8mb4',
	'dbcollat' => 'utf8mb4_unicode_ci',
        ...
);

Create Model Class

You need to perform database operations to save the uploaded files paths into database.

Create a file file_model.php under applications/models folder to create the required model class.

In the following source code I am using transaction from Codeigniter framework to perform the database operation so that I can rollback for any issue.

<?php

if (!defined('BASEPATH'))
    exit('No direct script access allowed');

/**
 *
 * @author https://roytuts.com
 */
class File_Model extends CI_Model {

    //table name
    private $file = 'files';   // files    
    
    function save_files_info($files) {
        //start db traction
        $this->db->trans_start();
		
        //file data
        $file_data = array();
        foreach ($files as $file) {
            $file_data[] = array(
                'file_name' => $file['file_name'],
                'file_orig_name' => $file['orig_name'],
                'file_path' => $file['full_path'],
                'upload_date' => date('Y-m-d H:i:s')
            );
        }
        
		//insert file data
        $this->db->insert_batch($this->file, $file_data);
        
		//complete the transaction
        $this->db->trans_complete();
        
		//check transaction status
        if ($this->db->trans_status() === FALSE) {
            foreach ($files as $file) {
                $file_path = $file['full_path'];
				
                //delete the file from destination
                if (file_exists($file_path)) {
                    unlink($file_path);
                }
            }
			
            //rollback transaction
            $this->db->trans_rollback();
            
			return FALSE;
        } else {
            //commit the transaction
            $this->db->trans_commit();
			
            return TRUE;
        }
    }

}

Create Controller Class

Create a controller file uploadfiles.php under application/controllers with the following source code.

The below controller class handles request and response for clients. So this controller will validate, upload files into the specified directory.

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

/**
 *
 * @author https://roytuts.com
 */
class UploadFiles extends CI_Controller {

    private $error;
    private $success;

    function __construct() {
        parent::__construct();
        $this->load->library('form_validation');
        $this->load->model('file_model', 'file');
    }

    private function handle_error($err) {
        $this->error .= $err . "\r\n";
    }

    private function handle_success($succ) {
        $this->success .= $succ . "\r\n";
    }

    function index() {
        if ($this->input->post('file_upload')) {
            //file upload destination
            $dir_path = './upload/';
            $config['upload_path'] = $dir_path;
            $config['allowed_types'] = '*';
            $config['max_size'] = '0';
            $config['max_filename'] = '255';
            $config['encrypt_name'] = TRUE;

            //upload file
            $i = 0;
            $files = array();
            $is_file_error = FALSE;

            if ($_FILES['upload_file1']['size'] <= 0) {
                $this->handle_error('Select at least one file.');
            } else {
                foreach ($_FILES as $key => $value) {
                    if (!empty($value['name'])) {
                        $this->load->library('upload', $config);
                        if (!$this->upload->do_upload($key)) {
                            $this->handle_error($this->upload->display_errors());
                            $is_file_error = TRUE;
                        } else {
                            $files[$i] = $this->upload->data();
                            ++$i;
                        }
                    }
                }
            }

            // There were errors, you have to delete the uploaded files
            if ($is_file_error && $files) {
                for ($i = 0; $i < count($files); $i++) {
                    $file = $dir_path . $files[$i]['file_name'];
                    if (file_exists($file)) {
                        unlink($file);
                    }
                }
            }

            if (!$is_file_error && $files) {
                $resp = $this->file->save_files_info($files);
                if ($resp === TRUE) {
                    $this->handle_success('File(s) was/were successfully uploaded.');
                } else {
                    for ($i = 0; $i < count($files); $i++) {
                        $file = $dir_path . $files[$i]['file_name'];
                        if (file_exists($file)) {
                            unlink($file);
                        }
                    }
                    $this->handle_error('Error while saving file info to Database.');
                }
            }
        }
        $data['errors'] = $this->error;
        $data['success'] = $this->success;
        $this->load->view('uploadfiles', $data);
    }

}

/* End of file uploadfiles.php */
/* Location: ./application/controllers/uploadfiles.php */

View File

I am going to create a form into a file called uploadfiles.php under application/views folder. This below file upload form expects at least one file must be selected using the browse button. You will also notice that once you select at least one file, a link to attach another file gets appeared for adding a new browse button for selecting another file.

<?php
defined('BASEPATH') OR exit('No direct script access allowed');
?><!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>CodeIgniter - Upload Multiple File(s) Example</title>
        <style type="text/css">
            body {
                background-color: #fff;
                margin: 40px;
                font: 13px/20px normal Helvetica, Arial, sans-serif;
                color: #4F5155;
            }
            #body{
                margin: 0 15px 0 15px;
            }
            #container {
				width: 600px;
                margin: auto;
            }
            .error {
                color: #E13300;
            }
            .info {
                color: gold;
            }
            .success {
                color: darkgreen;
            }
        </style>
		<!--<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous">
</script>-->
<script src="https://code.jquery.com/jquery-3.6.0.min.js" crossorigin="anonymous"></script>
    </head>
    <body>
		<div id="container">
			<div class="message_box">
				<?php
				if (isset($success) && strlen($success)) {
					echo '<div class="success">';
					echo '<p>' . $success . '</p>';
					echo '</div>';
				}

				if (isset($errors) && strlen($errors)) {
					echo '<div class="error">';
					echo '<p>' . $errors . '</p>';
					echo '</div>';
				}

				if (validation_errors()) {
					echo validation_errors('<div class="error">', '</div>');
				}
				?>
			</div>
			<div>
				<?php
				echo form_open_multipart($this->uri->uri_string(), array('id' => 'upload-file-form'));
				?>
				<fieldset>
					<legend>Upload Multiple File(s)</legend>
					<section>
						<label>Browse a file</label>
						<label>
							<input type="file" name="upload_file1" id="upload_file1" readonly="true"/>
						</label>
						<div id="moreImageUpload"></div>
						<div style="clear:both;"></div>
						<div id="moreImageUploadLink" style="display:none;margin-left: 10px;">
							<a href="javascript:void(0);" id="attachMore">Attach another file</a>
						</div>
					</section>
				</fieldset>
				<footer>
					<input type="submit" name="file_upload" value="Upload"/>
				</footer>
				<?php
				echo form_close();
				?>
			</div>
		</div>
    </body>
</html>
<script type="text/javascript">
    $(document).ready(function() {
        $("input[id^='upload_file']").each(function() {
            var id = parseInt(this.id.replace("upload_file", ""));
            $("#upload_file" + id).change(function() {
                if ($("#upload_file" + id).val() !== "") {
                    $("#moreImageUploadLink").show();
                }
            });
        });
    });
</script>
<script type="text/javascript">
    $(document).ready(function() {
        var upload_number = 2;
        $('#attachMore').click(function() {
            //add more file
            var moreUploadTag = '';
            moreUploadTag += '<div class="element"><label for="upload_file"' + upload_number + '>Upload File ' + upload_number + '</label>';
            moreUploadTag += '<input type="file" id="upload_file' + upload_number + '" name="upload_file' + upload_number + '"/>';
            moreUploadTag += '&nbsp;<a href="javascript:del_file(' + upload_number + ')" style="cursor:pointer;" onclick="return confirm(\"Are you really want to delete ?\")">Delete ' + upload_number + '</a></div>';
            $('<dl id="delete_file' + upload_number + '">' + moreUploadTag + '</dl>').fadeIn('slow').appendTo('#moreImageUpload');
            upload_number++;
        });
    });
</script>
<script type="text/javascript">
    function del_file(eleId) {
        var ele = document.getElementById("delete_file" + eleId);
        ele.parentNode.removeChild(ele);
    }
</script>

Notice when you need to upload a file or files you have to use the enctype=”multipart/form-data” and hence I have used form_open_multipart().

If there is no need to upload a file then you can use only form_open(). I have passed some attributes, in form_open_multipart(), which will be added in the html’s form tag.

I have also some other variables like $errors, $success which will show errors and success messages respectively. I have used Codeigniter’s built-in validation_errors() function which will show error messages.

Configuring Route

You need to replace our default controller in application/config/routes.php file as shown below:

$route['default_controller'] = 'uploadfiles';

Testing the Application

When you hit the URL http://localhost/codeigniter-multiple-files-upload in the browser you will see the output shown similar to the below image:

codeigniter multiple files upload

If you do not select any file and try to upload the file then you will see the following error:

codeigniter multiple files upload

When you select multiple files for upload, for example, as shown in the below image:

codeigniter multiple files upload

Make sure you create the upload folder before you hit the Upload button for uploading files otherwise you will see error The upload path does not appear to be valid

When files are successfully uploaded then you will see the following error:

codeigniter multiple files upload

In the database table you will find below output:

codeigniter multiple files upload

Source Code

Download

15 thoughts on “Codeigniter Multiple Files Upload

  1. Why create and use the `assets_url()` helper function? In this article it is completely pointless since all it does is returns base_url(). It is adding an extra trip to memory to consume the assets_url() function and for no reason when instead you could avoid it and use base_url() in your views and not /assets. If you want a decent replacement for the assets_url() function, I would suggest using the following alternative instead.

    In assets_helper.php (>=PHP7):

    // If the function does not exist, let’s create it!
    if (!function_exists(‘assets_url’)) {
    /**
    * A syntactic sugar function to help load assets.
    *
    * @param string|null $file The asset file to load
    * @param string $path The path for the asset
    *
    * @return string The assets full `path`
    */
    function assetsUrl(string $file = null, string $path = ‘assets’): string
    {
    return base_url($path . ‘/’ . $file);
    }
    }

    The function above proves much more useful for accessing assets relative to your public directory/FCPATH.

    Other than this little “mistake” in your code, everything else is pretty decent. Thank you for the article.

  2. thanks a lot for your post
    if I want to add one input text, example : description.
    how about the model and the controller ?

    1. in the same way as other input fields are added to the form and submitted to the controller. just add another input field and get the value of the input field in the controller and then pass the value to the model.

Leave a Reply

Your email address will not be published. Required fields are marked *