如何在 MSSQL 中存储和检索扩展的 ASCII 字符

How to store and retrieve extended ASCII characters in MSSQL

我很惊讶我无法通过搜索找到这个问题的直接答案。

我在 PHP 中有一个接受用户输入的 Web 应用程序。由于应用程序的性质,用户可能经常使用扩展的 ASCII 字符 (a.k.a."ALT codes").

我目前的具体问题是 ALT 代码 26,它是右箭头 (→)。这将与其他文本一起存储在同一字段中(例如,'this→that')。

我的列类型是 NVARCHAR。

这是我尝试过的方法:

  1. 我试过不做任何转换,只是像往常一样插入值,但值存储为 thisâ??that

  2. 我尝试使用 iconv('UTF-8', 'UCS-2', $value) 将 PHP 中的值转换为 UCS-2,但我收到一条错误消息 Unclosed quotation mark after the character string 't'.。查询最终看起来像这样:UPDATE myTable SET myColumn = 'this�!that'.

  3. 我试过进行上述转换,然后在引用值前添加一个 N,但我得到了相同的错误消息。查询如下所示:UPDATE myTable SET myColumn = N'this�!that'.

  4. 我尝试删除 UCS-2 转换并在引用值前添加 N,查询再次运行,但该值存储为 thisâ that.

  5. 我试过在PHP中使用utf8_decode($value),但是箭头只是被问号代替了。

那么谁能回答这个(看似简单的)问题,我如何将这个值存储在我的数据库中,然后按照最初输入的方式检索它?

我正在使用 PHP 5.5 和 MSSQL 2012。如果 driver/OS 版本有任何问题,它是通过 FreeTDS 连接的 Linux 服务器。不可能改变这个。

看来你的freetds.conf是错误的。您需要一个 >= 7.0 的 TDS 协议版本来支持 unicode。 See this for more details.

编辑您的freetds.conf

[global]
# TDS protocol version
tds version = 7.4
client charset = UTF-8

还要确保配置PHP正确:

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

您可以尝试对输入进行 base64 编码,这对于 PHP 的 base64_encode() and base64_decode() 来说相当简单,它应该可以处理您的用户向它抛出的任何内容。

(编辑:您显然也可以执行 。恕我直言,这似乎不是它应该负责的事情,但它是一个选项。)

接受的答案似乎可以解决问题;是的,您可以将其编码为 base64,然后再次将其解码回来,但是所有使用该远程数据库的应用程序都应该更改并支持要进行 base64 编码的字段。我的想法是,如果有一个远程 MS SQL 服务器数据库,可能会有一个(或多个)其他应用程序可以使用它,因此还必须更改该应用程序以支持普通和 base64 编码。而且您还必须处理纯文本和 base64 转换后的文本。

我稍微搜索了一下,找到了如何使用 MS SQL 命令和 PHP 将 UNICODE 字节转换为 HEX 数字来将 UNICODE 文本发送到 MS SQL 服务器。

如果您查看 mssql_fetch_array (http://php.net/manual/ru/function.mssql-fetch-array.php#80076) 的 PHP 文档,您会在注释中看到一个非常好的解决方案,它将文本转换为 UNICODE HEX 值然后将该十六进制数据直接发送到 MS SQL 服务器,如下所示:

将 Unicode 文本转换为 HEX 数据

// sending data to database 
$utf8 = 'Δοκιμή με unicode → Test with Unicode';  // some Greek text for example
$ucs2 = iconv('UTF-8', 'UCS-2LE', $utf8); 

// converting UCS-2 string into "binary" hexadecimal form 
$arr = unpack('H*hex', $ucs2); 
$hex = "0x{$arr['hex']}"; 

// IMPORTANT! 
// please note that value must be passed without apostrophes 
// it should be "... values(0x0123456789ABCEF) ...", not "... values('0x0123456789ABCEF') ..." 
mssql_query("INSERT INTO mytable (myfield) VALUES ({$hex})", $link);

现在所有文本实际上都作为 UNICODE 正确存储到 NVARCHAR 数据库字段,这就是您要将其作为纯文本而不是编码发送和存储所要做的全部工作。

要检索该文本,您需要要求 MS SQL 服务器发回 UNICODE 编码的文本,如下所示:

正在从 MS SQL 服务器检索 Unicode 文本

// retrieving data from database 
// IMPORTANT! 
// please note that "varbinary" expects number of bytes 
// in this example it must be 200 (bytes), while size of field is 100 (UCS-2 chars) 

// myfield is of 50 length, so I set VARBINARY to 100
$result = mssql_query("SELECT CONVERT(VARBINARY(100), myfield) AS myfield FROM mytable", $link); 

while (($row = mssql_fetch_array($result, MSSQL_BOTH))) 
{ 
    // we get data in UCS-2 
    // I use UTF-8 in my project, so I encode it back 
    echo '1. '.iconv('UCS-2LE', 'UTF-8', $row['myfield'])).PHP_EOL; 
    // or you can even use mb_convert_encoding to convert from UCS-2LE to UTF-8
    echo '2. '.mb_convert_encoding($row['myfield'], 'UTF-8', 'UCS-2LE').PHP_EOL;
} 

MS SQL Table INSERT

后带UNICODE数据

输出结果使用PHP页面显示值

我不确定你是否可以在这里访问我的测试页面,但你可以尝试查看实时结果: http://dbg.deve.wiznet.gr/php56/mssql/test1.php