Tableau PHP en CSV

104

J'essaie de convertir une gamme de produits en un fichier CSV, mais cela ne semble pas aller comme prévu. Le fichier CSV est une longue ligne, voici mon code:

for($i=0;$i<count($prods);$i++) {
$sql = "SELECT * FROM products WHERE id = '".$prods[$i]."'";
$result = $mysqli->query($sql);
$info = $result->fetch_array(); 
}

$header = '';

for($i=0;$i<count($info);$i++)  
  {
    $row = $info[$i];

    $line = '';
    for($b=0;$b<count($row);$b++)
    { 
    $value = $row[$b];                                      
        if ( ( !isset( $value ) ) || ( $value == "" ) )
        {
            $value = "\t";
        }
        else
        {
            $value = str_replace( '"' , '""' , $value );
            $value = '"' . $value . '"' . "\t";
        }
         $line .= $value;
        }
    $data .= trim( $line ) . "\n";
}
$data = str_replace( "\r" , "" , $data );

if ( $data == "" )
{
$data = "\n(0) Records Found!\n";                        
}

header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=your_desired_name.xls");
header("Pragma: no-cache");
header("Expires: 0");

array_to_CSV($data);


function array_to_CSV($data)
    {
        $outstream = fopen("php://output", 'r+');
        fputcsv($outstream, $data, ',', '"');
        rewind($outstream);
        $csv = fgets($outstream);
        fclose($outstream);
        return $csv;
    }

De plus, l'en-tête ne force pas un téléchargement. J'ai copié et collé la sortie et enregistré au format .csv

ÉDITER

PROBLÈME RÉSOLU:

Si quelqu'un d'autre cherchait la même chose, a trouvé une meilleure façon de le faire:

$num = 0;
$sql = "SELECT id, name, description FROM products";
if($result = $mysqli->query($sql)) {
     while($p = $result->fetch_array()) {
         $prod[$num]['id']          = $p['id'];
         $prod[$num]['name']        = $p['name'];
         $prod[$num]['description'] = $p['description'];
         $num++;        
    }
 }
$output = fopen("php://output",'w') or die("Can't open php://output");
header("Content-Type:application/csv"); 
header("Content-Disposition:attachment;filename=pressurecsv.csv"); 
fputcsv($output, array('id','name','description'));
foreach($prod as $product) {
    fputcsv($output, $product);
}
fclose($output) or die("Can't close php://output");
JohnnyFaldo
la source
Utilisez $ info [] = $ result-> fetch_array (); sinon, il aura les derniers détails du produit
GBD
@JohnnyFaldo: Merci mec! Juste ce dont j'avais besoin.
Cesar
Hey! Je sais que c'est une vieille question, mais vous pourriez répondre à votre propre question. Cela peut aider les gens à trouver une solution à un problème similaire.
Gustavo Straube
est-ce que quelqu'un d'autre obtient la première ligne et les deux premiers blocs de la deuxième ligne vide?
mach2

Réponses:

97

Au lieu d'écrire des valeurs, envisagez d'utiliser fputcsv().

Cela peut résoudre votre problème immédiatement.

Martin Lyne
la source
1
Je dois mentionner que cela créera un fichier sur votre serveur, vous devrez donc lire le contenu de ce fichier avant de le sortir, également si vous ne voulez pas enregistrer une copie, vous devrez `` lier '' le fichier lorsque vous avez terminé.
Martin Lyne
Merci d'avoir édité Vyktor, ma frappe est horrible aujourd'hui! Je suis généralement si prudent.
Martin Lyne
puis-je modifier le code que j'ai ci-dessus pour faire cela? comme il affiche tous les champs, et en utilisant des exemples de fputcsv dans le manuel, je ne peux pas le faire faire
JohnnyFaldo
7
array_to_CSV ($ données); function array_to_CSV ($ data) {$ outstream = fopen ("php: // output", 'r +'); fputcsv ($ outstream, $ data, ',', '"'); rewind ($ outstream); $ csv = fgets ($ outstream); fclose ($ outstream); return $ csv;}
JohnnyFaldo
oui qui l'a résolu merci, ont ajouté la solution dans la question d'origine
JohnnyFaldo
16

Il s'agit d'une solution simple qui exporte un tableau vers une chaîne csv:

function array2csv($data, $delimiter = ',', $enclosure = '"', $escape_char = "\\")
{
    $f = fopen('php://memory', 'r+');
    foreach ($data as $item) {
        fputcsv($f, $item, $delimiter, $enclosure, $escape_char);
    }
    rewind($f);
    return stream_get_contents($f);
}

$list = array (
    array('aaa', 'bbb', 'ccc', 'dddd'),
    array('123', '456', '789'),
    array('"aaa"', '"bbb"')
);
var_dump(array2csv($list));
trank
la source
5

Essayez d'utiliser;

PHP_EOL

Pour terminer chaque nouvelle ligne dans votre sortie CSV.

Je suppose que le texte délimite, mais ne passe pas à la ligne suivante?

C'est une constante PHP. Il déterminera la bonne fin de ligne dont vous avez besoin.

