Upload zip file, extract files and import to database in Laravel

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

Mastering Data Ingestion in Laravel: Uploading, Extracting, and Importing CSV Files

As a senior developer working with the Laravel ecosystem, we frequently encounter real-world data challenges. One common requirement is handling bulk data imports, often delivered as compressed files like ZIP archives containing CSVs. The question—is there a ready-made package for this?—is valid. While specialized packages exist for general file uploads or CSV manipulation, the most robust and customizable solution often lies in leveraging core PHP capabilities within the Laravel framework itself, ensuring maximum control over security and execution flow.

This post will walk you through the comprehensive, developer-centric approach to solving this exact problem: uploading a ZIP file, extracting the contents, and cleanly importing the resulting CSV data into your Laravel database.

The Implementation Strategy: Custom vs. Package Approach

For complex operations like file extraction and data mapping, while packages can save time, building custom logic ensures that the process is tailored precisely to your application's security standards and error handling requirements. If a perfect, well-maintained package doesn't exist for this exact workflow, implementing it yourself using native PHP tools is the superior path.

We will focus on a manual implementation utilizing PHP’s built-in ZipArchive class for extraction and Laravel’s Eloquent ORM for database interaction.

Step 1: Handling the File Upload in Laravel

First, we need to secure the file upload process within a Laravel controller. Security is paramount when handling user-uploaded files.

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;

class DataImportController extends Controller
{
    public function uploadAndProcess(Request $request)
    {
        $request->validate([
            'zip_file' => 'required|file|mimes:zip',
        ]);

        // Store the uploaded file securely on the disk
        $zipFile = $request->file('zip_file');
        $path = $zipFile->store('imports', 'local'); // Use Laravel Storage for robust file management

        // Proceed to extraction logic in the next step...
        return response()->json(['message' => 'File uploaded successfully. Starting processing...']);
    }
}

Step 2: Extracting the ZIP Archive

Inside your controller method, after storing the file, you need to retrieve it and use PHP’s ZipArchive class to extract its contents into a temporary directory. This step requires careful error handling.

use ZipArchive;
use Illuminate\Support\Facades\Storage;

// ... inside your controller method

if (!Storage::disk('local')->exists($path)) {
    return response()->json(['error' => 'File not found'], 404);
}

$zipPath = Storage::disk('local')->path($path);
$zip = new ZipArchive;

if ($zip->open($zipPath) === TRUE) {
    // Create a temporary directory for extraction
    $extractionDir = storage_path('app/temp_imports/' . time());
    if (!is_dir($extractionDir)) {
        mkdir($extractionDir);
    }

    // Extract the contents
    $zip->extractTo($extractionDir);
    $zip->close();

    // Now, $extractionDir contains the extracted CSV file.
    // You would typically move or process files here.
    return response()->json(['message' => 'ZIP extracted successfully to: ' . $extractionDir]);

} else {
    return response()->json(['error' => 'Failed to open ZIP file.'], 500);
}

Step 3: Importing the CSV Data to the Database

Once you have the extracted CSV file (let's assume it’s named data.csv), you use PHP’s file handling functions (fopen, fgetcsv) to read the data row by row, and then map that data directly into your Eloquent models. This is where Laravel shines, utilizing the power of migrations and efficient database writes.

// Assuming $extractionDir holds the path to the extracted folder
$csvFilePath = $extractionDir . '/data.csv';

if (file_exists($csvFilePath)) {
    $fileHandle = fopen($csvFilePath, 'r');
    // Read the header row (assuming first row is headers)
    $headers = fgetcsv($fileHandle);

    // Loop through the rest of the rows
    while (($data = fgetcsv($fileHandle)) !== FALSE) {
        // Map CSV data to your database model structure
        $model = new YourModel;
        $model->name = $data[0]; // Example mapping
        $model->value = $data[1];
        
        // Save the record using Eloquent
        $model->save();
    }
    fclose($fileHandle);
    return response()->json(['message' => 'Data imported successfully!']);
} else {
    return response()->json(['error' => 'CSV file not found in extraction directory.'], 400);
}

Conclusion: Control is King

While finding a single package might seem tempting, mastering the underlying mechanics—file manipulation via ZipArchive and data parsing via standard PHP functions integrated with Eloquent—gives you ultimate control. This approach ensures that your import process is secure, highly performant, and fully debuggable, aligning perfectly with the high standards of architecture promoted by frameworks like Laravel. By understanding these core components, you move beyond simply using a package to truly mastering the development cycle within Laravel.