This document provides guidance for AI coding agents working with the msphpsql GitHub repository — the open-source home of the sqlsrv and pdo_sqlsrv PHP extensions for Microsoft SQL Server.
| File | Purpose |
|---|---|
| README.md | Project overview, prerequisites, build basics |
| CHANGELOG.md | Full release history; current version at top |
| Linux-mac-install.md | Step-by-step install guide for every supported Unix platform |
| buildscripts/README.md | Detailed Windows build instructions (manual & scripted) |
| source/shared/version.h | Single source of truth for version numbers and preview state |
| Area | Path | Description |
|---|---|---|
| Shared core | source/shared/ |
C++ code shared by both extensions |
| SQLSRV extension | source/sqlsrv/ |
Procedural PHP API extension |
| PDO_SQLSRV extension | source/pdo_sqlsrv/ |
PDO interface extension |
| Packaging script | source/packagize.sh |
Copies shared/ into each extension dir for PECL packaging |
| Functional tests | test/functional/ |
.phpt test suites for both extensions |
| Extended tests | test/extended/ |
Always Encrypted v2 special tests |
| BVT tests | test/bvt/ |
Basic verification tests |
| Performance tests | test/Performance/ |
Benchmark suite (phpbench) |
| Windows build scripts | buildscripts/ |
builddrivers.py, buildtools.py |
| Samples | sample/ |
sqlsrv_sample.php, pdo_sqlsrv_sample.php |
| CI (Linux/Mac) | azure-pipelines.yml | Azure Pipelines — builds PHP from source, runs tests |
| CI (Windows) | appveyor.yml | AppVeyor — PHP SDK build matrix |
| Docker | Dockerfile-msphpsql | Ubuntu 24.04 dev environment image |
The drivers ship as two separate PHP extensions that share a common C++ core layer:
source/
├── shared/ # Core logic (ODBC, connection, statement, stream, error handling)
│ ├── core_conn.cpp # Connection management
│ ├── core_init.cpp # Driver initialization
│ ├── core_results.cpp # Result set processing
│ ├── core_stmt.cpp # Statement execution
│ ├── core_stream.cpp # Stream handling
│ ├── core_util.cpp # Utility functions
│ ├── core_sqlsrv.h # Main shared header (includes Zend API, ODBC, platform abstractions)
│ ├── version.h # Version constants
│ ├── FormattedPrint.cpp/h # Cross-platform printf implementation
│ ├── StringFunctions.cpp/h # Cross-platform string operations
│ ├── localizationimpl.cpp # Localization/encoding support
│ ├── msodbcsql.h # ODBC driver header
│ └── xplat_*.h, typedefs_for_linux.h, interlockedatomic*.h # Platform abstractions
│
├── sqlsrv/ # Procedural API extension
│ ├── conn.cpp # sqlsrv_connect(), sqlsrv_close(), etc.
│ ├── init.cpp # Extension module init/shutdown
│ ├── stmt.cpp # sqlsrv_query(), sqlsrv_fetch(), etc.
│ ├── util.cpp # Error handling, logging
│ ├── config.m4 # Linux/Mac autoconf build
│ └── config.w32 # Windows JScript build
│
├── pdo_sqlsrv/ # PDO extension
│ ├── pdo_dbh.cpp # PDO database handle (new PDO(...))
│ ├── pdo_init.cpp # Extension module init/shutdown
│ ├── pdo_parser.cpp # SQL parser for named params
│ ├── pdo_stmt.cpp # PDOStatement operations
│ ├── pdo_util.cpp # Error handling
│ ├── config.m4 # Linux/Mac autoconf build
│ └── config.w32 # Windows JScript build
│
└── packagize.sh # Copies shared/ into sqlsrv/ and pdo_sqlsrv/ for PECL
- Zend API integration: All C++ code uses the PHP Zend Engine API. The shared header
core_sqlsrv.hincludes<php.h>and<zend.h>with MSVC warning suppression for known benign warnings (4100, 4127, 4146, 4244, 4267, 4456, 4457, 4706). - Platform abstraction: Unix builds use
typedefs_for_linux.h,xplat_*.h, andinterlockedatomic*.hto map Win32 types/functions to POSIX equivalents (e.g.,stricmp→strcasecmp,GetLastError→errno). - ODBC layer: All SQL Server communication goes through the Microsoft ODBC Driver for SQL Server (version 17 or 18). The code never talks to TDS directly.
- MARS: Multiple Active Result Sets enabled by default via
MARS_Connection={Yes}.
Each extension has a config.m4 that registers the extension with PHP's build system:
# Build from PHP source tree (extensions in ext/ directory)
phpize
./configure --with-sqlsrv # or --with-pdo_sqlsrv
make
make installThe config.m4 includes logic to avoid double-compiling shared sources when both extensions are built as static (non-shared) in the same PHP build.
Each extension has a config.w32 (JScript) for the PHP Windows SDK build:
- Visual Studio: VS2019 for PHP 8.3, VS2022 for PHP 8.4+
- Security flags:
/NXCOMPAT,/DYNAMICBASE,/guard:cf,/ZH:SHA_256,/W4,/WX,/CETCOMPAT,/Qspectre(for VCVERS >= 1913) - Scripted builds:
buildscripts/builddrivers.pyautomates downloading PHP SDK, source, and building both extensions
source/packagize.sh copies shared/ files into both sqlsrv/ and pdo_sqlsrv/ directories, making each extension self-contained for PECL distribution. Note: PECL version strings must not contain hyphens (e.g., 5.13.0beta1 not 5.13.0-beta1).
The Dockerfile-msphpsql provides a complete Ubuntu 24.04 development environment with PHP, ODBC 18, and all build dependencies pre-installed.
All version information lives in source/shared/version.h:
| Constant | Purpose | Current |
|---|---|---|
SQLVERSION_MAJOR |
Incompatible API changes | 5 |
SQLVERSION_MINOR |
Backward-compatible features | 13 |
SQLVERSION_PATCH |
Backward-compatible bug fixes | 0 |
SQLVERSION_BUILD |
Build metadata (appended as +N) |
0 |
PREVIEW |
Set to 1+ for beta releases, 0 for stable | 0 |
PHP_SQLSRV_VERSION |
PECL version string for sqlsrv | "5.13.0" |
PHP_PDO_SQLSRV_VERSION |
PECL version string for pdo_sqlsrv | "5.13.0" |
Versioning rules:
- Follows semantic versioning
- When
PREVIEW > 0, the version string becomesMAJOR.MINOR.PATCH-betaN(e.g.,5.13.0-beta1) - PECL versions use
MAJOR.MINOR.PATCHbetaN(no hyphen) - The
PHP_SQLSRV_VERSIONandPHP_PDO_SQLSRV_VERSIONconstants must be updated manually (cannot use preprocessor macros due to PECL/Pickle constraints)
Tests use PHP's standard .phpt format:
--TEST--
Description of the test
--SKIPIF--
<?php require('skipif_*.inc'); ?>
--FILE--
<?php
// Test code here
?>
--EXPECT--
Expected output
| Directory | Contents | Count |
|---|---|---|
test/functional/sqlsrv/ |
SQLSRV extension tests | ~260+ tests |
test/functional/pdo_sqlsrv/ |
PDO_SQLSRV extension tests | ~280+ tests |
test/functional/setup/ |
SQL scripts, BCP data files, Python setup scripts | |
test/functional/inc/ |
Shared binary data (GIF files), TVP test data | |
test/extended/ |
Always Encrypted v2 tests | ~12 tests |
test/bvt/ |
Basic verification tests | |
test/Performance/ |
phpbench-based benchmarks |
Tests read connection info from MsSetup.inc (present in each test directory). Connection settings can be overridden via environment variables:
| Variable | Purpose | Default |
|---|---|---|
MSSQL_SERVER |
SQL Server hostname | TARGET_SERVER placeholder |
MSSQL_DATABASE_NAME |
Database name | TARGET_DATABASE placeholder |
MSSQL_UID |
SQL login username | TARGET_USERNAME placeholder |
MSSQL_PWD |
SQL login password | TARGET_PASSWORD placeholder |
MSSQL_DRIVER |
ODBC driver version string | ODBC Driver 18 for SQL Server |
# Run all sqlsrv tests
php run-tests.php test/functional/sqlsrv/
# Run all pdo_sqlsrv tests
php run-tests.php test/functional/pdo_sqlsrv/
# Run a single test
php run-tests.php test/functional/sqlsrv/sqlsrv_connect.phpt| File | Purpose |
|---|---|
MsSetup.inc |
Connection configuration (server, database, credentials, ODBC driver) |
MsCommon.inc |
~600 lines of shared helpers: connect(), isWindows(), testMode(), traceMode(), table creation, data generators |
MsHelper.inc |
Additional helper functions |
MsData.inc |
Test data constants |
skipif*.inc |
Skip conditions (OS, extensions, features, server version) |
tools.inc |
Diagnostic and utility functions |
Tests cover a wide range of features:
- Connectivity: Connect, close, connection options, connection resiliency, connection pooling
- Data types: All SQL Server types, Unicode, large objects, date/time, decimal precision
- Fetch modes: Forward-only, scrollable, buffered queries, client-side cursors
- Transactions: Commit, rollback, savepoints
- Stored procedures: Input/output params, return values, result sets
- Always Encrypted: Column encryption, key vault, enclave operations
- Azure AD / Entra: Authentication modes (
ActiveDirectoryPassword,ActiveDirectoryMSI, etc.) - Table-Valued Parameters (TVP): Sending structured data
- Bulk Copy (BCP):
test/functional/setup/*.datand*.fmtfiles
- Shared Core, Separate Extensions: Common logic goes in
source/shared/. Extension-specific API binding goes insource/sqlsrv/orsource/pdo_sqlsrv/. Never duplicate logic between extensions. - ODBC Abstraction: All database communication uses ODBC. Never implement protocol-level (TDS) communication.
- Cross-Platform: Code must compile and run on Windows, Linux, and macOS. Use the platform abstraction headers (
xplat_*.h,typedefs_for_linux.h) for OS-specific functionality. - PHP Zend Compatibility: Follow Zend Engine API conventions. Use
zend_*functions for memory management. Be aware of thread-safety requirements (ZTS vs NTS builds). - Security by Default: Windows builds enforce
/NXCOMPAT,/DYNAMICBASE,/guard:cf,/Qspectre,/CETCOMPAT. Never log credentials or connection strings in error output. - Backward Compatibility: Avoid breaking existing PHP userland code. New connection options should default to preserving existing behavior.
- Test Coverage: All changes must include
.phpttests. Bothsqlsrvandpdo_sqlsrvshould be tested when shared code changes. Tests have standard dependencies connectivity to a server and database. If a test includes dependencies beyond the standard that aren't present, they should include relevant skip logic.
- Reproduce the issue — write or identify a
.phpttest that demonstrates the bug - Determine if the fix belongs in
source/shared/(affects both extensions) or in an extension-specific file - Implement the fix
- Add or update
.phpttests in bothtest/functional/sqlsrv/andtest/functional/pdo_sqlsrv/if shared code changed - Update
CHANGELOG.mdwith a description under the appropriate version heading
- Add the ODBC keyword mapping in
source/shared/core_sqlsrv.h(connection option definitions) - Register the option in
source/shared/core_conn.cppconnection option arrays - Expose in
source/sqlsrv/conn.cppand/orsource/pdo_sqlsrv/pdo_dbh.cpp - Default to backward-compatible value
- Add tests for the new option in both test suites
- Document in
CHANGELOG.md
- Edit
source/shared/version.h:- Update
SQLVERSION_MAJOR,SQLVERSION_MINOR, and/orSQLVERSION_PATCH - Update
PHP_SQLSRV_VERSIONandPHP_PDO_SQLSRV_VERSIONstring literals - Set
PREVIEWto 0 for stable, or 1+ for beta releases
- Update
- Update
CHANGELOG.mdwith new version heading and release notes - The file header comment
Microsoft Drivers X.YY for PHP for SQL Serverin source files may need updating for major/minor bumps
- Create a
.phptfile in the appropriatetest/functional/subdirectory - Include standard skip logic:
--SKIPIF--with<?php require('skipif_*.inc'); ?> - Use
MsCommon.inchelpers for connection setup and data generation - Ensure the test is deterministic and cleans up after itself (drop temp tables, close connections)
- Provide explicit
--EXPECT--or--EXPECTF--output
- Set version in
source/shared/version.h(ensurePREVIEWis set correctly) - Run
source/packagize.shto copyshared/into both extension directories - Verify
PHP_SQLSRV_VERSION/PHP_PDO_SQLSRV_VERSIONstrings have no hyphens - Each extension directory becomes a self-contained PECL package
| Pipeline | Platform | Trigger |
|---|---|---|
Azure Pipelines (azure-pipelines.yml) |
Linux, macOS | Push to dev, fix/*; PRs to dev |
AppVeyor (appveyor.yml) |
Windows | Push (except legacy branches) |
Codecov (codecov.yml) |
Windows | Coverage reporting |
The Azure Pipelines job builds PHP from source on each target platform, compiles both extensions, then runs the full .phpt test suite against a SQL Server (Docker container on Linux, local instance on Windows/macOS).
The internal Azure DevOps repo (msphpsql) contains the production CI/CD pipelines for official builds, matrix testing, signing, packaging, and release. See that repo's AGENTS.md for pipeline architecture details.
dev— active development branch; all PRs should targetdevmain(ormaster) — stable release branchfix/*— bug fix branches (trigger CI)- Pull requests require CI to pass before merge
| Resource | Link |
|---|---|
| Microsoft Docs (PHP Drivers) | https://learn.microsoft.com/sql/connect/php/microsoft-php-driver-for-sql-server |
| ODBC Driver Docs | https://learn.microsoft.com/sql/connect/odbc/microsoft-odbc-driver-for-sql-server |
| PHP Internals (Building) | https://wiki.php.net/internals/windows/stepbystepbuild_sdk_2 |
| PECL sqlsrv | https://pecl.php.net/package/sqlsrv |
| PECL pdo_sqlsrv | https://pecl.php.net/package/pdo_sqlsrv |
| GitHub Issues | https://github.com/microsoft/msphpsql/issues |
| GitHub Releases | https://github.com/microsoft/msphpsql/releases |
- Check
test/functional/for usage patterns and expected behavior - Read
MsCommon.incfor available test helper functions - Consult
core_sqlsrv.hfor internal data structures and ODBC wrappers - For ODBC behavior, reference the Microsoft ODBC Driver documentation
- For PHP extension API, reference the PHP Internals Book
This document is automatically loaded as context for AI agents working in this repository.