PHP,ORM,MSSQL和Unicode,是否可以将这些工作结合起来?

时间:2014-06-15 14:41:23

标签: php sql-server pdo unicode orm

如果要将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.

  1. 是否可以自动在N和ZF之前添加任何char值?
  2. 是否有任何允许这种值操作的ORM / TableGateway库?
  3. 有没有办法从Linux启用服务器端预处理语句?
  4. 有没有人真正从Linux代码运行生产PHP并让它针对MSSQL运行? (如果是的话,你如何处理Unicode?)
  5. 编辑: 我可以将unicode从Linux保存到MSSQL,但是将FreeTDS协议升级到7/8似乎打破了所有框架/库/ orms,因为绝对需要改变带有N前缀的普通SQL。我不确定互联网上有谁声称升级到协议版本7/8修复了他们的unicode问题实际上做了什么,除了用非便携方式手写每个SQL语句。似乎继续使用Freetds 4.2是处理Unicode / UTF-8和mssql的最佳方式。

1 个答案:

答案 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!)