用於 SQL Server 之 PHP 的 Microsoft 驅動程式

下載 PHP 驅動程式

Microsoft PHP for SQL Server 驅動程式是 PHP 擴充功能,允許你從 PHP 腳本讀寫 Microsoft SQL 資料庫引擎 中的資料。 該套件附帶兩個驅動程式,這些驅動程式都包裹相同的 Microsoft ODBC 驅動程式 for SQL Server,且共享相同的連線選項,因此你可以選擇適合你程式碼庫的 API:

  • SQLSRV 會暴露一個針對 SQL Server 功能量身打造的程序式 API(sqlsrv_*函式)。
  • PDO_SQLSRV實作了 PHP 資料物件(PDO)介面,因此已使用 PDO 用於其他資料庫的程式碼也能以最小的修改來鎖定SQL Server。

兩個驅動程式都連接 Azure SQL Database、Microsoft Fabric 中的 SQL 資料庫、Azure SQL 受控執行個體,以及所有支援的 SQL Server 版本(包括 Express 版本)。 它們使用 PHP 串流來移動大型二進位和字元值,且不會完全載入記憶體。

選擇你的起點

目標 從這裡開始
建立一個 PHP 開發環境,執行你的第一個查詢 步驟 1:設定開發環境,接著步驟 2:建立 SQL 資料庫 ,步驟 3:使用 PHP 連接 SQL 的概念驗證
請在 Linux 或 macOS 上安裝驅動程式 Linux 和 macOS 的安裝教學,並下載 Microsoft PHP 驅動程式 for SQL Server
Connect to Azure SQL with passwordless authentication 使用 Microsoft Entra 認證連線選項連線。
讓現有應用程式具備對短暫故障的韌性 置連線韌性步驟四:用 PHP 韌性連接 SQL
在 SQLSRV 和 PDO_SQLSRV 之間做決定 PHP Microsoft 驅動程式概述,用於SQL Server執行函式比較
診斷安裝、連線或查詢問題 故障排除處理錯誤與警告,以及 日誌活動
讓現有應用程式更快 性能調校

快速連線

以下片段是可用 PHP 安裝對 SQL Server 或 Azure SQL 執行的最短端對端連線。 用它確認你的驅動程式、ODBC 相依關係和網路路徑是否已接線,然後再進入下一節的生產基線。

<?php
$server   = getenv('SQL_SERVER')   ?: 'localhost';
$database = getenv('SQL_DATABASE') ?: 'master';
$user     = getenv('SQL_USER');
$password = getenv('SQL_PASSWORD');

$dsn = "sqlsrv:Driver={ODBC Driver 18 for SQL Server};Server=$server;Database=$database;Encrypt=true";
$pdo = new PDO($dsn, $user, $password, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);

foreach ($pdo->query('SELECT @@VERSION AS version') as $row) {
    echo $row['version'], PHP_EOL;
}

對於對 Azure SQL 的無密碼連線,可以在 DSN 中加入Authentication=ActiveDirectoryMsi(managed identity)或其他Authentication值,然後丟棄$user/$password參數。 接下來的生產基線則會透過重試、超時和診斷來擴展相同的模式。

對於使用自簽憑證的本地 SQL Server,Encrypt=true驗證失敗。 新增 TrustServerCertificate=true 只針對地方開發。 請參閱 TLS 憑證錯誤 以了解生產替代方案。

Azure SQL 的生產環境基準

使用此片段作為與 PDO_SQLSRV 驅動程式建立生產導向Azure SQL連線的起點。 它會從環境變數(例如 Azure App 服務 應用程式設定)讀取伺服器和資料庫,使用管理身份驗證,啟用傳輸層安全(TLS)並驗證伺服器憑證,設定登入逾時以涵蓋冷啟動故障轉移,並設定 ConnectRetryCountConnectRetryInterval SQL Server 閒置連線韌性。 應用程式層 connectWithRetry 級與 queryWithRetry 輔助工具會以有界指數退讓包覆初始連線與每個語句,並將暫態連線錯誤(需要重新連線)與暫態查詢錯誤(重複使用同一連線)區分開來。

