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=ActiveDirectoryMsiODBC 17.3.1.1 或更新版本。 請參閱 連接字串 屬性「Authentication」所指定的無效值。ConnectRetryCount以及ConnectRetryInterval是 ODBC 連接字串 關鍵字,能讓 SQL Server 的閒置連線韌性:驅動程式會透明地重新連接中斷的閒置連線。 這與應用程式層queryWithRetry級不同,後者會重試因僵局或查詢逾時等暫態錯誤而失敗的 語句 。 兩者互補,所以兩者都保留。 至少要確保LoginTimeout,ConnectRetryCount * ConnectRetryInterval這樣 idle-reconnect 路徑才能達到全部預算;樣本會用 90 秒來覆蓋 5 × 15 秒的重試時間,加上冷備援時初次登入的餘裕。搭配駕駛端診斷來輔助應用層
error_log()級通話。 對於 PDO_SQLSRV,設定pdo_sqlsrv.log_severity在php.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)沒有包含你連接的主機時,請將資料加入
HostNameInCertificateDSN(例如*.database.usgovcloudapi.netAzure 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並讓 SQLSTATE08前綴決定是否重試。
關於此配置各部分的更多資訊,請參見:
如需 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 的端到端範例應用程式。 |
| 支援資源 | 社群與支援管道。 |