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

chu*_*die 5 php sql-server unicode orm pdo

如果要将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. 是否可以使用ZF自动添加N值的任何char值?
  2. 是否有任何ORM/TableGateway库允许这种值操作?
  3. 有没有办法从Linux启用服务器端预处理语句?
  4. 有没有人真正从Linux代码运行生产PHP并让它运行MSSQL?(如果是的话,你如何处理Unicode?)

编辑:我可以从Linux获得unicode保存到MSSQL,但是将FreeTDS协议升级到7/8似乎打破了所有框架/库/ orms,因为绝对需要改变带有N前缀的普通SQL.我不确定互联网上有谁声称升级到协议版本7/8修复了他们的unicode问题实际上做了什么,除了用非便携方式手写每个SQL语句.似乎继续使用Freetds 4.2是处理Unicode/UTF-8和mssql的最佳方式.

Tar*_*mán 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映像.登录后,我使用切换到root用户sudo -i,然后:

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
Run Code Online (Sandbox Code Playgroud)

测试一下

使用您自己的服务器替换以下命令中的服务器和凭据.

sqlcmd -S somedatabase.database.windows.net -U someuser -P somepassword
Run Code Online (Sandbox Code Playgroud)

此时您应该能够发出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
Run Code Online (Sandbox Code Playgroud)

此时,您应该将它作为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
Run Code Online (Sandbox Code Playgroud)

运行此操作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 !)