PDO DBLIB多字节(中文)字符编码 - SQL服务器

时间:2015-02-26 10:49:38

标签: sql-server pdo character-encoding freetds multibyte

在Linux机器上,我使用PDO DBLIB连接到MSSQL数据库并在SQL_Latin1_General_CP1_CI_AS表中插入数据。问题是,当我尝试插入中文字符(多字节)时,它们将被插入为哈市香åŠåŒºç æ±Ÿè·¯å·

我的(部分)代码如下:

$DBH = new PDO("dblib:host=$myServer;dbname=$myDB;", $myUser, $myPass);

$query = "
    INSERT INTO UserSignUpInfo
    (FirstName)
    VALUES
    (:firstname)";

$STH = $DBH->prepare($query);

$STH->bindParam(':firstname', $firstname);

到目前为止我尝试过:

  1. mb_convert_encoding上执行UTF-16LE$firstname,在查询中执行CAST as VARBINARY,如:

    $firstname = mb_convert_encoding($firstname, 'UTF-16LE', 'UTF-8');

    VALUES
    (CAST(:firstname AS VARBINARY));
    

    这导致正确插入字符,直到有一些非多字节字符,这会破坏PDO的执行。

  2. 将我的连接设置为utf8:

    $DBH = new PDO("dblib:host=$myServer;dbname=$myDB;charset=UTF-8;", $myUser, $myPass);
    $DBH->exec('SET CHARACTER SET utf8');
    $DBH->query("SET NAMES utf8");
    
  3. 在我的freetds.conf中将client charset设置为UTF-8

    哪个没有影响。

  4. 有没有办法在该SQL数据库中插入多字节数据?还有其他解决方法吗? 我曾想过尝试PDO ODBC甚至是mssql,但是在浪费时间之前最好先问一下这个问题。

    提前致谢。

    修改

    我最终使用MSSQLN数据类型前缀。当我有更多时间时,我会换掉并尝试PDO_ODBC。谢谢大家的答案!

5 个答案:

答案 0 :(得分:8)

  

有没有办法在[this specific] SQL中插入多字节数据   数据库?还有其他解决方法吗?

  1. 如果您可以切换到PDO_ODBC,Microsoft为Linux提供免费的SQL Server ODBC驱动程序(仅适用于支持Unicode的64位Red Hat Enterprise Linux和64位SUSE Linux Enterprise)。

    < / LI>
  2. 如果您可以更改为PDO_ODBC,那么插入Unicode的N前缀将起作用。

  3. 如果您可以将受影响的表从SQL_Latin1_General_CP1_CI_AS更改为UTF-8(这是MSSQL的默认值),那么这将是理想的。

  4. 您的案件受到更多限制。此解决方案适用于输入字符串中包含混合多字节和非多字节字符的情况,并且需要将它们保存到拉丁表,并且N数据类型前缀不起作用,并且你不想改变PDO DBLIB(因为微软的Linux PDO_ODBC在Linux上是barely supported)。这是一个解决方法。

    有条件地将输入字符串编码为 base64 。毕竟,这就是我们如何根据电子邮件安全地传输图片。

    工作示例:

    $DBH = new PDO("dblib:host=$myServer;dbname=$myDB;", $myUser, $myPass);
    
    $query = "
    INSERT INTO [StackOverflow].[dbo].[UserSignUpInfo]
               ([FirstName])
         VALUES
               (:firstname)";
    
    $STH = $DBH->prepare($query);
    
    $firstname = "输入中国文字!Okay!";
    
    /* First, check if this string has any Unicode at all */
    if (strlen($firstname) != strlen(utf8_decode($firstname))) {
        /* If so, change the string to base64. */
        $firstname = base64_encode($firstname);
    }
    
    $STH->bindParam(':firstname', $firstname);
    $STH->execute(); 
    

    然后向后,您可以测试base64字符串,并解码它们而不会损坏您现有的条目,如下所示:

    while ($row = $STH->fetch()) {
        $entry = $row[0];
    
        if (base64_encode(base64_decode($entry , true)) === $entry) {
    
             /* Decoding and re-encoding a true base64 string results in the original entry */
             print_r(base64_decode($entry) . PHP_EOL);
    
        } else {
    
             /* Previous entries not encoded will fall through gracefully */
             print_r($entry  . PHP_EOL);
        }
    }
    

    条目将保存为:

    Guan Tianlang
    5pys6Kqe44KS5a2maGVsbG8=
    

    但您可以轻松将它们转换回:

    Guan Tianlang
    输入中国文字!Okay!
    

答案 1 :(得分:2)

整理在这里不重要。

双字节字符需要存储在nvarcharncharntext字段中。你不需要进行任何演员。

n数据类型前缀代表National,它会导致SQL Server将文本存储为Unicode(UTF-16)。

修改

PDO_DBLIB不支持Unicode,现已弃用。

如果您可以切换到PDO_ODBC,Microsoft为Linux提供免费的SQL Server ODBC驱动程序,支持Unicode。

Microsoft - SQL Server ODBC Driver Documentation

Blog - Installing and Using the Microsoft SQL Server ODBC Driver for Linux

答案 2 :(得分:1)

您可以将表格列的Unicode兼容数据类型用于支持外语(例外情况显示在编辑2中)。

  

(char,varchar,text) Versus (nchar,nvarchar,ntext)

非Unicode:

最适合美国英语:&#34;使用1个字节对每个字符进行编码的数据类型的一个问题是数据类型只能代表256个不同的字符。这迫使多个编码规范(或代码页)用于不同的字母表,例如欧洲字母表,这些字母表相对较小。处理具有数千个字符的日语汉字或韩语韩语字母表等系统也是不可能的

<强>的Unicode

最适合需要支持至少一种外语的系统:&#34; Unicode规范为世界各地企业广泛使用的大多数字符定义了单一编码方案。所有计算机都使用单个Unicode规范将Unicode数据中的位模式一致地转换为字符。这可确保在所有计算机上始终将相同的位模式转换为相同的字符。数据可以从一个数据库或计算机自由传输到另一个数据库或计算机,而无需担心接收系统会将位模式错误地转换为字符。

示例:

此外,我已经尝试了一个示例,您可以在下面查看其屏幕,这对于与外语插入相关的问题是有帮助的,因为现在的问题。如nvarchar中所示的列,它确实支持中文

enter image description here

编辑1:

讨论了另一个相关问题here

编辑2:

显示Unicode不支持的脚本here

答案 3 :(得分:-1)

只需使用nvarchar,ntext,nChar,然后插入即可 使用

INSERT INTO UserSignUpInfo
    (FirstName)
    VALUES
    (N'firstname');

N将引用Unicode字符,它是世界范围内的标准。

参考:

https://aalamrangi.wordpress.com/2012/05/13/storing-and-retrieving-non-english-unicode-characters-hindi-czech-arabic-etc-in-sql-server/

https://technet.microsoft.com/en-us/library/ms191200(v=sql.105).aspx

https://irfansworld.wordpress.com/2011/01/25/what-is-unicode-and-non-unicode-data-formats/

答案 4 :(得分:-2)

此链接解释MYSQL中的中文字符。 Can't insert Chinese character into MySQL。 您必须创建表table_name()CHARACTER SET = utf8; 插入表格时Use UTF-8

set username utf8; INSERT INTO table_name (ABC,VAL); 

abd在CHARACTER SET utf8 COLLATE utf8_general_ci;

中创建数据库

然后你可以在表格中插入中文字符