ThinkPHP5连接SQL Server必须满足三个硬性条件:PHP已加载php_pdo_sqlsrv和php_sqlsrv扩展、系统安装匹配位数的Microsoft ODBC Driver、database.php中type设为sqlsrv;缺一则报“无法打开连接”或“驱动未找到”,且需通过phpinfo()确认模块真实启用,扩展名、php.ini路径、ODBC位数、hostname写法(推荐localhost而非127.0.0.1)、charset应设utf-8、表名Schema支持需修改核心文件。

ThinkPHP5 能直接连接 SQL Server,但必须满足三个硬性条件:PHP 已加载 php_pdo_sqlsrv 和 php_sqlsrv 扩展、系统已安装匹配位数的 Microsoft ODBC Driver、database.php 中 type 明确设为 sqlsrv。缺一不可,否则必然报错“无法打开与 SQL Server 的连接”或“驱动未找到”。
确认 PHP 扩展是否正确加载
不是“放了 DLL 就算启用”,而是要确保 phpinfo() 页面里真实出现 pdo_sqlsrv 和 sqlsrv 两个模块。常见失败点:
- 扩展名写错:
php_pdo_sqlsrv_7_nts_x64.dll和php_sqlsrv_7_nts_x64.dll必须严格匹配你的 PHP 版本(如 7.4)、线程模型(NTS/TS)和系统架构(x64/x86) -
php.ini中 extension 行被注释或路径错误,例如写成extension=php_pdo_sqlsrv.dll(缺少版本号后缀) - 扩展放在了错误目录:必须是当前运行环境实际加载的
ext目录,不是你“以为”的那个 - Apache/Nginx 服务没重启,或 CLI 和 Web 使用的不是同一份
php.ini
ODBC Driver 安装必须匹配系统位数
PHP 是 64 位,就必须装 64 位 ODBC Driver;PHP 是 32 位(如某些旧版 phpStudy),哪怕系统是 64 位 Windows,也必须装 32 位驱动。装错会导致 sqlsrv_connect() 直接返回 false,且无明确错误提示。
- 推荐安装
ODBC Driver 17 for SQL Server(支持 SQL Server 2008–2022,含 Linux 兼容性) - 下载地址:https://www.php.cn/link/7462d99d60e1fb77bf39840c19c44e6e
- 安装后无需配置,但必须重启 Web 服务才能生效
- 验证方式:在命令行执行
odbcad32.exe(Windows 自带),查看“驱动程序”页签中是否存在ODBC Driver 17 for SQL Server
database.php 配置的关键字段不能照搬 MySQL 习惯
SQL Server 对连接字符串更敏感,hostname、hostport、database 的写法直接影响能否握手成功:
立即学习“PHP免费学习笔记(深入)”;
-
hostname填localhost通常比127.0.0.1更可靠(避免命名管道 vs TCP 协议自动选择失败) -
hostport留空或填1433都可能失败;若 SQL Server 实例是默认实例,端口可省略;若为命名实例(如SQLExpress),应改用hostname写成localhost\SQLExpress,而非靠端口指定 -
database必须是真实存在的库名,大小写不敏感但拼写必须完全一致;首次连接时建议先用 SSMS 登录确认库名无空格/特殊字符 -
charset设为utf8无效,SQL Server 不识别该编码名;应改为utf-8或留空(由 driver 自动协商)
表名大小写与 Schema 问题常被忽略
TP5 默认把 UserProfile 这类驼峰表名转成 user_profile,但 SQL Server 表名是原样保留的,导致查询 404。更隐蔽的是 Schema 问题:SQL Server 默认 Schema 是 dbo,但如果你的表在 hr Schema 下,Db::table('hr.Employee') 会失败,因为 TP5 的 Sqlsrv.php 默认不解析 Schema 前缀。
- 临时解法:全部用原生查询
Db::query("SELECT * FROM hr.Employee") - 根治法:修改
thinkphp/library/think/db/connector/Sqlsrv.php的getFields()方法,把explode(' ', $tableName)改为支持.分隔,否则字段元信息都取不到 - 注意:修改核心文件后需清除 runtime/cache/ 下所有缓存,否则改动不生效



















