Обновите драйверы PHP для SQL Server

Обновите SQLSRV и PDO_SQLSRV вместе, чтобы оба расширения использовали одно и то же семейство релизов. Драйверы PHP используют драйвер Microsoft ODBC для SQL Server, поэтому перед обновлением проверьте системные требования.

Обновление меняет нативный код, загруженный в процессы PHP. Смешанное развертывание может продолжать работать на предыдущем релизе, завершаться сбоем при запуске PHP или предоставлять разные версии драйверов для CLI и веб-приложения. Инвентаризируйте все среды выполнения PHP и сохраняйте предыдущие файлы и конфигурацию до завершения верификации.

Выберите путь обновления

Текущая версия Установка цели Procedure
PIE PIE Запустите PIE с тем же исполняемым файлом PHP или явно указав php-config, затем проверьте все SAPI
ZIP-архив, созданный в Windows ZIP, выпущенный в Windows Замените обе DLL с указанием версии и обновите обе записи конфигурации вместе
ZIP, выпущенный в Windows PIE Установите оба PIE-пакета, замените версионные записи DLL на PIE-записи и удалите дубликаты
Архив выпуска для Linux или macOS PIE Установите оба пакета PIE, замените записи имён файлов архива на sqlsrv.so и pdo_sqlsrv.so, и сохраняйте порядок загрузки PDO
Linux или macOS PIE Новая минорная версия PHP Установите новые инструменты разработки PHP, создайте оба расширения для этой установки PHP и настройте каждый SAPI отдельно

Не перезаписывайте предыдущие бинарные файлы, пока у вас не будет резервной копии для отката. Не обновляйте только одно расширение, если приложение использует оба API.

Перед обновлением

  1. Запишите исполняемый файл PHP, конфигурационный файл, архитектуру, режим безопасности потоков и текущие версии драйверов.

    php --version
    php --ini
    php --ri sqlsrv
    php --ri pdo_sqlsrv
    
  2. Сделайте резервную копию php.ini файла и любых файлов, специфичных .ini для расширения, которые загружают sqlsrv или pdo_sqlsrv.

  3. Проверьте матрицу поддержки для целевой версии PHP и операционной системы.

  4. Проверьте таблицу совместимости ODBC в разделе Системные требования. Установите поддерживаемую версию ODBC до или во время обновления драйвера PHP, если этого требует целевой выпуск драйвера.

  5. Планируйте перезапуск каждого процесса, который загружает PHP, включая веб-сервер, PHP FastCGI Process Manager (PHP-FPM), работников очереди и долго работающих процессов командной строки.

  6. Запишите базовое значение для каждой среды выполнения:

    • ExtensionVer показано с помощью php --ri sqlsrv и php --ri pdo_sqlsrv.
    • Загружены файл конфигурации и отсканирован каталог .ini.
    • Каталог расширений и имена активных драйверов.
    • Успешно пройденный smoke-тест приложения, использующий каждый API, от которого зависит ваше приложение.
  7. Подготовьте откат:

    • Оставьте предыдущую PHP-среду выполнения, если измените минорную версию PHP. Запишите исполняемый файл, настроенный для каждого веб-сервера и воркера.
    • Сохраняйте копии предыдущих файлов SQLSRV и PDO_SQLSRV.
    • Храните копии каждого изменённого или относящегося к расширению .ini файла.
    • Запишите предыдущую версию пакета ODBC, если обновление изменит её.
    • Определите, как остановить трафик или воркеры, пока нативные файлы расширений заменяются.

Обновить Windows с помощью PIE

Используйте PHP Installer for Extensions (PIE) вместе с исполняемым файлом PHP, который обслуживает приложение. Сначала скачайте и проверьте PIE. Перед запуском любой из команд установки перенаправьте трафик приложения и остановите работу веб-сервера, процессов FastCGI и рабочих процессов, использующих эту PHP-установку. Не позволяйте им автоматически перезапускаться, пока оба расширения и их конфигурация не будут готовы. Оставьте отдельную командную сессию для PIE.

Временно прокомментируйте существующие записи SQLSRV и PDO_SQLSRV расширения в конфигурации CLI, используемой PIE. В противном случае процесс PHP, в котором работает PIE, может поддерживать загрузку старых 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. В каждой активной конфигурации замените версионные ZIP-записи, такие, как extension=php_sqlsrv_85_ts_x64.dll и extension=php_pdo_sqlsrv_85_ts_x64.dll, на:

extension=php_sqlsrv.dll
extension=php_pdo_sqlsrv.dll

Включите обе записи и удаляйте дублирующие записи SQLSRV и PDO_SQLSRV, даже если PIE сообщает, что автоматическое включение прошло успешно. Если веб-сервер использует другую PHP-установку, повторите обновление и внесение изменений в конфигурацию для этой установки.

Перезапустите каждый PHP-процесс, затем запустите php --ri sqlsrv и php --ri pdo_sqlsrv с помощью соответствующего исполняемого файла. Подтвердите, что ExtensionVer показывает целевую версию для обоих драйверов. Для веб-приложения ограничите доступ к диагностической странице перед созданием временной phpinfo() страницы. Проверьте оба значения, затем удалите страницу.

