web-dev-qa-db-fra.com

Comment puis-je sortir un CSV UTF-8 dans PHP que Excel va lire correctement?

J'ai cette chose très simple qui ne fait que produire des données au format CSV, mais il faut que ce soit UTF-8. J'ouvre ce fichier dans TextEdit ou TextMate ou Dreamweaver et il affiche correctement les caractères UTF-8, mais si je l'ouvre dans Excel, il fait plutôt ce genre de bêtise. Voici ce que j'ai en tête de mon document:

header("content-type:application/csv;charset=UTF-8");
header("Content-Disposition:attachment;filename=\"CHS.csv\"");

Tout cela semble avoir l'effet désiré, sauf qu'Excel (Mac, 2008) ne veut pas l'importer correctement. Il n’ya pas d’option dans Excel pour «ouvrir en tant que UTF-8» ou quoi que ce soit, alors… je commence à être un peu agacé.

Je n'arrive pas à trouver de solution claire à ce problème, même si beaucoup de personnes ont le même problème. Ce que je vois le plus, c’est d’inclure la nomenclature, mais je ne sais pas exactement comment le faire. Comme vous pouvez le voir ci-dessus, je ne fais que echoing ces données, je n'écris aucun fichier. Je peux le faire si j'en ai besoin, mais je ne le suis pas parce que cela ne semble pas être nécessaire pour le moment. De l'aide?

Mise à jour: j'ai essayé d'exécuter l'écho de la nomenclature sous la forme echo pack("CCC", 0xef, 0xbb, 0xbf); que je venais d'extraire d'un site qui tentait de détecter la nomenclature. Mais Excel ajoute simplement ces trois caractères à la toute première cellule lors de son importation et continue de gâcher les caractères spéciaux.

167
Ben Saufley

Pour citer un ingénieur du support technique Microsoft ,

Excel pour Mac ne prend actuellement pas en charge le format UTF-8.

Update, 2017: cela s'applique à toutes les versions de Microsoft Excel pour Mac antérieures à Office 2016. Les versions plus récentes (d'Office 365) prennent désormais en charge UTF-8.

Pour pouvoir lire le contenu UTF-8 qu'Excel est capable de lire avec succès sous Windows et OS X, vous devez effectuer deux opérations:

  1. Assurez-vous de convertir votre texte UTF-8 en UTF-16LE.

    mb_convert_encoding($csv, 'UTF-16LE', 'UTF-8');
    
  2. Assurez-vous que vous ajoutez la marque d'ordre d'octets UTF-16LE

    chr(255) . chr(254)
    

Le prochain problème qui apparaît uniquement avec Excel sous OS X (mais pas Windows) concerne l'affichage d'un fichier CSV avec des valeurs séparées par des virgules. Excel ne restitue les lignes qu'avec une seule ligne et tout le texte, ainsi la première rangée.

Pour éviter cela, utilisez des tabulations en tant que valeur séparée.

J'ai utilisé cette fonction des commentaires PHP } _ (en utilisant les onglets "\ t" au lieu de virgules) et cela fonctionnait parfaitement sous OS X et Windows Excel.

Notez que pour résoudre un problème avec une colonne vide à la fin d'une ligne, je devais changer la ligne de code qui dit:

    $field_cnt = count($fields);

à

    $field_cnt = count($fields)-1;

Comme certains commentaires sur cette page le disent, d'autres applications de tableur, telles que OpenOffice Calc, les propres numéros d'Apple et le tableur de Google Doc, ne présentent aucun problème avec les fichiers UTF-8 avec des virgules.

Voir le tableau dans cette question _ pour savoir ce qui fonctionne et ne fonctionne pas pour les fichiers Unicode CSV dans Excel


En guise de remarque, je pourrais ajouter que si vous utilisez Compositeur , vous devriez envisager d'ajouter League\Csv à vos besoins. League\Csv a une API vraiment agréable pour la construction de fichiers CSV .

Pour utiliser League\Csv avec cette méthode de création de fichiers CSV, extrayez cet exemple _

119
Tim Groeneveld

J'ai le même problème (ou similaire).

Dans mon cas, si j'ajoute une nomenclature à la sortie, cela fonctionne:

header('Content-Encoding: UTF-8');
header('Content-type: text/csv; charset=UTF-8');
header('Content-Disposition: attachment; filename=Customers_Export.csv');
echo "\xEF\xBB\xBF"; // UTF-8 BOM

