WindowsでSQL Server用のPHPドライバーをインストールしてください

この記事を使って、Windows上でPHP用のSQLSRVおよびPDO_SQLSRVドライバをインストールしてください。 ドライバーはMicrosoft ODBCドライバーfor SQL Serverを使用するPHP拡張機能です。

始める前に、PHPのバージョン、アーキテクチャ、スレッドセーフティモードが サポートマトリックスでサポートされているかを確認してください。 コマンドラインプロセスで使用されるPHPランタイムとウェブサーバーで使用されるPHPランタイムは、異なる php.ini ファイルを使用できます。 各ランタイムを個別に設定・検証してください。

手続きの最後に、sqlsrv_connect() と PDO sqlsrv ドライバの両方が意図された CLI またはウェブアプリケーションで利用可能となり、各 API はテストクエリを完了するはずです。 成功したファイルコピーだけではインストールが完了しません。

インストール方法を選択する

Method 次の場合に使用します。 インストールするもの
PHP拡張機能用インストーラー(PIE) インストーラーにPHP実行ファイルのドライバービルドを選択してもらいたいのです バージョンなしの php_sqlsrv.dll および php_pdo_sqlsrv.dll、自動構成が試行された
リリース済みのZIPパッケージ 自分で正確なプリビルドファイルを選び、検査し、デプロイする必要があります PHPのマイナーバージョン、スレッドセーフティモード、アーキテクチャによって選択されるバージョン付きDLL

両方の拡張機能で同じ方法を使用してください。 PIEとZIPの設定エントリを同時にアクティブにしないようにしましょう。

前提条件をインストールする

  1. Windows用のPHP サイトからサポート済みPHPビルドをインストールしてください。 PHPディレクトリを PATHに追加してください。

  2. PHPビルドに必要なVisual C++ Redistributableをインストールしてください。 その x64 または x86 アーキテクチャを、Windows 用 PHP の要件に記載されているとおり、PHP に一致させてください。

  3. 最新のMicrosoft ODBC Driver for SQL Serverをインストールしてください。

  4. PHPランタイムと設定ファイルを確認するために以下のコマンドを実行します:

    php --version
    php --ini
    

    Loaded Configuration Fileが(none)の場合、php.ini-developmentをPHPディレクトリのphp.iniにコピーしてください。

  5. php.iniでは、拡張ディレクトリを設定し、PHP Installer for Extensions(PIE)で必要な拡張機能を有効にします。

    extension_dir = "ext"
    extension=openssl
    extension=zip
    
  6. PHPが前提拡張を検出できるか確認してください:

    php --ri openssl
    php --ri zip
    

    PIEをダウンロードする前に、これらの必要条件を満たしてください。

PIE を使用してインストール

PIE はPHPランタイム用の対応する事前コンパイル済みドライバーをインストールします。 WindowsではCコンパイラは必要ありません。

  1. 書き込み可能なディレクトリに変更し、最新のPIE PHPアーカイブ(PHAR)をダウンロードしてください:

    curl.exe -fL --output pie.phar https://github.com/php/pie/releases/latest/download/pie.phar
    

    残りのPIEコマンドはファイルを .\pie.pharとして参照するため、この同じディレクトリから実行してください。

    PHARを実行する前に、GitHubのコマンドラインインターフェース(CLI)で確認してください:

    gh attestation verify --owner php .\pie.phar
    

    続行する前にダウンロードの確認をしてください:

    dir pie.phar
    php .\pie.phar --version
    
  2. ドライバーごとに個別にインストールしてください:

    php .\pie.phar install microsoft/sqlsrv
    php .\pie.phar install microsoft/pdo_sqlsrv
    
  3. コマンドラインのランタイムを確認してください:

    php --ri sqlsrv
    php --ri pdo_sqlsrv
    php -m | findstr /I "sqlsrv pdo_sqlsrv"
    

PIEはコマンドライン実行ファイルで使用される構成内で拡張を有効にしようとします。 PIEが拡張機能を有効にできないと報告した場合は、PIE固有の拡張機能エントリを追加してください。

