連線到 Microsoft Azure SQL Database

下載 PHP 驅動程式

SQLSRV 與 PDO_SQLSRV 驅動程式連接以下 Azure 與 Fabric SQL 目標,並使用完整修飾的伺服器名稱以及 連線選項 中的連線選項進行連線。 SQLSRV 會接收一個選項陣列;PDO_SQLSRV 會接收資料來源名稱(DSN)、必要時的獨立憑證參數,以及 PDO 屬性。

標的 伺服器名稱表單 附註
Azure SQL Database <server>.database.windows.net
Azure SQL 受控執行個體 你的實例的公用或私人端點 需要透過虛擬網路、虛擬私人網路(VPN)或公共端點連接網路。
Azure Synapse Analytics (workspace 中的專用 SQL pool ) <workspace>.sql.azuresynapse.net 支援的 Transact-SQL(T-SQL)語句與 SQL Server 不同。 有關支援的語法,請參閱 Synapse SQL 文件。
Microsoft Fabric 中的 SQL 資料庫 從資料庫項目的設定>>連線字串複製伺服器和資料庫 使用 SQL 資料庫連線,而非其 SQL 分析端點。 Microsoft Entra 認證是必須的。 如需詳細資訊,請參閱 在 Fabric 中連線到 SQL 資料庫。
Microsoft Fabric 中的倉庫 從 Fabric 入口複製倉庫的 SQL 連接字串 將 Database 設為倉庫名稱,並將 MultipleActiveResultSets 設為 false。 Microsoft Entra 認證是必須的。 欲了解更多資訊,請參閱 倉庫連接。

這兩個 PHP 擴充功能預設啟用多重主動結果集(MARS)。 倉庫不支援 MARS,所以請在 SQLSRV 選項陣列或 PDO_SQLSRV DSN 中明確停用它。 Fabric 和 Warehouse 中的 SQL 資料庫是不同的產品;不要假設一個支援的功能一定被另一個支援。

準備端點、身份和 PHP 主機

你的 PHP 程序需要網路存取 SQL 端點、支援登入方式,以及開啟所選資料庫的權限。 請分別檢查每個要求。 例如,開啟防火牆埠並不會授予資料庫存取權限。

  1. 在執行 PHP 的機器或容器上安裝 PHP 擴充功能和 Microsoft ODBC 驅動程式。 在那個流程中驗證擴充功能,而不只是在開發終端機裡。 更多資訊請參閱 載入驅動程式。
  2. 從目標的連線詳細資料複製伺服器和資料庫。 不要包含 HTTPS URL 配置。 使用服務所提供的主機名稱,讓憑證驗證能檢查預期的端點。 Azure SQL 受控執行個體 公共端點可以包含非預設埠;保留所提供的埠。
  3. 為你的 PHP 主機設定服務的網路存取。 對於私人端點,確認私人名稱解析及來自應用程式網路的路由。 公用防火牆規則不會提供通往私用位址的路由。
  4. 選擇 PHP 程序所使用的身份。 對於 Azure 託管的應用程式,啟用其受控識別,並辨識它是系統指派的還是使用者指派的。 開發者的 Azure CLI 登入並不是應用程式的受控識別。
  5. 讓資料庫管理員授權該身份存取所選資料庫及應用程式所需的最低權限。 針對 Warehouse,也請檢查 Fabric 的項目/工作區存取權限。 Azure 資源管理權限本身不會直接授予查詢應用程式資料表的權限。
  6. 在應用程式的設定中設定SQL_SERVER和SQL_DATABASE。 管理式身份範例中不要儲存密碼。

範例中是在不建立表格的情況下驗證連線。 通過這個檢查並不代表身分識別能讀取或寫入你的應用程式結構描述。 在同一身份下分別測試實際操作。

使用無密碼的 Microsoft Entra 認證

當您的主機環境公開受控識別端點,且 SQL 目標授與該受控識別存取權時,請使用受控識別。 以下完整程式使用系統指派的受控識別。 它們不是工作站範例。 在已設定的 Azure 主機SQL_SERVERSQL_DATABASE上執行,並可與其 PHP 程序共用。

這兩個程式都停用了 MARS,因此在選擇倉庫時,連線設定也適用。 他們一次只使用一個使用中陳述式。 關於身份設定及其他認證模式,請參見使用 Microsoft Entra 認證連接。

將 SQL_DATABASE 設為實際的資料庫名稱。 每個程式透過加倍閉合大括號並將名稱包覆在大括號內,為連線建立獨立的轉義值。 跳脫可以避免資料庫名稱中的特殊字元改變驅動程式讀取連線設定的方式。 程式保留原始名稱以檢查 DB_NAME() 的結果。

SQLSRV

將此程式存為 connect-azure-sqlsrv.php,並在已設定的主機上執行 php connect-azure-sqlsrv.php 。

