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 :

fputscsv et headers


Sujet :

Langage PHP

  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    495
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2004
    Messages : 495
    Par défaut fputscsv et headers
    Bonjour,

    Je génère un fichier CSV pour exporter des données d'un site marchand.
    Ce site utilise Symfony (v6), mais je ne pense pas que ça ait rapport au framework, donc je poste ici..

    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
    		$list[] = array("ID", "date de paiement", "nom", "prénom", "mail", "total", "types", "détails commande");
    		foreach($commandes as $commande) {
    			$total = Money::EUR(0);
    			$items = $commande->getItems();
    			$details = "";
    			$type = "";
    			$titre = "";
    			foreach($items as $item) {
    				$produit = $item->getProduit();
    				$total = $total->add( $produit->getPrice()->multiply( $item->getQuantity() ) );
    				if($item->getProduit()->getActivite() !== NULL) {
    					$type .= "Activité ";
    					$titre = $item->getProduit()->getActivite()->getTitre(); 
    					//var_dump($titre);
    				} else if($item->getProduit()->getPublication() !== NULL) {
    					$type .= "Publication ";
    					$titre = $item->getProduit()->getPublication()->getTitre(); 
    					//var_dump($titre);
    				} else if($item->getProduit()->getArticle() !== NULL) {
    					$titre = $item->getProduit()->getArticle()->getTitre(); 
    					$type .= "Article ";
    				}
    				$details .= substr($titre, 0, 20) . "\n" . $item->getProduit()->getTitre() ." à ". $moneyFormatter->format($item->getProduit()->getPrice()) ." x ". $item->getQuantity() ." = ". $moneyFormatter->format($item->getTotal()). " \n ";
    			}
     
     
    			$list[] = array(
    				$commande->getId(),
    				$commande->getDatePaiement()->format("d/m/Y H:i"),
    				$commande->getUser()->getNom(),
    				$commande->getUser()->getPrenom(),
    				$commande->getUser()->getMail(),
    				$moneyFormatter->format($total),
    				$type, 
    				$details,
    			);
    		}
     
            $response = new Response();
     
    		$fp = fopen('php://output', 'w');
    		fputs($fp, $bom =( chr(0xEF) . chr(0xBB) . chr(0xBF) ));
            foreach ($list as $fields) {
                fputcsv($fp, $fields, ";");
            }
    		fclose($fp);
    		$response->headers->set('Content-Type', 'application/octet-stream; charset=utf-8');
    		$response->headers->set('Content-Disposition', 'attachment; filename="export.csv"');
            return $response;
    Tout fonctionne correctement, jusqu’à ce que j’insère le "titre" de l'activité / publication / article dans la colonne détails.. donc ici :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $details .= $titre . "\n" . $item->getProduit()->getTitre() ." à ". $moneyFormatter->format($item->getProduit()->getPrice()) ." x ". $item->getQuantity() ." = ". $moneyFormatter->format($item->getTotal()). " | ";
    Ce titre peut être assez long.. Et apparemment quand il est trop long, ça pose un problème..
    apparemment les headers sont envoyés avant ma déclaration, sur cette ligne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    fputcsv($fp, $fields, ";");
    Je ne comprends pas comment ça se fait que fputscsv génère une sortie au niveau du navigateur.. J'ai fini par trouver d’où venait l'erreur en tâtonnant, mais après quelques recherches, il semblerait qu'il n'y ait pas de limite de taille à un champ CSV.. Donc j'ai essaye htmlentities sur mon titre, mais toujours pareil..

    Warning: Cannot modify header information - headers already sent by (ligne 78 qui est la ligne de fputscsv)
    Alors pourquoi fputscsv génère une sortie avant mon header, uniquement si le titre est trop long ? La je ne comprends pas d’où vient le souci.. Et laisser un substr pour limiter la longueur n'est pas une solution acceptable.

  2. #2
    Expert confirmé
    Avatar de Séb.
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    5 355
    Détails du profil
    Informations personnelles :
    Âge : 48
    Localisation : France

    Informations professionnelles :
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2005
    Messages : 5 355
    Billets dans le blog
    17
    Par défaut
    Alors pourquoi fputscsv génère une sortie avant mon header
    C'est ce que tu lui demandes. php://output écrit sur la sortie.

    uniquement si le titre est trop long ?
    Parce qu'il doit y avoir un système de tampon pour envoyer les données seulement tous les x ko de données.

    => Je ne connais pas Symfony, mais je suppose qu'il y a quelque chose à faire pour "lier" ton CSV à $response
    => Hors Symfony, il faudrait remplacer php://output par php://memory + rewind() + stream_get_contents() ou écrire le CSV dans un fichier plutôt que sur la sortie, et l'envoyer en fin de traitement avec readfile()

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    495
    Détails du profil
    Informations personnelles :
    Âge : 53
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2004
    Messages : 495
    Par défaut
    Ah merci, ça m'a débloqué

    avec ce 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
            $tmpFileName = (new Filesystem())->tempnam(sys_get_temp_dir(), 'sb_');
            $tmpFile = fopen($tmpFileName, 'wb+');
            if (!\is_resource($tmpFile)) {
                throw new \RuntimeException('Unable to create a temporary file.');
            }
    		fputs($tmpFile, $bom =( chr(0xEF) . chr(0xBB) . chr(0xBF) ));
            foreach ($list as $fields) {
                fputcsv($tmpFile, $fields, ";");
            }
     
    		$response = $this->file($tmpFileName, 'export.csv');
    		fclose($tmpFile);
    		$response->headers->set('Content-Type', 'text/csv; charset=utf-8');
            return $response;
    ça marche, sans substr sur le titre !

    Merci

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

Discussions similaires

  1. [Réseau] Headers vers un serveur http
    Par gexti dans le forum Entrée/Sortie
    Réponses: 5
    Dernier message: 04/05/2004, 15h58
  2. __declspec(dllexport) dans mon fichier header mais...?
    Par Jasmine dans le forum Autres éditeurs
    Réponses: 1
    Dernier message: 03/03/2004, 19h00
  3. mise en page (Header and Footer) en XML-XSL.
    Par christine dans le forum XSL/XSLT/XPATH
    Réponses: 4
    Dernier message: 01/03/2004, 17h31
  4. [C#]dimension fixe footer et header datagrid
    Par Dos dans le forum ASP.NET
    Réponses: 2
    Dernier message: 24/01/2004, 18h45
  5. [MFC] image dans un header de CListCtrl
    Par tut dans le forum MFC
    Réponses: 3
    Dernier message: 11/06/2003, 16h26

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