Excel 从 PHP 导出的字符编码

Character encoding on Excel export from PHP

更新:我更改了代码以插入 BOM,但没有得到肯定的结果。这是更新后的代码:

$output = fopen($file, 'w');

        $utf8_output_with_bom = chr(239) . chr(187) . chr(191) . $output;

        fputcsv($output, array('NOMBRE','APELLIDO','TELEFONO', 'RESPUESTA', 'DIA', 'HORA'), "\t");


        if ($key1!="No definida"){            

            // fetch the data
            $rows1 = mysqli_query($con, "SELECT cm_name, cm_surname, cr_phone, cr_message, DATE_FORMAT(cr_time,'%d/%m/%Y'), DATE_FORMAT(cr_time,'%H:%i') FROM ws_campreplies JOIN ws_campmsg WHERE cr_phone=cm_phone AND cr_fk_us_id='$id' AND cr_message='$key1' AND cm_fk_ca_id='$ca_id'");
            // loop over the rows, outputting them
            while ($row1 = mysqli_fetch_assoc($rows1)) {     
                fputcsv($output, $row1, "\t");        
            }
        }

我有一个 utf8_general_ci 数据库,在两个涉及的表(所有 utf8_general_ci)上有这个记录示例:

Table ws_campmsg:

Table ws_campreplies:

我唯一需要做的就是在 Excel 上导出它,这几乎完成了。此 PHP 文件创建 SQL 并导出正确的 XLS 文件:

$con = mysqli_connect(DB_SERVER,DB_USER,DB_PASS,DB_NAME);    
mysqli_set_charset($con, 'utf8');

[....]
        $ca_id = $_POST['ca_id'];            
        $key1 = $_POST['key1'];

        $file='../uploads/TemporalCsv_'.time().'.xls';

        header("Content-Type: application/xls");    
        header("Content-Disposition: attachment; filename=$file");  
        header("Pragma: no-cache"); 
        header("Expires: 0");


        $output = fopen($file, 'w');        


        fputcsv($output, array('NOMBRE','APELLIDO','TELEFONO', 'RESPUESTA', 'DIA', 'HORA'), "\t");


        if ($key1!="No definida"){            

            // fetch the data
            $rows1 = mysqli_query($con, "SELECT cm_name, cm_surname, cr_phone, cr_message, DATE_FORMAT(cr_time,'%d/%m/%Y'), DATE_FORMAT(cr_time,'%H:%i') FROM ws_campreplies JOIN ws_campmsg WHERE cr_phone=cm_phone AND cr_fk_us_id='$id' AND cr_message='$key1' AND cm_fk_ca_id='$ca_id'");
            // loop over the rows, outputting them
            while ($row1 = mysqli_fetch_assoc($rows1)) {                
                fputcsv($output, $row1, "\t");        
            }
        }

        fclose($output);
        echo $file;

如果我通过ca_id="438",和key1="CLAVE7",导出的文件是这个吗:


如您所见,现在唯一的问题是它没有正确显示 á 或 Á 等重音。由于我已经搜索了很多关于解决这个问题的方法,所以我做了一些尝试但没有得到肯定的结果,比如尝试在浏览器上直接导出文本格式(导出相同的编码错误):

$file='../uploads/TemporalCsv_'.time().'.txt';
header("Content-Type: text/tab-separated-values");

也尝试更改 headers(导出相同的编码错误)

header("Content-Type:   application/vnd.ms-excel; charset=utf-8");
header("Content-type:   application/x-msexcel; charset=utf-8");
header("Content-Disposition: attachment; filename=ventas.xls");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false);

在最近的尝试中,我发现用 iconv() 进行转换可能会有效,但是通过此修改会出现错误,因为 html_entity_decode() 接受字符串,而不是数组:

if ($key1!="No definida"){            

            // fetch the data
            $rows1 = mysqli_query($con, "SELECT cm_name, cm_surname, cr_phone, cr_message, DATE_FORMAT(cr_time,'%d/%m/%Y'), DATE_FORMAT(cr_time,'%H:%i') FROM ws_campreplies JOIN ws_campmsg WHERE cr_phone=cm_phone AND cr_fk_us_id='$id' AND cr_message='$key1' AND cm_fk_ca_id='$ca_id'");
            // loop over the rows, outputting them
            while ($row1 = mysqli_fetch_assoc($rows1)) {     
                iconv("UTF-8","WINDOWS-1255",html_entity_decode( $row1 ,ENT_COMPAT,'utf-8'));
                fputcsv($output, $row1, "\t");        
            }
        }

我希望我清楚地解释了自己。使用 PHPExcel 是我最后的机会,如果有任何可能在不使用 PHPExcel 的情况下更正此问题,我会更喜欢它。非常感谢。

您必须在输出的开头添加一个 BOM

$utf8_output_with_bom = chr(239) . chr(187) . chr(191) . $utf8_output;

UTF8 不需要 BOM。

示例:

$output = fopen($file, 'w');
fwrite($output, chr(239) . chr(187) . chr(191)); // Write the BOM to the beginning of the file
fputcsv($output, <...>);
fclose($output);

写入 CSV 的代码:

$output = fopen($file, 'w');

fwrite($output, chr(239) . chr(187) . chr(191));

fputcsv($output, array('NOMBRE', 'APELLIDO', 'TELEFONO', 'RESPUESTA', 'DIA', 'HORA'), "\t");

if ($key1 != "No definida") {

    // fetch the data
    $rows1 = mysqli_query($con, "SELECT cm_name, cm_surname, cr_phone, cr_message, DATE_FORMAT(cr_time,'%d/%m/%Y'), DATE_FORMAT(cr_time,'%H:%i') FROM ws_campreplies JOIN ws_campmsg WHERE cr_phone=cm_phone AND cr_fk_us_id='$id' AND cr_message='$key1' AND cm_fk_ca_id='$ca_id'");
    // loop over the rows, outputting them
    while ($row1 = mysqli_fetch_assoc($rows1)) {
        fputcsv($output, $row1, "\t");
    }

}

fclose($output);