使用odbc_connect查询IBM i数据库时部分字段乱码求助
问题背景
本地使用PDO连接ODBC($odbcConnect = new PDO("odbc:$dsn", "$userid", "$password");)可正常获取所有字段,但生产环境为Linux,PDO无法工作,改用odbc_connect($odbcConnect = odbc_connect("Driver={IBM i Access ODBC Driver}; system=$mapics_server; uid=$mapics_username; pwd=$mapics_password", "Nothing", "Nothing");)后,CODE_FOURNISSEUR和NOM_FOURNISSEUR字段出现乱码(如b"õððùô÷"),其余字段数据正常。
关联查询语句示例:
SELECT * FROM ( SELECT as numero_commande, as code_article, as mpn, as code_cadence, as code_fournisseur, as nom_fournisseur, as date_besoin, ROW_NUMBER() OVER (ORDER BY desc) AS Rank FROM amflib6. as POI JOIN as V on = JOIN as O on = WHERE " . implode(" AND ", $parametres) . " ) X WHERE Rank BETWEEN " . $premier . " AND " . $deuxieme;
原执行代码存在逻辑问题(混合使用预处理与直接执行):
$rows = array(); $stmt = odbc_prepare($odbcConnect, $queryPrepare); if (odbc_execute($stmt, $dataParams)) { $result = odbc_exec($odbcConnect, $query); while($row = odbc_fetch_array($result)) { dump($row); $rows[] = $row; } } else { dump("AHHHHHHHHHHHHH"); return []; } odbc_close($odbcConnect);
解决方法
1. 调整ODBC连接字符串的CCSID参数
IBM i数据库使用CCSID标识字符集,在连接字符串中指定对应编码的CCSID(如UTF-8对应1208),强制驱动转换字符集:
$odbcConnect = odbc_connect( "Driver={IBM i Access ODBC Driver}; system=$mapics_server; uid=$mapics_username; pwd=$mapics_password; CCSID=1208", "Nothing", "Nothing" );
常见CCSID对应:
- 1208:UTF-8
- 37:EBCDIC(美国英语)
- 500:EBCDIC(国际通用)
需根据数据库实际使用的字符集选择对应CCSID。
2. 手动转换字段编码
若连接参数调整无效,可在获取数据时手动将EBCDIC编码转成UTF-8:
while($row = odbc_fetch_array($result)) { // 转换乱码字段 if(isset($row['CODE_FOURNISSEUR'])) { $row['CODE_FOURNISSEUR'] = iconv('IBM-1047', 'UTF-8', $row['CODE_FOURNISSEUR']); } if(isset($row['NOM_FOURNISSEUR'])) { $row['NOM_FOURNISSEUR'] = iconv('IBM-1047', 'UTF-8', $row['NOM_FOURNISSEUR']); } $rows[] = $row; }
注:IBM-1047是IBM i常用的EBCDIC编码,若数据库使用其他EBCDIC编码,替换为对应值(如IBM-500)。
3. 修正查询执行逻辑
原代码混合使用odbc_prepare/odbc_execute和odbc_exec属于错误用法,需统一逻辑:
正确使用预处理查询
$rows = array(); $stmt = odbc_prepare($odbcConnect, $queryPrepare); if (odbc_execute($stmt, $dataParams)) { while($row = odbc_fetch_array($stmt)) { // 按需添加转码逻辑 if(isset($row['CODE_FOURNISSEUR'])) { $row['CODE_FOURNISSEUR'] = iconv('IBM-1047', 'UTF-8', $row['CODE_FOURNISSEUR']); } if(isset($row['NOM_FOURNISSEUR'])) { $row['NOM_FOURNISSEUR'] = iconv('IBM-1047', 'UTF-8', $row['NOM_FOURNISSEUR']); } $rows[] = $row; } } else { dump("查询执行失败"); return []; } odbc_close($odbcConnect);
4. 检查Linux ODBC驱动配置
确认Linux上的IBM i Access ODBC驱动为最新版本,或在odbcinst.ini中配置默认CCSID:
[IBM i Access ODBC Driver] Description=IBM i Access ODBC Driver Driver=/opt/ibm/iaccess/lib/libcwbodbc.so Setup=/opt/ibm/iaccess/lib/libcwbodbcs.so Driver64=/opt/ibm/iaccess/lib64/libcwbodbc.so Setup64=/opt/ibm/iaccess/lib64/libcwbodbcs.so FileUsage=1 CCSID=1208
内容的提问来源于stack exchange,提问作者Jacques Pirault

