Microsoft Drivers for PHP for SQL Server 概觀

下載 PHP 驅動程式

PHP for SQL Server 的Microsoft驅動程式包含兩個 PHP 擴充套件,分別為 SQLSRV 與 PDO_SQLSRV。 PDO_SQLSRV實作了 PHP 資料物件(PDO)介面。 這兩個擴充套件都使用 Microsoft ODBC 驅動程式 for SQL Server 來連接 Microsoft SQL。 他們的 PHP API、驅動程式專屬選項及預設 PHP 類型有所不同。 例如,SQLSRV 預設會以物件形式回傳日期和時間值 DateTime ,而 PDO_SQLSRV 預設會回傳字串。 關於系統需求,請參見 Microsoft PHP for SQL Server 驅動程式的系統需求。

選擇 SQLSRV 或 PDO_SQLSRV

如果你... 使用
開始一個其他地方沒有 PDO 程式碼的新專案 選擇你的應用程式會一致使用的介面。 SQLSRV 會提供程序式函式和明確的參數描述符。 PDO_SQLSRV 適合用於以 PDOStatement 和 PDO 物件為中心組織的程式碼。
已在另一個資料庫(MySQL、PostgreSQL、SQLite)中使用 PDO PDO_SQLSRV,這樣你的資料存取層才能在不同資料庫間保持一致。
使用需要 PDO 連線物件的框架或函式庫 PDO_SQLSRV.
需要手動、逐區塊控制串流資料何時傳送 SQLSRV,搭配 sqlsrv_send_stream_data()。 PDO_SQLSRV 也會串流大型值,方法是將 PHP 串流資源綁定為 PDO::PARAM_LOB,但它會在 execute() 期間自動傳送整個串流,而非由呼叫者控制分塊傳送。
維護一個已會呼叫 sqlsrv_* 函式的應用程式 SQLSRV,除非你打算重寫它的資料存取程式碼以支援 PDO。

安裝其中一個擴充功能或兩個都安裝。 Windows 下載檔案包含獨立的擴充功能二進位檔;在 Linux 和 macOS 上,需分別安裝 sqlsrv 和 pdo_sqlsrv 套件。 你可以在同一個 PHP 程序中載入兩者。 SQLSRV 回傳連線與語句資源;PDO_SQLSRV回傳 PDO 與 PDOStatement 物件。 不要把資源從一個 API 傳到另一個 API。

使用 PDO 並不代表 Transact-SQL(T-SQL)語法可以移植到其他資料庫。 PDO 提供通用的 PHP 介面;你的查詢、結構、認證和驅動程式專屬屬性仍可依賴 Microsoft SQL。 同樣地,使用 procedural 擴充功能也不需要整個應用程式都採用程序式寫法:你可以從自己的類別呼叫 SQLSRV。

在兩個 API 中比較相同的結果

在選擇應用程式預期的 PHP 表示方式之前,先執行這些程式。 會選取相同的整數、日期和 SQL NULL,但預設值並不相同。 不需要資料表或範例資料庫。

安裝並載入所選擴充功能。 在程序環境中為現有的 SQL Server 測試資料庫設置 SQL_SERVER、SQL_DATABASE、SQL_USER 和 SQL_PASSWORD。 伺服器憑證必須被信任且與已設定的端點相符。 關於設定與 Azure 的無密碼替代方案,請參見連接伺服器。

SQLSRV

將此完整程式儲存為 compare-sqlsrv.php,並執行 php compare-sqlsrv.php。