需要 PHP 8.0 及更新版本、PDO_SQLSRV 擴充功能,以及 SQL Server 17.3.1.1 及更新版本的 Microsoft ODBC 驅動程式。Authentication=ActiveDirectoryMsi 完整支援Authentication的數值清單,請參見使用 Microsoft Entra 認證連接

<?php
declare(strict_types=1);

// Transient errors that require a fresh connection to recover. SQLSTATE values
// starting with '08' cover ODBC connection-established and connection-broken
// states (for example, 08001, 08S01).
const CONNECT_RETRY_SQLSTATE_PREFIX = '08';

// SQL Server error codes that are transient regardless of when they surface:
// 1205 (deadlock victim), 1222 (lock request timeout), and the Azure SQL
// throttling, mid-query failover, and "database not currently available"
// codes that arrive with SQLSTATE HY000.
const TRANSIENT_SERVER_ERROR_CODES = [1205, 1222, 40501, 40613, 40197, 10928, 10929, 49918];

/**
 * Open a connection, retrying transient failures with exponential backoff.
 */
function connectWithRetry(string $dsn, array $options, int $maxAttempts = 3): PDO
{
    for ($attempt = 1; $attempt <= $maxAttempts; $attempt++) {
        try {
            $pdo = new PDO($dsn, null, null, $options);
            error_log(sprintf('connected on attempt %d/%d', $attempt, $maxAttempts));
            return $pdo;
        } catch (PDOException $e) {
            $sqlstate = (string) $e->getCode();
            $driverCode = isset($e->errorInfo[1]) ? (int) $e->errorInfo[1] : 0;
            $isTransient = str_starts_with($sqlstate, CONNECT_RETRY_SQLSTATE_PREFIX)
                || in_array($driverCode, TRANSIENT_SERVER_ERROR_CODES, true);
            if (!$isTransient || $attempt === $maxAttempts) {
                error_log(sprintf('connect failed on attempt %d/%d: %s', $attempt, $maxAttempts, $e->getMessage()));
                throw $e;
            }
            $delay = 2 ** ($attempt - 1); // 1, 2, 4 seconds
            error_log(sprintf('connect attempt %d hit transient %s/%d; retrying in %d seconds', $attempt, $sqlstate, $driverCode, $delay));
            sleep($delay);
        }
    }
    throw new RuntimeException('connectWithRetry exhausted retries');
}

/**
 * Run a parameterized query, retrying transient statement failures on the same
 * connection. Deadlocks (1205) roll back the transaction before the driver sees
 * the error, so rerunning a single statement is safe. If the statement was part
 * of a multistatement transaction, wrap the whole transaction in your own retry
 * loop so earlier statements replay too.
 */
function queryWithRetry(PDO $pdo, string $sql, array $params = [], int $maxAttempts = 3): PDOStatement
{
    for ($attempt = 1; $attempt <= $maxAttempts; $attempt++) {
        try {
            $stmt = $pdo->prepare($sql);
            $stmt->execute($params);
            return $stmt;
        } catch (PDOException $e) {
            $driverCode = isset($e->errorInfo[1]) ? (int) $e->errorInfo[1] : 0;
            $isTransient = in_array($driverCode, TRANSIENT_SERVER_ERROR_CODES, true);
            if (!$isTransient || $attempt === $maxAttempts) {
                error_log(sprintf('query failed on attempt %d/%d: %s', $attempt, $maxAttempts, $e->getMessage()));
                throw $e;
            }
            $delay = 2 ** ($attempt - 1);
            error_log(sprintf('query attempt %d hit transient code %d; retrying in %d seconds', $attempt, $driverCode, $delay));
            sleep($delay);
        }
    }
    throw new RuntimeException('queryWithRetry exhausted retries');
}

// Load endpoint details from application configuration. In Azure App Service,
// these can come from app settings or Key Vault-backed settings.
$server = getenv('SQL_SERVER') ?: null;
$database = getenv('SQL_DATABASE') ?: null;