Je crois que c’est un bidon plutôt laid, mais cela a fonctionné pour moi, du moins pour Excel 2007 Windows. Pas sûr que ça marche sur Mac.

258
Daniel Magliola

Voici comment je l’ai fait (c’est au navigateur Invite de télécharger le fichier csv):

header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=file.csv');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
echo "\xEF\xBB\xBF"; // UTF-8 BOM
echo $csv_file_content;
exit();

La seule chose qui résolve le problème d'encodage UTF8 dans l'aperçu CSV lorsque vous appuyez sur la barre d'espace sur Mac .. mais pas dans Excel Mac 2008 ... ne sait pas pourquoi

30
Jazzer

Je viens de traiter le même problème et j'ai proposé deux solutions. 

  1. Utilisez le PHPExcel class comme suggéré par bpeterson76

    • En utilisant cette classe pour générer le fichier le plus compatible, j’ai pu générer un fichier à partir de données codées UTF-8 qui s’ouvraient parfaitement dans Excel 2008 Mac, Excel 2007 Windows et Google Docs. 
    • Le plus gros problème avec PHPExcel est qu’il est lent et qu’il utilise beaucoup de mémoire, ce qui n’est pas un problème pour les fichiers de taille raisonnable, mais si votre fichier Excel/CSV contient des centaines ou des milliers de lignes, cette bibliothèque devient inutilisable
    • Voici une méthode PHP qui prend certaines données TSV et génère un fichier Excel dans le navigateur. Notez qu’elle utilise Excel5 Writer, ce qui signifie que le fichier doit être compatible avec les anciennes versions d’Excel, mais je n’en ai plus. accès à tout, donc je ne peux pas les tester. 

      function Excel_export($tsv_data, $filename) {
          $export_data = preg_split("/\n/", $tsv_data);
          foreach($export_data as &$row) {
              $row = preg_split("/\t/", $row);
          }
      
          include("includes/PHPExcel.php");
          include('includes/PHPExcel/Writer/Excel5.php');
      
          $objPHPExcel = new PHPExcel();          
      
          $objPHPExcel->setActiveSheetIndex(0);
          $sheet = $objPHPExcel->getActiveSheet();
          $row = '1';
          $col = "A";
          foreach($export_data as $row_cells) {
              if(!is_array($row_cells)) { continue; }
                  foreach($row_cells as $cell) {
                      $sheet->setCellValue($col.$row, $cell);
                      $col++;
                  }
              $row += 1;
              $col = "A";
          }
      
          $objWriter = new PHPExcel_Writer_Excel5($objPHPExcel);
          header('Content-Type: application/vnd.ms-Excel');
          header('Content-Disposition: attachment;filename="'.$filename.'.xls"');
          header('Cache-Control: max-age=0');
          $objWriter->save('php://output');   
          exit;   
      }
      
  2. En raison des problèmes d'efficacité rencontrés avec PHPExcel, j'ai également dû trouver un moyen de générer un fichier CSV ou TSV compatible UTF-8 et Excel. 

    • Le mieux que je pouvais trouver était un fichier compatible avec Excel 2008 Mac et Excel 2007 PC, mais pas avec Google Docs, qui convient assez à mon application. 
    • J'ai trouvé la solution ici , en particulier, cette réponse , mais vous devriez également lire la réponse acceptée car elle explique le problème. 
    • Voici le code PHP que j'ai utilisé, notez que j'utilise des données tsv (des tabulations comme délimiteurs au lieu de virgules): 

      header ( 'HTTP/1.1 200 OK' );
      header ( 'Date: ' . date ( 'D M j G:i:s T Y' ) );
      header ( 'Last-Modified: ' . date ( 'D M j G:i:s T Y' ) );
      header ( 'Content-Type: application/vnd.ms-Excel') ;
      header ( 'Content-Disposition: attachment;filename=export.csv' );
      print chr(255) . chr(254) . mb_convert_encoding($tsv_data, 'UTF-16LE', 'UTF-8');
      exit;
      
22
Jasdeep Gosal

J'avais le même problème et c'était résolu comme ci-dessous:

    header('Content-Encoding: UTF-8');
    header('Content-Type: text/csv; charset=utf-8' );
    header(sprintf( 'Content-Disposition: attachment; filename=my-csv-%s.csv', date( 'dmY-His' ) ) );
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Pragma: public');

    $df = fopen( 'php://output', 'w' );

    //This line is important:
    fputs( $df, "\xEF\xBB\xBF" ); // UTF-8 BOM !!!!!

    foreach ( $rows as $row ) {
        fputcsv( $df, $row );
    }
    fclose($df);
    exit();
