使用PHP FreeTDS扩展从MSSQL服务器获取UTF-8字符集的数据

19

使用FreeTDS扩展从MSSQL获取UTF-8编码的数据似乎无法实现。

连接中:

ini_set('mssql.charset', 'UTF-8');
$this->_resource = mssql_connect($config['servername'], $config['username'], $config['password']);

我没有使用任何其他扩展的能力。

我已经尝试创建~/.freetds.conf文件。

[global]
client charset = UTF-8

我已经尝试将参数传递给PHP:

php -d mssql.charset="UTF-8" index.php

数据仍然不是UTF-8编码。

php -i

mssql

MSSQL Support => enabled
Active Persistent Links => 0
Active Links => 0
Library version => FreeTDS

Directive => Local Value => Master Value
mssql.allow_persistent => On => On
mssql.batchsize => 0 => 0
mssql.charset => no value => no value
mssql.compatability_mode => Off => Off
mssql.connect_timeout => 5 => 5
mssql.datetimeconvert => On => On
mssql.max_links => Unlimited => Unlimited
mssql.max_persistent => Unlimited => Unlimited

有什么想法?

8个回答

31

我曾有类似的问题,尝试了网上所有的设置 - 无效。

在我的情况下,问题出在 FreeTDS 的配置上。在 Linux 上,文件路径是 /etc/freetds/freetds.conf。

我不得不把版本更改为 7.0 (也许其他数字也可以,我只是尝试了 7.0)

[global]
    # TDS protocol version
    tds version = 7.0

在此之后,驱动程序似乎接受了字符集的更改。

ini_set('mssql.charset', 'UTF-8');

顺便说一下:改变立即生效,之后不需要重新启动任何东西


3
非常感谢 @user1903844,这些解决方案帮助了我处理Ubuntu+MS SQL+PHP的问题。 - Bakhtiyor
6
需要版本大于等于7.0才能设置配置选项client charset = UTF-8,这可能是为什么Mariu Grigaitis使用它的解决方案没有奏效的原因。请参考此要点中提供的freetds.conf示例:https://gist.github.com/johnkary/6643856 - John Kary
太好了,终于有一个可行的答案了!将未注释的行改为7.0的值,然后它就可以工作了。不需要ini_set部分。 - Hannes Schneidermayer
1
很好。工作正常!可能FreeTDS版本7.0支持客户端格式(UTF-8,ISO-8859-1或其他格式)与UCS2-LE(MSSQL字符集)之间的自动转换,因此对程序员来说这是透明的。 - Marco Marsala
这在我的Xenial Xerus、PHP 7、MSSQL 2008、FreeTDS v0.91上仍然无法工作。 - katalin_2003

16

有时候,MSSQL和UTF-8可能会让人感到很痛苦。我不得不手动转换它。

问题在于:MSSQL实际上并不知道也不支持UTF-8。

从数据库中的值转换为UTF-8:

mb_detect_encoding($value, mb_detect_order(), true) === 'UTF-8' ? $value : mb_convert_encoding($value, 'UTF-8');

将UTF-8转换为数据库值:

mb_convert_encoding($value, 'UCS-2LE', mb_detect_encoding($value, mb_detect_order(), true));

幸运的是,我使用了Doctrine,所以我只需要创建一个自定义的StringType实现。


1
MS SqlServer使用UCS2-LE编码,而不是CP1252。也不是ISO8859-1(CP1252的子集)。也不是UTF-16(在UCS2之后出现)或'Unicode'(在Windows上是WideChar/UTF-16)。 - Henrik
你救了我的命。我会回答我的问题(https://stackoverflow.com/questions/47977752/invalid-column-name-column-accents-in-ms-sql-server/)如何在CodeIgniter中使用它。 - José Manuel Blasco

16

如果你使用 freeTDS,你应该修改 /etc/freetds/freetds.conf 中以下行:

[global]
# TDS protocol version
tds version = 4.2

变为:

[global]
# TDS protocol version
tds version = 8.0
;tds version = 4.2

最后加上这一行:

# set charset
client charset = UTF-8

客户端字符集在全局 [scope] 中。

在您的查询中,您应该使用 N 字符。例如:

$query = "INSERT INTO dbo.SMSOutbox (StationID, Dest, Text) VALUES ";
   $query .= '(';
   $query .= "'" . $this->stationId . "', ";
   $query .= "'" . $this->destination . "', ";
   $query .= "N'" . $this->text . "'";
   $query .= ')';

1
这对我很有帮助,再加上@louis-huppenbauer的转换。 - barryvanveen

15

您也可以通过在连接到数据库之前在$connectionInfo中添加CharacterSet UTF-8来解决此问题。

$serverName = "MyServer";
$connectionInfo = array( "Database"=>"AdventureWorks", "CharacterSet" => "UTF-8");
$conn = sqlsrv_connect( $serverName, $connectionInfo);

工作正常,无需进行额外的编码。


1
我简直不敢相信这不是被采纳的答案,它完美地解决了问题,而且非常容易实现。如果我能给你超过+1的评价,我一定会的。 - Shocklo
太棒了,感谢您的回答,我找了很久的解决方案,这个完美地解决了我的问题。 - Justin Hanley
我完全同意,这应该是被接受的答案! - Stijnster
这个答案对于微软的SQLSRV库是正确的,但对于作者特别询问的FreeTDS库是不正确的。 - serverSentinel

2

看起来需要版本 7.0 或更高。iconv() 似乎也可以很好地工作,但是比较繁琐。

$query = $this->db->query($sql);
$result = $query->fetchAll(PDO::FETCH_OBJ);
foreach ($result as $row) {
    foreach (get_object_vars($row) as $key => $value) {
    $row->$key = (mb_detect_encoding($value, mb_detect_order(), true) === 'UTF-8') 
            ? $value : iconv('iso-8859-1', 'utf-8', $value);
    }
    $results[] = $row;
}

这个可以工作!我说这话是因为有时人们会忽略那些没有得到太多投票的答案。 - WhiteFloater

2

我曾遇到这个问题,通过在连接到MSSQL服务器之前在我的php脚本中添加这一行来解决:

ini_set('mssql.charset', 'UTF-8');

0

0

我使用了与上面相同的方式,但是采用了Windows 1250编码:

$query = $this->db->query($sql);
$result = $query->fetchAll(PDO::FETCH_OBJ);
foreach ($result as $row) {
    foreach (get_object_vars($row) as $key => $value) {
    $row->$key = (mb_detect_encoding($value, mb_detect_order(), true) === 'UTF-8') 
            ? $value : iconv('windows-1250', 'utf-8', $value);
    }
    $results[] = $row;
}

然后它工作了,但我使用波兰字符


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接