Laravel 5 — CSV File Validations

CSV file is one of the most common method for your application users to import/insert multiple records. Instead of creating the resource one-by-one by navigating through the page, they could just easily edit the CSV file in Spreadsheet program such as Microsoft Excel.

However, there seems to be no built in method to validate the imported data. Here, I am going to share the methods I’d been using when implementing this feature.


Overview

By using Validation component that comes with Laravel, turns out we can easily do it, similar to when we are validating form data.

For the sake of this example, let’s say we are building an import form for books. The import form contains a file input with the name of ‘csv_file’, and the required input format are: title, author, year and publisher.

First, the controller codes (explanations below):


Read Data

$file_path = $request->csv_file->path();
if (($handle = fopen($file_path, "r")) !== FALSE) {
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
...
}
fclose($handle);
}

Modified from the PHP docs for fgetcsv(), first we use fopen and fgetcsv to read the CSV file line by line, specifying comma as the delimiter.

$book = array();
list(
$book['title'],
$book['author'],
$book['year'],
$book['publisher']
) = $data;

Use the PHP language construct, list(), to assign the extracted data into an associative array, $book. Remember to use the same key as you would in the name of create form, as we’ll need them for validations.


Validate Data

$csv_errors = Validator::make(
$book,
(new CreateBook)->rules()
)->errors();

Manually creates a validator using Laravel’s Validator class, passing in the $book array and the rules. The rules can be taken from the respective Form Request class as shown here, or you can directly specify the rules array here. An MessageBag instance will be returned which you can further modify.

$allowed_years = [2013, 2015];
if ( !in_array($book['year'], $allowed_years) ) {
$csv_errors->add('year', "Year must be either 2013 or 2015.");
}

Optionally, you could add in any custom validations as well. For example, here we only accept books that are published on year 2013 and 2015.

if ($csv_errors->any()) {
return redirect()->back()
->withErrors($csv_errors, 'import')
->with('error_line', $line);
}

If the validations don’t pass, redirects back to the upload form, passing in the error messages with a key ‘import’ and the line number. The key is specified to separate from other form errors for better controls.


Show error messages

Back in the upload form, add the lines above to Blade file to show the import errors if present. For this example, the alert box of Bootstrap is utilised to display them.

@if ($errors->import->any())

This line checks whether there is any import errors by using the specific key that was specified earlier.


* Notes

Depending on the use case / workloads, you might prefer to handle the CSV validations in queued jobs. In that case, you’ll have to build a good way to manage the queued jobs and notify user should any error occurs.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.