概况
前几天帮一个兄弟重写了一整套系统,从 ASP 成功迁移到了 PHP。
不过呢,在填这种奇怪搭配坑的路上总能够碰到一些神坑,掉进去之后半天也爬不出来。
遇到的坑
刚开始是直接装的 FreeTDS 然后再安装 PHP 的 pdo-dblib 扩展实现的连接,配置完 FreeTDS 再连接 SQL Server 的时候,一开始看起来还是挺正常的,能够直接连上,然后也能正常写。
开发到一半发现了不对劲的情况,在 参数带中文 的情况下, pdo 绑定参数之后带入查询,竟然查不到任何的结果(实际是存在匹配的记录,且在不使用绑定,然后直接用原始 SQL 语句写的情况下,能够查出来),就连写入也是有问题的。
更蹊跷的是,假如查询的时候 pdo 绑定参数值只带英文,能查到结果,且结果又不会有乱码,这我整个人就不好了。
查了半天的资料,然后结合自己的情况进行分析,排查,最后发现是 pdo-dblib 和 SQL Server 的 nvarchar 字段结合查询时,多字节字符无法正常工作,Stackoverflow上也有踩坑的同行。
解决办法更是瞠目结舌,要先把字符转码成 UTF-16LE 然后再带入查询,这样就神奇的查出来了。
这个解决办法是我不能接受的,我总不能在每个 Model 对这些异类字段做标记,然后修改底层其他 composer 包里封装的处理方法吧,这样下来万一哪天又掉新坑里也不足为奇了。
最后没办法,只能转到用 pdo-odbc 去连接了。
正确的连接姿势
首先就是在类 Unix 环境(比如我用 OSX)下面怎么远程连接到 SQL Server 上呢?
要连接,首先你得有一个连接媒介,在类 Unix 环境下面有一个工具叫做 FreeTDS,提供一个桥梁让系统和远端 SQL Server 之间进行通信。
OSX 借助 Brew 需要以下一条命令进行安装
1 | brew install freetds --with-unixodbc |
最后一个 with 参数必须要带,要不然就不会产生 tds 的 so 文件,后面 unixodbc 设置 driver 的时候就无法下手了,安装完之后,先配置 ODBC:
编辑 ~/.odbc.ini (大家请根据自己的实际情况编辑对应的文件),并在最后加上如下内容
1 | [服务源名称,比如test] |
然后编辑 /usr/local/etc/freetds.conf 并在最后加上如下内容
1 | [dataSourceName]#和前面odbc.ini文件里的Servername保持一致 |
保存之后,在确保 PHP 的 pdo-odbc 扩展是开启的状态下,直接用 pdo 的 odbc 方式去连 SQL Server 就好了。
PDO-ODBC 有坑么?
回答当然是,有!
无法多条同时批量插入(不知道是不是我姿势问题,反正我这边一次批量插入就出错,单条能够成功插入)
有时候查出来的部分结果的字段值是 null,而且不同的开发机器上相同的环境下,空的字段还不太一样,这就十分尴尬了。
究极解决方案
换 Windows 开发,然后用 pdo-sqlsrv 去连接(毕竟微软的数据库,得配套微软自己写的扩展去连才不会出事。。。)
不过你换 pdo-sqlsrv 的话,又得装其他库,也是蛮繁琐的。
如果服务器是 Windows Server 2003 的话,pdo-sqlsrv 最高还只能使用官方 2.0 的版本,2.0版本最高只支持 PHP 5.3。
假如你 SQL Server 是 2005 的话,pdo-sqlsrv也只支持到 3.0(最高支持到 PHP 5.4)。3.1 版本开始只有 SQL Server 2008+ 能享用了,所以 PHP 5.5+ 你就无望啦,于是 Laravel 你最高就只能用到 5.0 啦。
Laravel 5.0 的话自带的 DB 类支持的 sqlsrv 连接方式是没有 odbc 的,对于 odbc 连接 SQL Server 的支持也是在最近的 5.2.31 才加上的。
于是,想问各位客官,有没有一种想死的感觉?
要不是客户还有其他端的东西还得跑,我想整套给他转成 PHP + MySQL 了。
我的故事讲完啦。
总结
还是希望后面的兄弟可以少踩点坑,要不然我浪费的一下午时间就没有太大意义了。
以后少接这种奇怪搭配的活,要不然光搞定这些环境问题就要浪费你一大把时间。
最后,我还活着,打算开始写点 PHP 和 Laravel 入门教程了,希望可以让后人少走弯路 :)