もしあなたのウェブサーバーが別のPHPインストールを使っている場合は、設定する前に、そのインストールのPHPバージョン、アーキテクチャ、スレッドセーフティモードに対応する両方のドライバーをインストールしてください。 同じPHPインストールでウェブサーバーで別の php.ini を使っている場合は、そのファイルでインストール済みドライバーを有効にしてください。 ウェブランタイムは別途検証し、設定を変更した後はウェブサーバーを再起動してください。

PIEは選択したPHP のインストールを変更します。 IISの設定も、IISサイトの選択も、既存のPHPプロセスを再起動することもありません。

リリースされたZIPパッケージを手動でインストールしてください

ドライバーファイルを自分で選ぶ必要がある場合や、PIEが適さない場合にこの方法を使うと良いでしょう。

  1. Microsoft Drivers for PHP for SQL Serverのリリースページから、リリースされたドライバーバージョンのWindows ZIPファイルをダウンロードしてください。

  2. php -i | findstr /I "PHP Version Thread Safety Architecture extension_dir"を実行し、PHPバージョン、スレッドセーフティモード、アーキテクチャ、拡張ディレクトリを記録します。

  3. ZIPから、両方の一致する動的リンクライブラリ(DLL)を拡張ディレクトリにコピーします:

    php_sqlsrv_<php-version>_<ts-or-nts>_<x86-or-x64>.dll
    php_pdo_sqlsrv_<php-version>_<ts-or-nts>_<x86-or-x64>.dll
    

    例えば、PHP 8.5 x64のスレッドセーフランタイムは php_sqlsrv_85_ts_x64.dll と php_pdo_sqlsrv_85_ts_x64.dllを使用します。

  4. ランタイムで使用される php.ini に対応する拡張名を追加します:

    extension=php_sqlsrv_85_ts_x64.dll
    extension=php_pdo_sqlsrv_85_ts_x64.dll
    

    85、ts、x64をPHPランタイムの値に置き換えてください。 スレッドセーフと非スレッドセーフファイル、32ビットと64ビットファイル、または別のPHPマイナーバージョン用に作成されたファイルを混同しないでください。

  5. php --ri sqlsrv、php --ri pdo_sqlsrv、php -mで実行時間を検証してください。 ウェブサーバーの場合は、一時的なページを作成する前にphpinfo()してください。 Loaded Configuration Fileと両方のドライバーセクションを確認し、その後ページを閉じてください。

ウェブサーバーの設定

IISの場合は、php-cgi.exeに従って、意図したを FastCGI アプリケーションとして構成してください。 FastCGIアプリケーションがドライバーインストール時に使ったのと同じPHPディレクトリとアーキテクチャを使用しているか確認してください。

任意のWindowsウェブサーバーの場合:

  1. phpinfo()してから、一時的なページを作成してください。 ウェブサーバーのPHP実行ファイルとアクティブな php.ini設定を特定します。

  2. 両方のドライバーがウェブランタイム用にインストールされていることを確認してください。 別のPHPインストールの場合は、そのインストールのPHP実行ファイルでPIEを使用するか、リリースされたZIPから両方の一致するDLLを拡張ディレクトリにコピーしてください。 ドライバーエントリをウェブランタイムの設定に追加します。これには、php.ini だけが CLI と異なる場合を含めます。

  3. ウェブサーバーやFastCGIプロセスを再起動してください。

  4. ページに別々の sqlsrv と pdo_sqlsrv セクションが含まれているか確認してください。

  5. phpinfo()ページを削除してください。

両方のPHP APIをテストしてください

このプログラムを verify-php-drivers.phpとして保存してください:

<?php
$failures = [];

if (!extension_loaded('sqlsrv') || !function_exists('sqlsrv_connect')) {
    $failures[] = 'SQLSRV is not available.';
}

if (!extension_loaded('pdo_sqlsrv') || !in_array('sqlsrv', PDO::getAvailableDrivers(), true)) {
    $failures[] = 'PDO_SQLSRV is not available.';
}

