SQL ServerのPHPドライバーをアップグレードしてください

SQLSRVとPDO_SQLSRVを同時にアップグレードし、両方の拡張機能が同じリリースファミリーを使うようにしましょう。 PHPドライバーはMicrosoft ODBCドライバーfor SQL Serverを使用しているため、アップグレード前にシステム要件を確認してください。

アップグレードはPHPプロセスに読み込まれるネイティブコードを変更します。 混合デプロイメントは前バージョンを継続して実行したり、PHP起動時に失敗したり、CLIやウェブアプリケーションで異なるドライババージョンが使われたりします。 すべてのPHPランタイムを一覧化し、検証が完了するまで以前のファイルや設定を保持してください。

アップグレードパスを選びます

現在のインストール 対象のインストール Procedure
パイ パイ 同じPHP実行ファイルまたは明示的な php-configでPIEを実行し、すべてのSAPIを確認してください
Windowsで作成されたZIP Windows で作成された ZIP 両方のバージョン付きDLLを置き換え、両方の構成エントリを同時に更新します
Windows で作成された ZIP パイ 両方のPIEパッケージをインストールし、バージョン付きDLLエントリをPIEエントリに置き換え、重複を削除します
LinuxまたはmacOS向けのリリース済みアーカイブ パイ 両方のPIEパッケージをインストールし、アーカイブファイル名エントリを sqlsrv.so と pdo_sqlsrv.soに置き換え、PDOロード順序を保持します
LinuxまたはmacOS PIE 新しいPHPマイナーバージョン 新しいPHP開発ツールをインストールし、そのPHPインストール用に両方の拡張機能をビルドし、それぞれのSAPIを個別に設定します

ロールバックコピーができるまでは前のバイナリを上書きしないでください。 アプリケーションが両方のAPIを使う場合、1つの拡張機能だけをアップグレードしないでください。

アップグレードする前に

  1. PHP実行ファイル、設定ファイル、アーキテクチャ、スレッドセーフティモード、現在のドライバーバージョンを記録します。

    php --version
    php --ini
    php --ri sqlsrv
    php --ri pdo_sqlsrv
    
  2. php.iniファイルと、pdo_sqlsrvまたは.iniを読み込む拡張子固有のsqlsrvファイルをバックアップしてください。

  3. ターゲットとなるPHPバージョンとOSのサポート マトリックス を確認してください。

  4. システム要件のODBC互換性表を確認してください。 ターゲットドライバーのリリースで必要な場合は、PHPドライバーのアップグレード前またはアップグレード中にサポートされているODBCバージョンをインストールしてください。

  5. PHPを読み込むすべてのプロセスの再起動を予定してください。ウェブサーバー、PHP FastCGIプロセスマネージャー(PHP-FPM)、キューワーカー、長期間実行されているコマンドラインワーカーを含みます。

  6. 各ランタイムのベースラインを記録する:

    • php --ri pdo_sqlsrvとExtensionVerによって示されるphp --ri sqlsrv。
    • 読み込まれた設定ファイルとスキャンされた.iniディレクトリ
    • 拡張機能ディレクトリとアクティブドライバーのファイル名です。
    • アプリケーションが依存する各APIを使った、成功するアプリケーションのスモークテストです。
  7. ロールバックの準備:

    • PHPのマイナーバージョンを変更する場合は、以前のPHPランタイムをそのまま利用可能にしてください。 各ウェブサーバーとワーカーごとに設定された実行ファイルを記録します。
    • 以前のSQLSRVやPDO_SQLSRVファイルのコピーを保管してください。
    • 変更された php.ini や拡張機能固有の .ini ファイルのコピーをすべて保管してください。
    • アップグレードで変更された場合は、前のODBCパッケージのバージョンを記録してください。
    • ネイティブの拡張ファイルを置き換える間にトラフィックやワーカーを停止する方法を定義してください。

WindowsでPIEを使用したアップグレード

アプリケーションを提供するPHP実行ファイルと組み合わせて、PHP Installer for Extensions(PIE)を使いましょう。 まず、 PIEをダウンロードして検証します。 いずれかのインストールコマンドを実行する前に、アプリケーションへのトラフィックを切り離し、このPHPインストールを使用するウェブサーバー、FastCGIプロセス、ワーカーを停止してください。 拡張機能と設定が揃うまで自動再起動を防いでください。 PIE用のコマンドラインセッションを別に用意してください。

