在 Windows 上安裝 SQL Server 的 PHP 驅動程式

請使用這篇文章在 Windows 上安裝 PHP 適用的 SQLSRV 和 PDO_SQLSRV 驅動程式。 這些驅動程式是使用 Microsoft ODBC Driver for SQL Server 的 PHP 擴充套件。

開始前,請確認你的 PHP 版本、架構及執行緒安全模式是否在 支援矩陣中被支援。 命令列程序使用的 PHP 執行時與網頁伺服器使用的執行時可以使用不同的 php.ini 檔案。 分別配置並驗證每個執行環境。

在完成此程序後,sqlsrv_connect() 和 PDO sqlsrv 驅動程式都應可供預期的 CLI 或網頁應用程式使用,且每個 API 都應完成一次測試查詢。 僅僅成功複製檔案並不代表安裝完成。

選擇安裝方法

方法 在下列情況下使用 安裝的內容
PHP 擴充套件安裝程式(PIE) 你希望安裝程式為 PHP 執行檔選擇驅動程式版本 未版本化的 php_sqlsrv.dll 和 php_pdo_sqlsrv.dll,已嘗試自動配置
已發布的 ZIP 套件 你需要自行選擇、檢查或部署確切的預先建置檔案 依 PHP 次要版本、執行緒安全模式及架構選擇的版本控制 DLL

對兩個擴充功能都使用同一種方法。 不要同時啟用 PIE 和 ZIP 的設定項目。

安裝先決條件

  1. 從 PHP for Windows 網站安裝支援的 PHP 編譯版。 將 PHP 目錄加入PATH。

  2. 安裝你 PHP 建置所需的 Visual C++ Redistributable。 將其 x64 或 x86 架構與 PHP 相匹配,如 PHP for Windows 需求所述。

  3. 安裝最新的 Microsoft ODBC Driver for SQL Server。

  4. 執行以下指令以確認 PHP 執行時及設定檔:

    php --version
    php --ini
    

    如果 載入的設定檔 是 (none),則在 PHP 目錄中將 php.ini-development 複製到 php.ini。

  5. 在 php.ini中,設定擴充功能目錄並啟用 PHP 擴充套件安裝程式(PIE)所需的擴充功能:

    extension_dir = "ext"
    extension=openssl
    extension=zip
    
  6. 確認 PHP 能找到前置擴充功能:

    php --ri openssl
    php --ri zip
    

    在下載 PIE 前先修正這些必要條件。

使用 PIE 進行安裝

PIE 安裝了與 PHP 執行環境相符的預編譯擴充套件。 在 Windows 上不需要 C 編譯器。

  1. 切換到可寫入的目錄,並下載最新的 PIE PHP 壓縮檔(PHAR):

    curl.exe -fL --output pie.phar https://github.com/php/pie/releases/latest/download/pie.phar
    

    其餘的 PIE 指令以 .\pie.phar 指稱該檔案,因此請從同一個目錄執行這些指令。

    在執行 PHAR 之前,請先用 GitHub 命令列介面(CLI)驗證:

    gh attestation verify --owner php .\pie.phar
    

    繼續前請確認下載:

    dir pie.phar
    php .\pie.phar --version
    
  2. 分別安裝每個驅動程式:

    php .\pie.phar install microsoft/sqlsrv
    php .\pie.phar install microsoft/pdo_sqlsrv
    
  3. 驗證命令列執行環境:

    php --ri sqlsrv
    php --ri pdo_sqlsrv
    php -m | findstr /I "sqlsrv pdo_sqlsrv"
    

PIE 嘗試在命令列執行檔所使用的設定中啟用擴充功能。 如果 PIE 回報無法啟用擴充功能,請新增 PIE 專屬的擴充功能條目。

如果你的網頁伺服器使用另一個 PHP 安裝,請先安裝這兩個驅動程式,且需符合該安裝的 PHP 版本、架構與執行緒安全模式,再進行設定。 如果同一個 PHP 安裝在網頁伺服器上使用不同的 php.ini,請在該檔案中啟用已安裝的驅動程式。 另外檢查 Web 執行階段,並在更改設定後重新啟動網頁伺服器。

PIE 會變更所選的 PHP 安裝版本。 它不會設定 IIS、選擇 IIS 站點,或重新啟動現有的 PHP 程序。

手動安裝已發布的 ZIP 套件