<?php
$config = [];
foreach (['SQL_SERVER', 'SQL_DATABASE', 'SQL_USER', 'SQL_PASSWORD'] as $name) {
    $value = getenv($name);
    if ($value === false || $value === '') {
        throw new RuntimeException("Set $name before running this example.");
    }
    $config[$name] = $value;
}
foreach (['SQL_DATABASE', 'SQL_USER', 'SQL_PASSWORD'] as $name) {
    $config[$name] = '{' . str_replace('}', '}}', $config[$name]) . '}';
}
$conn = sqlsrv_connect($config['SQL_SERVER'], [
    'Database' => $config['SQL_DATABASE'],
    'UID' => $config['SQL_USER'],
    'PWD' => $config['SQL_PASSWORD'],
    'Encrypt' => true,
    'TrustServerCertificate' => false,
    'LoginTimeout' => 30,
    'CharacterSet' => 'UTF-8',
]);
if ($conn === false) {
    throw new RuntimeException(print_r(sqlsrv_errors(), true));
}
$stmt = null;
try {
    $stmt = sqlsrv_query($conn, "SELECT CAST(42 AS int) AS CountValue, "
        . "CAST('2026-10-19' AS date) AS DayValue, CAST(NULL AS int) AS Missing");
    if ($stmt === false) {
        throw new RuntimeException(print_r(sqlsrv_errors(), true));
    }
    $row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
    if ($row === false) {
        throw new RuntimeException(print_r(sqlsrv_errors(), true));
    }
    if (!is_array($row) || $row['CountValue'] !== 42
        || !($row['DayValue'] instanceof DateTime)
        || $row['DayValue']->format('Y-m-d') !== '2026-10-19'
        || $row['Missing'] !== null) {
        throw new RuntimeException('Unexpected SQLSRV values or default types.');
    }
    echo get_debug_type($row['CountValue']), ', ',
        get_debug_type($row['DayValue']), ', ', get_debug_type($row['Missing']), PHP_EOL;
} finally {
    if (is_resource($stmt)) {
        sqlsrv_free_stmt($stmt);
    }
    sqlsrv_close($conn);
}

預期產出:

int, DateTime, null

PDO_SQLSRV

將此獨立程式儲存為 compare-pdo.php,並執行 php compare-pdo.php。 它刻意將數值和日期的擷取保留為 PDO_SQLSRV 的預設值。

<?php
$config = [];
foreach (['SQL_SERVER', 'SQL_DATABASE', 'SQL_USER', 'SQL_PASSWORD'] as $name) {
    $value = getenv($name);
    if ($value === false || $value === '') {
        throw new RuntimeException("Set $name before running this example.");
    }
    $config[$name] = $value;
}
foreach (['SQL_DATABASE', 'SQL_USER', 'SQL_PASSWORD'] as $name) {
    $config[$name] = '{' . str_replace('}', '}}', $config[$name]) . '}';
}
$server = $config['SQL_SERVER'];
$database = $config['SQL_DATABASE'];
$pdo = new PDO(
    "sqlsrv:Server=$server;Database=$database;Encrypt=true;"
    . "TrustServerCertificate=false;LoginTimeout=30",
    $config['SQL_USER'],
    $config['SQL_PASSWORD'],
    [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::SQLSRV_ATTR_ENCODING => PDO::SQLSRV_ENCODING_UTF8,
    ]
);
$stmt = null;
try {
    $stmt = $pdo->query("SELECT CAST(42 AS int) AS CountValue, "
        . "CAST('2026-10-19' AS date) AS DayValue, CAST(NULL AS int) AS Missing");
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
    if ($row !== ['CountValue' => '42', 'DayValue' => '2026-10-19', 'Missing' => null]) {
        throw new RuntimeException('Unexpected PDO_SQLSRV values or default types.');
    }
    echo get_debug_type($row['CountValue']), ', ',
        get_debug_type($row['DayValue']), ', ', get_debug_type($row['Missing']), PHP_EOL;
} finally {
    $stmt = null;
    $pdo = null;
}

預期產出:

string, string, null

兩個程式都明確請求命名的結果鍵。 這些 PHP 陣列使用欄位名稱,如 CountValue,而非以零為基礎的數字索引。 SQL NULL 在任一 API 中都會變成 PHP null。 它不是空字串或缺少的結果列。

兩個程式都會從環境中讀取資料庫名稱、使用者名稱和密碼。 它們會將這些值跳脫一次,供 PHP 驅動程式的 ODBC 式連線處理使用。 雙重閉合大括號並將值包在大括號中,可以保留特殊字元;它不會重新命名資料庫或改變儲存的密碼。 更多資訊請參見 「連接伺服器」。

範例在發生錯誤時停止,並在 finally 中釋放資源。 SQLSRV 透過 false 和 sqlsrv_errors() 回報資料庫失敗;PDO_SQLSRV 會在連線失敗時擲回錯誤,並在已設定的錯誤模式下,針對查詢失敗使用例外狀況。 在網頁應用程式中,請在處理請求的程式碼中捕捉這些例外。 將診斷細節記錄在受保護的日誌中,而非回傳到瀏覽器。

