如果要将unicode数据保存到MSSQL,则需要保存为列类型nvarchar(et.al),并且必须在SQL STRING LITERALS前加上大写字母N.如果使用预准备语句,则不需要前缀值为N。
插入tbl(col)值(N'hello')
如果您使用的是像ZF DB这样的ORM,那么您正在使用PDO来连接到MSSQL(或者您正在Windows上部署,在这种情况下,您使用的是SQLSRV或PDO_SQLSRV,一切都会正常工作,我的问题不会有意义了。)
如果您正在使用任何连接到Linux上的mssql(sybase,dblib等)的PDO变体,那么您将无法获得真实的预处理语句,仅进行模拟。
如果您已经在线路级别模拟了预准备语句,则SQL完全写出只有字符串文字,这意味着您必须为任何潜在的unicode值添加前缀N.
编辑: 我可以将unicode从Linux保存到MSSQL,但是将FreeTDS协议升级到7/8似乎打破了所有框架/库/ orms,因为绝对需要改变带有N前缀的普通SQL。我不确定互联网上有谁声称升级到协议版本7/8修复了他们的unicode问题实际上做了什么,除了用非便携方式手写每个SQL语句。似乎继续使用Freetds 4.2是处理Unicode / UTF-8和mssql的最佳方式。
答案 0 :(得分:6)
更新:驱动程序不再处于预览状态。 MS已为现已发布的版本提供官方说明:https://www.microsoft.com/en-us/sql-server/developer-get-started/php-ubuntu
以下说明现已过时,因为MS已撤消预览驱动程序下载。
嗯,有Microsoft提供的ODBC驱动程序。这应该在这方面提供适当的行为。 请参阅帖子的结尾,了解我如何测试其行为(以初步方式)。它是针对Azure SQL数据库V12进行测试的。
如何在Ubuntu 16.04上安装Microsoft SQL ODBC驱动程序
这是在新的Ubuntu 16.04 Azure实例上测试的,该实例基于Canonical提供的Ubuntu 16.04 Azure映像。登录后,我使用sudo -i
切换到root用户,然后:
apt-get update
apt-get -y install atool make build-essential libc6 libkrb5-3 libgss3 e2fsprogs openssl equivs
wget https://download.microsoft.com/download/2/E/5/2E58F097-805C-4AB8-9FC6-71288AB4409D/msodbcsql-13.0.0.0.tar.gz
atool -x msodbcsql-13.0.0.0.tar.gz
rm msodbcsql-13.0.0.0.tar.gz
pushd msodbcsql-13.0.0.0/
./build_dm.sh --accept-warning | tee build_dm_result.txt
command=$(cat build_dm_result.txt | grep "Run the command" | cut -d"'" -f2)
rm build_dm_result.txt
sh -c "$command"
popd
echo "/usr/lib64" > /etc/ld.so.conf.d/microsoft-lib64.conf
ldconfig
pushd msodbcsql-13.0.0.0/
./install.sh install --accept-license
测试
使用您自己的命令替换以下命令中的服务器和凭据。
sqlcmd -S somedatabase.database.windows.net -U someuser -P somepassword
此时您应该能够发出SQL命令。好的,让我们使用php。
与php一起使用
我们必须确保没有安装libodbc1软件包并且不会安装它,因为php会使用它而不是我们的自定义编译软件包,这会导致编码问题。
cat > libodbc1<<EOL
Section: misc
Priority: optional
Standards-Version: 3.9.2
Package: libodbc1
Version: 9999
Description: fake pkg, so that we satisfy the dependency of php7-odbc, so that we can keep our custom built libodbc
EOL
equivs-build libodbc1
dpkg -i libodbc1_9999_all.deb
rm libodbc1
rm libodbc1_9999_all.deb
apt-get install php7.0-odbc php7.0-cli
此时,您应该将它作为ODBC驱动程序提供。
测试其行为
使用UTF-8编码创建一个php文件test.php,并使用以下内容。用您自己的连接字符串替换服务器,数据库和连接字符串中的凭据。
<?php
$pdo = new PDO('odbc:Driver={ODBC Driver 13 for SQL Server};Server=tcp:somedatabase.database.windows.net,1433;Database=somedatabase;Uid=someuser@somedatabase;Pwd=somepassword;Encrypt=yes;TrustServerCertificate=no;Connection Timeout=30;');
$str = 'Árvíztűrő tükörfúrógép, and... 你好,世界';
$pdo->prepare("DROP TABLE test")->execute();
$pdo->prepare("CREATE TABLE test(a NVARCHAR(MAX))")->execute();
$stmt = $pdo->prepare("INSERT INTO test VALUES(?)");
$stmt->bindParam(1, $str);
$stmt->execute();
$stmt = $pdo->prepare("SELECT * FROM test");
$stmt->execute();
$data = $stmt->fetchall();
var_dump($data[0][0]==$str); //Returns true
$stmt = $pdo->prepare("SELECT * FROM test WHERE a=?");
$stmt->bindParam(1, $str);
$stmt->execute();
$data = $stmt->fetchall();
var_dump($data[0][0]==$str); //Returns true
使用php -f test.php
运行此操作会显示我们返回字符串而没有任何损坏。此外,字符串在SQL Server Management Studio中看起来也很好。我在Azure门户的Performance Insight页面上观察到以下查询:(@P1 nvarchar(max))INSERT INTO test VALUES(@P1)
,因此显然使用了准备好的语句,因此我假设它可以处理您(和我的)场景。
(这篇文章在试图让它发挥作用时提供了很大的帮助:http://www.codesynthesis.com/~boris/blog/2011/12/02/microsoft-sql-server-odbc-driver-linux/谢谢boris!)