if ($server === null || $database === null) {
    throw new RuntimeException('Set SQL_SERVER and SQL_DATABASE in your application configuration.');
}

$dsn = sprintf(
    'sqlsrv:Driver={ODBC Driver 18 for SQL Server};Server=%s;Database=%s;'
    . 'Encrypt=true;TrustServerCertificate=false;'
    . 'LoginTimeout=90;Authentication=ActiveDirectoryMsi;'
    . 'ConnectRetryCount=5;ConnectRetryInterval=15;'
    . 'MultiSubnetFailover=true;',
    $server,
    $database
);

$options = [
    PDO::ATTR_ERRMODE               => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE    => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES      => false,
    PDO::SQLSRV_ATTR_QUERY_TIMEOUT  => 30,
];

$pdo = connectWithRetry($dsn, $options);
$stmt = queryWithRetry($pdo, 'SELECT TOP (?) name FROM sys.databases ORDER BY name', [5]);
foreach ($stmt as $row) {
    echo $row['name'], PHP_EOL;
}

此程式碼片段已針對 Azure SQL Database 故障轉移群組和 Azure SQL 受控執行個體 進行最佳化。

  • Driver={ODBC Driver 18 for SQL Server} 接著 ODBC 18 驅動單元。 如果主機同時安裝了 ODBC 17,PDO_SQLSRV 可以綁定到 ODBC 17。 舊版 17.x 版本會拒絕較 Authentication 新的值;例如,需要 Authentication=ActiveDirectoryMsi ODBC 17.3.1.1 或更新版本。 請參閱 連接字串 屬性「Authentication」所指定的無效值

  • ConnectRetryCount以及 ConnectRetryInterval 是 ODBC 連接字串 關鍵字,能讓 SQL Server 的閒置連線韌性:驅動程式會透明地重新連接中斷的閒置連線。 這與應用程式層 queryWithRetry級不同,後者會重試因僵局或查詢逾時等暫態錯誤而失敗的 語句 。 兩者互補,所以兩者都保留。 至少要確保 LoginTimeoutConnectRetryCount * ConnectRetryInterval 這樣 idle-reconnect 路徑才能達到全部預算;樣本會用 90 秒來覆蓋 5 × 15 秒的重試時間,加上冷備援時初次登入的餘裕。

  • 搭配駕駛端診斷來輔助應用層 error_log() 級通話。 對於 PDO_SQLSRV,設定 pdo_sqlsrv.log_severityphp.ini (僅可於初始化時設定);對於 SQLSRV,則在執行時呼叫 sqlsrv_configure("LogSubsystems", ...) 。 欲了解更多資訊,請參閱 日誌活動

    ; php.ini - enable PDO_SQLSRV driver diagnostics alongside the application-level
    ; error_log() calls in the sample. Use 1 (errors) in production; -1 (all) is
    ; useful during triage but very chatty.
    [pdo_sqlsrv]
    pdo_sqlsrv.log_severity = 1
    
  • 對於 使用者指派 的管理身份,將該身份的 ID 作為 PDO $username 的參數new PDO($dsn, $identityId, null, $options)()。 傳遞。 在 Azure App 服務Azure Container Instance 使用該身份的客戶端 ID;否則,使用其物件 ID。 PHP 驅動程式繼承自底層 Microsoft ODBC 驅動程式的 SQL Server 行為;更多資訊請參見「使用 Microsoft Entra ID 搭配 ODBC 驅動程式」。 PDO_SQLSRV DSN 本身會被 UID 拒絕,所以要用建構槽。 假扮null使用者(如範例所示)選擇系統指派的 Azure 主機管理身份。 對於 SQLSRV(程序式),輸入 UID 連線選項陣列。

  • 當你連接到故障轉移群組監聽器、可用性群組監聽器或故障轉移叢集實例端點時設定 MultiSubnetFailover=true 。 設定此值可提升單子網及多子網可用性群組監聽者的連線效能。 欲了解更多資訊,請參閱 高可用性支援與災難復原

  • 若要讀取擴展或可讀的次級資料,則可加入 ApplicationIntent=ReadOnly 資料來源名稱(DSN)。

  • 對於主權雲,當憑證主體替代名稱(SAN)沒有包含你連接的主機時,請將資料加入 HostNameInCertificate DSN(例如 *.database.usgovcloudapi.net Azure Government)。

  • 該驅動程式依賴底層的 Microsoft ODBC 驅動程式 for SQL Server 來取得令牌。 管理身份、服務主體和存取權杖流程都經過 ODBC。 如需詳細資訊,請參閱搭配使用 Microsoft Entra ID 與 ODBC 驅動程式

  • 為了提升安全性與跨環境的可攜性,請將連線資訊排除在程式碼之外。 將連線資訊儲存在應用程式的設定系統中,並使用 Azure Key Vault 來管理敏感值及集中管理的連線設定。

  • 等效的 SQLSRV 連線會使用 sqlsrv_connect($server, ['Database' => $database, 'Encrypt' => true, 'Authentication' => 'ActiveDirectoryMsi', /* ... */]) 並回傳一個資源。 重試模式相同:先捕捉 false 來自 sqlsrv_connect的回傳,檢查 sqlsrv_errors() SQLSTATE,然後在重試前退出。 範例請參考 步驟4:用PHP韌性連接SQL

  • 重試助手讀取$e->errorInfo[1]為 守護。isset() PDOException::$errorInfo 宣告為 ?array ,預設為 null,因此防禦檢查會退回到驅動程式代碼, 0 並讓 SQLSTATE 08 前綴決定是否重試。

