it-swarm.dev

Como posso produzir um CSV UTF-8 em PHP que o Excel irá ler corretamente?

Eu tenho uma coisa muito simples que apenas mostra algumas coisas no formato CSV, mas tem que ser UTF-8. Eu abro este arquivo em TextEdit ou TextMate ou Dreamweaver e ele exibe caracteres UTF-8 corretamente, mas se eu abri-lo no Excel está fazendo esse tipo de coisa boba em vez disso. Aqui está o que eu tenho na cabeça do meu documento:

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

Isso tudo parece ter o efeito desejado, exceto que o Excel (Mac, 2008) não quer importá-lo corretamente. Não há opções no Excel para eu "abrir como UTF-8" ou qualquer coisa, então… estou ficando um pouco irritado.

Eu não consigo encontrar nenhuma solução clara para isso em qualquer lugar, apesar de muitas pessoas terem o mesmo problema. O que eu mais vejo é incluir o BOM, mas não consigo exatamente descobrir como fazer isso. Como você pode ver acima eu estou apenas echoing esses dados, eu não estou escrevendo nenhum arquivo. Eu posso fazer isso se eu precisar, eu não sou apenas porque não parece ser uma necessidade para isso neste momento. Qualquer ajuda?

Atualização: tentei ecoar a lista de materiais como echo pack("CCC", 0xef, 0xbb, 0xbf); que acabei de extrair de um site que estava tentando detectar a BOM. Mas o Excel apenas acrescenta esses três caracteres à primeira célula quando importa e ainda atrapalha os caracteres especiais.

167
Ben Saufley

Para citar um engenheiro de suporte da Microsoft ,

Excel para Mac não suporta atualmente UTF-8

Update, 2017: Isso é válido para todas as versões do Microsoft Excel para Mac antes Office 2016. Versões mais recentes (do Office 365) agora suportam UTF-8.

Para produzir conteúdo UTF-8 que o Excel no Windows e OS X consiga ler com sucesso, você precisará fazer duas coisas:

  1. Certifique-se de converter seu texto UTF-8 em UTF-16LE

    mb_convert_encoding($csv, 'UTF-16LE', 'UTF-8');
    
  2. Certifique-se de adicionar a marca de ordem de byte UTF-16LE

    chr(255) . chr(254)
    

O próximo problema que aparece apenas no Excel no OS X (mas not Windows) será ao exibir um arquivo CSV com valores separados por vírgula, o Excel renderizará as linhas somente com uma linha e todo o texto junto com a vírgulas na primeira linha.

A maneira de evitar isso é usar as guias como seu valor separado.

Eu usei esta função dos comentários PHP (usando as abas "\ t" ao invés de vírgulas) e funcionou perfeitamente no OS X e no Windows Excel.

Observe que para corrigir um problema com uma coluna vazia como o final de uma linha, tive que alterar a linha de código que diz:

    $field_cnt = count($fields);

para

    $field_cnt = count($fields)-1;

Como dizem alguns dos outros comentários desta página, outros aplicativos de planilhas, como o OpenOffice Calc, o Numbers da Apple e o Spreadsheet do Google Doc não apresentam problemas com arquivos UTF-8 com vírgulas.

Veja a tabela nesta pergunta para o que funciona e não funciona para arquivos CSV Unicode no Excel


Como uma nota lateral, devo acrescentar que se você estiver usando o Composer , você deve dar uma olhada em adicionar League\Csv ao seu requer. League\Csv tem uma API muito legal para construir arquivos CSV .

Para usar League\Csv com este método de criação de arquivos CSV, confira this example

119
Tim Groeneveld

Eu tenho o mesmo (ou similar) problema.

No meu caso, se eu adicionar uma lista de materiais à saída, ela funciona:

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

Eu acredito que este é um hack muito feio, mas funcionou para mim, pelo menos para o Excel 2007 Windows. Não tenho certeza se funcionará no Mac.

258
Daniel Magliola