<?php
$server = getenv('SQL_SERVER');
$database = getenv('SQL_DATABASE');
if ($server === false || $server === '' || $database === false || $database === '') {
    throw new RuntimeException('Set SQL_SERVER and SQL_DATABASE.');
}
$databaseValue = '{' . str_replace('}', '}}', $database) . '}';

$conn = sqlsrv_connect($server, [
    'Database' => $databaseValue,
    'Authentication' => 'ActiveDirectoryMsi',
    'Encrypt' => true,
    'TrustServerCertificate' => false,
    'LoginTimeout' => 30,
    'MultipleActiveResultSets' => false,
    'CharacterSet' => 'UTF-8',
]);
if ($conn === false) {
    throw new RuntimeException(print_r(sqlsrv_errors(), true));
}

$stmt = null;
try {
    $stmt = sqlsrv_query(
        $conn,
        'SELECT DB_NAME() AS DatabaseName, CAST(1 AS int) AS Connected',
        [],
        ['QueryTimeout' => 30]
    );
    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 ($row !== ['DatabaseName' => $database, 'Connected' => 1]) {
        throw new RuntimeException('Unexpected database or connection result.');
    }
    echo 'Connected to ', $row['DatabaseName'], '.', PHP_EOL;
} finally {
    if (is_resource($stmt)) {
        sqlsrv_free_stmt($stmt);
    }
    sqlsrv_close($conn);
}

PDO_SQLSRV

將這個獨立程式存為 connect-azure-pdo.php,並在已設定的主機上執行 php connect-azure-pdo.php 。 它會設定 PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE,因此 int 結果是 PHP int。 若無此項,PDO_SQLSRV 預設會將此欄位以字串回傳。 PDO 編碼是一個屬性,不是 SQLSRV CharacterSet 選項。

<?php
$server = getenv('SQL_SERVER');
$database = getenv('SQL_DATABASE');
if ($server === false || $server === '' || $database === false || $database === '') {
    throw new RuntimeException('Set SQL_SERVER and SQL_DATABASE.');
}
$databaseValue = '{' . str_replace('}', '}}', $database) . '}';
$pdo = new PDO(
    "sqlsrv:Server=$server;Database=$databaseValue;Authentication=ActiveDirectoryMsi;"
    . "Encrypt=true;TrustServerCertificate=false;LoginTimeout=30;"
    . "MultipleActiveResultSets=false",
    null,
    null,
    [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::SQLSRV_ATTR_ENCODING => PDO::SQLSRV_ENCODING_UTF8,
        PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE => true,
    ]
);

$stmt = null;
try {
    $stmt = $pdo->prepare(
        'SELECT DB_NAME() AS DatabaseName, CAST(1 AS int) AS Connected',
        [PDO::SQLSRV_ATTR_QUERY_TIMEOUT => 30]
    );
    $stmt->execute();
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
    if ($row !== ['DatabaseName' => $database, 'Connected' => 1]) {
        throw new RuntimeException('Unexpected database or connection result.');
    }
    echo 'Connected to ', $row['DatabaseName'], '.', PHP_EOL;
} finally {
    $stmt = null;
    $pdo = null;
}

若 SQL_DATABASE 為 appdb,則每個程式會列印:

Connected to appdb.

ActiveDirectoryMsi它不使用你本地的 Azure CLI 登入方式。 在本地開發或持續整合(CI)時,請選擇由 PHP 擴充套件與 ODBC 驅動程式支援的認證方法。 你可以透過身份函式庫取得 Microsoft Entra 存取權杖,並透過 AccessToken 提供該權杖。 使用令牌時,請省略使用者名稱、密碼和 Authentication 設定。 在 SQLSRV 連線選項陣列或 PDO_SQLSRV DSN 中設定 AccessToken。 避免讓 token 出現在原始碼和日誌中。 欲了解更多資訊,請參閱 使用 Microsoft Entra 認證連線。

ActiveDirectoryServicePrincipal 使用用戶端 ID 和用戶端密碼;這不是無密碼驗證。 如果你使用它,請從受保護的應用程式設定中讀取秘密值。 SQL 認證僅適用於支援 SQL 認證的目標;Fabric 中的 SQL 資料庫與 Warehouse 均不支援 SQL 認證。

調整驗證設定以符合您的環境

每個連線使用一種認證機制。 切換到 AccessToken 時,請勿保留舊的使用者名稱、密碼或 Authentication 設定。