13
Reza Mamun

Excel ne prend pas en charge UTF-8. Vous devez encoder votre texte UTF-8 dans UCS-2LE.

mb_convert_encoding($output, 'UCS-2LE', 'UTF-8');
12
Leopold Gault

Pour faire suite à ceci:

Il semble que le problème concerne simplement Excel sur Mac. Ce n'est pas ainsi que je génère les fichiers, car même générer des fichiers CSV à partir d'Excel les casse. J'enregistre au format CSV, puis réimporte et tous les personnages sont mélangés.

Donc… il ne semble pas y avoir de réponse correcte à cela. Merci pour toutes les suggestions.

Je dirais que de tout ce que j'ai lu, la suggestion de @Daniel Magliola concernant la nomenclature serait probablement la meilleure solution pour un autre ordinateur. Mais cela ne résout toujours pas mon problème.

8
Ben Saufley

Cela fonctionne très bien dans Excel pour Windows et aussi pour Mac OS.

Résoudre les problèmes dans Excel qui n'affichent pas les caractères contenant des signes diacritiques, des lettres cyrilliques, des lettres grecques et des symboles monétaires.

function writeCSV($filename, $headings, $data) {   

    //Use tab as field separator
    $newTab  = "\t";
    $newLine  = "\n";

    $fputcsv  =  count($headings) ? '"'. implode('"'.$newTab.'"', $headings).'"'.$newLine : '';

    // Loop over the * to export
    if (! empty($data)) {
      foreach($data as $item) {
        $fputcsv .= '"'. implode('"'.$newTab.'"', $item).'"'.$newLine;
      }
    }

    //Convert CSV to UTF-16
    $encoded_csv = mb_convert_encoding($fputcsv, 'UTF-16LE', 'UTF-8');

    // Output CSV-specific headers
    header('Set-Cookie: fileDownload=true; path=/'); //This cookie is needed in order to trigger the success window.
    header("Pragma: public");
    header("Expires: 0");
    header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
    header("Cache-Control: private",false);
    header("Content-Type: application/octet-stream");
    header("Content-Disposition: attachment; filename=\"$filename.csv\";" );
    header("Content-Transfer-Encoding: binary");
    header('Content-Length: '. strlen($encoded_csv));
    echo chr(255) . chr(254) . $encoded_csv; //php array convert to csv/Excel

    exit;
}
6
Murali Krishna

Le fichier CSV doit inclure une marque d'ordre d'octet.

Ou comme suggéré et que la solution de contournement résonne simplement avec le corps HTTP

6
Cybot

Dans mon cas, le travail suivant est très agréable pour créer un fichier CSV avec des caractères UTF-8 affichés correctement dans Excel.

$out = fopen('php://output', 'w');
fprintf($out, chr(0xEF).chr(0xBB).chr(0xBF));
fputcsv($out, $some_csv_strings);

L'en-tête de nomenclature 0xEF 0xBB 0xBF permettra à Excel de connaître le codage correct.

5
Codemole

Depuis l'encodage UTF8 ne fonctionne pas bien avec Excel. Vous pouvez convertir les données en un autre type de codage à l'aide de iconv().

par exemple.

iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $value),
4
Abrar A. Shareef

Ajouter:

fprintf($file, chr(0xEF).chr(0xBB).chr(0xBF));

Ou:

fprintf($file, "\xEF\xBB\xBF");

Avant d'écrire un contenu dans un fichier CSV.

Exemple:

<?php
$file = fopen( "file.csv", "w");
fprintf( $file, "\xEF\xBB\xBF");
fputcsv( $file, ["english", 122, "বাংলা"]);
fclose($file);
4
Rejaul
**This is 100% works fine in Excel for both Windows7,8,10 and also All Mac OS.**
//Fix issues in Excel that are not displaying characters containing diacritics, cyrillic letters, Greek letter and currency symbols.