Обновить ZIP-установку в Windows

  1. Скачайте Windows ZIP целевой версии со страницы выпусков Microsoft Drivers for PHP for SQL Server.

  2. Убедитесь, что имена новой библиотеки динамических связей (DLL) совпадают с минорной версией PHP, архитектурой и режимом безопасности потоков. Остановите веб-сервер PHP или рабочие процессы перед заменой файлов.

  3. Замените оба php_sqlsrv_*.dll и php_pdo_sqlsrv_*.dll файла в каталоге расширений PHP. Сохраняйте существующие extension= записи, если имена файлов всё ещё совпадают. В противном случае обновляйте их вместе.

  4. Установите или обновите драйвер Microsoft ODBC для SQL Server, если для целевого PHP-драйвера нужна более новая поддерживаемая версия.

  5. Перезапустите все PHP-процессы, использующие заменённые DLL. Запущенный процесс оставляет старое нативное расширение загруженным до своего завершения.

Обновитесь на Linux или macOS с PIE

  1. Следуйте требованиям к настройке PIE и предварительным требованиям платформы, если PIE не установлен. Убедитесь, что инструменты разработки PHP и пакет разработки ODBC установлены. В интерактивной сессии PIE может предложить установить отсутствующие инструменты сборки через менеджер пакетов платформы. В неинтерактивной сессии установите их перед запуском PIE.

  2. Выберите установку PHP перед обновлением. Для версионной установки добавьте опцию --with-php-config PIE к обеим командам установки. Например, используйте pie install --with-php-config=/usr/bin/php-config8.4 microsoft/sqlsrv тогда, когда предполагаемый инструмент конфигурации — /usr/bin/php-config8.4. Примените тот же вариант к microsoft/pdo_sqlsrv. Для версионных исполняемых файлов Alpine используйте команды установки Alpine.

  3. Перенаправить трафик приложения и остановить веб-сервер, процессы PHP-FPM и воркеры, использующие эту PHP-установку. Не позволяйте им автоматически перезапускаться, пока оба расширения и их конфигурация не будут готовы. Оставьте отдельную командную сессию для PIE.

    Временно прокомментируйте существующие записи расширений SQLSRV и PDO_SQLSRV в конфигурации CLI, используемой PIE. Оставьте включёнными необходимые расширения PIE.

  4. Обновляйте оба пакета отдельно. Эти команды используют стандартную установку PHP от PIE:

    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 в сканируемом конфигурационном файле, который загружается после PDO, как описано в разделе «Загрузить драйверы на Linux и macOS». Повторите это изменение конфигурации для командной строки, PHP-FPM, веб-сервера и рабочих конфигураций, которые использует ваше приложение.

  6. Обновляйте драйвер Microsoft ODBC для SQL Server по мере необходимости целевого релиза.

  7. Перезапустите все CLI-воркеры, воркеры очереди, веб-сервер и службу PHP-FPM, использующие обновлённую установку PHP.

Перезагрузите и проверьте

Замена файла расширения не обновляет 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. Запустите существующий smoke-тест приложения, который проверяет и SQLSRV, и PDO_SQLSRV, если ваше приложение использует оба. Оставьте конфигурацию соединения без изменений во время этой проверки, чтобы тест апгрейда не проверял также несвязанное изменение параметров соединения.

Если драйвер не загружается, сравните версию PHP minor, архитектуру, режим безопасности потоков, каталог расширений и установку 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. Затем проведите smoke-тест приложения без изменений для проверки загрузки 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. Восстанавливайте предыдущий пакет ODBC только если сбой вызвала более новая версия, а старый пакет остаётся поддерживаться восстановленной вами версией драйвера PHP.

  5. Перезапустите процессы и повторно запустите базовые проверки версий и smoke-тесты приложений.

  6. Сохраняйте неудачные журналы обновления и точную ошибку запуска PHP или подключения. Они помогают определить, связано ли сбой с загрузкой PHP, загрузчиком операционной системы, ODBC или соединением с базой данных.

Устранение неполадок при обновлении

Симптом Вероятная причина Корректирующее действие
PIE выполняется успешно, но ExtensionVer остаётся без изменений Старая версионированная запись всё равно загружает предыдущий файл Замените старую запись, удалите дубликаты и перезапустите все процессы PHP
SQLSRV и PDO_SQLSRV сообщают о разных версиях Было заменено только одно расширение, или один SAPI имеет устаревшую конфигурацию Обновите и настройте оба расширения вместе в каждой среде выполнения
CLI указывает целевую версию, а сайт — нет. Веб-SAPI использует другую PHP-установку или не была перезапущена Сравните каталоги конфигураций и расширений, затем перезапустите правильный процесс
Запуск PHP сообщает об ошибке архитектуры или символа Расширение не соответствует сборке PHP Восстановите предыдущие файлы, затем перестройте или выберите файлы для правильной минорной версии PHP, архитектуры и режима безопасности потоков
Расширения загружаются, но соединения выходят из строя после изменения ODBC Конфигурация ODBC, поведение сертификатов, аутентификация или доступ к сети изменились Зафиксируйте ошибку SQLSTATE и нативную ошибку перед откатом или изменением настроек соединения
Воркер-процессы не работают, а новые веб-запросы успешно выполняются Долго работающие воркеры всё ещё сохраняют прежнее расширение или конфигурацию Переведите в режим завершения и заново запускайте каждый рабочий процесс