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

时间:2017-01-30 21:15:01

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

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

我在PHP中有一个用户输入的Web应用程序。由于应用程序的性质,用户可能经常使用扩展的ASCII字符(例如“ALT代码”)。

我目前的具体问题是使用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),但箭头只是替换为问号。

  6. 所以任何人都可以回答(看似简单的)问题,如何将这个值存储在我的数据库中,然后按照最初输入的方式检索它?

    我正在使用PHP 5.5和MSSQL 2012.如果驱动程序/操作系统版本的任何问题发挥作用,它是通过FreeTDS连接的Linux服务器。没有可能改变这一点。

4 个答案:

答案 0 :(得分:5)

您可以尝试对输入进行base64编码,使用PHP base64_encode()base64_decode()来处理这一点非常简单,它应该可以处理用户扔过它的内容。

(编辑:您显然也可以执行base64 encoding on the SQL Server side。这似乎不应该对imho负责,但它是一个选项。)

答案 1 :(得分:1)

好像你的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');

答案 2 :(得分:1)

看起来你有this→!that,UTF-8编码this→!that的ASCII副本。

在这里提出的建议之后把事情做好,并不能神奇地解决所有问题。特别是如果您的表格中已经存在数据损坏的话。

你需要重新开始寻找正确的道路。

  • 创建一个至少有一个nvarchar列的新表,让我们说TestTable(Column1)
  • 在测试过程中为硬编码输入创建一个空的UTF-8编码的 - PHP文件。 test.php
  • freetds.conf中,明确地在client charset = UTF-8[global]部分下添加设置[WhateverYourServerNameIs]。这是在FreeTDS和SQL Server之间进行通信时使用的字符集。

<强> test.php的

<?php
// character set to be used in response
header('Content-Type: text/plain; charset=utf-8');

// charset to be used in communication between PHP driver and FreeTDS.
ini_set('mssql.charset', 'UTF-8');

// make the connection
$conn = mssql_connect("ServerNameSpecifiedInFreetdsDotConf", "username", "passw0rd");

// select database
mssql_select_db("DatabaseName", $conn);

// insert something immediately
// do not forget to use the N prefix, may cause problems with mssql_query if omitted
$insertQuery = mssql_query("Insert Into TestTable(Column1) Select N'this→that';", $conn);

// list all the records
$query = mssql_query( "Select * From TestTable", $conn );
while ($row = mssql_fetch_array($query))
    echo $row["Column1"].PHP_EOL;

mssql_close($conn); // close the connection
?>

反复运行test.php,看看会发生什么。如果您在PHP响应和SQL Server Management Studio上看到this→that,则意味着您已全部设置。

如果您仍然得到意想不到的结果,请告诉我们。

答案 3 :(得分:1)

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

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

如果你查看mssql_fetch_arrayhttp://php.net/manual/ru/function.mssql-fetch-array.php#80076)的PHP文档,你会在评论中看到一个非常好的解决方案,将文本转换为UNICODE HEX值然后发送HEX数据直接发送到MS SQL Server,如下所示:

将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;
} 

INSERT后带有UNICODE数据的MS SQL表

MS SQL Table

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

PHP Output

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