【问题标题】:How to store and retrieve extended ASCII characters in MSSQL如何在 MSSQL 中存储和检索扩展的 ASCII 字符
【发布时间】:2017-01-30 21:15:00
【问题描述】:

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

我有一个接受用户输入的 PHP 网络应用程序。由于应用程序的性质,用户可能经常使用扩展的 ASCII 字符(也称为“ALT 代码”)。

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

我的列类型是 NVARCHAR。

这是我尝试过的:

  1. 我尝试过不进行任何转换,只是照常插入值,但该值被存储为 thisâ??that

  2. 我尝试在 PHP 中使用 iconv('UTF-8', 'UCS-2', $value) 将值转换为 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。如果有任何驱动程序/操作系统版本的问题,它是通过 FreeTDS 连接的 Linux 服务器。这是不可能改变的。

【问题讨论】:

  • 你确定sql server中存储的值不正确吗? SSMS 并不总是能很好地显示扩展集中的字符。您可以检查该字符的实际 unicode 值。听起来您可能需要在 PHP 端做一些事情才能使其对扩展字符集有效。
  • 回答这个问题:“我已经尝试在 PHP 中使用 utf8_decode($value),但是箭头被替换为问号。”,这可能是因为没有表示该值在 ISO-8859-1 字符集中。 utf8_decode 将字符串转换为 ISO-8859-1 字符集。
  • @SeanLange:当从数据库中检索到值以显示在应用程序中时,它会按照我提到的方式显示(损坏)。
  • 我会在数据库中查看实际存储的值。您可以使用 UNICODE 函数来获取有问题的字符的代码。
  • @georaldc:是的,我知道为什么会这样。我刚刚提到这是我尝试过的事情之一,以防止任何人建议尝试。

标签: php sql-server sql-server-2012 freetds php-5.5


【解决方案1】:

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

(编辑:您显然也可以使用base64 encoding on the SQL Server side。这似乎不是它应该为恕我直言负责的事情,但这是一种选择。)

【讨论】:

  • 好主意!我刚刚测试了它,它似乎按预期工作。我必须在存储它之前和之后添加这些步骤,但这是迄今为止唯一对我有用的东西。谢谢!仅供参考,它不会让我在 16 小时内奖励赏金。我猜其他人将有 16 个小时的时间来提出更好的解决方案!
【解决方案2】:

您的freetds.conf 似乎是错误的。您需要 TDS 协议版本 >= 7.0 才能支持 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');

【讨论】:

  • 好吧,tds version 应该7.4,因为 OP 正在访问 SQL Server 2012 实例。您链接到的文档说:For best results, use the highest version of the protocol supported by your server.
  • @LayZee 来自同一链接:4.2 仍适用于所有产品,但受其限制。 ASCI 而不是 UTF-8 是一个限制。仅使用新产品并不意味着您不能使用旧协议。
  • 我同意。我只是想指出 7.4 是可能的,甚至在文档中推荐。
  • 我的 freetds.conf 版本指定 7.1 版。根据上面问题 cmets 中的建议,我确实尝试过 ini_set('mssql.charset', 'UTF-8')。不幸的是,这些并不能解决我的问题。
【解决方案3】:

接受的答案似乎可以完成工作;是的,您可以将其编码为base64,然后再次将其解码,但是使用该远程数据库的所有应用程序都应更改并支持将字段编码为base64。我的想法是,如果有一个远程 MS SQL Server 数据库,则可能有其他应用程序(或多个应用程序)可以使用它,因此还必须更改该应用程序以支持纯编码和base64 编码。而且您还必须处理纯文本和base64 转换后的文本。

我搜索了一下,发现如何使用 MS SQL 命令和 PHP 将 UNICODE 文本发送到 MS SQL Server 以将 UNICODE 字节转换为 HEX 数字。

如果您查看mssql_fetch_array (http://php.net/manual/ru/function.mssql-fetch-array.php#80076) 的 PHP 文档,您会在 cmets 看到一个非常好的解决方案,它将文本转换为 UNICODE HEX 值,然后将该 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 Server 发回这样的 UNICODE 编码文本:

从 MS SQL Server 检索 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;
} 

插入后带​​有 UNICODE 数据的 MS SQL 表

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

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

【讨论】:

    猜你喜欢
    • 2019-06-11
    • 2020-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多