在 Linux 和 macOS 上安裝 Microsoft 的 PHP 驅動程式

這些說明會安裝 PHP、Microsoft ODBC 驅動程式 for SQL Server,以及 SQLSRV 和 PDO_SQLSRV 擴充功能。 每個分頁都使用其安裝來源的儲存庫所提供的 PHP 套件,因此指令中的版本會因分頁而異。 如果該軟體庫提供不同的 PHP 版本,請用 支援對照表 中列出的另一個 PHP 版本來取代它。

SQLSRV 與 PDO_SQLSRV 驅動程式使用相同的 ODBC 相依性,且可獨立安裝。 如果你的應用程式同時使用這兩個驅動程式,請同時安裝兩個擴充功能。

程序結束時,CLI 與所選網頁伺服器執行時應載入兩個擴充功能,兩個 PHP API 皆可用,且每個 API 的範例應回傳資料庫伺服器版本。

開始之前

  1. 選擇目前驅動版本支援且可用於目前作業系統版本的 PHP 版本。

  2. 決定你需要哪些 PHP 執行環境:

    • CLI 用於腳本、排程任務或背景工作程序。
    • 適用於由 Apache 託管的 PHP 的 Apache 模組
    • PHP-FPM nginx 或 Apache FastCGI 配置。
  3. 確認作業系統架構。 已發佈的 Linux 壓縮檔包含 x64 二進位檔,而已發布的 macOS 壓縮檔則包含 Arm64 二進位檔。 PIE 會為電腦上的 PHP 安裝建置,並且是本文中的主要安裝路徑。

  4. 安裝 Microsoft ODBC 驅動程式及 UnixODBC 開發套件。 Microsoft 套件負責資料庫通訊。 UnixODBC 套件提供建置 SQLSRV 與 PDO_SQLSRV 所需的標頭。

  5. 安裝或更改擴充功能後,計劃重新啟動所有網頁伺服器、PHP-FPM 池和長時間執行的工作程序。

平台套件管理器會安裝 PHP 及原生的前置條件。 PIE 負責編譯並安裝 PHP 擴充功能。 PHP 設定控制每個執行環境是否載入它們。 ODBC 驅動程式負責擴充功能載入後的資料庫通訊與加密。

用 PIE 安裝驅動程式

PIE,即 PHP 擴充套件安裝程式,是目前驅動程式版本中支援的擴充套件安裝程式。 它取代了已淘汰的 PHP 擴充社群函式庫(PECL) 工作流程。

在安裝驅動程式前,請先完成以下各節的平台前置條件。 然後分別安裝 PIE 和每個驅動程式:

安裝 PIE

PIE 可運行於 PHP 8.1 及更新版本。 當你選擇另一個 PHP 安裝的開發工具時,它可以將擴充功能安裝到另一個 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) 配置可能有所不同。 成功的命令列安裝並不代表網頁伺服器載入了驅動程式。

命令列請參閱 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 上安裝 Microsoft SQL Server 的 ODBC 驅動程式,然後安裝開發標頭。

sudo apt-get install unixodbc-dev g++ make git -y

步驟 3. 安裝 Microsoft SQL Server 的 PHP 驅動程式,搭配 PIE(Ubuntu)