echo $failures === []
    ? "SQLSRV and PDO_SQLSRV are available." . PHP_EOL
    : implode(PHP_EOL, $failures) . PHP_EOL;

exit($failures === [] ? 0 : 1);

まずコマンドラインから実行してください:

php verify-php-drivers.php

予想される出力:

SQLSRV and PDO_SQLSRV are available.

ウェブランタイムを検証する必要がある場合は、ファイルを一時的にサイトのドキュメントルートに置き、ブラウザでリクエストしてください。 テスト後に取り外してください。 このプログラムはデータベースの認証情報を要求または公開することなくPHPのAPIを検証します。

データベース接続のテスト

拡張の読み込みは最初のインストールチェックに過ぎません。 両方のAPIをアプリケーションが使用するデータベースに対してテストし、ODBCドライバー、ネットワークパス、暗号化、認証、クエリ実行、返された値、クリーンアップもカバーします。

PowerShellでプロンプトに応じて一時的な環境変数を設定しましょう。 サーバー名とデータベース名を生の値として入力し、引用符やドライバーエンコードなしで入力します。 認証情報ダイアログやプロンプトを使って、データベースに接続できるテストアカウントの認証情報を入力してください。 コマンドラインや録画されたターミナルセッションに認証情報を含めないでください:

$env:SQL_SERVER_NAME = Read-Host "Server name (tcp:<server>,1433)"
$env:SQL_DATABASE = Read-Host "Database name"
$credential = Get-Credential -Message "Enter the database test account"
if ($null -eq $credential) {
    throw "Database test credentials are required."
}
$env:SQL_UID = $credential.UserName
$env:SQL_PWD = $credential.GetNetworkCredential().Password
Remove-Variable credential

資格情報プロンプトはパスワードを隠します。 環境には平文パスワードが含まれているため、PHPはそれを読み取ることができます。 これらの変数はテストセッションでのみ使用し、印刷せず、テスト後にクリアしてください。

このプログラムを test-php-drivers.phpとして保存してください。 環境変数の値は変更しないでください。 プログラムは閉鎖ブレースを倍増させ、外側のブレースを追加してから、データベース名、ユーザー名、パスワードをドライバーに渡します。 このエンコーディングによりリテラルな中括弧が保持され、セミコロンで接続オプションを区切るのを防ぎます。

<?php
$serverName = getenv('SQL_SERVER_NAME');
$database = getenv('SQL_DATABASE');
$uid = getenv('SQL_UID');
$pwd = getenv('SQL_PWD');

if ($serverName === false || $serverName === ''
    || $database === false || $database === ''
    || $uid === false || $uid === ''
    || $pwd === false || $pwd === '') {
    fwrite(STDERR, "Set SQL_SERVER_NAME, SQL_DATABASE, SQL_UID, and SQL_PWD." . PHP_EOL);
    exit(1);
}

$database = '{' . str_replace('}', '}}', $database) . '}';
$uid = '{' . str_replace('}', '}}', $uid) . '}';
$pwd = '{' . str_replace('}', '}}', $pwd) . '}';

$connectionOptions = [
    "Database" => $database,
    "UID" => $uid,
    "PWD" => $pwd,
    "Encrypt" => 1,
    "TrustServerCertificate" => 0,
];

$sqlsrvConnection = sqlsrv_connect($serverName, $connectionOptions);
if ($sqlsrvConnection === false) {
    foreach (sqlsrv_errors() as $error) {
        fwrite(
            STDERR,
            "SQLSRV {$error['SQLSTATE']} ({$error['code']}): {$error['message']}" . PHP_EOL
        );
    }
    exit(1);
}

$sqlsrvStatement = sqlsrv_query($sqlsrvConnection, "SELECT 1 AS TEST_VALUE");
if ($sqlsrvStatement === false) {
    foreach (sqlsrv_errors() as $error) {
        fwrite(
            STDERR,
            "SQLSRV {$error['SQLSTATE']} ({$error['code']}): {$error['message']}" . PHP_EOL
        );
    }
    sqlsrv_close($sqlsrvConnection);
    exit(1);
}