練習結束後,如果你不再需要它們,請刪除 compare-sqlsrv.php 和 compare-pdo.php。 完成後,從測試程序中清除憑證環境變數。

選擇類型、編碼與錯誤處理

決定你的應用程式預期使用哪些 PHP 類型、如何處理文字和錯誤,以及何時釋出資料庫資源。

決策 SQLSRV PDO_SQLSRV 對應用程式碼的影響
整數結果類型 SQL int 欄位的原生 PHP 整數。 預設為字串;PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE 要求支援的數值 PHP 類型。 嚴格比較與序列化輸出可能有所不同。 不要假設每個 SQL 的數值類型都可用 PHP 整數或浮點數表示。
日期與時間結果 DateTime 預設為物件;ReturnDatesAsStrings 選擇字串。 預設為字串;PDO::SQLSRV_ATTR_FETCHES_DATETIME_TYPE 選擇物件。 在序列化或傳給應用程式程式碼前,先將表示法正規化。
字元編碼 明確設定 CharacterSet => 'UTF-8' 。 預設為 UTF-8;設定為 PDO::SQLSRV_ATTR_ENCODING。 不要把 SQLSRV 選項傳遞到 PDO DSN。
錯誤處理 立即檢查 false 並擷取完整的 SQLSRV 錯誤集合。 配置 PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION。 缺失的資料列和失敗的查詢需要不同的處理方式。
參數重用 在描述符中以參照方式綁定變數。 使用 bindParam() 表示變數,或使用 bindValue() 表示其目前值。 重新指派變數影響的是參考綁定,而非先前的值綁定。
Cleanup 釋放陳述式,然後關閉連線資源。 先參照 release statement,然後是 PDO 物件。 一個語句可以在另一個參考被設定為 null 後,仍能維持 PDO 連線的存續。

如果你遷移現有應用程式,請先用代表性的數值測試這些行為,再修改其資料庫程式碼。 包含非 ASCII 文字、SQL NULL、日期、精確十進位值及儲存程序輸出參數。 也要比較你的框架如何配置 PDO 屬性。 僅僅替換函式名稱並不能遷移錯誤處理、參考綁定或回傳的 PHP 型別。

若想使用包含兩種 API 的寫入與讀取範例工作流程,請參閱 程式設計指南。 對於重複執行和鍵入的輸入,請使用 Compare query execution functions。

了解每個元件的功能

你的擴充功能選擇會改變 PHP API 及其型別轉換。 這兩個擴充功能都使用 ODBC 與伺服器通訊、加密連線及進行驗證。 作業系統提供受信任的憑證與服務,如 Windows 驗證 或 Kerberos。 SQL 目標控制權限、結構以及支援的 T-SQL 語句。

比較程式使用 SQL 認證來連接 SQL Server。 對於 Azure SQL Database、Azure SQL 受控執行個體、Azure Synapse Analytics、Fabric 中的 SQL 資料庫,或 Fabric 中的 Warehouse,請先設定服務端點並啟用支援的認證,再重新使用擷取模式。 這兩個 Fabric 產品都需要 Microsoft Entra ID 認證;Warehouse 也需要停用多個主動結果集(MARS)。 在 SQL Server 上成功進行型別比較,並不代表不同目標支援本概述中列出的所有功能。

兩個擴充包都能提供什麼

  • 整合認證、SQL 認證,以及根據目標支援的 Microsoft Entra ID 認證。 管理身份不使用應用程式密碼; ActiveDirectoryServicePrincipal 使用用戶端 ID 和用戶端秘密。 更多資訊請參見 「連接伺服器」。
  • 參數化查詢、預先準備的語句,以及方向性(輸入/輸出)參數。 更多資訊請參閱「 執行函數比較 」及「 使用方向參數」。
  • 交易、用於大型字元與二進位值的串流輸入參數,以及表格值參數。
  • 始終加密,包括 ODBC 驅動程式與 SQL Server 目標支援的安全隔區。 欲了解更多資訊,請參閱《使用 Microsoft Drivers for PHP for SQL Server 的 Always Encrypted》。
  • 連接至 SQL Server、Azure SQL Database、Azure SQL 受控執行個體、Azure Synapse Analytics、Microsoft Fabric 中的 SQL 資料庫,以及 Microsoft Fabric 中的 Warehouse。 認證與 SQL 功能依目標而異;詳見 Azure 與 Fabric 連線。