關於此配置各部分的更多資訊,請參見:

如需 Azure SQL 暫態錯誤清單,請參閱 「Troubleshoot transient connection errors」

重點功能

  • 兩個 API 與一個驅動程式套件:程序式 SQLSRV 用於SQL Server優先程式碼,或 PDO_SQLSRV 用於可攜式 PDO 程式碼。
  • 廣泛支援平台:可在 Windows、Linux 及 macOS 上運行,並支援 PHP 版本。
  • 加密連線:透過 Encrypt=true的 TLS 加密連線,伺服器憑證驗證由 TrustServerCertificate控制。
  • Microsoft Entra ID 認證:無密碼連線,包含受管理身份、服務主體及存取權杖,皆透過底層的 Microsoft ODBC 驅動程式 for SQL Server 進行。
  • 始終加密:用戶端加密用於敏感欄位,並可選地設置安全隔區用於原地操作。
  • 連線彈性:內建閒置連線會以 和 ConnectRetryInterval進行重試ConnectRetryCount
  • PHP 串流:將大型二進位與字元值讀寫為串流,而非載入記憶體。
  • 豐富的 SQL Server 資料型別支援datetimeoffset、table-valued parameters、nvarchar 以及帶有 PDO::SQLSRV_ENCODING_UTF8的 Unicode。

開始

文章 Description
系統需求 支援 PHP、作業系統及 SQL Server 版本。
支援矩陣 PHP 驅動程式版本的詳細相容性矩陣。
下載 Microsoft PHP for SQL Server 驅動程式 下載連結並發布相關資料。
Linux 與 macOS 安裝教學 在 Linux 和 macOS 上安裝驅動程式及其 ODBC 前置條件。
載入驅動程式 啟用 中的 php.ini擴展。
開始使用 PHP SQL 驅動程式 端對端的攻略,將四個入門步驟串連起來。
PHP SQL 驅動程式概述 套件裡有什麼?什麼時候該選擇 SQLSRV 或 PDO_SQLSRV。

設定和連線

文章 Description
連接伺服器 從 PHP 開啟一個連接到 SQL Server 實例的連線。
連線選項 完整參考資料,包含連線關鍵字、預設值及其設定方法。
連線到 Microsoft Azure SQL Database 將 PHP 應用程式連接到 Azure SQL Database。
連接指定的埠口 鎖定非預設的 TCP 埠。
連接共用 在 PHP 請求間重複使用 ODBC 連線。
停用多個主動結果集(MARS) 關閉 MARS 以達成相容性。
LocalDB 的支援 連接到 SQL Server 的 LocalDB 實例。
高可用性支援與災難復原 可用性群組監聽器與多子網故障轉移。
閒置連線韌性 空閒連線斷裂時自動重新連接。

