php - 从一个数据库读取数据并使用 PHP 插入另一个数据库时出现编码错误

标签 php postgresql utf-8 character-encoding pervasive

使用 PHP,我试图从 Pervasive DB v9.5 读取数据并将其插入 Windows 2008 上的 PostgreSQL 9.3(编码:UTF-8)。我没有选择或编码 PervasiveDB(我只是从中读取数据).使用 ODBC,我从 Pervasive 读取数据并将其毫无问题地写入控制台。但是,当我尝试将它插入到 Postgre 中时,我遇到了

Warning: pg_execute(): Query failed: ERROR:  invalid byte sequence for encoding "UTF8": 0x94 in file.php on line ..

所以,我看到 Postgres 不喜欢我给的字符串。

然后我用

var_dump(iconv_get_encoding('all'));

看到我的编码是 ISO-8859-1

并用

修改字符串
iconv ( 'ISO-8859-1' , 'UTF-8' , $a)

现在,错误消失了。但是,到达 Postgres 的字符串不正确。

我使用的代码如下。我的测试字符串是 aöaçaşaıağaüaÖaÇaŞaİaĞaÜ

$a是来自Pervasive的字符串

echo $a; 

给 aöaçaşaıağaüaÖaÇaŞaİaĞaÜ

echo iconv ( 'ISO-8859-1' , 'UTF-8' , $a)

给出a┬öa┬ça┬şa┬ıa┬ğa┬üa┬Öa┬Ça┬Şa┬İa┬Ğa┬Ü

<?php
//var_dump(iconv_get_encoding('all'));

$conn = pg_connect("host=localhost port=5432 dbname=xxx user=xxx password=".$argv[1]);

$result = pg_prepare($conn, "my_query", 'SELECT * FROM func_my_deneme($1)');

$connect_string = "DRIVER={Pervasive ODBC Client Interface}; SERVERNAME=localhost; SERVERDSN=xxx;";
$pervasiveconn = odbc_connect($connect_string, 'xxx', 'xxx');

$pervasive_result = odbc_exec($pervasiveconn ,"SELECT something");

while(odbc_fetch_row($pervasive_result)){
  $a=odbc_result($pervasive_result,1);

  echo $a;

  $result = pg_execute($conn, "my_query", array(iconv ( 'ISO-8859-1' , 'UTF-8' , $a)));
}
?>

最佳答案

您似乎只关注这里的两个编码交换之一。

你有:

(pervasive's native encoding) -> (PHP string)

(PHP string) -> (PostgreSQL)

其中,您只显式处理了第二个。您假设 Pervasive 的 ODBC 驱动程序返回的数据是 PHP 的默认编码,在您的系统上是 iso-8859-1。

您的测试表明假设可能是正确的,但简单地回显字符串并不是判断的好方法,因为这引入了另一个编码步骤:

(PHP string) -> (whatever decodes it for viewing)

可以是网络浏览器、终端或其他任何东西。如果查看者期望某些编码恰好与 Pervasive 使用的相同,它将正确解码输出。

尝试:

echo $a;
echo "aöaçaşaıağaüaÖaÇaŞaİaĞaÜ";

并确保查看器为两者显示相同的值。确保在编辑源文件时将编码设置为 iso-8859-1,而不是其他编码,这样您粘贴的字符串的字面量字节是正确的。

此时,如果您的编辑器设置正确,您应该会得到一个错误,因为并非所有这些字符在 iso-8859-1 中都是合法的。第一个无效的是 ş

很明显,来自 Pervasive 的不可能是 iso-8859-1。要真正打印 latin-1 字符串,您可以回显转义字节。例如,这个字符串:

aöaçaaaüaÖaÇaaaaÜ

其中所有字符都是合法的 iso-8859-1,以 iso-8859-1 编码打印:

echo "a\xf6a\xe7aaa\xfca\xd6a\xc7aaaa\xdc"

在这里,使用十六进制转义来指定非7位字符,以明确确保字节序列的编码是你所想的,而不会对文本编辑器等造成任何混淆。

注意当您查看它时打印不正确,因为读取输入的任何内容都不会将其解码为 iso-8859-1。


您应该做的是查看从 Pervasive 获得的字符串的字节,看看它到底是什么。然后确定其编码并将其解码为 utf-8,然后您可以通过 client_encoding = utf-8 连接将其发送到 PostgreSQL。 @deceze 为此推荐了 bin2hex(我不会说 PHP,所以不知道该推荐什么)。所以显示输出:

echo bin2hex($a) . "\n";

或者 - 甚至更好 - 确保您从配置/文档中确定来自 Pervasive 的数据的编码是什么,而不是猜测。或者只是强制它。

快速查看 Pervasive 文档表明 ODBC 驱动程序有一个 encoding 参数,它采用所需编码的代码页 ID。所以尝试:

$connect_string = "DRIVER={Pervasive ODBC Client Interface}; SERVERNAME=localhost; SERVERDSN=xxx; encoding=65001";

(至少,Microsoft 将 65001 定义为 utf-8 代码页 this doc)。

关于php - 从一个数据库读取数据并使用 PHP 插入另一个数据库时出现编码错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24547389/

相关文章:

PHP PDO : How long are prepared mysql queries cached?

sql - 确保至少一个外键不为空

linux - Ubuntu Linux 中内存压缩期间的 Postgres 延迟问题

javascript - Node.JS JSON.parse UTF-8 问题

php - 从另一个文件调用php函数

php - concrete5中主题的目录结构

php - 保存 RichText(所见即所得输出)的最佳方式是什么?

javascript - Sequelize 如何连接 2 个表 1 :N

php - UTF-8贯穿始终

php - 以下正确的字符编码是什么