How to Import CSV file data to MySQL in CodeIgniter 4
CSV is a widely used format for exchanging data between applications.
The database and data dumps should be in a proper format to import data smoothly and without any issue.
In this tutorial, I show how you can import CSV file data in the MySQL database in the CodeIgniter 4 project.
1. Database configuration
- Open
.env
file which is available at the project root.
NOTE – If dot (.) not added at the start then rename the file to .env.
- Remove # from start of database.default.hostname, database.default.database, database.default.username, database.default.password, and database.default.DBDriver.
- Update the configuration and save it.
database.default.hostname = 127.0.0.1 database.default.database = testdb database.default.username = root database.default.password = database.default.DBDriver = MySQLi
2. Create Table
- Create a new table
users
using migration.
php spark migrate:create create_users_table
- Now, navigate to
app/Database/Migrations/
folder from the project root. - Find a PHP file that ends with
create_users_table
and open it. - Define the table structure in the
up()
method. - Using the
down()
method deleteusers
table which calls when undoing migration.
<?php namespace App\Database\Migrations; use CodeIgniter\Database\Migration; class CreateUsersTable extends Migration { public function up() { $this->forge->addField([ 'id' => [ 'type' => 'INT', 'constraint' => 5, 'unsigned' => true, 'auto_increment' => true, ], 'name' => [ 'type' => 'VARCHAR', 'constraint' => '100', ], 'email' => [ 'type' => 'VARCHAR', 'constraint' => '100', ], 'city' => [ 'type' => 'VARCHAR', 'constraint' => '100', ], 'status' => [ 'type' => 'INT', 'constraint' => '2', ], ]); $this->forge->addKey('id', true); $this->forge->createTable('users'); } //-------------------------------------------------------------------- public function down() { $this->forge->dropTable('users'); } }
- Run the migration –
php spark migrate
3. CSV file structure
In the example, I am using the following structure –
Name, Email, City, Status Yogesh singh, yogesh@makitweb.com, Bhopal, 1 Sonarika Bhadoria, bsonarika@makitweb.com, Delhi, 1 Ankit singh, ankitsingh@makitweb.com, Bhopal, 1
The first row contains field names.
NOTE – I am skipping the first row while record inserting.
While file importing if a row does not contain all 4 fields then I am skipping it.
If in your CSV file the first row also contains data then just need to remove a condition in the controller.
4. Model
- Create
Users.php
file inapp/Models/
folder. - Open the file.
- Specify table name
"users"
in$table
variable, primary key"id"
in$primaryKey
, Return type"array"
in$returnType
. - In
$allowedFields
Array specify field names –['name', 'email','city','status']
that can be set during insert and update.
Completed Code
<?php namespace App\Models; use CodeIgniter\Model; class Users extends Model { protected $table = 'users'; protected $primaryKey = 'id'; protected $returnType = 'array'; protected $allowedFields = ['name', 'email','city','status']; protected $useTimestamps = false; protected $validationRules = []; protected $validationMessages = []; protected $skipValidation = false; }
5. Route
- Open
app/Config/Routes.php
file. - Define 2 routes –
- / – Display file upload view and user list.
- users/importFile – It is used to upload a CSV file and insert records.
Completed Code
$routes->get('/', 'UsersController::index'); $routes->post('users/importFile', 'UsersController::importFile');
6. Controller
- Create
UsersController.php
file inapp/Controllers/
folder. - Open the file.
- Import
Users
Model. - Create two methods –
- index() – Select all records from the
users
table and assign to$data['users']
. Loadusers/index
view and pass$data
. - importFile() – This method is called on form submit to upload the file and import data.
- index() – Select all records from the
File Upload
Set file validation –
'file' => 'uploaded[file]|max_size[file,1024]|ext_in[file,csv],'
- uploaded – Fails if the name of the parameter does not match the name of any uploaded files.
- max_size – Set maximum file upload size in KB -1024 (1 MB).
- ext_in – Valid file extensions – csv.
If the file is not validated then return to the users/index
view with validation response.
If the file is valid then upload the file to public/csvfile
location.
NOTE –
csvfile
folder will be created if the folder does not exist in thepublic
folder while file uploading.
Read file data
Open the uploaded CSV file in read mode.
I assigned the total number of columns in a row – 4 to $numberOfFields
. Modify its value according to the number of columns in your CSV file.
Loop on the file and count total elements in $filedata
Array and assign it to $num
.
To skip the first row of the CSV file I have added $i > 0
condition. Remove this condition if your CSV file also contains data on the 1st row.
If $num == $numberOfFields
then initialize $importData_arr
Array. Set the key name with the MySQL database field name.
Insert data
Loop on the $importData_arr
Array and check if email already exists in the users
table. If not exist then insert a new record and increment $count
by 1.
Return the total number of records inserted using SESSION flash.
Completed Code
<?php namespace App\Controllers; use App\Models\Users; class UsersController extends BaseController{ public function index(){ ## Fetch all records $users = new Users(); $data['users'] = $users->findAll(); return view('users/index',$data); } // File upload and Insert records public function importFile(){ // Validation $input = $this->validate([ 'file' => 'uploaded[file]|max_size[file,1024]|ext_in[file,csv],' ]); if (!$input) { // Not valid $data['validation'] = $this->validator; return view('users/index',$data); }else{ // Valid if($file = $this->request->getFile('file')) { if ($file->isValid() && ! $file->hasMoved()) { // Get random file name $newName = $file->getRandomName(); // Store file in public/csvfile/ folder $file->move('../public/csvfile', $newName); // Reading file $file = fopen("../public/csvfile/".$newName,"r"); $i = 0; $numberOfFields = 4; // Total number of fields $importData_arr = array(); // Initialize $importData_arr Array while (($filedata = fgetcsv($file, 1000, ",")) !== FALSE) { $num = count($filedata); // Skip first row & check number of fields if($i > 0 && $num == $numberOfFields){ // Key names are the insert table field names - name, email, city, and status $importData_arr[$i]['name'] = $filedata[0]; $importData_arr[$i]['email'] = $filedata[1]; $importData_arr[$i]['city'] = $filedata[2]; $importData_arr[$i]['status'] = $filedata[3]; } $i++; } fclose($file); // Insert data $count = 0; foreach($importData_arr as $userdata){ $users = new Users(); // Check record $checkrecord = $users->where('email',$userdata['email'])->countAllResults(); if($checkrecord == 0){ ## Insert Record if($users->insert($userdata)){ $count++; } } } // Set Session session()->setFlashdata('message', $count.' Record inserted successfully!'); session()->setFlashdata('alert-class', 'alert-success'); }else{ // Set Session session()->setFlashdata('message', 'File not imported.'); session()->setFlashdata('alert-class', 'alert-danger'); } }else{ // Set Session session()->setFlashdata('message', 'File not imported.'); session()->setFlashdata('alert-class', 'alert-danger'); } } return redirect()->route('/'); } }
7. View
Create a users
folder at app/Views/
and create index.php
in users
folder.
Display bootstrap alert message if 'message'
SESSION exists. Also, set alert class using 'alert-class'
Session.
Load validation service \Config\Services::validation()
and assign it to $validation
.
Create <form method="post" action="<?=site_url('users/importFile')?>" enctype="multipart/form-data">
.
Create a file element and submit button. Display error in <div >
if not validated.
Loop on $users
to display users list in <table >
.
Completed Code
<!DOCTYPE html> <html> <head> <title>How to Import CSV file data to MySQL in CodeIgniter 4</title> <link rel="stylesheet" type="text/css" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> </head> <body> <div class="container"> <div class="row"> <div class="col-md-12"> <?php // Display Response if(session()->has('message')){ ?> <div class="alert <?= session()->getFlashdata('alert-class') ?>"> <?= session()->getFlashdata('message') ?> </div> <?php } ?> <?php $validation = \Config\Services::validation(); ?> <form method="post" action="<?=site_url('users/importFile')?>" enctype="multipart/form-data"> <?= csrf_field(); ?> <div class="form-group"> <label for="file">File:</label> <input type="file" class="form-control" id="file" name="file" /> <!-- Error --> <?php if( $validation->getError('file') ) {?> <div class='alert alert-danger mt-2'> <?= $validation->getError('file'); ?> </div> <?php }?> </div> <input type="submit" class="btn btn-success" name="submit" value="Import CSV"> </form> </div> </div> <div class="row"> <!-- Users list --> <div class="col-md-12 mt-4" > <h3 class="mb-4">Users List</h3> <table width="100%"> <thead> <tr> <th>ID</th> <th>Name</th> <th>Email</th> <th>City</th> <th>Status</th> </tr> </thead> <tbody> <?php if(isset($users) && count($users) > 0){ foreach($users as $user){ ?> <tr> <td><?= $user['id'] ?></td> <td><?= $user['name'] ?></td> <td><?= $user['email'] ?></td> <td><?= $user['city'] ?></td> <td><?= $user['status'] ?></td> </tr> <?php } }else{ ?> <tr> <td colspan="5">No record found.</td> </tr> <?php } ?> </body> </table> </div> </div> </div> </body> </html>
8. Run
- Navigate to the project using Command Prompt if you are on Windows or terminal if you are on Mac or Linux, and
- Execute “php spark serve” command.
php spark serve
- Run
http://localhost:8080
in the web browser.
9. Output
10. Conclusion
In the example, I read the CSV file row by row and check if all fields are available or not. If available then I inserted it.
Add required validation to avoid duplicacy of data and before inserting also check if values are in the required format.