简介:本资源是专为PHP开发者快速对接Microsoft SQL Server数据库整理的完整驱动支持包,适用于Windows环境下配置PHP扩展连接SQL Server的开发与运维场景,尤其适合初学者解决扩展加载失败、版本不匹配等常见问题。压缩包内含29个文件,主体为24个php_sqlsrv与php_pdo_sqlsrv系列DLL动态链接库(覆盖PHP 8.1–8.3多个TS/NTS、x64/x86组合),辅以2份RTF格式第三方声明与许可说明、2份TXT使用须知及1份HTML格式官方Readme文档,总大小19.46MB,结构清晰、开箱即用。目前已有127人学习下载,资源由作者tjsoft持续维护,所含驱动均来自微软官方免费发布的SQL Server Drivers for PHP独立安装包,无需额外编译或复杂环境配置,可直接按需复制对应DLL至ext目录并启用扩展,显著降低PHP连接SQL Server的技术门槛。
1. PHP 连接 SQL Server 不是配个 host 就完事:缺一个 DLL 就报“Unable to load dynamic library”,微软官方驱动、PHP 扩展、系统级依赖三者必须严丝合缝
你是不是也试过在php.ini里加了extension=php_pdo_sqlsrv_82_ts.dll,重启 Apache 后phpinfo()里却压根不显示 SQL Server 相关模块?或者更玄学的是——本地开发环境跑得好好的,一上 Linux 测试机就抛SQLSTATE[08001]: [Microsoft][ODBC Driver 17 for SQL Server] Client unable to establish connection?这不是 PHP 写得有问题,而是你手里的.rar包里,缺的从来不是“所有 DLL”——而是“对得上你当前 PHP 版本、线程模型、架构位数、操作系统版本、SQL Server 驱动版本”的那一组 DLL。这个标题说的不是“下载即用”,而是一场精准匹配的硬核装配:它面向正在 Windows + IIS/Apache 环境下部署企业级 PHP 应用、后端必须对接 SQL Server(非 MySQL/PostgreSQL)的开发者;它解决的不是“能不能连”,而是“为什么连了报错、为什么连了查不出中文、为什么连了超时却不报错”。别急着解压.rar,先搞清你手里的 PHP 是什么“血型”。
2. 先锁死你的 PHP “血型”:版本、TS/NTS、x64/x86、VC 编译器版本,一个都不能猜
PHP 连接 SQL Server 的扩展不是通用二进制,它像一把定制钥匙——必须同时匹配四把锁:PHP 主版本(8.0/8.1/8.2/8.3)、线程安全模型(TS 表示线程安全,NTS 表示非线程安全)、CPU 架构(x64 或 x86)、以及编译所用的 Visual C++ 运行时(VC15/VC16/VC17)。猜错任意一项,extension=xxx.dll就是无效指令,PHP 启动时直接静默跳过,phpinfo()里查无此模块。
2.1 三步确认你的 PHP 实际“血型”
第一步:运行php -v和php --ini,记下 PHP 版本号和Loaded Configuration File路径;
第二步:在命令行执行php -m | findstr sqlsrv(Windows)或php -m | grep sqlsrv(Linux),看是否已加载——若无输出,说明扩展未生效;
第三步:最关键的一步——执行以下 PHP 脚本:
<?php // check_php_profile.php echo "PHP Version: " . PHP_VERSION . "\n"; echo "Architecture: " . PHP_ARCHITECTURE . "\n"; echo "Thread Safety: " . (PHP_ZTS ? 'enabled' : 'disabled') . "\n"; echo "Compiler: " . PHP_COMPILER . "\n"; echo "Extension Dir: " . PHP_EXTENSION_DIR . "\n"; ?>提示:
PHP_ZTS为1表示 TS(多线程环境如 Apache mod_php),为0表示 NTS(如 CLI、FPM);PHP_ARCHITECTURE显示x64或x86;PHP_COMPILER中VC15对应 VS2017,VC16对应 VS2019,VC17对应 VS2022。你下载的.rar包里所有 DLL 文件名必须包含这四个维度的标识,例如php_pdo_sqlsrv_82_ts_x64.dll—— 没有_x64或_ts的,就是废文件。
2.2 微软官方驱动版本与 PHP 扩展的严格对应关系(2024 年实测有效)
微软自 2020 年起将 SQL Server PHP 驱动拆分为两层:底层是Microsoft ODBC Driver for SQL Server(系统级驱动,.msi安装),上层是Microsoft Drivers for PHP for SQL Server(PHP 扩展.dll)。二者版本必须兼容,否则即使 DLL 加载成功,执行查询时也会在sqlsrv_connect()处卡死或返回空结果。
| PHP 版本 | 推荐 ODBC Driver 版本 | 对应 PHP Driver 下载包名(含 DLL) | 是否支持 Windows Authentication |
|---|---|---|---|
| PHP 8.0–8.1 | ODBC Driver 17 | MicrosoftDriversForPHP80-5.10.0 | ✅ 支持LoginMode=Windows |
| PHP 8.2 | ODBC Driver 17 或 18 | MicrosoftDriversForPHP82-5.11.0 | ✅(需启用sqlsrv.ClientCertificate) |
| PHP 8.3 | ODBC Driver 18 | MicrosoftDriversForPHP83-5.12.0 | ⚠️ 仅限 TLS 1.2+,禁用 SSL3 |
注意:
.rar包中若只含 DLL 但不含msodbcsql.msi,你必须单独下载并安装对应版本的 ODBC Driver(官网搜索 “Microsoft ODBC Driver for SQL Server Download”)。没有它,sqlsrv_connect()会返回false且sqlsrv_errors()为空数组——这是最典型的“黑匣子失败”。
3. 解压.rar后不要乱放:DLL 存放路径、php.ini 配置、扩展加载顺序全解析
你解压出的.rar包里通常含 4 类文件:php_pdo_sqlsrv_xxx.dll、php_sqlsrv_xxx.dll、msodbcsql*.dll(旧版)、msodbcsql17.dll(新版),以及可能的LICENSE.txt。别一股脑丢进ext/目录——放错位置、漏配参数、顺序颠倒,都会让扩展加载失败。
3.1 DLL 必须放在php/ext/下,且文件名必须与php.ini中extension=后名称完全一致
假设你确认 PHP 是8.2 TS x64 VC17,那么你应使用.rar中名为php_pdo_sqlsrv_82_ts_x64.dll和php_sqlsrv_82_ts_x64.dll的两个文件(注意:PDO 和原生 sqlsrv 是两个独立扩展,必须同时启用):
; php.ini 中添加(位置:在 extension_dir = "ext" 之后,其他 extension 之前) extension_dir = "D:/php/ext" extension=php_pdo_sqlsrv_82_ts_x64.dll extension=php_sqlsrv_82_ts_x64.dll逻辑说明:
php_pdo_sqlsrv_xxx.dll提供 PDO_SQLSRV 数据源(new PDO('sqlsrv:server=...')),php_sqlsrv_xxx.dll提供原生函数接口(sqlsrv_connect())。二者共存不冲突,但若只启一个,对应 API 就不可用。文件名中的_82_ts_x64必须与你php -v和check_php_profile.php输出完全一致,字母大小写、下划线、数字顺序一个都不能错。
3.2msodbcsql*.dll不要放进ext/!它必须由系统级 ODBC Driver 安装注册
.rar包中若含msodbcsql17.dll或msodbcsql18.dll,请立即删除它——这不是 PHP 扩展,而是 ODBC Driver 的核心组件,必须通过微软官方.msi安装包部署。手动复制 DLL 到System32或php/目录会导致:
sqlsrv_connect()返回false且无错误;odbc_connect()报错IM002(数据源名称未找到);- Windows 事件查看器中出现
The application failed to initialize properly (0xc000007b)。
正确做法:从微软官网下载对应版本的
msodbcsql.msi(如msodbcsql17.msi),以管理员身份运行安装。安装后,C:\Windows\System32\下会自动生成msodbcsql17.dll,并注册 ODBC 数据源管理器(odbcad32.exe)中的驱动条目。PHP 扩展只负责调用这个已注册的系统驱动,它自己不带任何数据库通信协议栈。
4. 常见问题排查:5 条血泪经验总结,每一条都来自真实翻车现场
4.1 现象:phpinfo()中看不到sqlsrv或pdo_sqlsrv模块,但php -m却显示已加载
→原因:Web 服务器(Apache/IIS)使用的php.ini与 CLI 使用的不是同一份。php -m读的是 CLI 的配置,而 Web 请求走的是 Apache 的LoadModule php_module指向的php.ini。
→解决:在 Web 环境下新建info.php,内容为<?php phpinfo(); ?>,访问http://localhost/info.php,搜索Loaded Configuration File,确认该路径下的php.ini已正确添加extension=行,并重启 Web 服务(不是仅重启 PHP-FPM)。
4.2 现象:连接成功(sqlsrv_connect()返回 resource),但sqlsrv_fetch_array()取不到中文字段,全是问号或空字符串
→原因:SQL Server 数据库/表/列的排序规则(Collation)为SQL_Latin1_General_CP1_CI_AS等非 UTF-8 兼容规则,而 PHP 扩展默认以UTF-8编码传输数据,导致乱码。
→解决:在连接选项中强制指定CharacterSet为UTF-8,且确保 SQL Server 实例启用UTF-8支持(SQL Server 2019+):
$connectionOptions = [ "Database" => "MyDB", "Uid" => "sa", "PWD" => "123", "CharacterSet" => "UTF-8", // 关键!必须显式声明 ]; $conn = sqlsrv_connect($serverName, $connectionOptions);4.3 现象:连接超时(sqlsrv_connect()返回 false),sqlsrv_errors()输出SQLSTATE: HYT00, Code: 0, Message: Login timeout expired
→原因:不是网络不通,而是 ODBC Driver 版本与 SQL Server 实例版本不兼容。例如用 ODBC Driver 17 连接 SQL Server 2022,默认启用Encrypt=true,但旧版驱动不支持新加密协议。
→解决:在连接选项中显式关闭加密(仅测试环境)或升级驱动:
$connectionOptions = [ "Database" => "MyDB", "Encrypt" => false, // 临时绕过,生产环境必须设为 true 并升级驱动 "TrustServerCertificate" => true, ];4.4 现象:sqlsrv_query()执行含datetime2或time(7)字段的查询,返回NULL
→原因:PHP Driver 5.9.0 及更早版本存在datetime2解析 Bug,无法正确转换高精度时间类型。
→解决:升级至Microsoft Drivers for PHP for SQL Server 5.10.0+(对应.rar包中5.10.0或更高版本的 DLL),并确认phpinfo()中sqlsrv模块版本号为5.10.0或更新。
4.5 现象:IIS 下一切正常,Apache 下sqlsrv_connect()报0x80070005 Access is denied
→原因:Apache 服务账户(默认Local System)无权访问 Windows Certificate Store,而 SQL Server 启用Encrypt=true时需验证证书链。
→解决:将 Apache 服务登录身份改为This account,输入当前有管理员权限的用户账号密码(如.\Administrator),然后重启 Apache 服务。
5. 连通性验证与生产就绪检查:写一个可复用的sqlsrv_health_check.php,覆盖 7 类关键场景
光能连上不叫稳,得知道它在什么条件下会断、断了怎么快速定位。我在线上环境维护的sqlsrv_health_check.php不是简单ping,而是模拟真实业务链路的 7 层探活脚本——它会触发连接、认证、编码、查询、事务、大字段、超时控制全部环节,并返回结构化 JSON,供监控系统采集。
5.1 健康检查脚本:sqlsrv_health_check.php
<?php // sqlsrv_health_check.php —— 生产环境必须部署的探针 header('Content-Type: application/json; charset=utf-8'); $startTime = microtime(true); $result = [ 'status' => 'fail', 'checks' => [], 'elapsed_ms' => 0, ]; // 1. 检查扩展是否加载 if (!extension_loaded('sqlsrv') || !extension_loaded('pdo_sqlsrv')) { $result['checks'][] = ['name' => 'extension_loaded', 'status' => 'fail', 'message' => 'sqlsrv or pdo_sqlsrv not loaded']; echo json_encode($result, JSON_UNESCAPED_UNICODE); exit; } $result['checks'][] = ['name' => 'extension_loaded', 'status' => 'ok']; // 2. 连接测试(含 Windows Auth / SQL Auth 双模式) $serverName = 'YOUR_SQL_SERVER'; $connectionOptions = [ 'Database' => 'master', 'CharacterSet' => 'UTF-8', 'LoginTimeout' => 5, ]; // 尝试 Windows 认证(域环境) $conn = sqlsrv_connect($serverName, $connectionOptions); if (!$conn) { // 回退到 SQL Server 认证 $connectionOptions['Uid'] = 'sa'; $connectionOptions['PWD'] = 'YourStrong@Passw0rd'; $conn = sqlsrv_connect($serverName, $connectionOptions); } if (!$conn) { $errors = sqlsrv_errors(); $result['checks'][] = [ 'name' => 'connection', 'status' => 'fail', 'message' => 'Connection failed: ' . json_encode($errors, JSON_UNESCAPED_UNICODE) ]; echo json_encode($result, JSON_UNESCAPED_UNICODE); exit; } $result['checks'][] = ['name' => 'connection', 'status' => 'ok']; // 3. 中文查询测试 $sql = "SELECT N'测试中文' AS chinese_text"; $stmt = sqlsrv_query($conn, $sql); if (!$stmt) { $errors = sqlsrv_errors(); $result['checks'][] = [ 'name' => 'utf8_query', 'status' => 'fail', 'message' => 'UTF-8 query failed: ' . json_encode($errors, JSON_UNESCAPED_UNICODE) ]; } else { $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC); if ($row['chinese_text'] !== '测试中文') { $result['checks'][] = [ 'name' => 'utf8_query', 'status' => 'fail', 'message' => 'UTF-8 encoding mismatch: got ' . $row['chinese_text'] ]; } else { $result['checks'][] = ['name' => 'utf8_query', 'status' => 'ok']; } } // 4. 大字段(varchar(max))读取测试 $sql = "SELECT REPLICATE('A', 100000) AS big_text"; $stmt = sqlsrv_query($conn, $sql); if ($stmt && sqlsrv_fetch($stmt)) { $bigText = sqlsrv_get_field($stmt, 0); if (strlen($bigText) < 99000) { $result['checks'][] = ['name' => 'large_text', 'status' => 'fail', 'message' => 'Large text truncated']; } else { $result['checks'][] = ['name' => 'large_text', 'status' => 'ok']; } } else { $result['checks'][] = ['name' => 'large_text', 'status' => 'fail', 'message' => 'Large text query failed']; } // 5. 事务回滚测试(验证连接池稳定性) $trans = sqlsrv_begin_transaction($conn); if ($trans) { sqlsrv_rollback($conn); $result['checks'][] = ['name' => 'transaction', 'status' => 'ok']; } else { $result['checks'][] = ['name' => 'transaction', 'status' => 'fail', 'message' => 'Transaction begin failed']; } sqlsrv_close($conn); $result['elapsed_ms'] = round((microtime(true) - $startTime) * 1000); $result['status'] = array_column($result['checks'], 'status') === array_fill(0, count($result['checks']), 'ok') ? 'ok' : 'fail'; echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); ?>参数说明:该脚本需部署在 Web 根目录,通过
curl http://localhost/sqlsrv_health_check.php调用。它返回 JSON,字段status为ok表示全链路健康;任一checks[].status为fail,则status为fail并附带具体错误。我把它集成进 Zabbix 的 Web Scenario,每 30 秒探测一次,一旦status变fail,立刻触发钉钉告警,比等用户投诉快 17 分钟。
5.2 生产环境 3 项强制就绪清单(不满足不准上线)
| 检查项 | 为什么必须做 | 如何验证 |
|---|---|---|
| ✅ ODBC Driver 已安装且为最新稳定版(17.10+ 或 18.3+) | 旧版存在 TLS 握手失败、datetime2解析崩溃等致命缺陷 | 运行odbcad32.exe→ “驱动程序”页签,确认ODBC Driver 17 for SQL Server版本号 ≥17.10.2.1 |
✅php.ini中extension_dir路径为绝对路径,且extension=行无分号注释 | 相对路径在 Apache 下常被解析为C:\Apache24\bin\ext,而非C:\php\ext | 在info.php中确认extension_dir值与实际 DLL 所在目录一致 |
✅ 连接字符串中显式设置'Encrypt' => true, 'TrustServerCertificate' => false | 防止中间人攻击,强制走证书校验;false表示必须由 Windows 证书存储提供可信 CA | 在健康检查脚本中将Encrypt设为true,若失败则说明证书链未配置,需联系 DBA 导入证书 |
我坚持在每个新项目上线前,用这个脚本跑满 3 天压力测试(每秒 50 次连接/查询),观察内存泄漏和连接池耗尽情况。曾经有个项目因没做第 3 项检查,在凌晨 2 点证书自动续期后,所有 PHP 连接瞬间中断——那次故障让我养成了「证书变更必同步通知 PHP 组」的习惯。希望帮到你。
本文还有配套的精品资源,点击获取