IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JavaScript Discussion :

PhpSpreadsheet et dépassement de mémoire


Sujet :

JavaScript

  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Avril 2003
    Messages
    277
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2003
    Messages : 277
    Par défaut PhpSpreadsheet et dépassement de mémoire
    Bonjour,

    Je vous contacte parce que je suis arrivé au bout de tous les contournements que j'ai pu trouver.

    J'utilise PhpSpreadsheet pour générer des fichiers excel d'erreurs : en fonction d'un fichier en entrée, le site effectue des contrôles et génère des résultats de qualité de contrôle de données.
    En fonction du nombre d'enregistrements du fichier en entrée et du nombre d'erreurs que celui-ci génère, le fichier peut être très volumineux (plus de 150 000 erreurs, donc lignes dans excel).

    Mon traitement génère 13 fichiers excel. Je me rends compte qu'au fur et à mesure que le traitement avance et génère les fichiers Excel, l'utilisation mémoire augmente. Je le mesure avec ce code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
            $used = round(memory_get_usage(true) / 1024 / 1024, 2);
            $peak = round(memory_get_peak_usage(true) / 1024 / 1024, 2);
            $percentUsed = round(($used / ($memoryLimit / 1024 / 1024)) * 100, 2);
            $percentPeak = round(($peak / ($memoryLimit / 1024 / 1024)) * 100, 2);
            file_put_contents($logFile, "[Chunk] RAM utilisée: {$used}MB ({$percentUsed}%) | Pic: {$peak}MB ({$percentPeak}%)" . PHP_EOL, FILE_APPEND);
    Malgré les 48 Go proposés par l'hébergeur, un process PHP est limité à 2 Go.

    Voici le code pour générer un des fichiers Excel :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
            $spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
            $sheet = $spreadsheet->getActiveSheet();
     
            $headers = ['Code', 'Message', 'Prêt', 'Tiers', 'Collateral', 'Valeur trouvée', 'Niveau Erreur', 'Type Validation', 'Date'];
            $sheet->fromArray([$headers], NULL, 'A1');
     
            $chunkSize = 500;
            $row = 2;
     
            foreach (array_chunk($erreursDetailleesTransaction, $chunkSize) as $chunk) {
                $sheet->fromArray($chunk, NULL, "A$row");
                $row += count($chunk);
            }
     
            // Log RAM utilisée
            $used = round(memory_get_usage(true) / 1024 / 1024, 2);
            $peak = round(memory_get_peak_usage(true) / 1024 / 1024, 2);
            $percentUsed = round(($used / ($memoryLimit / 1024 / 1024)) * 100, 2);
            $percentPeak = round(($peak / ($memoryLimit / 1024 / 1024)) * 100, 2);
            file_put_contents($logFile, "[Chunk] RAM utilisée: {$used}MB ({$percentUsed}%) | Pic: {$peak}MB ({$percentPeak}%)" . PHP_EOL, FILE_APPEND);
     
            // Styles
            $headerRange = 'A1:I1';
            $dataRange = 'A2:I' . (count($erreursDetailleesTransaction) + 1);
     
            $sheet->getStyle($headerRange)->applyFromArray([
                'font' => ['bold' => true, 'color' => ['rgb' => 'FFFFFF']],
                'fill' => ['fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID, 'startColor' => ['rgb' => '4F81BD']],
                'borders' => ['allBorders' => ['borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN]],
            ]);
     
            $sheet->getStyle($dataRange)->applyFromArray([
                'borders' => ['allBorders' => ['borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN]],
            ]);
     
            foreach (range('A', 'I') as $col) {
                $sheet->getColumnDimension($col)->setAutoSize(false);
            }
     
            $sheet->getColumnDimension('A')->setWidth(15);
            $sheet->getColumnDimension('B')->setWidth(70);
            $sheet->getColumnDimension('C')->setWidth(20);
            $sheet->getColumnDimension('D')->setWidth(20);
            $sheet->getColumnDimension('E')->setWidth(20);
            $sheet->getColumnDimension('F')->setWidth(15);
            $sheet->getColumnDimension('G')->setWidth(20);
            $sheet->getColumnDimension('H')->setWidth(70);
            $sheet->getColumnDimension('I')->setWidth(15);
     
            $sheet->getStyle($headerRange)->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER);
            $sheet->getStyle($headerRange)->getAlignment()->setVertical(\PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER);
            $sheet->getStyle($dataRange)->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER);
            $sheet->getStyle($dataRange)->getAlignment()->setVertical(\PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER);
     
            $sheet->setSelectedCell('A1');
     
            $filePathTransaction .= '.xlsx';
            $writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
            $writer->setPreCalculateFormulas(false);
            $writer->save($filePathTransaction);
            $spreadsheet->disconnectWorksheets();
            unset($spreadsheet, $sheet, $writer, $erreursDetailleesTransaction);
            gc_collect_cycles();
    Je suis passé par des chunks, par tout plein de contournements et il se trouve que c'est le code ci-dessus qui "résiste" le mieux. J'obtiens une erreur invisible dès que j'approche des 2048 Mo d'utilisation de la RAM, toujours pendant la génération d'un fichier Excel.

    Auriez-vous des idées lumineuses pour me sortir de ce pétrin ? Ca fait des semaines que je tourne en rond. J'essaie de libérer la mémoire au maximum mais j'ai l'impression que ça ne change rien.
    J'en arrive à me demander si finalement, il est possible de générer un tel fichier Excel via un site web.

    J'ai bien conscience que la mise en forme prend beaucoup de ressources mais c'est vraiment un prérequis, sinon je génèrerais un fichier CSV.

    La solution est peut-être évidente, je débute, donc n'hésitez pas à me dire si je fais n'importe quoi.

    Je vous remercie pour votre aide et reste à votre disposition pour vous apporter un maximum d'éléments supplémentaires.

  2. #2
    Expert confirmé
    Avatar de mathieu
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    10 575
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 10 575
    Par défaut
    après avoir lu les premières lignes de votre message, j'ai commencé à penser au format csv. et en arrivant à la fin, je me suis rendu compte que vous n'avez pas eu besoin de moi pour penser à ce format.
    le format csv a plusieurs avantages dont celui de pouvoir être découpé en plusieurs morceaux si le contenu est trop volumineux pour l'application de départ ou celle d'arrivée.

    mais à part le format, il y a une autre chose à étudier : pourquoi utiliser un tableur pour un si grand nombre de données ? ces logiciels sont plutôt prévus pour une utilisation plus réduite.
    en plus vous avez les données déjà accessibles dans votre code php donc ça serait beaucoup plus efficace de faire une interface web pour traiter ces données. cela réglerait les soucis d'importation et d'exportation ainsi que les probables futurs soucis de format quand les différents utilisateurs n'utiliseront pas les mêmes versions du tableur.

  3. #3
    Membre émérite
    Homme Profil pro
    Autre
    Inscrit en
    Juillet 2021
    Messages
    426
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Autre

    Informations forums :
    Inscription : Juillet 2021
    Messages : 426
    Par défaut
    Bonjour,

    En alternative de PhpSpreadsheet, voir OpenSpout qui est conçu pour traiter des gros fichiers en utilisant peu de mémoire.

Discussions similaires

  1. utiliser PhpSpreadsheet sans composer
    Par ouldfella dans le forum Bibliothèques et frameworks
    Réponses: 4
    Dernier message: 12/06/2020, 09h16
  2. Réponses: 6
    Dernier message: 29/11/2019, 08h03
  3. [PhpSpreadSheet] Pourquoi PhpSpreadSheet retourne les deux dernières lignes vides ?
    Par cubano2301 dans le forum Bibliothèques et frameworks
    Réponses: 0
    Dernier message: 31/01/2019, 13h15
  4. PhpSpreadsheet et UTF8
    Par bob456 dans le forum Bibliothèques et frameworks
    Réponses: 0
    Dernier message: 27/09/2018, 19h23
  5. [PhpSpreadSheet] Export Excel de données
    Par tankay dans le forum Bibliothèques et frameworks
    Réponses: 0
    Dernier message: 18/07/2014, 14h08

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo