php - MS SQL Server 通过 Linux 上的 PHP 支持非模拟准备语句

标签 php sql-server linux pdo freetds

总结

我正在尝试使用准备好的语句来阻止 SQL 注入(inject),但无法找到我需要的支持来保证它正常工作。


场景

我在 Linux 上托管一个站点,该站点连接到带有 FreeTDS 版本 0.91 的 Microsoft SQL Server,特别是使用 FreeTDS 的 dblib。我已将数据库连接的 tds 版本设置为 7.4,并且正在使用 PHP 的 PDO。对象。

根据FreeTDS documentation , 4.2不支持prepared statements:

TDS 4.2 has limitations

  • ASCII only, of course.
  • RPC is not supported.
  • BCP is not supported.
  • varchar fields are limited to 255 characters. If your table defines longer fields, they'll be truncated.
  • dynamic queries (also called prepared statements) are not supported.

然而,没有任何迹象表明 7.4 不支持准备好的语句,这让我有理由相信它们至少不会引发驱动程序错误。

PHP 的 PDO 通过 PDO::setAttribute() 支持连接特定属性. 我对 PDO::ATTR_ERRMODE 感兴趣,它可以将所有错误设置为异常,而 PDO::ATTR_EMULATE_PREPARES 可以强制数据库在兼容时执行准备好的语句。


问题

测试连接时,我收到以下错误:

Database error: SQLSTATE[IM001]: Driver does not support this function: driver does not support setting attributes

如果无法设置 PDO::ATTR_EMULATE_PREPARES,我无法保证数据库确实按预期执行准备好的语句。

是否可以修改我的方法,或者是否有其他方法来 保证准备好的语句在 Linux 的 MS SQL Server 上安全执行?

最佳答案

解决方案

使用 ODBC而不是 dblib ,它提供了 PDO 的全部功能。 请注意,ODBC 有两种可能的配置:standalone ODBCFreeTDS with ODBC driver .根据我的经验,要为连接设置字符集,必须使用 ODBC 驱动程序通过 FreeTDS 完成,这样组合配置更可取。


ODBC 设置

我在网上搜索了许多不同的 StackOverflow 帖子和各种文档资源,了解如何正确安装 ODBC。我从以下三个引用文献中提取了我的解决方案:

下面是我用来配置 ODBC 的步骤列表使用 FreeTDS在基于 Debian 的系统上。

TDS 8.0 支持准备好的语句。

注意:不支持 SET NAMES aSET CHARSET a在连接上;需要通过设置 FreeTDS 属性使用组合配置来定义字符集。使用独立的 ODBC 驱动程序默认字符集为 ASCII ,这给出了奇怪的结果。看我的other post有关可能问题的示例。

安装需要的包:

sudo apt-get install freetds-bin freetds-common unixodbc tdsodbc php5-odbc

  • freetds-bin提供 FreeTDS,以及 tsqlisql (用于后期调试)。
  • freetds-common已经安装在系统上,但不包括这两个调试工具。安装 freetds-bin稍后在定义配置后不会出现问题。
  • unixodbc是ODBC驱动
  • tdsodbc为ODBC提供TDS协议(protocol)
  • php5-odbc是使用 ODBC 驱动程序的 php 模块。请注意,您的 PHP 版本可能与我的不同。

配置独立 unixODBC

/etc/odbcinst.ini 中的 ODBC 驱动程序设置:

[odbc]
Description     = ODBC driver
Driver          = /usr/lib/x86_64-linux-gnu/odbc/libtdsodbc.so
Setup           = /usr/lib/x86_64-linux-gnu/odbc/libtdsS.so 
UsageCount      = 1

/etc/odbc.ini 中创建系统范围的数据源名称配置:

[datasourcename]
 Driver         = odbc
 Description    = Standalone ODBC
 Server         = <IP or hostname>
 Port           = <port>
 TDS_Version    = 8.0

配置 unixODBC 和 FreeTDS:

/etc/odbcinst.ini 中的 ODBC 驱动程序设置:

[odbc]
Description     = ODBC driver
Driver          = /usr/lib/x86_64-linux-gnu/odbc/libtdsodbc.so
Setup           = /usr/lib/x86_64-linux-gnu/odbc/libtdsS.so 
UsageCount      = 1

/etc/odbc.ini 中创建系统范围的数据源名称配置:

[datasourcename]
Driver          = FreeTDS_odbc
Description     = Uses FreeTDS configuration settings defined in /etc/freetds/freetds.conf
Servername      = datasourcename
TDS_Version     = 8.0

/etc/freetds/freetds.conf 中将 ODBC 数据源名称配置添加到 FreeTDS :

[datasourcename]
    host = <IP or hostname>
    port = <port>
    client charset = UTF-8
    tds version = 8.0
    text size = 20971520
    encryption = required

IMPORTANT: make sure that the odbc files are readable by the process that will be reading them. If you are running your webserver using a www-data user, they must have the proper permissions to read those files!

您现在可以在 freetds.conf 中设置连接字符集并使用 PDO 作为连接到数据库

$pdo = new PDO('odbc:datasourcename');

测试:

使用 tsql检查 FreeTDS 是否已配置并且可以连接到数据库。

tsql -S datasourcename -U username -P password

使用 isql检查 ODBC 是否正确连接。

isql -v datasourcename username password

将 ODBC 与 PHP 链接:

将 ODBC PHP 模块添加到 php.ini通过添加以下内容:

extension = odbc.so

请注意您的 php.ini位置将取决于您使用的网络服务器。 使用 <?php phpinfo(); ?>并通过网络服务器查看它以找到它的位置。

重新启动 Apache

编辑: 添加了有关驱动程序字符集功能的信息,因为我遇到了独立 ODBC 配置问题,它会忽略任何更改连接字符集的尝试。

关于php - MS SQL Server 通过 Linux 上的 PHP 支持非模拟准备语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38338596/

相关文章:

PHP if OR 是否检查了第二部分是否为真?

php - Laravel 通过 id 读取表数据

sql-server - 在 SELECT 中设置列​​的值?

linux - 使用 crontab 从 sas 发送附件输出

c++ - IPC : Communication of C++-program with a group of bash scripts and C++-programs

php - apache httpd 耗尽内存直到挂起

java - 类图中的public、protection、private的作用是什么?有什么例子吗?

sql - 如何为每笔具有多次插入的交易获取唯一 ID

c# - 标签云算法的建议

linux - 将文本处理命令的结果转发到 .ods 文件中的特定位置