PDO_ODBC 的字符编码问题
Posted
技术标签:
【中文标题】PDO_ODBC 的字符编码问题【英文标题】:Character encoding issue with PDO_ODBC 【发布时间】:2011-03-28 21:14:07 【问题描述】:当使用 PDO_ODBC 和以下代码从 php 访问 Microsoft SQL 数据库时,我遇到了编码问题。从数据库输出的文本是乱码。
$dsn = "odbc:DRIVER=SQL Server;SERVER=$hostname;DATABASE=$database;charset=UTF-8";
$pdo = new PDO($dsn,$username,$password);
$sql = "SELECT text FROM atable";
$result = $PDO->query($sql);
while($data = $result->fetchObject())
$values[] = $data->text;
dpm($values);
(来源:bayimg.com)
这是通过 Drupal 模块完成的。 Drupal 中的所有内容都可以使用 UTF-8。最干净的解决方案是能够以 UTF-8 从数据库中检索数据,或者在输出之前将其转换为 UTF-8。
我试过这些都没有成功
$dsn = "odbc:DRIVER=SQL Server;SERVER=$hostname;DATABASE=$database;client_charset=utf-8"
$dsn = "odbc:DRIVER=SQL Server;SERVER=$hostname;DATABASE=$database;charset=utf-8"
$pdo->exec('SET NAMES utf8')
在new PDO(...)
之后
$pdo->exec('SET CHARACTER SET utf8');
在new PDO(...)
之后
PS:代码目前是在 Windows 上开发的,但它也必须在 GNU/Linux 上运行。
【问题讨论】:
【参考方案1】:在 Linux 上运行并使用 FreeTDS 驱动程序时,可以使用 freetds.conf
文件中的 client charset
设置来配置客户端的字符集。为了在使用 PDO ODBC 和 unixODBC 时使用 freetds.conf
文件,需要使用 ODBC-combined configuration 配置 ODBC 数据源。使用ODBC-only configuration 配置ODBC 数据源时,不使用文件freetds.conf
。有了这个,我就能够从 MS SQL Server 数据库中检索和插入 UTF-8 数据。
作为一名 Linux/Unix 人员,我无法理解/找到如何配置在 Windows 上使用 PDO ODBC 时使用的字符集的方法。我的模糊理解是,在系统级别配置时,可以将 ODBC 数据源配置为使用 de SQL Server 数据库的字符集或转换为客户端计算机字符集。
【讨论】:
如果我使用 ODBC-only 配置并连接 PHP PDO odbc,我无法获取 UTF-8 数据。【参考方案2】:将字符编码设置为 UTF-8 时,您还需要将查询编码为 UTF-8 并对结果进行解码。该字符集告诉驱动程序您本机使用 UTF8。因此,您需要将 UTF8 转换回 PHP 可以理解的格式(ASCII 或 mbstring)。
$dsn = "odbc:DRIVER=SQL Server;SERVER=$hostname;DATABASE=$database;charset=UTF-8";
$pdo = new PDO($dsn,$username,$password);
$sql = utf8_encode("SELECT text FROM atable");
$result = $PDO->query($sql);
while($data = $result->fetchObject())
$values[] = utf8_decode($data->text);
// possibly also: $values[] = utf8_decode($data[utf8_encode('text')]);
dpm($values);
【讨论】:
好吧,如前所述,这是通过 Drupal 模块完成的。 Drupal 期望所有字符串都是 UTF-8 编码的,它还输出其编码设置为 UTF-8 的页面。一旦将 ODBC 数据源配置为使用 UTF-8(请参阅我的答案),PDO 就会返回使用 dpm() 函数正确输出的 UTF-8 编码数据。对来自 PDO 的数据调用 utf8_decode() 会产生乱码输出,因为字符串将显示在 UTF-8 编码的页面中。【参考方案3】:您可以在连接字符串中使用 ClientCharset 属性(不带空格)设置所需的字符编码。 就我而言,它是 UTF-8。
$connection_string = "DRIVER=FreeTDS;SERVER=$serverip;Port=1433;DATABASE=$dbname;ClientCharset=UTF-8";
$conn = odbc_connect($connection_string,$username,$pwd);
详情请参考以下页面..
https://www.freetds.org/userguide/dsnless.html
【讨论】:
【参考方案4】:您可以使用此代码来解决您的问题:
$result = odbc_exec($this->con, $sql);
$data = fetch2Array($result);
private function fetch2Array($result)
$rows = array();
while($myRow = odbc_fetch_array( $result ))
$rows[] = $this->arrayToUTF($myRow);
return $rows;
private function arrayToUTF($arr)
foreach ($arr as $key => $value)
$arr[$key] = utf8_encode($value);
return $arr;
【讨论】:
关于 PDO 解决方案的问题请求,此答案未使用 PDO。此外,建议的解决方案与 Veggivore 几年前的解决方案是多余的(即使用 utf8_encode() 转换值)。【参考方案5】:您可以使用此代码来解决您的问题:
第一 发布数据转换
'$word = iconv("UTF-8","Windows-1254",$_POST['search']);'
还有 读取数据转换
while($data = $result->fetchObject())
$values[] = iconv("Windows-1254", "UTF-8",$data->text));
SQL 字符串
$sql = "SELECT * FROM yourtables WHERE text LIKE '%$word%'";
or
$sql = "SELECT * FROM yourtables";
【讨论】:
以上是关于PDO_ODBC 的字符编码问题的主要内容,如果未能解决你的问题,请参考以下文章