當你需要自己選擇驅動檔案或 PIE 不適合時,可以用這個方法。

  1. 請從 Microsoft Drivers for PHP for SQL Server releases 頁面下載已發行的驅動程式版本的 Windows ZIP 檔。

  2. 執行 php -i | findstr /I "PHP Version Thread Safety Architecture extension_dir" 並記錄 PHP 版本、執行緒安全模式、架構及擴充功能目錄。

  3. 從 ZIP 檔案中,將兩個相符的動態連結函式庫(DLL)複製到擴充功能目錄:

    php_sqlsrv_<php-version>_<ts-or-nts>_<x86-or-x64>.dll
    php_pdo_sqlsrv_<php-version>_<ts-or-nts>_<x86-or-x64>.dll
    

    例如,PHP 8.5 x64 執行緒安全執行階段會使用 php_sqlsrv_85_ts_x64.dll 和 php_pdo_sqlsrv_85_ts_x64.dll。

  4. 將相符的擴充功能名稱新增至執行階段所使用的 php.ini:

    extension=php_sqlsrv_85_ts_x64.dll
    extension=php_pdo_sqlsrv_85_ts_x64.dll
    

    將 ts、x64 和 85 替換為你的 PHP 執行階段的值。 不要混用安全執行緒與非執行緒安全檔案、32位元與64位元檔案,或是為其他PHP小版本所編譯的檔案。

  5. 使用 php --ri sqlsrv、php --ri pdo_sqlsrv 和 php -m 驗證執行階段。 對於網頁伺服器,在建立臨時頁面前,先phpinfo()權限。 確認 已載入的設定檔 和兩個驅動程式區塊,然後移除該頁面。

設定網頁伺服器

對於 IIS,請依照 php-cgi.exe 將目標 設定為 FastCGI 應用程式。 確認 FastCGI 應用程式使用與你安裝驅動程式相同的 PHP 目錄和架構。

針對任何 Windows 網頁伺服器:

  1. phpinfo(),然後再建立臨時 頁面。 識別網頁伺服器的 PHP 執行檔與作用中的 php.ini。

  2. 確保這兩個驅動程式都已安裝於 Web 執行階段。 若是獨立安裝 PHP 版本,請使用 PIE 搭配該安裝的 PHP 執行檔,或將兩個相符的 DLL 從已發佈的 ZIP 複製到其擴充目錄。 將驅動程式條目加入網頁執行時的設定,包括僅在其 php.ini 與 CLI 不同時也是如此。

  3. 重新啟動網頁伺服器或 FastCGI 程序。

  4. 請確認該頁面包含分開的 sqlsrv 與 pdo_sqlsrv 區段。

  5. 刪除該 phpinfo() 頁面。

測試兩個 PHP API

將此程式儲存為 verify-php-drivers.php:

<?php
$failures = [];

if (!extension_loaded('sqlsrv') || !function_exists('sqlsrv_connect')) {
    $failures[] = 'SQLSRV is not available.';
}

if (!extension_loaded('pdo_sqlsrv') || !in_array('sqlsrv', PDO::getAvailableDrivers(), true)) {
    $failures[] = 'PDO_SQLSRV is not available.';
}

echo $failures === []
    ? "SQLSRV and PDO_SQLSRV are available." . PHP_EOL
    : implode(PHP_EOL, $failures) . PHP_EOL;

exit($failures === [] ? 0 : 1);

先從命令列執行:

php verify-php-drivers.php

預期產出:

SQLSRV and PDO_SQLSRV are available.

如果你需要驗證網頁執行環境,請暫時將檔案放在網站的文件根目錄,並在瀏覽器中請求該檔案。 測試後再取下。 此程式能驗證 PHP API,且不要求或公開資料庫憑證。

測試資料庫連線

擴充功能載入只是首次安裝檢查。 將兩個 API 都針對應用程式使用的資料庫目標進行測試,因此測試同時涵蓋 ODBC 驅動程式、網路路徑、加密、認證、查詢執行、回傳值及清理。

在 PowerShell 中透過回應提示來設定臨時環境變數。 以原始值輸入伺服器和資料庫名稱,無需引號或驅動程式編碼。 使用可連線至資料庫的測試帳號憑證對話方塊或提示。 請不要在命令列或錄製的終端機會話中加入憑證:

$env:SQL_SERVER_NAME = Read-Host "Server name (tcp:<server>,1433)"
$env:SQL_DATABASE = Read-Host "Database name"
$credential = Get-Credential -Message "Enter the database test account"
if ($null -eq $credential) {
    throw "Database test credentials are required."
}
$env:SQL_UID = $credential.UserName
$env:SQL_PWD = $credential.GetNetworkCredential().Password
Remove-Variable credential

認證提示會遮蔽密碼。 環境包含明文密碼,讓 PHP 能讀取。 這些變數只在測試時使用,不要列印,測試後再清除。

將此程式儲存為 test-php-drivers.php。 保持環境值不變。 程式會將右大括號加倍並增加外層大括號,然後將資料庫名稱、使用者名稱和密碼傳給驅動程式。 此編碼保留了字面上的大括號,並防止分號分隔連接選項。

<?php
$serverName = getenv('SQL_SERVER_NAME');
$database = getenv('SQL_DATABASE');
$uid = getenv('SQL_UID');
$pwd = getenv('SQL_PWD');

if ($serverName === false || $serverName === ''
    || $database === false || $database === ''
    || $uid === false || $uid === ''
    || $pwd === false || $pwd === '') {
    fwrite(STDERR, "Set SQL_SERVER_NAME, SQL_DATABASE, SQL_UID, and SQL_PWD." . PHP_EOL);
    exit(1);
}