PIEで使用されるCLI構成内の既存のSQLSRVおよびPDO_SQLSRV拡張エントリを一時的にコメントアウトします。 そうでなければ、PIEを実行しているPHPプロセスが古いDLLを読み込んだままにし、置き換えを妨げる可能性があります。 PIEの前提拡張は有効にしておきましょう。

pie.pharを含むディレクトリから、両方のパッケージを別々にインストールしてください:

php .\pie.phar install microsoft/sqlsrv
php .\pie.phar install microsoft/pdo_sqlsrv

PIEは php_sqlsrv.dll と php_pdo_sqlsrv.dllをインストールします。 すべてのアクティブな構成において、extension=php_sqlsrv_85_ts_x64.dll や extension=php_pdo_sqlsrv_85_ts_x64.dll などのバージョン付きZIPエントリを以下のように置き換えてください:

extension=php_sqlsrv.dll
extension=php_pdo_sqlsrv.dll

両方のエントリを有効にし、PIEが自動有効化が成功したと報告しても、重複するSQLSRVやPDO_SQLSRVエントリを削除してください。 もしウェブサーバーが別のPHPインストールを使っている場合は、そのインストールでアップグレードと設定の変更を繰り返し行ってください。

各PHPプロセスを再起動し、対応する実行ファイルで php --ri sqlsrv と php --ri pdo_sqlsrv を実行します。 ExtensionVer が両方のドライバーについてターゲットバージョンを報告していることを確認してください。 ウェブアプリケーションの場合、一時的なページを作成する前にphpinfo()してください。 両方の値を確認してからページを削除してください。

Windows ZIPインストールのアップグレード

  1. ターゲットリリースのWindows ZIPは、Microsoft Drivers for PHP for SQL Serverのリリースページからダウンロードできます。

  2. 新しい動的リンクライブラリ(DLL)の名前がPHPのマイナーバージョン、アーキテクチャ、スレッドセーフティモードと一致しているか確認してください。 ファイルを置き換える前にPHPのウェブサーバーやワーカープロセスを停止してください。

  3. PHP拡張ディレクトリ内の php_sqlsrv_*.dll ファイルと php_pdo_sqlsrv_*.dll ファイルの両方を置き換えてください。 ファイル名が一致しているなら、既存の extension= エントリをそのまま残してください。 それ以外の場合は、まとめて更新してください。

  4. ターゲットとなるPHPドライバーが新しい対応バージョンを必要とする場合は、SQL Server Microsoft ODBCドライバーをインストールしたりアップグレードしたりしてください。

  5. 置き換えたDLLを使うすべてのPHPプロセスを再起動してください。 実行中のプロセスは、終了するまで古いネイティブ拡張を読み込みたままにします。

LinuxやmacOSでPIE を使用してアップグレードしてください

  1. PIEがインストールされていない場合は、PIEの設定とプラットフォームの前提条件を参照してください。 PHP開発ツールとODBC開発パッケージがインストールされているか確認してください。 インタラクティブセッションでは、PIEはプラットフォームパッケージマネージャーを通じて不足しているビルドツールのインストールを促すことができます。 非インタラクティブなセッションでは、PIEを実行する前にそれらをインストールしてください。

  2. アップグレード前に対象のPHPを選択してください。 バージョン付きインストールの場合は、両方のインストールコマンドにPIEの --with-php-config オプションを追加してください。 例えば、意図された設定ツールが pie install --with-php-config=/usr/bin/php-config8.4 microsoft/sqlsrv である場合は、/usr/bin/php-config8.4 を使います。 同じオプションを microsoft/pdo_sqlsrvにも適用してください。 Alpineのバージョン対応実行ファイルについては、 Alpineのインストールコマンドを使ってください。

  3. アプリケーションのトラフィックを切り離し、このPHPインストールを利用するウェブサーバー、PHP-FPM プロセス、ワーカーを停止します。 拡張機能と設定が揃うまで自動再起動を防いでください。 PIE用のコマンドラインセッションを別に用意してください。

    PIEで使用されるCLI構成内の既存のSQLSRVおよびPDO_SQLSRV拡張エントリを一時的にコメントアウトします。 PIEの前提となる拡張機能は有効にしておきましょう。

  4. 両方のパッケージを別々にアップグレードしてください。 これらのコマンドはPIEのデフォルトのPHPインストールを使用しています:

    pie install microsoft/sqlsrv
    pie install microsoft/pdo_sqlsrv
    
  5. アプリケーションで使われているPHPインストールのアクティブな設定をすべて確認してください。 以前の手動インストールで extension=SQLSRV_8.4_NTS.so や extension=PDO_SQLSRV_8.4_NTS.soなどのアーカイブファイル名が使われている場合は、それらのエントリをPIEでインストールされたファイル名に置き換えてください。

    extension=sqlsrv.so
    extension=pdo_sqlsrv.so
    

    両方のドライバーエントリを再有効にし、重複するものを削除してください。 PDO_SQLSRVは、Linux と macOS でドライバーを読み込むで説明されているように、PDOの後に読み込まれるスキャン済みの構成ファイルに保持してください。 この設定変更を、アプリケーションが使用するコマンドライン、PHP-FPM、ウェブサーバー、ワーカーの構成にも適用します。

  6. ターゲット リリースで必要な場合は、SQL Server 用 Microsoft ODBC ドライバーをアップグレードしてください。

  7. アップグレードされたPHPインストールを使用しているCLIワーカー、キューワーカー、ウェブサーバー、PHP-FPM サービスを再起動してください。