請依照 「用 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 模組測試,請將憑證排除在網站一般可讀的設定檔之外:

  1. 在文件根目錄外建立一個私人檔案。 請使用Apache設定目錄中未使用的檔名。 在 Linux 上:

    sudo install -o root -g root -m 600 /dev/null /etc/apache2/php-sql-driver-test.conf
    

    在 Red Hat 上,請將 /etc/httpd 替換為 /etc/apache2。 在 macOS 上,以啟動 Homebrew Apache 的帳號建立該檔案:

    install -m 600 /dev/null "$(brew --prefix)/etc/httpd/php-sql-driver-test.conf"
    

    只有檔案擁有者和 root 能讀取這些設定。 啟動 Apache 的帳號必須能讀取該檔案。

  2. 在文字編輯器中編輯私人檔案,並新增以下條目:

    SetEnv SQL_SERVER_NAME "tcp:<server>,1433"
    SetEnv SQL_DATABASE "<database>"
    SetEnv SQL_UID "<user_id>"
    SetEnv SQL_PWD "<password>"
    

    在雙引號參數中,對每個字面反斜線寫入 \",並對每個字面雙引號寫入 \\。 在引號內保留前置和後置空格。 Apache 也會用 ${NAME} 參照代替。 如果某個值包含該序列或換行,則改用命令列測試。 欲了解更多資訊,請參閱 Apache 設定中的引號與逸出。

  3. 在網站的虛擬主機內,新增一個 Files 區塊,僅對 testsql.php 包含私人檔案。 若未設定虛擬主機,則將區塊置於主伺服器設定中。 將佔位符替換為私有檔案的絕對路徑:

    <Files "testsql.php">
        Include "<absolute-path-to-private-file>"
    </Files>
    
  4. 重新啟動 Apache。 測試後,移除 Files 你新增的區塊,刪除私有檔案,然後重新啟動 Apache。 保留其他網站設定。

PHP-FPM 預設會清除繼承的環境變數,nginx 也不會把環境傳給 PHP-FPM。 請僅在獨立測試 PHP-FPM 服務與集區下使用以下 Ubuntu 或 Red Hat 程序。 不要把測試憑證加到執行其他應用程式的服務或池裡:池裡的每個腳本都能讀取這些憑證。 如果你用共享主機,建議改用命令列測試。

  1. 建立一個位於文件根目錄外、由 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 語法。

  2. 可以在 Ubuntu 上執行 sudo systemctl edit php-fpm,或在 Red Hat 上執行 sudo systemctl edit php8.4-fpm。 新增這個 systemd 覆寫:

    [Service]
    EnvironmentFile=/etc/php-sql-driver-test.env
    
  3. 將這些項目加入目前使用中的 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
    
  4. 重新載入 systemd 並重新啟動適用的 PHP-FPM 服務:

    sudo systemctl daemon-reload
    sudo systemctl restart php8.4-fpm
    

    在 Red Hat 上,請將 php-fpm 替換為 php8.4-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(在 macOS 上為http://localhost:8080/testsql.php)。 連線成功時會顯示資料庫伺服器的版本字串。 這兩個例子都寫入 PHP 錯誤日誌。 如果頁面顯示失敗訊息,請檢查那個日誌。

要比較命令列與網頁伺服器的行為,請為終端機設定相同的環境變數並執行:

php testsql.php

如果從命令列執行成功但瀏覽器中沒有顯示任何訊息,請檢查 Apache 日誌檔案。 如需更多協助,請參閱 PHP SQL 驅動程式的支援資源。

分別評估 SQL Server、Azure SQL Database、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 Silicon 上,設定 Homebrew include 和 library flags
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,然後重新啟動它
nginx 回傳 HTTP 502 給瀏覽器 nginx 轉 PHP-FPM 路由設定 檢查 fastcgi_pass 通訊端是否符合已安裝的 PHP-FPM 版本,確認服務是否正常運作
瀏覽器範例會回報缺少的環境值 網頁伺服器或 PHP-FPM 環境 設定所選網頁執行階段的變數,然後重新啟動該執行階段
擴充功能已載入,但連線失敗 ODBC、網路、憑證、認證或 SQL 產品 從伺服器日誌讀取 SQLSTATE 和原生錯誤;除非錯誤顯示載入或二進位相容性,否則不要重建擴充功能

移除臨時測試設定

驗證後:

  1. 從文件根目錄中刪除 verify-php-drivers.php、testsql.php 以及任何暫存的 phpinfo() 頁面。

  2. 移除臨時憑證和環境轉送項目。

  3. 當你更改 systemd 覆寫時,重新載入服務管理員,然後重新啟動 PHP-FPM 或網頁伺服器。

  4. 保留應用程式所需的擴充功能條目和已安裝的套件。