$sqlsrvRow = sqlsrv_fetch_array($sqlsrvStatement, SQLSRV_FETCH_ASSOC);
if ($sqlsrvRow === false || $sqlsrvRow === null || (int) $sqlsrvRow['TEST_VALUE'] !== 1) {
    fwrite(STDERR, "SQLSRV returned an unexpected result." . PHP_EOL);
    sqlsrv_free_stmt($sqlsrvStatement);
    sqlsrv_close($sqlsrvConnection);
    exit(1);
}

echo "SQLSRV query: 1" . PHP_EOL;
sqlsrv_free_stmt($sqlsrvStatement);
sqlsrv_close($sqlsrvConnection);

$failed = false;
try {
    $pdoConnection = new PDO(
        "sqlsrv:server=$serverName;Database=$database;Encrypt=1;TrustServerCertificate=0",
        $uid,
        $pwd,
        [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
    );
    $pdoStatement = $pdoConnection->query("SELECT 1 AS TEST_VALUE");
    $pdoRow = $pdoStatement->fetch(PDO::FETCH_ASSOC);
    if ($pdoRow === false || (int) $pdoRow['TEST_VALUE'] !== 1) {
        throw new RuntimeException("PDO_SQLSRV returned an unexpected result.");
    }

    echo "PDO_SQLSRV query: 1" . PHP_EOL;
} catch (Throwable $exception) {
    fwrite(STDERR, $exception->getMessage() . PHP_EOL);
    $failed = true;
} finally {
    unset($pdoStatement);
    unset($pdoConnection);
}

exit($failed ? 1 : 0);

検証したのと同じPHP実行ファイルでプログラムを実行してください:

php test-php-drivers.php

予想される出力:

SQLSRV query: 1
PDO_SQLSRV query: 1

拡張チェックが通ってもこのプログラムが失敗した場合は、SQLSTATEとネイティブエラーを使って原因となっているレイヤーを特定します。 ネットワーク、証明書、認証、またはデータベース権限のエラーが原因で、PHP拡張機能を再インストールしないでください。

テスト後にスクリプトと一時変数を削除してください:

Remove-Item .\verify-php-drivers.php, .\test-php-drivers.php
Remove-Item Env:\SQL_SERVER_NAME, Env:\SQL_DATABASE, Env:\SQL_UID, Env:\SQL_PWD

Troubleshooting

症状: 確認すべきこと 修正
Could not open input file: .\pie.phar 現在のディレクトリとダウンロード先 検証済みPHARを含むディレクトリに戻るか、再度ダウンロードして検証してください
Unable to load dynamic library extension_dir正確なDLL名、PHPのマイナーバージョン、アーキテクチャ、およびスレッドセーフティモード 対応するDLLを選択するか、意図したPHP実行ファイルでPIEを再実行します
The specified module could not be found ドライバーDLL依存関係 拡張 DLL が存在するか確認し、対応する Visual C++ 再頒布可能パッケージをインストールし、残っている不足 DLL 依存関係を確認してください
CLIは両方のドライバーを読み込みますが、IISは読み込みません 異なるPHP実行ファイルまたは php.ini php --iniとphpinfo()を比較し、IISランタイムを設定し、FastCGIを再起動します
Module "sqlsrv" is already loaded PIEとZIPの両方のエントリー、または繰り返しのエントリー SQLSRVエントリ1つとPDO_SQLSRVエントリ1つを保持しておいてください
PDOレポート could not find driver PDO_SQLSRV の構成 php --ri pdo_sqlsrvを実行してPDO::getAvailableDrivers()を確認しろ
PIEは成功を報告していますが、古いバージョンが残っています バージョン付きZIPエントリが引き続き有効です 古いエントリをPIEのバージョンなしのDLLエントリに置き換え、すべてのPHPプロセスを再起動します

両方の拡張機能が起動すれば、PHPはそれぞれのAPIを呼び出せます。 ドライバーファイルを変更する前にSQLSRVエラーやPDO例外をキャプチャしてください。 ネットワーク、認証、暗号化、証明書、データベース権限のエラーはPHP拡張機能を再インストールしても解決しません。