再起動して確認

拡張モジュールのファイルを置き換えても、すでに古いバイナリを読み込んだPHPプロセスが更新されることはありません。 アップグレードを検証する前に、ウェブサーバー、PHP-FPM、そして長期間稼働しているPHPワーカーを再起動してください。

  1. コマンドラインのランタイムを確認してください:

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

    LinuxやmacOSでは、最後のコマンドを php -m | grep -E 'sqlsrv|pdo_sqlsrv'に置き換えてください。

  2. ウェブアプリケーションの場合、一時的なページを作成する前にphpinfo()してください。 両方のドライバーで読み込まれた設定ファイル、拡張機能ディレクトリ、ExtensionVer を確認してください。 ExtensionVerがターゲットバージョンを報告しているか確認し、その後ページを削除してください。

  3. アプリケーションが両方を使用している場合は、SQLSRV と PDO_SQLSRV の両方を検証する既存のアプリケーション スモーク テストを実行してください。 このチェック中は接続設定を変更しないようにしてください。アップグレードテストで無関係な接続変更もテストされないようにするためです。

ドライバがロードできなかった場合は、PHPのマイナーバージョン、アーキテクチャ、スレッドセーフティモード、拡張ディレクトリ、ODBCインストールをアップグレード前に記録した値と比較してください。

APIとバージョンの両方を検証してください

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

<?php
$results = [
    'SQLSRV' => [
        'loaded' => extension_loaded('sqlsrv') && function_exists('sqlsrv_connect'),
        'version' => phpversion('sqlsrv'),
    ],
    'PDO_SQLSRV' => [
        'loaded' => extension_loaded('pdo_sqlsrv')
            && in_array('sqlsrv', PDO::getAvailableDrivers(), true),
        'version' => phpversion('pdo_sqlsrv'),
    ],
];

$failed = false;
foreach ($results as $name => $result) {
    $version = $result['version'] === false ? 'unknown' : $result['version'];
    echo "$name: " . ($result['loaded'] ? 'loaded' : 'missing') . ", version $version" . PHP_EOL;
    $failed = $failed || !$result['loaded'] || $result['version'] === false;
}

exit($failed ? 1 : 0);

CLI実行ファイルでプログラムを実行し、一時的に各ウェブランタイム経由で実行します。 報告された両方のバージョンが、あなたがインストールしたリリースと一致しているか確認してください。 確認後にウェブコピーを削除してください。

このプログラムはPHP拡張層を検証します。 変更されていないアプリケーションのスモークテストを実行し、ODBCの読み込み、接続オプション、認証、データベースアクセス、返されたPHP型、クリーンアップの動作を確認します。

アップグレード前後のデータベースの挙動を確認してください

アップグレード前後で同じプログラムと接続設定を使いましょう。 テストを変更せずに保つことで、ドライバーの変更とアプリケーションや接続設定の変更を分けることができます。

