How can I output a UTF-8 CSV in PHP that Excel will read properly?

后端 未结 30 2475
半阙折子戏
半阙折子戏 2020-11-22 06:08

I\'ve got this very simple thing that just outputs some stuff in CSV format, but it\'s got to be UTF-8. I open this file in TextEdit or TextMate or Dreamweaver and it displa

相关标签:
30条回答
  • 2020-11-22 06:30

    To quote a Microsoft support engineer,

    Excel for Mac does not currently support UTF-8

    Update, 2017: This is true of all versions of Microsoft Excel for Mac before Office 2016. Newer versions (from Office 365) do now support UTF-8.

    In order to output UTF-8 content that Excel both on Windows and OS X will be able to successfully read, you will need to do two things:

    1. Make sure that you convert your UTF-8 CSV text to UTF-16LE

      mb_convert_encoding($csv, 'UTF-16LE', 'UTF-8');
      
    2. Make sure that you add the UTF-16LE byte order mark to the start of the file

      chr(255) . chr(254)
      

    The next problem that appears only with Excel on OS X (but not Windows) will be when viewing a CSV file with comma separated values, Excel will render rows only with one row and all of the text along with the commas in the first row.

    The way to avoid this is to use tabs as your separated value.

    I used this function from the PHP comments (using tabs "\t" instead of commas) and it worked perfectly on OS X and Windows Excel.

    Note that to fix an issue with an empty column as the end of a row, that I did have to change the line of code that says:

        $field_cnt = count($fields);
    

    to

        $field_cnt = count($fields)-1;
    

    As some of the other comments on this page say, other spreadsheet apps like OpenOffice Calc, Apple's own Numbers and Google Doc's Spreadsheet have no issues with UTF-8 files with commas.

    See the table in this question for what works and doesn't work for Unicode CSV files in Excel


    As a side note, I might add that if you are using Composer, you should have a look at adding League\Csv to your requires. League\Csv has a really nice API for building CSV files.

    To use League\Csv with this method of creating CSV files, check out this example

    0 讨论(0)
  • 2020-11-22 06:30
    //convert UTF-8 file without BOM to UTF-16LE for excel on mac
    $fileUtf8String = file_get_contents("file.ext");
    file_put_contents("file.ext", "\xFF\xFE" . mb_convert_encoding($fileUtf8String, "UTF-16LE", "UTF-8"));
    
    0 讨论(0)
  • 2020-11-22 06:31
    **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;
    }
    
    0 讨论(0)
  • 2020-11-22 06:32

    I use this and it works

    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 讨论(0)
  • 2020-11-22 06:33

    Since UTF8 encoding doesn't play well with Excel. You can convert the data to another encoding type using iconv().

    e.g.

    iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $value),
    
    0 讨论(0)
  • 2020-11-22 06:36

    I just dealt with the same problem, and came up with two solutions.

    1. Use the PHPExcel class as suggested by bpeterson76.

      • Using this class generates the most widely compatible file, I was able to generate a file from UTF-8 encoded data that opened fine in Excel 2008 Mac, Excel 2007 Windows, and Google Docs.
      • The biggest problem with using PHPExcel is that it's slow and uses a lot of memory, which isn't an issue for reasonably sized files, but if your Excel/CSV file has hundreds or thousands of rows, this library becomes unusable.
      • Here is a PHP method that will take some TSV data and output an Excel file to the browser, note that it uses the Excel5 Writer, which means the file should be compatible with older versions of Excel, but I no longer have access to any, so I cannot test them.

        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. Because of the efficiency issues with PHPExcel, I also had to figure out how to generate a UTF-8 & Excel compatible CSV or TSV file.

      • The best I could come up with was a file that was compatible with Excel 2008 Mac, and Excel 2007 PC, but not Google Docs, which is good enough for my application.
      • I found the solution here, specifically, this answer, but you should also read the accepted answer as it explains the problem.
      • Here is the PHP code I used, note that I am using tsv data (tabs as delimiters instead of commas):

        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;
        
    0 讨论(0)
提交回复
热议问题