function generateCSVFile($filename, $headings, $data) {

    //Use tab as field separator
    $newTab  = "\t";
    $newLine  = "\n";

    $fputcsv  =  count($headings) ? '"'. implode('"'.$newTab.'"', $headings).'"'.$newLine : '';

    // Loop over the * to export
    if (! empty($data)) {
      foreach($data as $item) {
        $fputcsv .= '"'. implode('"'.$newTab.'"', $item).'"'.$newLine;
      }
    }

    //Convert CSV to UTF-16
    $encoded_csv = mb_convert_encoding($fputcsv, 'UTF-16LE', 'UTF-8');

    // Output CSV-specific headers
    header('Set-Cookie: fileDownload=true; path=/'); //This cookie is needed in order to trigger the success window.
    header("Pragma: public");
    header("Expires: 0");
    header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
    header("Cache-Control: private",false);
    header("Content-Type: application/octet-stream");
    header("Content-Disposition: attachment; filename=\"$filename.csv\";" );
    header("Content-Transfer-Encoding: binary");
    header('Content-Length: '. strlen($encoded_csv));
    echo chr(255) . chr(254) . $encoded_csv; //php array convert to csv/Excel
    exit;
}
2
Sagar72427

Pour moi, aucune des solutions ci-dessus n'a fonctionné. Voici ce que j'ai fait pour résoudre le problème: Modifiez la valeur à l'aide de cette fonction dans le code PHP: 

$value = utf8_encode($value);

Cette valeur de sortie correctement dans une feuille Excel. 

1
Barani r

Vous devez utiliser le codage "Windows-1252". 

header('Content-Encoding: Windows-1252');
header('Content-type: text/csv; charset=Windows-1252');
header("Content-Disposition: attachment; filename={$filename}");

Peut-être devez-vous convertir vos chaînes:

private function convertToWindowsCharset($string) {
  $encoding = mb_detect_encoding($string);

  return iconv($encoding, "Windows-1252", $string);
}
1
roNn23

Que diriez-vous de simplement sortir pour Excel lui-même? C’est une excellente classe qui vous permet de générer des fichiers XLS côté serveur. Je l'utilise fréquemment pour les clients qui ne peuvent pas "comprendre" les CSV et qui n'ont jusqu'à présent jamais eu de plainte. Cela permet également un formatage supplémentaire (ombrage, hauteur des lignes, calculs, etc.) que csv ne fera jamais. 

1
bpeterson76

vous pouvez convertir votre chaîne CSV avec iconv . par exemple:

$csvString = "Möckmühl;in Möckmühl ist die Hölle los\n";
file_put_contents('path/newTest.csv',iconv("UTF-8", "ISO-8859-1//TRANSLIT",$csvString) );
1
foued611

La conversion de texte déjà codé en utf-8 à l'aide de mb_convert_encoding n'est pas nécessaire. Ajoutez simplement trois caractères devant le contenu d'origine:

$newContent = chr(239) . chr(187) . chr(191) . $originalContent

Pour moi, cela a résolu le problème des caractères spéciaux dans les fichiers csv.

1
Rvanlaak

Je suis sur Mac. Dans mon cas, il me suffisait de spécifier le séparateur avec "sep=;\n" et de coder le fichier en UTF-16LE comme ceci:

$data = "sep=;\n" .mb_convert_encoding($data, 'UTF-16LE', 'UTF-8');
1
Sebastien Horin

#output un fichier CSV UTF-8 dans PHP qu'Excel lira correctement.

//Use tab as field separator   
$sep  = "\t";  
$eol  = "\n";    
$fputcsv  =  count($headings) ? '"'. implode('"'.$sep.'"', $headings).'"'.$eol : '';
0
Murali Krishna

J'utilise ceci et ça marche 

header('Content-Description: File Transfer');
header('Content-Type: text/csv; charset=UTF-16LE');
header('Content-Disposition: attachment; filename=file.csv');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
// output headers so that the file is downloaded rather than displayed
// create a file pointer connected to the output stream
$output = fopen('php://output', 'w');
fputs( $output, "\xEF\xBB\xBF" );
// output the column headings
fputcsv($output, array('Thông tin khách hàng đăng ký'));
// fetch the data
$setutf8 = "SET NAMES utf8";
$q = $conn->query($setutf8);
$setutf8c = "SET character_set_results = 'utf8', character_set_client =
'utf8', character_set_connection = 'utf8', character_set_database = 'utf8',
character_set_server = 'utf8'";
$qc = $conn->query($setutf8c);
$setutf9 = "SET CHARACTER SET utf8";
$q1 = $conn->query($setutf9);
$setutf7 = "SET COLLATION_CONNECTION = 'utf8_general_ci'";
$q2 = $conn->query($setutf7);
$sql = "SELECT id, name, email FROM myguests";
$rows = $conn->query($sql);
$arr1= array();
if ($rows->num_rows > 0) {
// output data of each row
while($row = $rows->fetch_assoc()) {
    $rcontent = " Name: " . $row["name"]. " - Email: " . $row["email"];  
    $arr1[]["title"] =  $rcontent;
}
} else {
     echo "0 results";
}
$conn->close();
// loop over the rows, outputting them
foreach($arr1 as $result1):
   fputcsv($output, $result1);