$database = '{' . str_replace('}', '}}', $database) . '}';
$uid = '{' . str_replace('}', '}}', $uid) . '}';
$pwd = '{' . str_replace('}', '}}', $pwd) . '}';

$connectionOptions = [
    "Database" => $database,
    "UID" => $uid,
    "PWD" => $pwd,
    "Encrypt" => 1,
    "TrustServerCertificate" => 0,
];

$sqlsrvConnection = sqlsrv_connect($serverName, $connectionOptions);
if ($sqlsrvConnection === false) {
    foreach (sqlsrv_errors() as $error) {
        fwrite(
            STDERR,
            "SQLSRV {$error['SQLSTATE']} ({$error['code']}): {$error['message']}" . PHP_EOL
        );
    }
    exit(1);
}

$sqlsrvStatement = sqlsrv_query($sqlsrvConnection, "SELECT 1 AS TEST_VALUE");
if ($sqlsrvStatement === false) {
    foreach (sqlsrv_errors() as $error) {
        fwrite(
            STDERR,
            "SQLSRV {$error['SQLSTATE']} ({$error['code']}): {$error['message']}" . PHP_EOL
        );
    }
    sqlsrv_close($sqlsrvConnection);
    exit(1);
}

$sqlsrvRow = sqlsrv_fetch_array($sqlsrvStatement, SQLSRV_FETCH_ASSOC);
if ($sqlsrvRow === false || $sqlsrvRow === null || (int) $sqlsrvRow['TEST_VALUE'] !== 1) {
    fwrite(STDERR, "SQLSRV returned an unexpected result." . PHP_EOL);
    sqlsrv_free_stmt($sqlsrvStatement);
    sqlsrv_close($sqlsrvConnection);
    exit(1);
}

echo "SQLSRV query: 1" . PHP_EOL;
sqlsrv_free_stmt($sqlsrvStatement);
sqlsrv_close($sqlsrvConnection);

$failed = false;
try {
    $pdoConnection = new PDO(
        "sqlsrv:server=$serverName;Database=$database;Encrypt=1;TrustServerCertificate=0",
        $uid,
        $pwd,
        [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
    );
    $pdoStatement = $pdoConnection->query("SELECT 1 AS TEST_VALUE");
    $pdoRow = $pdoStatement->fetch(PDO::FETCH_ASSOC);
    if ($pdoRow === false || (int) $pdoRow['TEST_VALUE'] !== 1) {
        throw new RuntimeException("PDO_SQLSRV returned an unexpected result.");
    }

    echo "PDO_SQLSRV query: 1" . PHP_EOL;
} catch (Throwable $exception) {
    fwrite(STDERR, $exception->getMessage() . PHP_EOL);
    $failed = true;
} finally {
    unset($pdoStatement);
    unset($pdoConnection);
}

exit($failed ? 1 : 0);

用你驗證過的同一個 PHP 執行檔執行程式:

php test-php-drivers.php

預期產出:

SQLSRV query: 1
PDO_SQLSRV query: 1

如果擴充檢查通過但此程式失敗,則使用 SQLSTATE 與原生錯誤來識別其所屬層。 不要因為網路、憑證、認證或資料庫權限錯誤而重新安裝 PHP 擴充功能。

測試後移除腳本和暫存變數:

Remove-Item .\verify-php-drivers.php, .\test-php-drivers.php
Remove-Item Env:\SQL_SERVER_NAME, Env:\SQL_DATABASE, Env:\SQL_UID, Env:\SQL_PWD

Troubleshooting

徵兆 要檢查的事項 修復
Could not open input file: .\pie.phar 目前目錄與下載位置 返回包含已驗證 PHAR 的目錄,或重新下載並再次驗證它
Unable to load dynamic library extension_dir、精確的 DLL 名稱、PHP 小版本、架構及執行緒安全模式 選擇匹配的 DLL,或用預期的 PHP 執行檔重執行 PIE
The specified module could not be found 驅動程式 DLL 相依性 確認 DLL 擴充套件是否存在,安裝對應的 Visual C++ Redistributable,並檢查任何剩餘缺少的 DLL 相依性
CLI 會載入兩個驅動程式,但 IIS 不會 不同的 PHP 執行檔或 php.ini 比較php --ini與phpinfo(),配置 IIS 執行環境,並重新啟動 FastCGI
Module "sqlsrv" is already loaded 無論是 PIE 還是 ZIP 條目,或重複條目 保留一個 SQLSRV 條目和一個 PDO_SQLSRV 條目
PDO報表 could not find driver PDO_SQLSRV 配置 執行 php --ri pdo_sqlsrv 去檢查 PDO::getAvailableDrivers()
PIE 顯示成功,但舊版本仍然存在 版本化的 ZIP 項目仍處於作用中 將舊項目替換成 PIE 未版本的 DLL 項目,並重新啟動所有 PHP 程序

如果兩個擴充功能都載入,PHP 可以呼叫它們的 API。 在更改驅動程式檔案前,先擷取 SQLSRV 錯誤或 PDO 例外。 重新安裝 PHP 擴充功能無法解決網路、認證、加密、憑證和資料庫權限錯誤。