このガイドを使って接続を開き、PHPが受け取る値を検証し、作業終了後に接続を解放してください。 プログラムはローカルまたはリモートのSQL Serverテストデータベースに対してSQL Server認証を使用します。 パスワードレスの Azure および Fabric 接続には、Azure SQL および Fabric SQL に接続をご利用ください。
SQLSRVはサーバー名と接続オプションの連想配列を受け入れます。 PDO_SQLSRV は PHP データオブジェクト(PDO)を実装し、データソース名(DSN)文字列、個別の認証情報引数、そして複数の PDO 属性を受け入れます。 両者ともMicrosoftのODBCドライバーfor SQL Serverを使用しています。 あるAPIで動作する接続が、他のAPIのオプション名やPHP型を互換的に使えるようにするわけではありません。
接続する前に
- 対応するPHPランタイムとMicrosoft ODBCドライバーをインストールし、使用予定のPHP拡張を読み込みます。
- アプリケーションを実行するPHPプロセスを確認してください。
php --iniを実行してコマンドライン構成を確認し、php -mを実行してそのロードされた拡張機能をリストしてください。 SQLSRVはsqlsrvが必要です。 PDO_SQLSRVPDOとpdo_sqlsrvが必要です。 ウェブサーバーは端末とは異なるphp.ini、ランタイム、アカウントを使うことができます。 - サーバーアドレス、データベース名、接続許可付きのアイデンティティを取得してください。 データベースログインがすべてのテーブルに自動的に権限を与えるわけではありません。
- ネットワークアクセスと信頼できるサーバー証明書を設定しましょう。 これらのプログラムは暗号化と証明書の検証を明示的に要求します。 証明書に記載されているホスト名で接続し、証明書がカバーしていないIP アドレスに置き換えずにしてください。
これらの変数はPHPプロセスの環境で、シェル、開発ツール、ホスティング設定を使って設定してください。 パスワードファイルをコミットしたり、環境変数を出力したりしないでください。
| Variable | 価値 |
|---|---|
SQL_SERVER |
オプションで tcp: を前に付け、その後に ,<port> を続けたサーバー ホスト名。 |
SQL_DATABASE |
あなたのログインでアクセスできる既存のデータベースです。 |
SQL_USER |
SQL Server のログイン アカウント。 |
SQL_PASSWORD |
そのログインのパスワードは、保護された構成で指定されます。 |
ウェブリクエストのパラメータではなく、信頼できるアプリケーション設定からサーバーやデータベースの設定を読み取ってください。 PDOの例では、それらの設定をDSNに配置しています。 その接続キーワードはアプリケーション管理下に置いてください。
実際のデータベース名、ユーザー名、パスワードを環境変数に保存し、自分で波かっこを追加したり二重にしたりせずにしてください。 両方のPHP拡張は、SQLSRV配列オプションやPDOコンストラクタ引数に対してもODBCスタイルのエスケープを必要とします。つまり、閉じ波括弧を二重にし、値を波括弧で囲むことです。 各プログラムはこれを一度だけ行ってから、これらの値をドライバーに渡します。 外側の括弧は、値の先頭と末尾の中括弧そのものを保持し、データベース名内のセミコロンが PDO DSN 設定を分離しないようにします。 このエスケープは、Transact-SQL(T-SQL)パラメータバインディングとは別です。
SQLSRVで開いて、クエリを実行し、閉じて
このプログラムを connect-sqlsrv.phpとして保存し、php connect-sqlsrv.phpを実行してください。 テーブルを作成したりデータを変更したりせずにT-SQLクエリを実行します。
CharacterSet 文字データとしてUTF-8を選択します。データベースの列の種類や照合順序は変更しません。
<?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 {
$sql = "SELECT CAST(42 AS int) AS Value, N'caf' + NCHAR(233) AS Label, "
. "CAST(NULL AS int) AS Missing";
$stmt = sqlsrv_query($conn, $sql, [], ['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 !== ['Value' => 42, 'Label' => "caf\u{00e9}", 'Missing' => null]) {
throw new RuntimeException('Unexpected SQLSRV values or PHP types.');
}
echo json_encode($row, JSON_THROW_ON_ERROR), PHP_EOL;
} finally {
if (is_resource($stmt)) {
sqlsrv_free_stmt($stmt);
}
sqlsrv_close($conn);
}
予想される出力:
{"Value":42,"Label":"caf\u00e9","Missing":null}
接続とステートメントはPHP リソースで、sqlsrv_* 関数に渡すハンドルです。 どちらのハンドルを使う前に、必ず false を確認してください。 失敗直後に sqlsrv_errors() を取得してください。なぜなら、後のSQLSRV呼び出しでエラーコレクションを置き換えることができるからです。
SQLSRV_FETCH_ASSOC 列名をキーとする連想配列を返します。
SQLSRV_FETCH_NUMERIC ゼロベースの数値キーを返します。デフォルトの SQLSRV_FETCH_BOTH は両方の形を含みます。
sqlsrv_fetch_array()の場合、nullはこれ以上行がないことを意味し、falseはエラーを意味します。 行内のSQL NULL はPHP nullで、行が欠けているわけではありません。 これらの値を区別する際には === を使用してください。
PDO_SQLSRVで開いて、クエリを実行して、閉じる
この別プログラムを connect-pdo.phpとして保存し、同じ環境で php connect-pdo.php 実行してください。
sqlsrv: は PHP の汎用的な PDO_ODBC ドライバではなく、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::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::SQLSRV_ATTR_ENCODING => PDO::SQLSRV_ENCODING_UTF8,
]
);
$stmt = null;
try {
$sql = "SELECT CAST(42 AS int) AS Value, N'caf' + NCHAR(233) AS Label, "
. "CAST(NULL AS int) AS Missing";
$stmt = $pdo->prepare($sql, [PDO::SQLSRV_ATTR_QUERY_TIMEOUT => 30]);
$stmt->execute();
$row = $stmt->fetch();
if ($row !== ['Value' => '42', 'Label' => "caf\u{00e9}", 'Missing' => null]) {
throw new RuntimeException('Unexpected PDO_SQLSRV values or PHP types.');
}
echo json_encode($row, JSON_THROW_ON_ERROR), PHP_EOL;
} finally {
$stmt = null;
$pdo = null;
}
予想される出力:
{"Value":"42","Label":"caf\u00e9","Missing":null}
PDO_SQLSRVはこの int 列をデフォルトでPHP文字列として返します。 サポートされている数値列に対してPHPの数値型を要求するには、PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE を trueに設定してください。
decimal 値に対してPHPキャストを無差別に使わないでください。浮動小数点変換は精度を失う可能性があります。
PDO属性は接続または文オブジェクトの設定です。
PDO::ATTR_ERRMODE
PDO::ERRMODE_EXCEPTIONでは、データベース操作の失敗で PDOException をスローします。 接続の構築は、その設定に関わらず失敗時に例外をスローします。
PDO::FETCH_ASSOC は名前付きキーを与え、 PDO::FETCH_NUM はゼロベースの数値キーを与え、 PDO::FETCH_BOTH は両方を与えます。
fetch() 結果の最後には false を返します。行内のSQLの NULL 値はPHP nullのままです。
これらのコマンドラインプログラムは、失敗すると実行が停止するようにします。 ウェブアプリケーションでは、リクエストを処理するコードで例外をキャッチします。 保護ログに診断詳細を記録し、一般的なエラー応答を返します。
sqlsrv_errors()、例外トレース、接続文字列、またはトークンをブラウザに送信しないでください。
認証モードの選択
| Mode | 用途 | 参照先 |
|---|---|---|
| SQL Server認証 | Microsoft Entra ID が利用できない場合のオンプレミス SQL Server、コンテナ、Azure SQL | SQL Server認証による接続 |
| 統合認証(接続設定にユーザー名やパスワードは設定しない) | Windowsアイデンティティ、またはKerberos向けに設定されたLinux/macOSクライアント | Windows 認証で接続 |
Microsoft Entra ID(AuthenticationまたはAccessTokenキーワード) |
Microsoft Entra ID 用に構成された Azure SQL と Fabric SQL のターゲット | Microsoft Entra 認証を使用して接続する |
SQL認証の場合、SQLSRVは接続オプション配列で UID と PWD を取ります。 PDO_SQLSRVは、ユーザー名とパスワードをDSNキーワードとしてではなく、new PDO() の第2引数と第3引数として受け取ります。 アクセストークンの場合、SQLSRVはoptions配列で AccessToken を受け取り、PDO_SQLSRVはDSNで取ります。
ユーザー名、パスワード、Authentication、AccessTokenを省くと、両方のドライバーはTrusted_Connection=Yesを使用してODBCに統合認証を要求します。 LinuxおよびmacOSでは、このリクエストには有効なKerberosチケットと ODBC統合認証設定が必要です。 任意のローカル アカウントにリモート サーバーへのアクセスを許可するわけではありません。
接続とそのステートメントの設定
接続設定は開いたセッションに適用されます。 ステートメントの設定は特定のクエリに適用されます。 アプリケーションがデフォルト以外の値を必要とする場合、タイムアウトや結果型を明示的に設定してください。
| Purpose | SQLSRV | PDO_SQLSRV | Behavior owner |
|---|---|---|---|
| エンドポイントとデータベース | サーバーの引数と Database オプション。 |
Server と Database DSN キーワード。 |
ODBCとSQLターゲット。 |
| SQL 資格情報 |
UID と PWD のオプション。 |
コンストラクターのユーザー名とパスワードの引数。 | 拡張機能の認証情報の処理とサーバー認証。 |
| Microsoft Entra 認証 |
Authentication オプション、または別 AccessToken オプション。 |
認証情報を省略した外部トークン用の Authentication または AccessToken DSN キーワード |
ODBC認証;アプリケーションは外部トークンを取得します。 |
| Encryption |
Encrypt => true。 |
Encrypt=true DSN内の |
ODBC のトランスポート セキュリティ。 |
| 証明書の検証 |
TrustServerCertificate => false。 |
TrustServerCertificate=false DSN内で。 |
ODBCおよびオペレーティングシステムの証明書信頼構成。 |
| 接続確立のタイムアウト |
LoginTimeout 接続オプション(秒) |
LoginTimeout DSNキーワードは、秒単位です。 |
ODBC。 ステートメントの実行タイムアウトではありません。 |
| クエリのタイムアウト |
QueryTimeout ステートメント オプション(秒)。 |
PDO::SQLSRV_ATTR_QUERY_TIMEOUT、接続またはステートメントについて。 |
拡張およびODBCステートメント処理。 |
| 文字エンコード |
CharacterSet => 'UTF-8' 接続オプション。 |
PDO::SQLSRV_ATTR_ENCODING => PDO::SQLSRV_ENCODING_UTF8。 |
PHP拡張機能の変換。 PDO_SQLSRVの既定はUTF-8です。SQLSRVの既定はシステム エンコーディングです。 |
| 日付と時間オブジェクト |
ReturnDatesAsStrings はデフォルトで false されるため、日付と時刻の列は DateTime オブジェクトを返します。 |
既定では文字列です。オブジェクトを要求するには PDO::SQLSRV_ATTR_FETCHES_DATETIME_TYPE を使用します。 |
PHP拡張機能の型変換。 |
| 複数アクティブ結果セット (MARS) |
MultipleActiveResultSets 接続オプション。 |
MultipleActiveResultSets DSNキーワード。 |
ODBCとターゲットのサポート。 両方の拡張機能はデフォルトで有効化しています。Warehouse in Fabricでは無効にしてください。 |
| アイドル状態からの回復 |
ConnectRetryCount と ConnectRetryInterval の接続オプション。 |
同じDSNキーワード | ODBC。 任意のアプリケーション操作を再試行することはありません。 |
キーワード、許容値、デフォルト情報の完全なリストについては、接続オプションをご覧ください。 PDOのDSNにCharacterSet、QueryTimeout、またはPDO::定数名を配置しないでください。
接続寿命の管理
リクエストやジョブがデータベース作業を必要とする場合は、接続を開いてください。 そのリクエストやジョブの間ずっと再利用し、完了したら解放してください。 行ごとに接続/切断を繰り返さないでください。 長期的なワーカーの場合は、次のジョブを受け入れる前にステートメントを解放し、各トランザクションを完了します。
SQLSRVは接続を閉じると関連するステートメントを閉じます。 明示的にステートメントを早期に解放すると、接続を終了せずにリソースを解放します。 PDOの場合、 $pdo = null を割り当てるとその変数の参照だけが削除されます。
PDOStatementまたは他の変数は接続を保持することができます。 そのリファレンスも解放してください。
closeCursor() 保留中の結果を解放し、ステートメントを再利用できるようにします。これは接続クローズ方式ではありません。
両方のAPIはオートコミットモードで始まります。正常に実行されたステートメントは、トランザクションを開始しない限り、別のアプリケーションコミットなしでコミットされます。 一緒に成功するか一緒に失敗する必要がある書き込みのグループの場合は、sqlsrv_begin_transaction() または $pdo->beginTransaction()を使い、その後でコミットまたはロールバックを明示的に行います。 未処理のトランザクションで接続を閉じるのはロールバックを試みるのであって、コミットではありません。 トランザクション ポリシーの実装にシャットダウン クリーンアップだけ頼らないでください。 完全な例については トランザクションを実行する を参照してください。
PHPの接続ハンドルを解放しても、必ずしも物理的なネットワーク接続が閉じるわけではありません。 ODBCプーリングではそれを再利用のために保持できます。 プーリングはPHPリソースを無期限に保持する理由ではなく、PDO_SQLSRVも PDO::ATTR_PERSISTENT => trueをサポートしていません。 プラットフォーム固有のプーリング構成については 、接続プーリングを参照してください。
ガイドを SQL ターゲットに適用します
ハンドル、フェッチ、クリーンアップのパターンは、サポートされるSQLターゲット上の両方の拡張機能に適用されます。 接続エンドポイント、認証、ネットワークアクセス、SQL の機能は様々です。
| 目標 | 適応 |
|---|---|
| SQL Server | プログラムは SQL ログインを使用します。 統合認証もPHPプロセスのアイデンティティを設定する際の選択肢の一つです。 |
| Azure SQL Database | 論理サーバーのホスト名と明示的なデータベースを使いましょう。 これらのプログラムでは、SQL 資格情報ではなく Microsoft Entra 認証を使用してください。 |
| Azure SQL Managed Instance | インスタンスエンドポイントとそのネットワークアクセス要件を活用してください。 プライベートエンドポイントがワークステーションからアクセス可能だとは思わないでください。 |
| Azure Synapse Analytics | SQLプールエンドポイントを使用し、オブジェクトを作成または修正するクエリを調整する前に T-SQL のサポートを確認してください。 |
| Microsoft Fabric の SQL データベース | データベース接続情報とMicrosoft Entra認証を活用しましょう。 SQL analytics エンドポイントを置き換えないでください。 |
| Microsoft Fabric のウェアハウス | そのウェアハウス エンドポイントとデータベース、Microsoft Entra 認証、MultipleActiveResultSets=falseを活用しましょう。 |
サービス固有の設定については、AzureおよびFabric接続を参照してください。
接続のトラブルシューティング
失敗したステップから始めましょう。 TCP(伝送制御プロトコル)のチェックが成功しても、認証や証明書の検証が成功したとは限りません。
| 症状: | チェック |
|---|---|
Call to undefined function sqlsrv_connect() |
実行中のPHPプロセスはsqlsrvを読み込みませんでした。
php.iniと起動時の警告を確認してください。 |
PDOレポート could not find driver |
そのプロセスに pdo_sqlsrv が読み込まれており、sqlsrv が PDO::getAvailableDrivers() に現れることを確認します。 |
| ODBCドライバーが見つかりません | Microsoft ODBCドライバーをインストールし、その登録状況とアーキテクチャを確認してください。 PHP拡張をインストールしてもODBCはインストールされません。 |
| 接続タイムアウトまたはサーバーが見つからない | サーバー名、ポート、名前解決、ルーティング、ファイアウォールルール、そしてSQL ServerがTCPで待ち受けているかどうかを確認してください。 |
| 証明書チェーンやホスト名の検証が失敗する | 正しい信頼チェーンをインストールし、証明書のホスト名を使いましょう。
TrustServerCertificate=trueを単なる本番環境向けの修正として扱わないでください。 |
| ログインに失敗する、またはデータベースを開けない | 認証モード、データベース名、ログイン/ユーザーマッピング、権限を確認してください。 認証情報を省略すると、統合認証が要求されます。SQL 認証が選択されるわけではありません。 |
| ターミナルでは成功するが、ウェブリクエストは失敗する | PHPランタイム、ロードされた拡張機能、プロセスID/実行ユーザー情報、環境変数、ネットワークアクセスを比較してください。 設定詳細を含む公開 phpinfo() ページを公開しないでください。 |
| 後続の操作は、ハンドルが閉じられていると失敗します | すべてのステートメントの処理中は接続を維持してください。 接続を閉じた後に新しい接続を作成する;古いハンドルは自動的に再び開かない。 |
その他の接続に関する記事
- 指定されたポートに接続
- 接続オプション
- 接続プール
- 複数のアクティブ結果セット(MARS)を無効にする
- LocalDB のサポート
- 高可用性および災害復旧のサポート
- Microsoft Azure SQL Database への接続
- アイドル状態の接続回復性