Windows, par exemple, utilise "\ r \ n". Je me suis cassé la tête avec celui-là quand ma sortie ne passait pas à une nouvelle ligne.

comment écrire une nouvelle ligne unifiée en PHP?

Martyn Shutt
la source
2

Je sais que c'est vieux, j'ai eu un cas où j'avais besoin que la clé de tableau soit également incluse dans le CSV, alors j'ai mis à jour le script de Jesse Q pour le faire. J'ai utilisé une chaîne comme sortie, car implode ne peut pas ajouter de nouvelle ligne (la nouvelle ligne est quelque chose que j'ai ajouté et devrait vraiment être là).

Veuillez noter que cela ne fonctionne qu'avec des tableaux à valeur unique (key, value). mais pourrait facilement être mis à jour pour gérer plusieurs dimensions (key, array()).

function arrayToCsv( array &$fields, $delimiter = ',', $enclosure = '"', $encloseAll = false, $nullToMysqlNull = false ) {
    $delimiter_esc = preg_quote($delimiter, '/');
    $enclosure_esc = preg_quote($enclosure, '/');

    $output = '';
    foreach ( $fields as $key => $field ) {
        if ($field === null && $nullToMysqlNull) {
            $output = '';
            continue;
        }

        // Enclose fields containing $delimiter, $enclosure or whitespace
        if ( $encloseAll || preg_match( "/(?:${delimiter_esc}|${enclosure_esc}|\s)/", $field ) ) {
            $output .= $key;
            $output .= $delimiter;
            $output .= $enclosure . str_replace($enclosure, $enclosure . $enclosure,     $field) . $enclosure;
            $output .= PHP_EOL;
        }
        else {
            $output .= $key;
            $output .= $delimiter;
            $output .= $field;
            $output .= PHP_EOL;
        }
    }

    return  $output ;
}
J nui
la source
1

Dans mon cas, mon tableau était multidimensionnel, potentiellement avec des tableaux comme valeurs. J'ai donc créé cette fonction récursive pour démonter complètement le tableau:

function array2csv($array, &$title, &$data) {
    foreach($array as $key => $value) {      
        if(is_array($value)) {
            $title .= $key . ",";
            $data .= "" . ",";
            array2csv($value, $title, $data);
        } else {
            $title .= $key . ",";
            $data .= '"' . $value . '",';
        }
    }
}

Étant donné que les différents niveaux de mon tableau ne se prêtaient pas bien au format CSV plat, j'ai créé une colonne vide avec la clé du sous-tableau pour servir d '"intro" descriptive au niveau de données suivant. Exemple de sortie:

agentid     fname           lname      empid    totals  sales   leads   dish    dishnet top200_plus top120  latino  base_packages
G-adriana   ADRIANA EUGENIA PALOMO PAIZ 886                0    19              0         0         0         0      0

Vous pourriez facilement supprimer cette colonne "intro" (descriptive), mais dans mon cas, j'avais des en-têtes de colonne répétitifs, c'est-à-dire inbound_leads, dans chaque sous-tableau, ce qui m'a donné une pause / titre précédant la section suivante. Retirer:

$title .= $key . ",";
$data .= "" . ",";

après is_array () pour compacter davantage le code et supprimer la colonne supplémentaire.

Puisque je voulais à la fois une ligne de titre et une ligne de données, je passe deux variables dans la fonction et à la fin de l'appel à la fonction, termine les deux avec PHP_EOL:

$title .= PHP_EOL;
$data .= PHP_EOL;

Oui, je sais que je laisse une virgule supplémentaire, mais par souci de brièveté, je ne l'ai pas traité ici.

Jesse Q
la source
Cela semble être une réponse spécifique à une question très générale et vous avez certes laissé des virgules supplémentaires (en raison du problème réel de l'utilisation de chaînes au lieu de tableaux), ainsi que de ne pas citer la ligne d'en-tête et d'avoir des appels supplémentaires inutiles. J'ai remodelé tout cela dans une réponse à une autre question .
LWC
1

Les tableaux de données sont convertis au format csv 'text / csv' par la fonction php intégrée fputcsv prend soin des virgules, des guillemets et etc.
Regardez
https://coderwall.com/p/zvzwwa/array-to-comma-separated -string-in-php
http://www.php.net/manual/en/function.fputcsv.php

Avraham Markov
la source
Un lien vers une solution est le bienvenu, mais veuillez vous assurer que votre réponse est utile sans elle: ajoutez du contexte autour du lien afin que vos collègues utilisateurs aient une idée de ce que c'est et pourquoi il est là, puis citez la partie la plus pertinente de la page que vous '' relier au cas où la page cible ne serait pas disponible. Les réponses qui ne sont guère plus qu'un lien peuvent être supprimées.
geisterfurz007
0

Cela a fonctionné pour moi.

 $f=fopen('php://memory','w');
 $header=array("asdf ","asdf","asd","Calasdflee","Start Time","End Time" );      
 fputcsv($f,$header);
 fputcsv($f,$header);
 fputcsv($f,$header); 
 fseek($f,0);
 header('content-type:text/csv'); 
 header('Content-Disposition: attachment; filename="' . $filename . '";');
 fpassthru($f);```
Amir Khan
la source