環境 設定 責任
具有系統指派受控識別的 Azure 主機 將 Authentication 設定為 ActiveDirectoryMsi。 不要提供使用者名稱或密碼。 ODBC 從主機的識別端點取得權杖。
具有使用者指派受控識別的 Azure 主機 將 Authentication 設定為 ActiveDirectoryMsi。 透過 SQLSRV 的 UID 選項或 PDO 的使用者名稱參數,提供識別值的 ID。 不要提供密碼。 所需的 ID 取決於主機服務。 App Service 與 容器執行個體 使用 client ID;請查詢其他主機的 ODBC 身份指引。
使用外部令牌提供者的工作站或 CI 取得 SQL 服務的權杖,然後設定 AccessToken。 省略使用者名稱、密碼和 Authentication 設定。 您的應用程式或身分識別程式庫會取得並重新整理該權杖。 兩個 PHP 擴充功能皆不會自動使用你的 Azure CLI 登入。
具有用戶端密碼的服務主體 將 Authentication 設定為 ActiveDirectoryServicePrincipal。 對於 SQLSRV,設定 UID 為用戶端 ID 和 PWD 為密鑰。 對於 PDO,將客戶端 ID 和 secret 作為建構子的使用者名稱和密碼參數傳遞。 保護並輪換這個密鑰。 這種方法並非無需密碼。
在支援它的目標上進行 SQL 登入 SQLSRV 使用 UID/PWD;PDO 使用建構子參數二與三。 目標會驗證 SQL 憑證。 這個選項不適用於任何一款 Fabric 產品。

請求 SQL 服務的權杖,而不是 Azure 資源管理的權杖。 代幣的 受眾 會識別接受該代幣的服務。 對於 Azure 公有雲,請從你的身分識別程式庫要求 scope https://database.windows.net/.default。 確認另一片雲端的適當資源。 將權杖以字串形式傳給 PHP 擴充套件;不要手動轉換成 ODBC 的存取權杖結構。

當工作程序持續執行時,權杖可能會過期。 在開啟另一個連線前取得有效的權杖,並在長時間執行的工作中依需要更新權杖。 切勿記錄包含存取權杖的 DSN。 欲了解更多關於 ODBC 認證的資訊,請參閱 使用 Microsoft Entra ID 搭配 ODBC 驅動程式。

將加密與身分驗證分開進行

Encrypt=true 要求加密傳輸。 TrustServerCertificate=false 需要驗證伺服器憑證,包括其身分。 Microsoft Entra 認證可確認您的應用程式身分;它不會取代伺服器憑證驗證。

使用 SQL 服務提供的端點,並維護客戶端作業系統的憑證信任儲存庫。 不要為了避開名稱解析問題而把主機名稱替換成 IP 位址。 對於私有端點,修正名稱解析與路由,同時保留服務預期的連線名稱。

LoginTimeout 限制連線建立。 QueryTimeout 用於 SQLSRV,而 PDO::SQLSRV_ATTR_QUERY_TIMEOUT 用於 PDO_SQLSRV 的陳述式執行。 提高查詢逾時時間無法修復缺少的受控身分識別端點或錯誤的資料庫使用者。

依故障階段進行故障排除

失效階段 要檢查的事項
PHP 無法載入擴充功能 確認執行階段版本、架構、擴充功能組建、ODBC 安裝,以及應用程式處理程序所使用的 php.ini。
傳輸控制協定(TCP)連線逾時 從 PHP 主機驗證複製的端點與埠、名稱解析、防火牆規則、虛擬網路路由及私有端點設定。
憑證驗證失敗 檢查端點名稱、憑證鏈和客戶端信任儲存庫。 保持啟用憑證驗證。
管理身分識別無法取得權杖 確認該身份在該主機上已啟用,且其身份端點可用。 不要在一般筆電上測試ActiveDirectoryMsi,然後期待 Azure CLI 登入就能符合其要求。
令牌認證失敗 檢查該代幣的預期服務、到期日、租戶和身份。 確認該身份可存取資料庫。 移除所有使用者名稱、密碼和 Authentication 設定。
登入成功,但所選資料庫無法開啟 確認資料庫名稱,以及其管理員是否已建立該目標身分識別,或已授與其存取權限。
連線開啟,但應用程式查詢失敗 檢查物件權限及目標支援的 T-SQL 功能。 連線測試並不會建立應用程式結構描述存取權限。
Warehouse 拒絕連線設定 在 SQLSRV 選項陣列或 PDO DSN 中設定 MultipleActiveResultSets 為 false,並使用 Microsoft Entra 認證。

SQLSRV 會回傳 false 並透過 sqlsrv_errors() 揭露錯誤集合。 PDO 建構函式會拋出 PDOException;範例也會為陳述式失敗啟用例外。 立即將診斷記錄在受限日誌中,並保持 SQLSRV 警告與錯誤區分。 不要將原始診斷、權杖或連線細節回傳給瀏覽器。

中斷連線處理方案

服務可以在維護或故障轉移期間斷開閒置會話或中斷操作。 ODBC 閒置連線復原力與應用程式重試解決了不同的問題。 關於重試關鍵字及受控斷線測試,請參見 閒置連線韌性。

不要因為客戶端失去連線就重播寫入。 伺服器可能在回應遺失前就已經寫入了。 使用應用程式專屬的重試政策,以及偵測重複工作的方法。 在請求或工作結束時釋放語句與連線控制代碼,包括錯誤路徑。 關於生命週期與池化行為,請參見 連接伺服器。