プロンプトに答えて、テストアカウントの SQL_SERVER_NAME、SQL_DATABASE、SQL_UID、SQL_PWD の環境変数を設定しましょう。 シェルの引用符やドライバーのエンコーディングなしで生の値を入力します。 コマンドラインや録画されたターミナルセッションに認証情報を含めないでください。

Windows 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

LinuxやmacOSならBashを使いましょう。 値を読む前にコマンドトレーシングを無効にしてください。 パスワードのプロンプトでは入力内容は表示されません:

set +x
IFS= read -r -p 'Server name (tcp:<server>,1433): ' SQL_SERVER_NAME
IFS= read -r -p 'Database name: ' SQL_DATABASE
IFS= read -r -p 'User name: ' SQL_UID
IFS= read -r -s -p 'Password: ' SQL_PWD
printf '\n'
export SQL_SERVER_NAME SQL_DATABASE SQL_UID SQL_PWD

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

このプログラムを test-driver-upgrade.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-driver-upgrade.php

両ランとも以下の成果が出るはずです:

SQLSRV query: 1
PDO_SQLSRV query: 1

もしアップグレード後の実行が失敗した場合は、正確なSQLSTATEまたは例外を保持します。 次に、障害をベースライン、拡張バージョン、アクティブ設定、ODBCバージョン、プロセス再起動の状態と比較します。 展開ウィンドウ内で不一致が修正できない場合は、両方のPHP拡張を一緒にロールバックしてください。

検証後、テストファイルを削除し、一時的な環境変数をクリアしてください。 PowerShell で、以下を実行します。

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

Linux または macOS で、次を実行:

rm verify-driver-upgrade.php test-driver-upgrade.php
unset SQL_SERVER_NAME SQL_DATABASE SQL_UID SQL_PWD

失敗したアップグレードをロールバックする

  1. 影響を受けたウェブサーバー、PHP-FPM プール、長時間実行中のワーカーを停止させてください。

  2. もしPHPのマイナーバージョンを変更した場合は、前のPHPランタイムを復元し、各ウェブサーバーとワーカーをそのインストールに戻してください。

  3. 両方の以前のドライバーファイルを復元してください。 前のSQLSRVとPDO_SQLSRV設定エントリを一緒に復元します。

  4. 新しいバージョンが障害の原因となっており、かつ復元したPHPドライババージョンが古いパッケージをサポートしている場合にのみ、以前のODBCパッケージを復元してください。

  5. プロセスを再起動し、ベースラインのバージョンチェックとアプリケーションのスモークテストを再実行してください。

  6. 失敗したアップグレードログと、正確なPHPの起動エラーまたは接続エラーを保管してください。 これらは、障害がPHPの読み込み、オペレーティングシステムローダー、ODBC、またはデータベース接続のいずれかに起因しているかを特定するのに役立ちます。

アップグレードのトラブルシューティング

症状: 考えられる原因 是正措置
PIEは成功していますが、ExtensionVerは変更されていません 古いバージョン付きエントリは依然として前のファイルを読み込みます 古いエントリを置き換え、重複を削除し、すべてのPHPプロセスを再起動してください
SQLSRVとPDO_SQLSRVは異なるバージョンを報告します 1つの拡張機能だけが置き換えられた、あるいは1つのSAPIの構成が古くなっています 両方の拡張機能を毎ランタイムで同時にアップグレード・設定してください
CLIはターゲットバージョンを報告しますが、ウェブサイトは報告していません ウェブSAPIは別のPHPインストールを使っているか、再起動されていない可能性があります 設定ディレクトリと拡張ディレクトリを比較し、正しいプロセスを再起動してください
PHP の起動時にアーキテクチャまたはシンボルのエラーが報告される 拡張はPHPビルドと一致しません 以前のファイルを復元し、その後正しいPHPマイナーバージョン、アーキテクチャ、スレッドセーフティモードに合わせてファイルを再構築または選択します
拡張はロードされますが、ODBC変更後に接続が失敗します ODBCの設定、証明書の挙動、認証、またはネットワークアクセスが変更されました ロールバックや接続設定を変更する前に、SQLSTATEとネイティブエラーをキャプチャしてください
ワーカープロセスで障害が発生する一方で、新しいウェブリクエストは成功します 長時間実行中のワーカーは、以前の拡張機能または設定を引き続き保持しています すべてのワーカープロセスをドレインして再起動してください