这些说明将指导你安装 PHP、Microsoft ODBC Driver for SQL Server,以及 SQLSRV 和 PDO_SQLSRV 扩展。 每个标签页都使用该标签页从中安装的仓库提供的 PHP 包,因此命令中的版本在不同标签页之间会有所不同。 如果该仓库提供不同的版本,请将其替换为 支持矩阵 中列出的另一个 PHP 版本。
SQLSRV 和 PDO_SQLSRV 驱动使用相同的 ODBC 依赖,可以独立安装。 如果你的应用同时使用两个驱动,就安装两个扩展。
在过程结束时,CLI 和所选的 Web 服务器运行时应加载两个扩展,两个 PHP API 都应可用,且每个 API 的示例应返回数据库服务器版本。
开始之前
选择当前驱动版本支持的 PHP 版本,并可用于你的操作系统发行版。
决定你需要哪些PHP运行时:
- 用于脚本、调度任务或工作程序的命令行界面。
- 用于Apache托管PHP的Apache模块。
- 用于 nginx 的 PHP-FPM 或 Apache FastCGI 配置。
确认操作系统架构。 已发布的Linux归档包含x64二进制文件,发布的macOS归档文件包含Arm64二进制文件。 PIE 适用于计算机上的 PHP 安装,是本文的主要安装路径。
安装 Microsoft ODBC 驱动和 unixODBC 开发包。 Microsoft 包负责数据库通信。 unixODBC 包提供了构建 SQLSRV 和 PDO_SQLSRV 所需的头文件。
计划在安装或更改扩展后重启所有 Web 服务器、PHP-FPM 池和长期运行的工作进程。
平台包管理器安装PHP和原生前置条件。 PIE负责构建和安装PHP扩展。 PHP 配置控制每个运行时是否加载它们。 ODBC 驱动在扩展加载后处理数据库通信和加密。
使用 PIE 安装驱动程序
PIE,即 PHP 扩展安装程序,是当前驱动版本中支持的扩展安装程序。 它取代了已被弃用的 PHP 扩展社区库(PECL) 工作流程。
请先完成以下各节中列出的平台先决条件,然后再安装驱动程序。 然后分别安装PIE和每个驱动:
安装PIE
PIE 运行于 PHP 8.1 及更高版本。 当你选择另一个PHP安装的开发工具时,它可以为该安装安装扩展。
请先安装 curl 和 GitHub CLI,然后再继续。 平台部分包括 curl,而最小安装可能不提供这些内容。
下载PIE PHP归档(PHAR),并在安装或运行前通过GitHub命令行界面(CLI)进行验证:
pie_tmp=$(mktemp -d)
curl -fL --output "$pie_tmp/pie.phar" https://github.com/php/pie/releases/latest/download/pie.phar
gh attestation verify --owner php "$pie_tmp/pie.phar"
只有在验证成功时才继续:
sudo install -m 755 "$pie_tmp/pie.phar" /usr/local/bin/pie
rm "$pie_tmp/pie.phar"
rmdir "$pie_tmp"
unset pie_tmp
临时目录是私有的,属于你的账户。 如果下载或验证失败,不要安装或运行PHAR。 在重试前先删除临时文件和目录。
确认已安装的 PHAR 可与你打算使用的 PHP 可执行文件一起运行:
php /usr/local/bin/pie --version
安装SQLSRV和PDO_SQLSRV驱动
在 Linux 和 macOS 上,PIE 会检查所需的编译器和 PHP 开发工具。 在运行 PIE 之前,先安装 ODBC 平台开发包和一个 C++ 编译器。 从交互式终端运行PIE。 当它需要权限将文件安装到系统目录时,可以要求你输入 sudo 密码。
PIE 以用于调用它的 PHP 安装为目标。 对于版本化安装,可以在每个安装命令中添加 --with-php-config 以选择该版本的开发工具。 例如,当预期工具为 pie install --with-php-config=/usr/bin/php-config8.4 microsoft/sqlsrv 时,使用 /usr/bin/php-config8.4。 将同样的选项应用到 microsoft/pdo_sqlsrv。 Alpine 使用版本化的可执行名; 请遵循 Alpine 命令 ,而非本节中未版本化的命令。
为每个扩展运行一条命令。 这些命令使用PIE默认的PHP安装:
pie install microsoft/sqlsrv
pie install microsoft/pdo_sqlsrv
PIE 尝试通过平台的 PHP 配置工具或条 extension= 目启用每个扩展,若无法启用则会警告。 PHP 为每个执行环境使用服务器应用程序接口(SAPI)。 在 Debian、Ubuntu 和 SUSE 上,命令行、Apache 和 PHP FastCGI Process Manager(PHP-FPM) 配置可能有所不同。 成功的命令行安装并不意味着 Web 服务器加载了驱动程序。
查看 php --ini 以获取命令行。 在为网页服务器创建临时 phpinfo() 页面之前,先 限制诊断页面的访问。 检查已加载的配置文件和每个运行时扫描的.ini文件。 如果缺少这些条目,请按照 在 Linux 和 macOS 上加载驱动程序 中的说明,以按正确的加载顺序添加它们。 配置更改后重启网页服务器或 PHP-FPM。 Red Hat 通常会在 SAPI 之间共享 php.ini ,但在依赖一次 PIE 运行前,请先验证当前的配置。
安装到你的平台上
选择您的操作系统和网页服务器配置。 完成该标签页的安装步骤,然后按照 “测试您的安装”操作。
在 Ubuntu 上安装
注释
以下命令使用 packages.sury.org PHP仓库,以便选择支持的PHP版本。 按照 Microsoft 官方说明安装适用于你的 Ubuntu 发行版的 ODBC 驱动程序。
步骤 1. 安装 PHP (Ubuntu)
sudo apt-get update
sudo apt-get install ca-certificates apt-transport-https curl gnupg2 lsb-release -y
sudo install -d -m 755 /etc/apt/keyrings
sudo curl -fsSL https://packages.sury.org/php/apt.gpg -o /etc/apt/keyrings/php.gpg
sudo chmod 644 /etc/apt/keyrings/php.gpg
echo "deb [signed-by=/etc/apt/keyrings/php.gpg] https://packages.sury.org/php/ $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/php.list
sudo apt-get update
sudo apt-get install php8.4 php8.4-dev php8.4-xml -y
步骤 2. 安装必备组件 (Ubuntu)
按照“在 Linux 上安装适用于 SQL Server 的 Microsoft ODBC 驱动程序”中的说明,然后安装开发头文件。
sudo apt-get install unixodbc-dev g++ make git -y
步骤 3. 安装带有 PIE 的 Microsoft SQL Server (Ubuntu) 的 PHP 驱动程序
按照“用 PIE 安装驱动”操作,并在两个安装命令中都添加 --with-php-config=/usr/bin/php-config8.4。 请使用 php8.4 --ini 检查命令行配置文件。
/usr/local/bin/pie install --with-php-config=/usr/bin/php-config8.4 microsoft/sqlsrv
/usr/local/bin/pie install --with-php-config=/usr/bin/php-config8.4 microsoft/pdo_sqlsrv
步骤 4. 安装 Apache 并配置驱动程序加载(Ubuntu)
sudo apt-get install apache2 libapache2-mod-php8.4 -y
sudo a2enmod php8.4
步骤 5. 重启 Apache 并测试示例脚本(Ubuntu)
sudo systemctl restart apache2
若要测试安装,请参阅本文档末尾 的“测试安装 ”。
旧版 PECL 安装
PECL 已弃用于当前驱动程序版本发布。 使用PIE进行新安装和升级。 如果已有部署被钉在 PECL,保持其包版本与 PHP 运行时保持一致,并计划迁移到 PIE。
测试你的安装
验证命令行运行时。 在 Alpine 上,将php替换为php84。 对于在其他发行版上的版本化 PHP 安装,可以使用其对应的可执行文件。
php --ri sqlsrv
php --ri pdo_sqlsrv
php -m | grep -E "sqlsrv|pdo_sqlsrv"
两个 --ri 命令都应打印包含 ExtensionVer的模块信息。 模块列表应包含单独的 sqlsrv 行和 pdo_sqlsrv 行。
在测试连接前,先使用 verify-php-drivers.php 验证两个 PHP API 接口:
<?php
$checks = [
'SQLSRV' => extension_loaded('sqlsrv') && function_exists('sqlsrv_connect'),
'PDO_SQLSRV' => extension_loaded('pdo_sqlsrv')
&& in_array('sqlsrv', PDO::getAvailableDrivers(), true),
];
$failed = false;
foreach ($checks as $name => $loaded) {
echo "$name: " . ($loaded ? 'loaded' : 'missing') . PHP_EOL;
$failed = $failed || !$loaded;
}
exit($failed ? 1 : 0);
预期输出:
SQLSRV: loaded
PDO_SQLSRV: loaded
对于 PHP-FPM 或网页服务器,在创建临时页面前先phpinfo()。 确认 已加载的配置文件、 extension_dir和两个驱动部分。 更改配置或更换扩展后,重启 PHP-FPM 或网页服务器。 验证后删除页面。
要测试实时连接,可以在系统文档根目录下创建一个名为 testsql.php 的文件。 该路径在 Ubuntu、Debian 和 Red Hat 上是 /var/www/html,在 SUSE 上是 /srv/www/htdocs,在 Alpine 上是 /var/www/localhost/htdocs,而在 macOS 上是 $(brew --prefix)/var/www。 在运行脚本之前,先为PHP进程设置 SQL_SERVER_NAME、 SQL_DATABASE、 SQL_UID和 SQL_PWD 环境变量。 不要在文档根目录下把凭证硬编码在文件里。
对于命令行测试,使用 交互式提示 设置环境变量,无需在shell历史中输入密码。
对于 Apache 模块测试,请勿将凭证放入网站通常可读的配置文件中:
在文档根节点外创建一个私有文件。 使用 Apache 配置目录中未使用的文件名。 在 Linux 上:
sudo install -o root -g root -m 600 /dev/null /etc/apache2/php-sql-driver-test.conf在 Red Hat 上,将
/etc/apache2替换为/etc/httpd。 在 macOS 上,使用启动 Homebrew Apache 的账户创建该文件:install -m 600 /dev/null "$(brew --prefix)/etc/httpd/php-sql-driver-test.conf"只有文件所有者和 root 用户能读取这些设置。 启动Apache的账户必须能够读取该文件。
在文本编辑器中编辑私有文件,添加以下条目:
SetEnv SQL_SERVER_NAME "tcp:<server>,1433" SetEnv SQL_DATABASE "<database>" SetEnv SQL_UID "<user_id>" SetEnv SQL_PWD "<password>"在双引号参数中,每个字面反斜杠写作
\",每个字面双引号写作\\。 在引号内保留前置和后置空格。 Apache也用${NAME}来替代引用。 如果某个值包含该序列或换行,则使用命令行测试。 更多信息请参见 Apache 配置引用和转义。在网站的虚拟主机内,添加一个
Files块,仅为testsql.php包含私有文件。 如果没有配置虚拟主机,则将该块置入主服务器配置。 用私有文件的绝对路径替换占位符:<Files "testsql.php"> Include "<absolute-path-to-private-file>" </Files>重启Apache。 测试后,移除你添加的
Files块,删除私有文件,然后重新启动Apache。 保留无关站点设置。
PHP-FPM 默认清除继承的环境变量,nginx不会将其环境传递给PHP-FPM。 仅在隔离的测试 PHP-FPM 服务和池中使用以下 Ubuntu 或 Red Hat 流程。 不要把测试凭据添加到运行其他应用的服务或池里:该池中的每个脚本都能读取它们。 如果你用的是共享主机,建议用命令行测试。
在文档根目录外创建一个root拥有的文件,例如
/etc/php-sql-driver-test.env,并限制访问:sudo touch /etc/php-sql-driver-test.env sudo chmod 600 /etc/php-sql-driver-test.env将连接设置添加到文件中:
SQL_SERVER_NAME="tcp:<server>,1433" SQL_DATABASE="<database>" SQL_UID="<user_id>" SQL_PWD="<password>"每个设置都各占一行。 在双引号中,对于每个字面反斜杠写
\\,对于每个字面双引号写\"。 美元符号和反引号不会被解释为 shell 表达式。 直接编辑文件,而不是在 shell 中运行它或执行 source 命令加载它。 更多信息请参见 systemd EnvironmentFile 语法。可以在 Ubuntu 上运行
sudo systemctl edit php-fpm,或在sudo systemctl edit php8.4-fpmRed Hat 上运行。 添加这个 systemd 覆盖配置:[Service] EnvironmentFile=/etc/php-sql-driver-test.env将这些条目添加到活跃 PHP-FPM 池配置中。 常见的位置包括 Ubuntu 上的
/etc/php/8.4/fpm/pool.d/www.conf和 Red Hat 上的/etc/php-fpm.d/www.conf:env[SQL_SERVER_NAME] = $SQL_SERVER_NAME env[SQL_DATABASE] = $SQL_DATABASE env[SQL_UID] = $SQL_UID env[SQL_PWD] = $SQL_PWD重新加载systemd并重启适用的 PHP-FPM 服务:
sudo systemctl daemon-reload sudo systemctl restart php8.4-fpm在 Red Hat 上,将
php8.4-fpm替换为php-fpm。
测试后,删除临时环境文件、你添加的 EnvironmentFile= 条目、测试池条目和 testsql.php。 只有当服务覆盖文件是为本次测试创建且没有其他设置时,才删除服务覆盖文件。 保留所有已有的覆盖项和池设置。 删除测试配置后,重新加载systemd并再次重启 PHP-FPM。
SQLSRV 示例
保持环境值不变。 每个示例在连接前都会检查并拒绝缺失或空的设置。 每个示例随后将右大括号加倍并添加外层大括号,然后将数据库名称、用户名和密码传递给驱动程序。 这种编码保留了字面大括号,并防止分号分隔连接选项。
<?php
$serverName = getenv('SQL_SERVER_NAME');
$databaseName = getenv('SQL_DATABASE');
$uid = getenv('SQL_UID');
$pwd = getenv('SQL_PWD');
if ($serverName === false || $serverName === ''
|| $databaseName === false || $databaseName === ''
|| $uid === false || $uid === ''
|| $pwd === false || $pwd === '') {
handle_failure("Set SQL_SERVER_NAME, SQL_DATABASE, SQL_UID, and SQL_PWD.");
}
$databaseName = '{' . str_replace('}', '}}', $databaseName) . '}';
$uid = '{' . str_replace('}', '}}', $uid) . '}';
$pwd = '{' . str_replace('}', '}}', $pwd) . '}';
$connectionOptions = array(
"Database" => $databaseName,
"UID" => $uid,
"PWD" => $pwd,
"Encrypt" => 1,
"TrustServerCertificate" => 0
);
function handle_failure($message) {
error_log($message);
http_response_code(500);
echo "<h1>Failure</h1>";
echo "An error occurred. Check the server error log for details.";
exit(1);
}
function format_errors($errors) {
$lines = [];
foreach ($errors as $error) {
$lines[] = "SQLSTATE: {$error['SQLSTATE']}, code: {$error['code']}, message: {$error['message']}";
}
return implode(PHP_EOL, $lines);
}
$conn = sqlsrv_connect($serverName, $connectionOptions);
if ($conn === false) {
handle_failure(format_errors(sqlsrv_errors()));
}
$tsql = "SELECT @@Version AS SQL_VERSION";
$stmt = sqlsrv_query($conn, $tsql);
if ($stmt === false) {
handle_failure(format_errors(sqlsrv_errors()));
}
$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
if ($row === null || $row === false) {
handle_failure("Query returned no rows.");
}
echo "<h1>Success</h1>";
echo htmlspecialchars($row['SQL_VERSION']);
sqlsrv_free_stmt($stmt);
sqlsrv_close($conn);
?>
PDO_SQLSRV 示例
<?php
$serverName = getenv('SQL_SERVER_NAME');
$databaseName = getenv('SQL_DATABASE');
$uid = getenv('SQL_UID');
$pwd = getenv('SQL_PWD');
if ($serverName === false || $serverName === ''
|| $databaseName === false || $databaseName === ''
|| $uid === false || $uid === ''
|| $pwd === false || $pwd === '') {
handle_failure(new RuntimeException("Set SQL_SERVER_NAME, SQL_DATABASE, SQL_UID, and SQL_PWD."));
}
$databaseName = '{' . str_replace('}', '}}', $databaseName) . '}';
$uid = '{' . str_replace('}', '}}', $uid) . '}';
$pwd = '{' . str_replace('}', '}}', $pwd) . '}';
function handle_failure($exception) {
error_log($exception->getMessage());
http_response_code(500);
echo "<h1>Failure</h1>";
echo "An error occurred. Check the server error log for details.";
exit(1);
}
try {
$conn = new PDO(
"sqlsrv:server=$serverName;Database=$databaseName;Encrypt=1;TrustServerCertificate=0",
$uid,
$pwd
);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$tsql = "SELECT @@Version AS SQL_VERSION";
$stmt = $conn->query($tsql);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if ($row === false) {
throw new RuntimeException("Query returned no rows.");
}
echo "<h1>Success</h1>";
echo htmlspecialchars($row['SQL_VERSION']);
} catch (Throwable $exception) {
handle_failure($exception);
}
unset($stmt);
unset($conn);
?>
将浏览器指向 http://localhost/testsql.php (http://localhost:8080/testsql.php 在 macOS 上)。 连接成功时,数据库服务器的版本字符串会显示。 这两个示例都会将错误详细信息写入 PHP 错误日志。 如果页面显示失败,请查看该日志。
要比较命令行和网页服务器的行为,请为终端设置相同的环境变量并运行:
php testsql.php
如果命令行运行成功但浏览器中没有任何提示,请检查 Apache日志文件。 如需更多帮助,请参见 PHP SQL 驱动的支持资源。
分别评估SQL Server、Azure SQL 数据库、Azure SQL 托管实例、Azure Synapse Analytics、Microsoft Fabric中的SQL数据库和Microsoft Fabric中的Warehouse的连接程序。 所选的认证方法、连接选项和查询必须得到目标的支持。 安装在客户端进行。 成功的扩展检查并不能证明目标是否接受凭证、信任客户端或支持所有数据库功能。
排查安装问题
| 问题 | 所属图层 | 纠正措施 |
|---|---|---|
PIE 找不到 phpize、php-config 或标头 |
PHP 开发包 | 安装目标PHP版本的开发包,并传递匹配 --with-php-config 选项 |
| 编译失败是因为缺少一个 C++ 编译器 | 操作系统构建工具 | 安装平台的C++编译器包,例如 g++ 或 gcc-c++ |
编译找不到 sql.h |
ODBC 开发包或编译器路径 | 安装 unixodbc-dev 或 unixODBC-devel;在 Apple 芯片上,设置 Homebrew include 和库标志 |
php --ri 提示没有扩展功能 |
PHP 配置 | 检查已加载的php.ini和扫描目录,添加正确的条目,然后重新开始流程 |
PDO报告 could not find driver |
PDO_SQLSRV 加载或 PDO 加载顺序 | 先确认 PDO 加载成功,PDO_SQLSRV 使用后续扫描的配置文件 |
| CLI 能用,但 Apache、nginx 或 PHP-FPM 失败 | SAPI 专用配置 | 将CLI输出与 phpinfo()对比,配置网页SAPI,并重启 web SAPI |
| nginx 向浏览器返回 HTTP 502 | nginx 到 PHP-FPM 的路由配置 | 检查 fastcgi_pass 套接字是否匹配安装的 PHP-FPM 版本,确认服务是否正常运行 |
| 浏览器示例报告环境值缺失 | 网页服务器或 PHP-FPM 环境 | 配置所选Web运行时的变量,然后重启它 |
| 扩展程序已加载,但连接失败 | ODBC、网络、证书、认证或SQL产品 | 读取服务器日志中的 SQLSTATE 和本地错误;除非错误表明存在加载或二进制兼容性问题,否则不要重建扩展 |
移除临时测试配置
验证后:
删除文档根目录中的
verify-php-drivers.php、testsql.php以及任何临时phpinfo()页面。移除临时凭证和环境转发条目。
更改 systemd 覆盖后重新加载服务管理器,然后重启 PHP-FPM 或 Web 服务器。
保留应用所需的扩展条目和已安装的包。