首页 > 解决方案 > 将数据保存为 CSV 并编码为 utf-8

问题描述

我有一个编码为utf8mb4. 我连接到这个数据库并设置了 utf8 字符集:

$dbHandler = new PDO("mysql:host=$dbHost;dbname=$dbName;charset=utf8mb4", $dbUsername, $dbPassword);

所有数据都是在 DB 中编码的属性。我想获取数据并将其保存为 CSV:

$fp = fopen('data.csv', 'w+');
foreach ($result as $row) {
...
    fputcsv($fp, $csvData, ';');
}

但是随后所有的编码都被破坏了: groÃ<9f>eZubehör.

我尝试添加 BOM(没有帮助)和转换array_map("utf8_encode", $csvData);(某些字符显示正确:große, Zubehör,但有些不是:Kabelverl?ng, F?r)。任何想法?

编辑:

Hexdump 输出文件开头:

00000000: efbb bf70 726f 6475 6374 3b61 7274 6963  ...product;artic
00000010: 6c65 3b73 6b75 3b64 6174 653b 6e61 6d65  le;sku;date;name
00000020: 0a30 3030 3239 3039 3530 3030 3b3b 3b3b  .00028151000;;;;
00000030: 2242 7265 616b 6f75 742d 626f 7820 4b70  "Breakout-box Kp
00000040: 6c2e 223b 223c 7374 726f 6e67 3e42 7265  l.";"<strong>Bre
00000050: 616b 6f75 742d 626f 7820 4b70 6c2e 3c2f  akout-box Kpl.</ 

带有 1 条记录的文件的 Hexdump 输出,我们可以在其中看到问题(F..r 而不是 Für)。顺便说一句 - 原始字符串由 ucwords 和 strtolower 修改:

00000000: 3030 3032 3930 3936 3030 333b 3b3b 3b22  00028151000;;;;"
00000010: 4e65 747a 7465 696c 2032 3230 762f 3132  Netzteil 220v/12
00000020: 7620 46e3 9c72 2041 766c 223b 223c 7374  v F..r Avl";"<st
00000030: 726f 6e67 3e4e 6574 7a74 6569 6c20 3232  rong>Netzteil 22
00000040: 3076 2f31 3276 2046 e39c 7220 4176 6c3c  0v/12v F..r Avl<
00000050: 2f73 7472 6f6e 673e 3c62 723e 3c62 723e  /strong><br><br>
00000060: 4f45 4d20 4e75 6d6d 6572 3a20 3030 3032  OEM Nummer: 0002
00000070: 3930 3936 3030 3322 3b31 3038 2e34 363b  9096003";108.46;
00000080: 3030 3032 3930 3936 3030 332d 6e65 747a  00028151000-netz
00000090: 7465 696c 2d32 3230 762d 3132 762d 6675  teil-220v-12v-fu
000000a0: 722d 6176 6c3b 4875 7371 7661 726e 613b  r-avl;Husqvarna;
000000b0: 4452 4f50 444f 574e 3b59 3b4e 3b68 7474  DROPDOWN;Y;N;htt
000000c0: 7073 3a2f 2f73 7061 7265 7061 7274 7366  ps://sparepartsf
000000d0: 696e 6465 722e 6b74 6d2e 636f 6d2f 5350  inder.fha.com/SP
000000e0: 462f 496d 6167 6573 2f6d 6170 732f 3130  F/Images/maps/10
000000f0: 3030 3032 3932 302e 6769 663b 313b 4154  0002920.gif;1;AT
00000100: 3b57 6964 6765 743b 224b 544d 204f 7269  ;Ponret;"KTM Ori
00000110: 6769 6e61 6c20 4572 7361 747a 7465 696c  ginal Ersatzteil
00000120: 6522 3b22 4875 7371 7661 726e 6120 4e65  e";"Husqvarna Ne
00000130: 747a 7465 696c 2032 3230 762f 3132 7620  tzteil 220v/12v 
00000140: 46e3 9c72 2041 766c 202d 204f 454d 204e  F..r Avl - OEM N
00000150: 756d 6d65 723a 2030 3030 3239 3039 3630  ummer: 000290960
00000160: 3033 223b 3b22 4b61 7566 656e 2053 6965  03";;"Kaufen Sie
00000170: 2048 7573 7176 6172 6e61 204e 6574 7a74   Husqvarna Netzt
00000180: 6569 6c20 3232 3076 2f31 3276 2046 e39c  eil 220v/12v F..
00000190: 7220 4176 6c20 6d69 7420 4f45 4d2d 4e75  r Avl mit OEM-Nu
000001a0: 6d6d 6572 2030 3030 3239 3039 3630 3033  mmer 00028151000
000001b0: 2062 6569 2065 696e 656d 2048 7573 7176   bei einem Husqv
000001c0: 6172 6e61 2d56 6572 7472 6167 7368 c3a4  arna-Vertragsh..
000001d0: 6e64 6c65 722e 2057 6972 2068 6162 656e  ndler. Wir haben
000001e0: 2065 696e 6520 6772 6fc3 9f65 2041 7573   eine gro..e Aus
000001f0: 7761 686c 2061 6e20 4875 7371 7661 726e  wahl an Husqvarn
00000200: 612d 4572 7361 747a 7465 696c 656e 2c20  a-Ersatzteilen, 
00000210: 4163 6365 7373 6f72 6965 732c 2043 6c6f  Accessories, Clo
00000220: 7468 696e 672c 204d 5820 4265 6b6c 6569  thing, MX Beklei
00000230: 6475 6e67 2075 6e64 205a 7562 6568 c3b6  dung und Zubeh..
00000240: 722e 220a                                r.".

file data.csv输出:

data.csv: Non-ISO extended-ASCII text, with very long lines

标签: phpencodingutf-8php-7

解决方案


问题是我正在使用strtolowerand ucfirst。我把它改成

$name = mb_convert_case($name, MB_CASE_LOWER, "UTF-8");
$name = mb_convert_case($name, MB_CASE_TITLE, "UTF-8");

它有效。


推荐阅读