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

Langage PHP Discussion :

fputcsv ne dépasse pas 7,8Ko [PHP 5.4]


Sujet :

Langage PHP

  1. #1
    Membre actif Avatar de elvan49
    Profil pro
    Développeur Web
    Inscrit en
    Octobre 2006
    Messages
    274
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Octobre 2006
    Messages : 274
    Points : 204
    Points
    204
    Par défaut fputcsv ne dépasse pas 7,8Ko
    Bonjour à tous,

    C'est pourtant pas la première fois que je génère des fichiers csv avec fpucsv(), mais dépassant 15000 lignes c'est une première...
    Le problème (incompréhensible), est que je suis obligé de limiter la boucle dans laquelle fpucsv agit pour que la génération se déroule correctement.
    Si le fichier généré devait dépasser 8ko, il est généré vide à 0.

    Le contexte : je récupère dans une table des enregistrements qui peuvent aller jusqu'à 16000 lignes, en fonction des filtres définit par les utilisateurs.
    Puis j'écris dans un fichier .csv ces résultats pour le télécharger immédiatement (un export quoi...)

    J'ai d'abord pensé qu'un charactère spécial mettait le bazar, mais si je force la requête à exclure la ligne qui aurait dû être responsable, la génération se comporte toujours de la même façon, au-delà de 8Ko elle génère à 0 octet.

    Voici un extrait de mon code
    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
    $delimiteur = ';';
    $fichier  = fopen($chemin, 'w+');
    //fputs($fichier, $bom =( chr(0xEF) . chr(0xBB) . chr(0xBF) ));
    // première ligne
    fputcsv($fichier, $lignes_csv[0], $delimiteur);
    
    // lignes suivantes
    $taille = array();
    for ($i=0;$i < $nb ;$i++){
    $lignes_csv[$i] = array($row['UNIQUE_IDENTIFIER'][$i],$row['APPLICATION'][$i],$row['BASICAT_CODE'][$i],$row['ENTITES_SUPPORT'][$i],$row['ENTITES_EXPLOITANTE'][$i],$row['SERVICE_PRINCIPAL'][$i],$row['NIVEAUX_CHACO'][$i],$row['DEPARTEMENT_CAB'][$i],$row['EDS'][$i],$row['MODELE_CHANGE'][$i]);
    $saisie = fputcsv($fichier, $lignes_csv[$i], $delimiteur);
    if( $saisie == false){
    var_dump("erreur à la ligne $i : ".$row['APPLICATION'][$i]);
    die();
        }
    else{
    $taille[] = $saisie;
        }
    }
    
    fclose($fichier);
    //var_dump(count($taille));die();
    // fichier
    header("Pragma: nocache public");
    header("Expires: 0");
    header("Content-Type: text/csv");
    header("Content-Length: $chemin");
    header("Content-Disposition: attachment; filename=$file");
    readfile($chemin);
    unlink($chemin);
    Précision : le contrôle avec les variables et c'était juste pour vérifier que tout se passait bien... et à priori il n'y a pas d'erreur

    Si quelqu'un a une idée lumineuse d'un truc qui m'a échappé ? Merci d'avance

  2. #2
    Membre expert
    Avatar de Dendrite
    Femme Profil pro
    Développeuse informatique
    Inscrit en
    Juin 2008
    Messages
    2 129
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 59
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeuse informatique
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Juin 2008
    Messages : 2 129
    Points : 3 628
    Points
    3 628
    Billets dans le blog
    8
    Par défaut
    Bonjour, d'où sort $nb ?

    edit

    http://php.net/manual/fr/function.fputcsv.php#104980

    A priori, il y a une erreur dans ton code (mais comme on ne voit pas tout)... Le manuel parle de 5MB sans problème...

    Si tes données sont issues d'une base de données, tu as vu ceci sur le manuel PHP ?
    Bien sûr, il faut adapter et remettre en mysqli ou PDO...


    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
    <?php
    //Utility function to output a mysql query to csv with the option to write to file or send back to the browser as a csv attachment.
        function query_to_csv($db_conn, $query, $filename, $attachment = false, $headers = true) {
     
            if($attachment) {
                // send response headers to the browser
                header( 'Content-Type: text/csv' );
                header( 'Content-Disposition: attachment;filename='.$filename);
                $fp = fopen('php://output', 'w');
            } else {
                $fp = fopen($filename, 'w');
            }
     
            $result = mysql_query($query, $db_conn) or die( mysql_error( $db_conn ) );
     
            if($headers) {
                // output header row (if at least one row exists)
                $row = mysql_fetch_assoc($result);
                if($row) {
                    fputcsv($fp, array_keys($row));
                    // reset pointer back to beginning
                    mysql_data_seek($result, 0);
                }
            }
     
            while($row = mysql_fetch_assoc($result)) {
                fputcsv($fp, $row);
            }
     
            fclose($fp);
        }
     
        // Using the function
        $sql = "SELECT * FROM table";
        // $db_conn should be a valid db handle
     
        // output as an attachment
        query_to_csv($db_conn, $sql, "test.csv", true);
     
        // output to file system
        query_to_csv($db_conn, $sql, "test.csv", false);
    ?>
    Adapté, ça donne ceci :

    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
    function sql_to_csv($db, $sql, $filename, $first_line_fields=false){
      $sth = $db->prepare($sql);
      $sth->execute();
      $fp = fopen($filename, 'w');
      while($row = $sth->fetch(PDO::FETCH_ASSOC)){
        if($first_line_fields){
          $keys=array_keys($row);
          fputcsv($fp, $keys,';');
        }
        fputcsv($fp, $row,';');
        $first_line_fields=false;
      }
      fclose($fp);
    }
    $pdo = new PDO('mysql:host=localhost;port=3306;dbname=scoop;charset=utf8','root', '');
    sql_to_csv($pdo,'select * from batiment order by nom','toto.csv',true);
    unset($pdo);

  3. #3
    Membre actif Avatar de elvan49
    Profil pro
    Développeur Web
    Inscrit en
    Octobre 2006
    Messages
    274
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Octobre 2006
    Messages : 274
    Points : 204
    Points
    204
    Par défaut
    Je te remercie Dendrite,

    Alors je ne peux pas passer en PDO pour des raisons que je ne développerai pas ici mais qui n'a pas d'incidence sur mon problème.
    Le $nb c'est le nombre de ligne retournées par la requête ORACLE
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $nb = oci_fetch_all($sql, $row);
    Je vais tenter de redire pourquoi c'est obscur car ça l'est :
    1. Je fais une requête qui (par exemple me retourne 149 lignes)
    2. la vérification de la requête est faite, via pl/sql et divers var_dump posés aux bons endroits pour voir ce qui était généré, le pb ne vient pas de la base, de sa liaison
    3. après plusieurs tests, en limitant le nombre de ligne écrites grâce à fputcsv, j'arriv à un chiffre fixe de 94 lignes.
    4. à 94 lignes le fichiers csv sort nickel, à 95 et + il sort vide à 0 octet
    5. je retouche la requête pour exclure les deux premiers résultats pour vérifier si les données de la ligne 95 ne seraient pas responsable (caractère spécial, invisible ou autre)
    6. les 94 lignes sortent toujours nickel dans mon csv avec en moins les deux premiers résultats, et en plus les deux suivants qui remplacent du coup, donc le pb ne vient pas des données...
    7. je fais un test pour savoir si la fonction fputcsv génère un false en retour et du coup à quel moment (quelle ligne)
    8. sur les 149 lignes pas une seule ne revient avec un false.
    9. si j'affiche le résultat directement dans le naivgateur, (suppression des header attachment etc.) TOUT (les 149 entres) sont affichées
    10. donc, ça semble être lors de la génération finale, la sortie pour téléchargement que le fichier se corrompt...

    Je ne peux pas mieux expliquer...
    Je précise qu'en début de fichier j'ai mis :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    ini_set('upload_max_filesize', '20M');
    ini_set('post_max_size', '21M');

  4. #4
    Membre actif Avatar de elvan49
    Profil pro
    Développeur Web
    Inscrit en
    Octobre 2006
    Messages
    274
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Octobre 2006
    Messages : 274
    Points : 204
    Points
    204
    Par défaut
    Alors, comme toujours, c'est une ânerie !!!
    ma ligne de header :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    header("Content-Length: ". $chemin);
    est pas bonne !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    header("Content-Length: ". filesize($chemin));
    Voilà !!! là c'est bon! et le truc marrant c'est qu'en dessous de 8Ko de fichier ça ne lui posait pas de souci mais au-delà, fallait pas pousser quand même !

    Conclusion : je resterai poli avec moi-même.
    En tout cas merci Dendrite pour ton écoute

  5. #5
    Membre expert
    Avatar de Dendrite
    Femme Profil pro
    Développeuse informatique
    Inscrit en
    Juin 2008
    Messages
    2 129
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 59
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeuse informatique
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Juin 2008
    Messages : 2 129
    Points : 3 628
    Points
    3 628
    Billets dans le blog
    8
    Par défaut
    Bon ben super, si tout est réglé...
    Tu parlais de 15 000 lignes au début ?
    On est d'accord qu'il ne vaut mieux pas construire le tableau PHP de 15000 lignes, mais générer pour chaque ligne à la volée l'écriture dans le csv ?
    cf l'algo de cette fonction, qui peut certainement être améliorée encore...
    Et toi, tu n'as qu'à changer la ligne pdo pour la remettre dans la librairie qui t'arrange...

    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
    function sql_to_csv($db, $sql, $filename, $first_line_fields=false){
      $sth = $db->prepare($sql);
      $sth->execute();
      $fp = fopen($filename, 'w');
      while($row = $sth->fetch(PDO::FETCH_ASSOC)){
        if($first_line_fields){
          $keys=array_keys($row);
          fputcsv($fp, $keys,';');
        }
        fputcsv($fp, $row,';');
        $first_line_fields=false;
      }
      fclose($fp);
    }
    $pdo = new PDO('mysql:host=localhost;port=3306;dbname=scoop;charset=utf8','root', '');
    sql_to_csv($pdo,'select * from batiment order by nom','toto.csv',true);
    unset($pdo);

  6. #6
    Membre actif Avatar de elvan49
    Profil pro
    Développeur Web
    Inscrit en
    Octobre 2006
    Messages
    274
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Octobre 2006
    Messages : 274
    Points : 204
    Points
    204
    Par défaut
    Oui on est parfaitement d'accord !
    Dans une petite boucle le fputcsv...


    même un peu plus de 16000, mais seulement si les utilisateurs ne font aucun filtres. Les filtres ayant pour vocation de limiter grâce à une génération de where clauses le nombre de résultat.

  7. #7
    Modérateur
    Avatar de grunk
    Homme Profil pro
    Lead dév - Architecte
    Inscrit en
    Août 2003
    Messages
    6 692
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Lead dév - Architecte
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2003
    Messages : 6 692
    Points : 20 244
    Points
    20 244
    Par défaut
    Citation Envoyé par Dendrite Voir le message
    On est d'accord qu'il ne vaut mieux pas construire le tableau PHP de 15000 lignes, mais générer pour chaque ligne à la volée l'écriture dans le csv ?
    D'un point de vue performance il vaut mieux écrire 1x plutot que 15000. Si le tableau de 15000 prend trop de place en mémoire vaut mieux faire découper en paquet et faire par exemple 3 écritures de 5000 lignes.
    Et c'est sans compter l'usure disque qui peut être extrêmement significative sur un service très utilisé.

  8. #8
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 912
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 912
    Points : 6 705
    Points
    6 705
    Par défaut
    À noter que l'on peut directement créer le fichier csv avec MySQL:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    SELECT *
    FROM matable
    INTO OUTFILE 'fichier.csv'
    FIELDS TERMINATED BY ',' 
    ENCLOSED BY '"'
    FIELDS ESCAPED BY '"'
    LINES TERMINATED BY '\n';

  9. #9
    Membre expert
    Avatar de Dendrite
    Femme Profil pro
    Développeuse informatique
    Inscrit en
    Juin 2008
    Messages
    2 129
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 59
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeuse informatique
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Juin 2008
    Messages : 2 129
    Points : 3 628
    Points
    3 628
    Billets dans le blog
    8
    Par défaut
    J'adore ce forum ! J'en apprends tous les jours.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 0
    Dernier message: 19/11/2010, 15h50
  2. [AJAX] Je ne dépasse pas 1 avec readyState (IE)
    Par beegees dans le forum AJAX
    Réponses: 4
    Dernier message: 07/08/2009, 12h17
  3. Réponses: 0
    Dernier message: 23/06/2009, 22h57
  4. mon débit de téléchargement ne dépasse pas 20 ko/s
    Par amigo0 dans le forum Dépannage et Assistance
    Réponses: 7
    Dernier message: 27/07/2007, 11h56
  5. [AJAX] AJAX+Firefox : readyState ne dépasse pas le 1
    Par TheRedLed dans le forum Général JavaScript
    Réponses: 1
    Dernier message: 13/04/2007, 14h42

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