Lưu ý
Cần có ủy quyền mới truy nhập được vào trang này. Bạn có thể thử đăng nhập hoặc thay đổi thư mục.
Cần có ủy quyền mới truy nhập được vào trang này. Bạn có thể thử thay đổi thư mục.
Use this article to install the SQLSRV and PDO_SQLSRV drivers for PHP on Windows. The drivers are PHP extensions that use the Microsoft ODBC Driver for SQL Server.
Before you start, confirm that your PHP version, architecture, and thread-safety mode are supported in the support matrix. The PHP runtime used by a command-line process and the runtime used by a web server can use different php.ini files. Configure and verify each runtime separately.
At the end of the procedure, both sqlsrv_connect() and the PDO sqlsrv driver should be available to the intended CLI or web application, and each API should complete a test query. A successful file copy alone isn't a completed installation.
Choose an installation method
| Method | Use it when | What it installs |
|---|---|---|
| PHP Installer for Extensions (PIE) | You want the installer to select the driver build for the PHP executable | Unversioned php_sqlsrv.dll and php_pdo_sqlsrv.dll, with automatic configuration attempted |
| Released ZIP package | You need to choose, inspect, or deploy exact prebuilt files yourself | Versioned DLLs selected by PHP minor version, thread-safety mode, and architecture |
Use one method for both extensions. Don't keep PIE and ZIP configuration entries active at the same time.
Install prerequisites
Install a supported PHP build from the PHP for Windows site. Add the PHP directory to
PATH.Install the Visual C++ Redistributable required by your PHP build. Match its x64 or x86 architecture to PHP, as described in the PHP for Windows requirements.
Install the latest Microsoft ODBC Driver for SQL Server.
Run the following commands to confirm the PHP runtime and configuration file:
php --version php --iniIf Loaded Configuration File is
(none), copyphp.ini-developmenttophp.iniin the PHP directory.In
php.ini, set the extension directory and enable the extensions required by the PHP Installer for Extensions (PIE):extension_dir = "ext" extension=openssl extension=zipConfirm that PHP can locate the prerequisite extensions:
php --ri openssl php --ri zipFix these prerequisites before downloading PIE.
Install with PIE
PIE installs the matching precompiled driver for the PHP runtime. It doesn't require a C compiler on Windows.
Change to a directory you can write to, and download the latest PIE PHP archive (PHAR):
curl.exe -fL --output pie.phar https://github.com/php/pie/releases/latest/download/pie.pharThe remaining PIE commands refer to the file as
.\pie.phar, so run them from this same directory.Before you run the PHAR, verify it with the GitHub command-line interface (CLI):
gh attestation verify --owner php .\pie.pharConfirm the download before you continue:
dir pie.phar php .\pie.phar --versionInstall each driver separately:
php .\pie.phar install microsoft/sqlsrv php .\pie.phar install microsoft/pdo_sqlsrvVerify the command-line runtime:
php --ri sqlsrv php --ri pdo_sqlsrv php -m | findstr /I "sqlsrv pdo_sqlsrv"
PIE attempts to enable the extensions in the configuration used by the command-line executable. If PIE reports that it couldn't enable an extension, add the PIE-specific extension entries.
If your web server uses another PHP installation, install both drivers for that installation's PHP version, architecture, and thread-safety mode before configuring it. If the same PHP installation uses a different php.ini for the web server, enable the installed drivers in that file. Verify the web runtime separately, and restart the web server after changing its configuration.
PIE changes the selected PHP installation. It doesn't configure IIS, select an IIS site, or restart existing PHP processes.
Manually install a released ZIP package
Use this method when you need to select the driver files yourself or when PIE isn't suitable.
Download the Windows ZIP for the released driver version from the Microsoft Drivers for PHP for SQL Server releases page.
Run
php -i | findstr /I "PHP Version Thread Safety Architecture extension_dir"and record the PHP version, thread-safety mode, architecture, and extension directory.From the ZIP, copy both matching dynamic-link libraries (DLLs) to the extension directory:
php_sqlsrv_<php-version>_<ts-or-nts>_<x86-or-x64>.dll php_pdo_sqlsrv_<php-version>_<ts-or-nts>_<x86-or-x64>.dllFor example, a PHP 8.5 x64 thread-safe runtime uses
php_sqlsrv_85_ts_x64.dllandphp_pdo_sqlsrv_85_ts_x64.dll.Add the matching extension names to the
php.iniused by the runtime:extension=php_sqlsrv_85_ts_x64.dll extension=php_pdo_sqlsrv_85_ts_x64.dllReplace
85,ts, andx64with the values for your PHP runtime. Don't mix thread-safe and non-thread-safe files, 32-bit and 64-bit files, or files built for another PHP minor version.Verify the runtime with
php --ri sqlsrv,php --ri pdo_sqlsrv, andphp -m. For a web server, restrict diagnostic-page access before creating a temporaryphpinfo()page. Verify the Loaded Configuration File and both driver sections, then remove the page.
Configure a web server
For IIS, configure the intended php-cgi.exe as a FastCGI application by following the PHP IIS installation guidance. Confirm that the FastCGI application uses the same PHP directory and architecture that you used to install the drivers.
For any Windows web server:
Restrict diagnostic-page access before creating a temporary
phpinfo()page. Identify the web server's PHP executable and activephp.ini.Ensure both drivers are installed for the web runtime. For a separate PHP installation, use PIE with that installation's PHP executable, or copy both matching DLLs from the released ZIP to its extension directory. Add the driver entries to the web runtime's configuration, including when only its
php.inidiffers from the CLI.Restart the web server or FastCGI processes.
Confirm the page contains separate
sqlsrvandpdo_sqlsrvsections.Remove the
phpinfo()page.
Test both PHP APIs
Save this program as 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);
Run it first from the command line:
php verify-php-drivers.php
Expected output:
SQLSRV and PDO_SQLSRV are available.
If you need to verify a web runtime, place the file temporarily in the site's document root and request it in a browser. Remove it after testing. This program verifies the PHP APIs without requiring or exposing database credentials.
Test a database connection
Extension loading is only the first installation check. Test both APIs against the database target that the application uses so the test also covers the ODBC driver, network path, encryption, authentication, query execution, returned values, and cleanup.
Set temporary environment variables in PowerShell by answering prompts. Enter the server and database names as raw values, without quotes or driver encoding. Use the credential dialog or prompt for a test account that can connect to the database. Don't include credentials in a command line or recorded terminal session:
$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
The credential prompt masks the password. The environment contains the plaintext password so PHP can read it. Use these variables only in the test session, don't print them, and clear them after testing.
Save this program as test-php-drivers.php. Keep the environment values unchanged. The program doubles closing braces and adds outer braces before passing the database name, user name, and password to the driver. This encoding preserves literal braces and prevents semicolons from separating connection options.
<?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);
Run the program with the same PHP executable that you verified:
php test-php-drivers.php
Expected output:
SQLSRV query: 1
PDO_SQLSRV query: 1
If the extension check passes but this program fails, use the SQLSTATE and native error to identify the owning layer. Don't reinstall the PHP extensions for a network, certificate, authentication, or database-permission error.
Remove the script and temporary variables after testing:
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
| Symptom | What to check | Fix |
|---|---|---|
Could not open input file: .\pie.phar |
Current directory and download location | Return to the directory containing the verified PHAR, or download and verify it again |
Unable to load dynamic library |
extension_dir, exact DLL name, PHP minor version, architecture, and thread-safety mode |
Select the matching DLL or rerun PIE with the intended PHP executable |
The specified module could not be found |
Driver DLL dependencies | Confirm the extension DLL exists, install the matching Visual C++ Redistributable, and inspect any remaining missing DLL dependency |
| CLI loads both drivers but IIS doesn't | Different PHP executable or php.ini |
Compare php --ini with phpinfo(), configure the IIS runtime, and restart FastCGI |
Module "sqlsrv" is already loaded |
Both PIE and ZIP entries, or repeated entries | Keep one SQLSRV entry and one PDO_SQLSRV entry |
PDO reports could not find driver |
PDO_SQLSRV configuration | Run php --ri pdo_sqlsrv and check PDO::getAvailableDrivers() |
| PIE reports success but an old version remains | Versioned ZIP entries still active | Replace old entries with PIE's unversioned DLL entries and restart every PHP process |
If both extensions load, PHP can call their APIs. Capture SQLSRV errors or the PDO exception before changing driver files. Network, authentication, encryption, certificate, and database-permission errors aren't fixed by reinstalling the PHP extension.