Exportation de Données Massives : Éviter les Surcharges Mémoire avec Laravel & Vue 3

Comment exporter des journaux financiers et des mouvements de stocks de plus de 100 000 lignes grâce aux curseurs de base de données et au flux HTTP continu sans dépasser les limites mémoire de PHP.

Akram Hafaiedh
Akram Hafaiedh
Développeur Full Stack
2026-03-255 min de lecture
// BACKEND & PIPELINE ENGINEERING
PRODUCTION VERIFIED
TECHNICAL CASE STUDY

Exportation de Données Massives : Éviter les Surcharges Mémoire avec Laravel & Vue 3

PHP 8.3QUEUESPARALLEL WORKERS

Exportation de Données Massives : Éviter les Surcharges Mémoire

L'exportation de journaux financiers, de listes de factures ou d'historiques de stocks contenant des dizaines de milliers de lignes déclenche fréquemment des plantages mémoire en PHP (Fatal error: Allowed memory size exhausted).

Charger des collections d'objets Eloquent complètes en mémoire avant d'écrire un fichier CSV ou Excel est une mauvaise pratique. Voici comment nous avons conçu une réponse HTTP en flux continu (streamed response) s'appuyant sur des curseurs de base de données pour conserver une empreinte mémoire constante sous les 10 Mo.


1. Utiliser les Curseurs Eloquent à Faible Empreinte Mémoire

Au lieu de faire appel à ->get(), utilisez ->cursor(). Les curseurs Eloquent récupèrent les enregistrements ligne par ligne via les générateurs PDO sans hydrater l'ensemble des modèles simultanément.

php
class=class="text-emerald-500 dark:text-emerald-400 font-medium">"text-slate-500 italic">// app/Http/Controllers/FinancialExportController.php
namespace App\Http\Controllers;

use App\Models\Transaction;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\StreamedResponse;

class FinancialExportController extends Controller
{
    public function exportCsv(Request $request): StreamedResponse
    {
        $companyId = $request->user()->active_company_id;
        $fileName = 'export_financier_' . date('Y_m_d_His') . '.csv';

        $headers = [
            'Content-Type' => 'text/csv',
            'Content-Disposition' => "attachment; filename="{$fileName}"",
            'Pragma' => 'no-cache',
            'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
            'Expires' => '0',
        ];

        return response()->stream(function () use ($companyId) {
            $output = fopen('php:class=class="text-emerald-500 dark:text-emerald-400 font-medium">"text-slate-500 italic">//output', 'w');

            class=class="text-emerald-500 dark:text-emerald-400 font-medium">"text-slate-500 italic">// Écriture du BOM CSV pour la prise en charge UTF-8 sous MS Excel
            fputs($output, $bom = (chr(0xEF) . chr(0xBB) . chr(0xBF)));

            class=class="text-emerald-500 dark:text-emerald-400 font-medium">"text-slate-500 italic">// Écriture de l'en-tête CSV
            fputcsv($output, ['Référence', 'Date', 'Type', 'Montant', 'Statut']);

            class=class="text-emerald-500 dark:text-emerald-400 font-medium">"text-slate-500 italic">// Lecture progressive via curseur
            Transaction::where('company_id', $companyId)
                ->orderBy('created_at', 'desc')
                ->cursor()
                ->each(function (Transaction $tx) use ($output) {
                    fputcsv($output, [
                        $tx->reference_number,
                        $tx->created_at->format('Y-m-d H:i:s'),
                        strtoupper($tx->type),
                        number_format($tx->amount, 2, '.', ''),
                        $tx->status,
                    ]);
                });

            fclose($output);
        }, 200, $headers);
    }
}

2. Gestion des Téléchargements en Flux Continu dans Vue 3

Pour télécharger des flux d'exportation sans interrompre l'expérience utilisateur de l'application monopage :

ts
class=class="text-emerald-500 dark:text-emerald-400 font-medium">"text-slate-500 italic">// services/exportService.ts
import axios from 'axios';

export async function downloadFinancialExport(): Promise<void> {
    const response = await axios.get('/api/exports/financial-csv', {
        responseType: 'blob',
    });

    const blob = new Blob([response.data], { type: 'text/csv;charset=utf-8;' });
    const link = document.createElement('a');
    const url = URL.createObjectURL(blob);
    
    link.setAttribute('href', url);
    link.setAttribute('download', class="text-emerald-500 dark:text-emerald-400 font-medium">`export_financier_${Date.now()}.csv`);
    link.style.visibility = 'hidden';
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
}

L'utilisation des flux continus HTTP et des curseurs a permis d'exporter plus de 100 000 lignes de transactions instantanément sans aucun pic de mémoire ni délai d'attente serveur.

Engineering Collaboration

Building a High-Scale SaaS or Complex System?

Let’s discuss your architecture, full-stack development, or system modernization needs.

Articles Similaires

// BACKEND & PIPELINE ENGINEERING
PRODUCTION VERIFIED
TECHNICAL CASE STUDY

Éliminer les Requêtes N+1 et Optimiser l'Indexation Multi-Locataires sous Forte Charge SaaS

PHP 8.3QUEUESPARALLEL WORKERS
Backend
2026-03-30•Backend

Éliminer les Requêtes N+1 et Optimiser l'Indexation Multi-Locataires sous Forte Charge SaaS

Read Article
// FRONTEND & UI RENDERING
PRODUCTION VERIFIED
TECHNICAL CASE STUDY

Moderniser un Moteur de Contenu : Migration d'un Blog Laravel Blade vers Vue 3 avec Recherche & Recommandations

VUE 3NEXT.JS 15TAILWIND
Frontend
2026-03-15•Frontend

Moderniser un Moteur de Contenu : Migration d'un Blog Laravel Blade vers Vue 3 avec Recherche & Recommandations

Read Article