Aqui está como eu fiz isso (isso é para solicitar o navegador para baixar o arquivo 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();

A única coisa que corrigiu o problema de codificação UTF8 na visualização CSV quando você clicou na barra de espaço no Mac .. mas não no Excel Mac 2008 ... não sei porque

30
Jazzer

Acabei de lidar com o mesmo problema e encontrei duas soluções. 

  1. Use o PHPExcel class como sugerido por bpeterson76

    • Usando essa classe gera o arquivo mais amplamente compatível, eu era capaz de gerar um arquivo de dados codificados em UTF-8 que abriu bem no Excel 2008 Mac, Excel 2007 Windows e Google Docs. 
    • O maior problema com o uso do PHPExcel é que ele é lento e usa muita memória, o que não é um problema para arquivos razoavelmente dimensionados, mas se seu arquivo Excel/CSV tiver centenas ou milhares de linhas, essa biblioteca ficará inutilizável
    • Aqui está um método PHP que irá pegar alguns dados TSV e enviar um arquivo Excel para o navegador, note que ele usa o Excel5 Writer, o que significa que o arquivo deve ser compatível com versões mais antigas do Excel, mas não tenho mais acesso a qualquer um, por isso não posso testá-los. 

      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. Por causa dos problemas de eficiência com PHPExcel, eu também tive que descobrir como gerar um arquivo CSV ou TSV compatível com UTF-8 e Excel. 

    • O melhor que consegui criar foi um arquivo que fosse compatível com o Excel 2008 Mac e o Excel 2007 PC, mas não com o Google Docs, o que é bom o suficiente para meu aplicativo. 
    • Eu encontrei a solução aqui , especificamente, esta resposta , mas você também deve ler o resposta aceita como explica o problema. 
    • Aqui está o código PHP que usei, observe que estou usando dados do tsv (guias como delimitadores em vez de vírgulas): 

      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

Eu estava tendo o mesmo problema e foi resolvido como abaixo:

    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

O Excel não suporta UTF-8. Você tem que codificar seu texto UTF-8 no UCS-2LE.

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

Para acompanhar isso:

Parece que o problema é simplesmente com o Excel no Mac. Não é como eu estou gerando os arquivos, porque até mesmo gerar CSVs do Excel está quebrando-os. Eu salvo como CSV e reimporte, e todos os personagens estão confusos.

Então… não parece haver uma resposta correta para isso. Obrigado por todas as sugestões.

Eu diria que, de tudo que li, a sugestão do Daniel Magliola sobre o BOM provavelmente seria a melhor resposta para algum outro computador. Mas ainda não resolve o meu problema.

8
Ben Saufley

Isso funciona bem no Excel para Windows e Mac OS.

Corrigir problemas no Excel que não exibem caracteres contendo diacríticos, letras cirílicas, letras em grego e símbolos monetários.

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

O arquivo CSV inclui uma marca de ordem de byte.

Ou como sugerido e solução apenas ecoar com o corpo HTTP

6
Cybot

No meu caso seguinte funciona muito bem para fazer arquivo CSV com caracteres UTF-8 exibidos corretamente no Excel.

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

O cabeçalho BOM 0xEF 0xBB 0xBF permitirá que o Excel saiba a codificação correta.

5
Codemole

Desde codificação UTF8 não joga bem com o Excel. Você pode converter os dados para outro tipo de codificação usando iconv().

por exemplo.

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

Adicionar:

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

Ou:

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

Antes de escrever qualquer conteúdo para o arquivo CSV.

Exemplo:

<?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

Conforme investiguei e descobri que o UTF-8 não está funcionando bem no MAC e no Windows, tentei com o Windows-1252, ele suporta bem em ambos, mas você deve selecionar o tipo de codificação no Ubuntu. meu código$valueToWrite = mb_convert_encoding($value, 'Windows-1252');

$response->headers->set('Content-Type', $mime . '; charset=Windows-1252');
    $response->headers->set('Pragma', 'public');
    $response->headers->set('Content-Endcoding','Windows-1252');
    $response->headers->set('Cache-Control', 'maxage=1');
    $response->headers->set('Content-Disposition', $dispositionHeader);
    echo "\xEF\xBB\xBF"; // UTF-8 BOM
2
Ho Ha

Para mim, nenhuma das soluções acima funcionou. Abaixo está o que eu fiz para resolver o problema: Modifique o valor usando esta função no código PHP: 

$value = utf8_encode($value);

Essa saída é avaliada corretamente em uma planilha do Excel. 

1
Barani r

Você tem que usar a codificação "Windows-1252". 

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

Talvez você tenha que converter suas strings:

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

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

Que tal apenas produzir para o próprio Excel? Esta é uma excelente classe que permite gerar arquivos XLS do lado do servidor. Eu uso freqüentemente para clientes que não conseguem "descobrir" o csv e até agora nunca tiveram uma reclamação. Ele também permite alguma formatação extra (sombreamento, altura de linha, cálculos, etc.) que o csv nunca fará. 

1
bpeterson76

você pode converter sua String CSV com iconv . por exemplo:

$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

A conversão de texto codificado já utf-8 usando mb_convert_encoding não é necessária. Basta adicionar três caracteres à frente do conteúdo original:

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

Para mim, isso resolveu o problema de caracteres especiais em arquivos csv.

1
Rvanlaak

Eu estou no Mac, no meu caso eu só tinha que especificar o separador com "sep=;\n" e codificar o arquivo em UTF-16LE assim:

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

#output um CSV UTF-8 em PHP que o Excel irá ler corretamente.

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

Eu uso isso e funciona 

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

EASY solução para o Mac Excel 2008: Eu lutei com isso soo muitas vezes, mas aqui foi minha solução fácil: Abra o arquivo .csv no Textwrangler que deve abrir seus caracteres UTF-8 corretamente. Agora na barra de status inferior mude o formato de arquivo de "Unicode (UTF-8)" para "Ocidental (ISO Latin 1)" e salve o arquivo. Agora vá para o seu Mac Excel 2008 e selecione Arquivo> Importar > Selecione csv> Encontre seu arquivo> em Origem do Arquivo selecione "Windows (ANSI)" e voila os caracteres UTF-8 estão sendo exibidos corretamente. Pelo menos para mim ...

0
Poul

Eu tive esse mesmo problema quando eu tinha uma rotina VBA do Excel que importava dados. Como o CSV é um formato de texto simples, estava trabalhando em torno disso programaticamente abrindo os dados em um editor de arquivos simples como o WordPad e salvando-o novamente como texto unicode ou copiando-o para a área de transferência e colando-o no Excel. Se o Excel não analisar automaticamente o CSV nas células, isso é facilmente solucionado usando o recurso "Texto para Colunas" incorporado.

0
Alain

Eu apenas tentei esses cabeçalhos e obtive o Excel 2013 em um PC com Windows 7 para importar o arquivo CSV com caracteres especiais corretamente. A Byte Order Mark (BOM) foi a chave final que fez com que funcionasse.

 
 cabeçalho ('Content-Encoding: UTF-8'); 
 cabeçalho ('Tipo de conteúdo: texto/csv; charset = UTF-8'); 
 header ("Content-disposition: anexo; filename = filename.csv"); 
 cabeçalho ("Pragma: public"); 
 cabeçalho ("Expires: 0"); 
 echo "\ xEF\xBB\xBF"; // BOM UTF-8 
 
0
Brian

Caso contrário, você pode:

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

O problema ainda ocorre quando você o salva como um arquivo .txt e os abre no Excel com vírgula como um delimitador?

O problema pode não ser a codificação, pode ser que o arquivo não seja um CSV perfeito de acordo com os padrões do Excel.

0
Alain

Você pode anexar os 3 bytes ao arquivo antes de exportar, funciona para mim. Antes de fazer esse sistema, trabalhe apenas no Windows e no HP -UX, mas falhou no 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 );

Tenha uma BOM UTF-8 (3 bytes, hex EF BB BF) no início do arquivo. Caso contrário, o Excel interpretará os dados de acordo com a codificação padrão do seu código do idioma (por exemplo, cp1252) em vez de utf-8 

Gerando arquivo CSV para o Excel, como ter uma nova linha dentro de um valor

0
Cherry Yap

Este post é bem antigo, mas depois de horas de tentativas eu quero compartilhar minha solução ... talvez ajude alguém a lidar com Excel, Mac e CSV e tropeçar nessa ameaça. Estou gerando um csv dinamicamente como saída de um banco de dados com usuários do Excel em mente. (UTF-8 com BOM)

Eu tentei muitos iconv´s mas não consegui fazer umlalauts alemão trabalhando no Mac Excel 2004. Uma solução: PHPExcel. É ótimo, mas para o meu projeto um pouco demais. O que funciona para mim é criar o arquivo csv e converter este arquivo csv para xls com este PHPsnippet: csv2xls . o resultado xls funciona com o Excel alemão umlauts (ä, ö, Ü, ...).

0
t Book