endforeach;
0
BoRnbeBaD

Solution EASY pour Mac Excel 2008: Je me suis souvent heurté à cette difficulté, mais voici ma solution facile: Ouvrez le fichier .csv dans Textwrangler, ce qui devrait ouvrir correctement vos caractères UTF-8. Dans la barre d’état inférieure, changez le format de fichier de "Unicode (UTF-8)" à "Western (ISO Latin 1)" et enregistrez le fichier . À présent, accédez à votre Mac Excel 2008 et sélectionnez Fichier> Importer> Sélectionner csv> Recherchez votre fichier> dans Origine du fichier, sélectionnez "Windows (ANSI)" et voilà les caractères UTF-8 s’affichent correctement. Au moins ça le fait pour moi ...

0
Poul

J'ai eu ce même problème quand j'avais une routine Excel VBA qui importait des données. Comme le format CSV est un format de texte brut, j’y travaillais en ouvrant les données par programme dans un éditeur de fichier simple comme Wordpad, puis en les ré-enregistrant sous forme de texte unicode ou en les copiant dans le presse-papiers et en les collant dans Excel. Si Excel n'analyse pas automatiquement le fichier CSV dans des cellules, vous pouvez facilement y remédier en utilisant la fonction intégrée "Texte en colonnes".

0
Alain

Je viens d'essayer ces en-têtes et j'ai demandé à Excel 2013 sur un ordinateur Windows 7 d'importer correctement le fichier CSV avec des caractères spéciaux. La marque de commande d’octets (BOM) était la clé finale qui l’a fait fonctionner.


 en-tête ('Content-Encoding: UTF-8'); 
 en-tête ('Content-type: text/csv; charset = UTF-8'); 
 en-tête ("Contenu-disposition: pièce jointe; nomfichier = nomfichier.csv"); 
 en-tête ("Pragma: public"); 
 en-tête ("Expires: 0"); 
 echo "\ xEF\xBB\xBF"; // Nomenclature UTF-8 

0
Brian

Sinon, vous pouvez:

header("Content-type: application/x-download");
header("Content-Transfer-Encoding: binary");
header("Content-disposition: attachment; filename=".$fileName."");
header("Cache-control: private");

echo utf8_decode($output);
0
user3519396

Le problème persiste-t-il quand vous enregistrez le fichier dans un fichier .txt et que vous l'ouvrez dans Excel avec une virgule comme séparateur?

Le problème n’est peut-être pas du tout l’encodage, c’est peut-être simplement que le fichier n’est pas un fichier CSV parfait selon les normes Excel.

0
Alain

Vous pouvez ajouter les 3 octets au fichier avant de l'exporter, cela fonctionne pour moi. Auparavant, ce système ne fonctionnait que sous Windows et HP -UX mais échouait sous Linux.

FileOutputStream fStream = new FileOutputStream( f );
final byte[] bom = new byte[] { (byte) 0xEF, (byte) 0xBB, (byte) 0xBF };
OutputStreamWriter writer = new OutputStreamWriter( fStream, "UTF8" );
fStream.write( bom );

Avoir une nomenclature UTF-8 (3 octets, hex EF BB BF) au début du fichier. Sinon, Excel interprétera les données en fonction du codage par défaut de votre environnement local (par exemple, cp1252) au lieu de utf-8. 

Générer un fichier CSV pour Excel, comment avoir une nouvelle ligne dans une valeur

0
Cherry Yap

This Post est assez vieux, mais après des heures d’essais, je veux partager ma solution… peut-être que cela aide quelqu'un qui traite avec Excel, Mac et CSV et trébuche sur cette menace. Je génère un csv de manière dynamique en tant que sortie d'une base de données avec les utilisateurs d'Excel à l'esprit. (UTF-8 avec nomenclature)

J’ai essayé beaucoup d’iconv, mais je n’ai pas pu utiliser des trémas allemands sous Mac Excel 2004. Une solution: PHPExcel. C'est génial mais pour mon projet un peu trop. Ce qui fonctionne pour moi, c’est de créer le fichier csv et de convertir ce fichier csv en xls avec ce script PHPsnippet: csv2xls . le résultat xls fonctionne avec les trémas allemands Excel (ä, ö, Ü, ...).

0
t Book