Authenticate

文章 Description
使用 Microsoft Entra 驗證進行連線 管理身份、服務主體、存取權杖和密碼流程。
使用 SQL Server 認證連接 使用包含使用者名稱和密碼的 SQL 登入。
使用 Windows 驗證 連接 在網域加入的主機上使用 Windows 整合認證。

Secure

文章 Description
安全性考量 PHP 應用的威脅模型與防禦深度指引。
一直用 PHP 驅動程式加密 為敏感欄位設定客戶端加密。
Always Encrypted 具有安全記憶體保護區 啟用加密欄位的豐富操作,並具備安全區塊。

資料擷取與更新

文章 Description
程式指南 兩台驅動程式的端對端程式指南。
執行函數比較 選擇適合你工作負載的執行函式。
直接與預備陳述執行(PDO_SQLSRV) 何時使用直接執行,何時使用預先陳述。
資料擷取 擷取列、欄和串流值。
更新資料 插入、更新和刪除資料列。
執行參數化查詢 綁定參數以防範 SQL 注入。
以串流方式傳送資料 將大型二進位和字元值串流到 SQL Server。
執行交易 將語句分成原子交易。
使用表格值參數 將參數傳給 TABLE 儲存程序。
指定游標類型並選擇列 選擇僅前進、靜態、動態或鍵集游標。

數據類型

文章 Description
資料型態轉換 驅動程式如何將 PHP 型別映射到 SQL Server 型別。
預設 SQL Server 資料型態 每個 PHP 值的預設 SQL Server 類型。
預設 PHP 資料型態 每個 SQL Server 欄位類型的預設 PHP 類型。
指定 SQL Server 資料型別(SQLSRV) 綁定參數時會覆寫 SQL Server 類型。
指定 PHP 資料型別 擷取時要覆蓋 PHP 類型。
傳送與取回 UTF-8 資料 用於 PDO::SQLSRV_ENCODING_UTF8 Unicode 往返。
在 Linux 和 macOS 上傳送與取回 ASCII 資料 在非 Windows 主機上處理 ASCII 往返。
格式化小數與貨幣(SQLSRV) 使用 SQLSRV 驅動程式格式化 十進位金錢 欄位。
格式:小數點與貨幣(PDO_SQLSRV) 格式化十 進位金錢 欄位,並附上PDO_SQLSRV驅動程式。
非系統區域設定 局部十進位分隔符及其他地區考量。

錯誤和診斷

文章 Description
處理錯誤與警告 兩個驅動程式都有錯誤與警告處理。
配置錯誤與警告處理(SQLSRV) 調整 SQLSRV 驅動程式如何回報錯誤與警告。
處理錯誤與警告(SQLSRV) 檢查 SQLSRV 函式所回傳的錯誤。
伐木活動 啟用驅動程式日誌以進行診斷擷取。

部署和操作

文章 Description
性能調校 連線管理、批次處理、預備語句、游標、記憶體,以及伺服器端監控。
Troubleshooting 診斷常見的安裝、連線、查詢、資料型別、交易及容器問題。

Reference

文章 Description
SQLSRV 驅動程式 API 參考 所有 sqlsrv_* 函式、參數與回傳值。
PDO_SQLSRV 駕駛員參考 PDO_SQLSRV驅動程式支援的 PDO 與 PDOS 模式方法。
常數 驅動程式會暴露的常數,包括型別與編碼常數。
文章 Description
發行說明 各版本歷史,包含新功能、錯誤修正、平台支援變更及下載連結。
關於文件中的程式碼範例 本節範例程式碼所使用的慣例。
PHP SQL 驅動程式的範例 SQLSRV 與 PDO_SQLSRV 的端到端範例應用程式。
支援資源 社群與支援管道。