diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md new file mode 100644 index 00000000..62047a12 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -0,0 +1,19 @@ +Please check the [FAQ (frequently-asked questions)](https://github.com/Microsoft/msphpsql/wiki/FAQ) first. If you have other questions or something to report, please address the following (skipping questions might delay our responses): + +### PHP Driver version or file name + +### SQL Server version + +### Client operating system + +### PHP version + +### Microsoft ODBC Driver version + +### Table schema + +### Problem description + +### Expected behavior and actual behavior + +### Repro code or steps to reproduce diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..516e0e70 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,11 @@ +### Is your feature request related to a problem? Please describe. +A clear and concise description of what the problem is. + +### Describe the solution you'd like +A clear and concise description of what you want to happen. + +### Describe alternatives you've considered +A clear and concise description of any alternative solutions or features you've considered. + +### Additional context +Add any other context about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/other.md b/.github/ISSUE_TEMPLATE/other.md new file mode 100644 index 00000000..e69de29b diff --git a/CHANGELOG.md b/CHANGELOG.md index e91dafaa..afdb62ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,56 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) +## 5.10.0 - 2022-01-31 +Updated PECL release packages. Here is the list of updates: + +### Added +- Support for PHP 8.1 +- Support for macOS Monterey, Debian 11, Ubuntu 21.04 and 21.10, Alpine 3.13, 3.14 and 3.15 +- Support for Apple M1 ARM64 hardware -- requires [MS ODBC Driver 17.8+](https://docs.microsoft.com/sql/connect/odbc/linux-mac/install-microsoft-odbc-driver-sql-server-macos?view=sql-server-ver15) +- Adjusted connection keyword and value validation for more flexibility +- Feature Request [#795](https://github.com/microsoft/msphpsql/issues/795) - adding support for [Table-valued parameters](https://github.com/Microsoft/msphpsql/wiki/Features#tvp) +- Feature Request [#1320](https://github.com/microsoft/msphpsql/issues/1320) - allow PDO::ATTR_EMULATE_PREPARES to be set at the connection level + +### Removed +- Support for PHP 7.3 +- Support for Ubuntu 16.04, Alpine 3.11 and Alpine 3.12 + +### Fixed +- Issue [#1244](https://github.com/microsoft/msphpsql/issues/1244) - use lower case for object names for PDO::lastInsertId() - pull request [#1245](https://github.com/microsoft/msphpsql/pull/1245) by morozov +- Pull request [#1251](https://github.com/microsoft/msphpsql/pull/1251) - simplified implementations of last insert id and quote +- Issue [#1258](https://github.com/microsoft/msphpsql/issues/1258) - updated pdo_sqlsrv_get_driver_methods as per documentation - pull request [#1259](https://github.com/microsoft/msphpsql/pull/1259) +- Pull request [#1260](https://github.com/microsoft/msphpsql/pull/1260) - cleaned up redundant code +- Issue [#1261](https://github.com/microsoft/msphpsql/issues/1261) - simplified get_field_as_string and made it more robust - pull request [#1265](https://github.com/microsoft/msphpsql/pull/1265) +- Pull request [#1262](https://github.com/microsoft/msphpsql/pull/1262) - simplified parse_param_array in sqlsrv +- Pull request [#1267](https://github.com/microsoft/msphpsql/pull/1267) - replaced the obsolete MACRO ZVAL_NEW_ARR with array_init +- Pull request [#1275](https://github.com/microsoft/msphpsql/pull/1275) - fixed warning compiling core_stmt.cpp by mlocati +- Pull request [#1288](https://github.com/microsoft/msphpsql/pull/1288) - applied mask to pdo quote for binary inputs +- Pull request [#1290](https://github.com/microsoft/msphpsql/pull/1290) - updated list of supported processor architecture +- Issue [#1307](https://github.com/microsoft/msphpsql/issues/1307) - added TVP support to non-procedure statements +- Issue [#1310](https://github.com/microsoft/msphpsql/issues/1310) - adjusted sql_data_type and column size for NULL parameters - pull request [#1311](https://github.com/microsoft/msphpsql/pull/1311) by gjcarrette +- Pull request [#1326](https://github.com/microsoft/msphpsql/pull/1326) - php drivers simply pass Azure AD Authentication to ODBC driver, which will verify the settings +- Issue [#1329](https://github.com/microsoft/msphpsql/issues/1329) - reset sql type and column size for input params +- Issue [#1331](https://github.com/microsoft/msphpsql/issues/1331) - restore PDO::ATTR_ERRMODE if calling PDO::lastInsertId() call fails - pull request [#1330](https://github.com/microsoft/msphpsql/pull/1330) by mpyw and pull request [#1332](https://github.com/microsoft/msphpsql/pull/1332) + +### Limitations +- No support for inout / output params when using sql_variant type +- No support for inout / output params when formatting decimal values +- In Linux and macOS, setlocale() only takes effect if it is invoked before the first connection. Attempting to set the locale after connecting will not work +- Always Encrypted requires [MS ODBC Driver 17+](https://docs.microsoft.com/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server) + - Only Windows Certificate Store and Azure Key Vault are supported. Custom Keystores are not yet supported + - Issue [#716](https://github.com/Microsoft/msphpsql/issues/716) - With Always Encrypted enabled, named parameters in subqueries are not supported + - Issue [#1050](https://github.com/microsoft/msphpsql/issues/1050) - With Always Encrypted enabled, insertion requires the column list for any tables with identity columns + - [Always Encrypted limitations](https://docs.microsoft.com/sql/connect/php/using-always-encrypted-php-drivers#limitations-of-the-php-drivers-when-using-always-encrypted) + +### Known Issues +- This release requires ODBC Driver 17.4.2 or above. Otherwise, a warning about failing to set an attribute may be suppressed when using an older ODBC driver. +- Connection pooling on Linux or macOS is not recommended with [unixODBC](http://www.unixodbc.org/) < 2.3.7 +- When pooling is enabled in Linux or macOS + - unixODBC <= 2.3.4 (Linux and macOS) might not return proper diagnostic information, such as error messages, warnings and informative messages + - due to this unixODBC bug, fetch large data (such as xml, binary) as streams as a workaround. See the examples [here](https://github.com/Microsoft/msphpsql/wiki/Features#pooling) + + ## 5.10.0-beta2 - 2021-12-02 Updated PECL release packages. Here is the list of updates: diff --git a/LICENSE b/LICENSE index 6b4b06b4..aa5995c1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright(c) 2021 Microsoft Corporation +Copyright(c) 2022 Microsoft Corporation All rights reserved. MIT License diff --git a/Linux-mac-install.md b/Linux-mac-install.md index 33034897..8a0b4911 100644 --- a/Linux-mac-install.md +++ b/Linux-mac-install.md @@ -1,7 +1,7 @@ # Linux and macOS Installation Tutorial for the Microsoft Drivers for PHP for SQL Server -The following instructions assume a clean environment and show how to install PHP 8.0, the Microsoft ODBC driver, the Apache web server, and the Microsoft Drivers for PHP for SQL Server on Ubuntu, RedHat, Debian, Suse, Alpine, and macOS. These instructions advise installing the drivers using PECL, but you can also download the prebuilt binaries from the [Microsoft Drivers for PHP for SQL Server](https://github.com/Microsoft/msphpsql/releases) Github project page and install them following the instructions in [Loading the Microsoft Drivers for PHP for SQL Server](https://docs.microsoft.com/sql/connect/php/loading-the-php-sql-driver). For an explanation of extension loading and why we do not add the extensions to php.ini, see the section on [loading the drivers](https://docs.microsoft.com/sql/connect/php/loading-the-php-sql-driver#loading-the-driver-at-php-startup). +The following instructions assume a clean environment and show how to install PHP 8.1, the Microsoft ODBC driver, the Apache web server, and the Microsoft Drivers for PHP for SQL Server on Ubuntu, RedHat, Debian, Suse, Alpine, and macOS. These instructions advise installing the drivers using PECL, but you can also download the prebuilt binaries from the [Microsoft Drivers for PHP for SQL Server](https://github.com/Microsoft/msphpsql/releases) Github project page and install them following the instructions in [Loading the Microsoft Drivers for PHP for SQL Server](https://docs.microsoft.com/sql/connect/php/loading-the-php-sql-driver). For an explanation of extension loading and why we do not add the extensions to php.ini, see the section on [loading the drivers](https://docs.microsoft.com/sql/connect/php/loading-the-php-sql-driver#loading-the-driver-at-php-startup). -The following instructions install PHP 8.0 by default using `pecl install`, if the PHP 8.0 packages are available. You may need to run `pecl channel-update pecl.php.net` first. Note that some supported Linux distros default to PHP 7.1 or earlier, which is not supported for the latest version of the PHP drivers for SQL Server -- please see the notes at the beginning of each section to install PHP 7.4 or 7.3 instead. +The following instructions install PHP 8.1 by default using `pecl install`, if the PHP 8.1 packages are available. You may need to run `pecl channel-update pecl.php.net` first. Note that some supported Linux distros default to PHP 7.1 or earlier, which is not supported for the latest version of the PHP drivers for SQL Server -- please see the notes at the beginning of each section to install PHP 7.4 or 8.0 instead. Also included are instructions for installing the PHP FastCGI Process Manager, PHP-FPM, on Ubuntu. This is needed if you are using the nginx web server instead of Apache. @@ -20,14 +20,14 @@ While these instructions contain commands to install both SQLSRV and PDO_SQLSRV ## Installing the drivers on Ubuntu > [!NOTE] -> To install PHP 7.4 or 7.3, replace 8.0 with 7.4 or 7.3 in the following commands. +> To install PHP 7.4 or 8.0, replace 8.1 with 7.4 or 8.0 in the following commands. ### Step 1. Install PHP ```bash sudo su add-apt-repository ppa:ondrej/php -y apt-get update -apt-get install php8.0 php8.0-dev php8.0-xml -y --allow-unauthenticated +apt-get install php8.1 php8.1-dev php8.1-xml -y --allow-unauthenticated ``` ### Step 2. Install prerequisites Install the ODBC driver for Ubuntu by following the instructions on the [Install the Microsoft ODBC driver for SQL Server (Linux)](https://docs.microsoft.com/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-ver15). @@ -37,10 +37,10 @@ Install the ODBC driver for Ubuntu by following the instructions on the [Install sudo pecl install sqlsrv sudo pecl install pdo_sqlsrv sudo su -printf "; priority=20\nextension=sqlsrv.so\n" > /etc/php/8.0/mods-available/sqlsrv.ini -printf "; priority=30\nextension=pdo_sqlsrv.so\n" > /etc/php/8.0/mods-available/pdo_sqlsrv.ini +printf "; priority=20\nextension=sqlsrv.so\n" > /etc/php/8.1/mods-available/sqlsrv.ini +printf "; priority=30\nextension=pdo_sqlsrv.so\n" > /etc/php/8.1/mods-available/pdo_sqlsrv.ini exit -sudo phpenmod -v 8.0 sqlsrv pdo_sqlsrv +sudo phpenmod -v 8.1 sqlsrv pdo_sqlsrv ``` If there is only one PHP version in the system, then the last step can be simplified to `phpenmod sqlsrv pdo_sqlsrv`. @@ -48,10 +48,10 @@ If there is only one PHP version in the system, then the last step can be simpli ### Step 4. Install Apache and configure driver loading ```bash sudo su -apt-get install libapache2-mod-php8.0 apache2 +apt-get install libapache2-mod-php8.1 apache2 a2dismod mpm_event a2enmod mpm_prefork -a2enmod php8.0 +a2enmod php8.1 exit ``` ### Step 5. Restart Apache and test the sample script @@ -63,42 +63,42 @@ To test your installation, see [Testing your installation](#testing-your-install ## Installing the drivers with PHP-FPM on Ubuntu > [!NOTE] -> To install PHP 7.4 or 7.3, replace 8.0 with 7.4 or 7.3 in the following commands. +> To install PHP 7.4 or 8.0, replace 8.1 with 7.4 or 8.0 in the following commands. ### Step 1. Install PHP ```bash sudo su add-apt-repository ppa:ondrej/php -y apt-get update -apt-get install php8.0 php8.0-dev php8.0-fpm php8.0-xml -y --allow-unauthenticated +apt-get install php8.1 php8.1-dev php8.1-fpm php8.1-xml -y --allow-unauthenticated ``` Verify the status of the PHP-FPM service by running ```bash -systemctl status php8.0-fpm +systemctl status php8.1-fpm ``` ### Step 2. Install prerequisites Install the ODBC driver for Ubuntu by following the instructions on the [Install the Microsoft ODBC driver for SQL Server (Linux)](https://docs.microsoft.com/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-ver15). ### Step 3. Install the PHP drivers for Microsoft SQL Server ```bash -sudo pecl config-set php_ini /etc/php/8.0/fpm/php.ini +sudo pecl config-set php_ini /etc/php/8.1/fpm/php.ini sudo pecl install sqlsrv sudo pecl install pdo_sqlsrv sudo su -printf "; priority=20\nextension=sqlsrv.so\n" > /etc/php/8.0/mods-available/sqlsrv.ini -printf "; priority=30\nextension=pdo_sqlsrv.so\n" > /etc/php/8.0/mods-available/pdo_sqlsrv.ini +printf "; priority=20\nextension=sqlsrv.so\n" > /etc/php/8.1/mods-available/sqlsrv.ini +printf "; priority=30\nextension=pdo_sqlsrv.so\n" > /etc/php/8.1/mods-available/pdo_sqlsrv.ini exit -sudo phpenmod -v 8.0 sqlsrv pdo_sqlsrv +sudo phpenmod -v 8.1 sqlsrv pdo_sqlsrv ``` If there is only one PHP version in the system, then the last step can be simplified to `phpenmod sqlsrv pdo_sqlsrv`. -Verify that `sqlsrv.ini` and `pdo_sqlsrv.ini` are located in `/etc/php/8.0/fpm/conf.d/`: +Verify that `sqlsrv.ini` and `pdo_sqlsrv.ini` are located in `/etc/php/8.1/fpm/conf.d/`: ```bash -ls /etc/php/8.0/fpm/conf.d/*sqlsrv.ini +ls /etc/php/8.1/fpm/conf.d/*sqlsrv.ini ``` Restart the PHP-FPM service: ```bash -sudo systemctl restart php8.0-fpm +sudo systemctl restart php8.1-fpm ``` ### Step 4. Install and configure nginx @@ -118,7 +118,7 @@ Next, uncomment and modify the section following `# pass PHP scripts to FastCGI # location ~ \.php$ { include snippets/fastcgi-php.conf; - fastcgi_pass unix:/run/php/php8.0-fpm.sock; + fastcgi_pass unix:/run/php/php8.1-fpm.sock; } ``` ### Step 5. Restart nginx and test the sample script @@ -133,29 +133,29 @@ To test your installation, see [Testing your installation](#testing-your-install To install PHP on Red Hat 7, run the following: > [!NOTE] -> To install PHP 7.4 or 7.3, replace remi-php80 with remi-php74 or remi-php73 respectively in the following commands. +> To install PHP 7.4 or 8.0, replace remi-php81 with remi-php74 or remi-php80 respectively in the following commands. ```bash sudo su yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm yum install https://rpms.remirepo.net/enterprise/remi-release-7.rpm subscription-manager repos --enable=rhel-7-server-optional-rpms yum install yum-utils -yum-config-manager --enable remi-php80 +yum-config-manager --enable remi-php81 yum update # Note: The php-pdo package is required only for the PDO_SQLSRV driver -yum install php php-pdo php-xml php-pear php-devel re2c gcc-c++ gcc +yum install php php-pdo php-pear php-devel ``` To install PHP on Red Hat 8, run the following: > [!NOTE] -> To install PHP 7.4 or 7.3, replace remi-8.0 with remi-7.4 or remi-7.3 respectively in the following commands. +> To install PHP 7.4 or 8.0, replace remi-8.1 with remi-7.4 or remi-8.0 respectively in the following commands. ```bash sudo su dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm dnf install https://rpms.remirepo.net/enterprise/remi-release-8.rpm dnf install yum-utils dnf module reset php -dnf module install php:remi-8.0 +dnf module install php:remi-8.1 subscription-manager repos --enable codeready-builder-for-rhel-8-x86_64-rpms dnf update # Note: The php-pdo package is required only for the PDO_SQLSRV driver @@ -196,7 +196,7 @@ To test your installation, see [Testing your installation](#testing-your-install ## Installing the drivers on Debian > [!NOTE] -> To install PHP 7.4 or 7.3, replace 8.0 in the following commands with 7.4 or 7.3. +> To install PHP 7.4 or 8.0, replace 8.1 in the following commands with 7.4 or 8.0. ### Step 1. Install PHP ```bash @@ -205,7 +205,7 @@ apt-get install curl apt-transport-https wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list apt-get update -apt-get install -y php8.0 php8.0-dev php8.0-xml php8.0-intl +apt-get install -y php8.1 php8.1-dev php8.1-xml php8.1-intl ``` ### Step 2. Install prerequisites Install the ODBC driver for Debian by following the instructions on the [Install the Microsoft ODBC driver for SQL Server (Linux)](https://docs.microsoft.com/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-ver15). @@ -223,10 +223,10 @@ You may need to add `/usr/sbin` to your `$PATH`, as the `locale-gen` executable sudo pecl install sqlsrv sudo pecl install pdo_sqlsrv sudo su -printf "; priority=20\nextension=sqlsrv.so\n" > /etc/php/8.0/mods-available/sqlsrv.ini -printf "; priority=30\nextension=pdo_sqlsrv.so\n" > /etc/php/8.0/mods-available/pdo_sqlsrv.ini +printf "; priority=20\nextension=sqlsrv.so\n" > /etc/php/8.1/mods-available/sqlsrv.ini +printf "; priority=30\nextension=pdo_sqlsrv.so\n" > /etc/php/8.1/mods-available/pdo_sqlsrv.ini exit -sudo phpenmod -v 8.0 sqlsrv pdo_sqlsrv +sudo phpenmod -v 8.1 sqlsrv pdo_sqlsrv ``` If there is only one PHP version in the system, then the last step can be simplified to `phpenmod sqlsrv pdo_sqlsrv`. As with `locale-gen`, `phpenmod` is located in `/usr/sbin` so you may need to add this directory to your `$PATH`. @@ -234,10 +234,10 @@ If there is only one PHP version in the system, then the last step can be simpli ### Step 4. Install Apache and configure driver loading ```bash sudo su -apt-get install libapache2-mod-php8.0 apache2 +apt-get install libapache2-mod-php8.1 apache2 a2dismod mpm_event a2enmod mpm_prefork -a2enmod php8.0 +a2enmod php8.1 ``` ### Step 5. Restart Apache and test the sample script ```bash @@ -248,27 +248,22 @@ To test your installation, see [Testing your installation](#testing-your-install ## Installing the drivers on Suse > [!NOTE] -> In the following instructions, replace `` with your version of Suse - if you are using Suse Enterprise Linux 15, it will be SLE_15_SP1 or SLE_15_SP2. For Suse 12, use SLE_12_SP4 (or above if applicable). Not all versions of PHP are available for all versions of Suse Linux - please refer to `http://download.opensuse.org/repositories/devel:/languages:/php` to see which versions of Suse have the default version PHP available, or check `http://download.opensuse.org/repositories/devel:/languages:/php:/` to see which other versions of PHP are available for which versions of Suse. +> In the following instructions, replace `` with your version of Suse - if you are using Suse Enterprise Linux 15, it will be SLE_15_SP3 or SLE_15_SP4 (or above). For Suse 12, use SLE_12_SP5 (or above). Not all versions of PHP are available for all versions of Suse Linux - please refer to `http://download.opensuse.org/repositories/devel:/languages:/php` to see which versions of Suse have the default version PHP available, or check `http://download.opensuse.org/repositories/devel:/languages:/php:/` to see which other versions of PHP are available for which versions of Suse. > [!NOTE] -> Packages for PHP 7.4 or above are not available for Suse 12 and Package for PHP 8.0 is not yet available for Suse 15. -> To install PHP 7.3, replace the repository URL below with the following URL: - `https://download.opensuse.org/repositories/devel:/languages:/php:/php73//devel:languages:php:php73.repo`. +> Packages for PHP 7.4 or above are not available for Suse 12, as of today. ### Step 1. Install PHP ```bash sudo su zypper -n ar -f https://download.opensuse.org/repositories/devel:languages:php//devel:languages:php.repo zypper --gpg-auto-import-keys refresh -zypper -n install php7 php7-devel php7-openssl +zypper -n install php8 php8-pdo php8-devel php8-openssl ``` ### Step 2. Install prerequisites Install the ODBC driver for Suse by following the instructions on the [Install the Microsoft ODBC driver for SQL Server (Linux)](https://docs.microsoft.com/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-ver15). ### Step 3. Install the PHP drivers for Microsoft SQL Server -> [!NOTE] -> If you get an error message saying `Connection to 'pecl.php.net:443' failed: Unable to find the socket transport "ssl"`, edit the pecl script at /usr/bin/pecl and remove the `-n` switch in the last line. This switch prevents PECL from loading ini files when PHP is called, which prevents the OpenSSL extension from loading. - ```bash sudo pecl install sqlsrv sudo pecl install pdo_sqlsrv @@ -280,10 +275,10 @@ exit ### Step 4. Install Apache and configure driver loading ```bash sudo su -zypper install apache2 apache2-mod_php7 -a2enmod php7 -echo "extension=sqlsrv.so" >> /etc/php7/apache2/php.ini -echo "extension=pdo_sqlsrv.so" >> /etc/php7/apache2/php.ini +zypper install apache2 apache2-mod_php8 +a2enmod php8 +echo "extension=sqlsrv.so" >> /etc/php8/apache2/php.ini +echo "extension=pdo_sqlsrv.so" >> /etc/php8/apache2/php.ini exit ``` ### Step 5. Restart Apache and test the sample script @@ -295,7 +290,7 @@ To test your installation, see [Testing your installation](#testing-your-install ## Installing the drivers on Alpine > [!NOTE] -> The default version of PHP is 7.3. PHP 7.4 or above may be available from testing or edge repositories for Alpine. You can instead compile PHP from source. +> PHP 8.1 or above may be available from testing or edge repositories for Alpine. You can instead compile PHP from source. ### Step 1. Install PHP PHP packages for Alpine can be found in the `edge/community` repository. Please check [Enable Community Repository](https://wiki.alpinelinux.org/wiki/Enable_Community_Repository) on their WIKI page. Add the following line to `/etc/apk/repositories`, replacing `` with the URL of an Alpine repository mirror: @@ -306,9 +301,18 @@ Then run: ```bash sudo su apk update -# Note: The php7-pdo package is required only for the PDO_SQLSRV driver +# Note: The php*-pdo package is required only for the PDO_SQLSRV driver +# For PHP 7.* apk add php7 php7-dev php7-pear php7-pdo php7-openssl autoconf make g++ +# For PHP 8.* +apk add php8 php8-dev php8-pear php8-pdo php8-openssl autoconf make g++ +# The following symbolic links are optional but useful +ln -s /usr/bin/php8 /usr/bin/php +ln -s /usr/bin/phpize8 /usr/bin/phpize +ln -s /usr/bin/pecl8 /usr/bin/pecl +ln -s /usr/bin/php-config8 /usr/bin/php-config ``` + ### Step 2. Install prerequisites Install the ODBC driver for Alpine by following the instructions on the [Install the Microsoft ODBC driver for SQL Server (Linux)](https://docs.microsoft.com/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-ver15). @@ -318,12 +322,15 @@ sudo pecl install sqlsrv sudo pecl install pdo_sqlsrv sudo su echo extension=pdo_sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/10_pdo_sqlsrv.ini -echo extension=sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/00_sqlsrv.ini +echo extension=sqlsrv.so >> `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/20_sqlsrv.ini ``` ### Step 4. Install Apache and configure driver loading ```bash +# For PHP 7.* sudo apk add php7-apache2 apache2 +# For PHP 8.* +sudo apk add php8-apache2 apache2 ``` ### Step 5. Restart Apache and test the sample script ```bash @@ -343,18 +350,23 @@ If you do not already have it, install Homebrew as follows: > If using Apple M1 ARM64 hardware, please install Homebrew and PHP directly without using the emulator Rosetta 2. > [!NOTE] -> To install PHP 7.4 or 7.3, replace php@8.0 with php@7.4 or php@7.3 respectively in the following commands. +> To install PHP 7.4 or 8.0, replace php@8.1 with php@7.4 or php@8.0 respectively in the following commands. ### Step 1. Install PHP ```bash brew tap brew tap homebrew/core -brew install php@8.0 +brew install php@8.1 ``` PHP should now be in your path. Run `php -v` to verify that you are running the correct version of PHP. If PHP is not in your path or it is not the correct version, run the following: ```bash -brew link --force --overwrite php@8.0 +brew link --force --overwrite php@8.1 +``` + +If using Apple M1 ARM64, you might need to set the path: +```bash +export PATH="/opt/homebrew/bin:$PATH" ``` ### Step 2. Install prerequisites @@ -395,13 +407,15 @@ To find the Apache configuration file, `httpd.conf`, for your Apache installatio ``` The following commands append the required configuration to `httpd.conf`. Be sure to substitute the path returned by the preceding command in place of `/usr/local/etc/httpd/httpd.conf`: ```bash -echo "LoadModule php7_module /usr/local/opt/php@8.0/lib/httpd/modules/libphp7.so" >> /usr/local/etc/httpd/httpd.conf +echo "LoadModule php7_module /usr/local/opt/php@8.1/lib/httpd/modules/libphp7.so" >> /usr/local/etc/httpd/httpd.conf (echo ""; echo "SetHandler application/x-httpd-php"; echo "";) >> /usr/local/etc/httpd/httpd.conf ``` + ### Step 5. Restart Apache and test the sample script ```bash sudo apachectl restart ``` + To test your installation, see [Testing your installation](#testing-your-installation) at the end of this document. ## Testing Your Installation diff --git a/README.md b/README.md index 6ba07a1f..2f75d72e 100644 --- a/README.md +++ b/README.md @@ -13,28 +13,20 @@ Thank you for taking the time to participate in the [sentiment survey](https://g ### Status of Most Recent Builds -Azure Pipelines | AppVeyor (Windows) | Travis CI (Linux) | Coverage (Windows) | Coverage (Linux) | -|---------------------|--------------------------|--------------------------|---------------------------------------|-------------------------------------------| -| [![az-image][]][az-site] | [![av-image][]][av-site] | [![tv-image][]][tv-site] | [![Coverage Codecov][]][codecov-site] | [![Coverage Coveralls][]][coveralls-site] | +| Azure Pipelines (Linux) | AppVeyor (Windows) | Coverage (Windows) | +|--------------------------|--------------------------|---------------------------------------| +| [![az-image][]][az-site] | [![av-image][]][av-site] | [![Coverage Codecov][]][codecov-site] | [av-image]: https://ci.appveyor.com/api/projects/status/vo4rfei6lxlamrnc?svg=true [av-site]: https://ci.appveyor.com/project/msphpsql/msphpsql/branch/dev -[tv-image]: https://travis-ci.org/microsoft/msphpsql.svg?branch=dev -[tv-site]: https://travis-ci.org/microsoft/msphpsql/ [az-site]: https://dev.azure.com/sqlclientdrivers-ci/msphpsql/_build/latest?definitionId=6&branchName=dev [az-image]: https://dev.azure.com/sqlclientdrivers-ci/msphpsql/_apis/build/status/Microsoft.msphpsql?branchName=dev -[Coverage Coveralls]: https://coveralls.io/repos/github/microsoft/msphpsql/badge.svg?branch=dev&&service=github -[coveralls-site]: https://coveralls.io/github/microsoft/msphpsql?branch=dev [Coverage Codecov]: https://codecov.io/gh/microsoft/msphpsql/branch/dev/graph/badge.svg [codecov-site]: https://codecov.io/gh/microsoft/msphpsql ## Get Started -* [**Windows + SQL Server + PHP 7**](https://www.microsoft.com/sql-server/developer-get-started/php/windows) -* [**Ubuntu + SQL Server + PHP 7**](https://www.microsoft.com/sql-server/developer-get-started/php/ubuntu) -* [**RedHat + SQL Server + PHP 7**](https://www.microsoft.com/sql-server/developer-get-started/php/rhel) -* [**SUSE + SQL Server + PHP 7**](https://www.microsoft.com/sql-server/developer-get-started/php/sles) -* [**macOS + SQL Server + PHP 7**](https://www.microsoft.com/sql-server/developer-get-started/php/mac/) +Please follow the [Getting started](https://docs.microsoft.com/sql/connect/php/getting-started-with-the-php-sql-driver) page. ## Announcements @@ -45,19 +37,19 @@ Azure Pipelines | AppVeyor (Windows) | Travis CI (Linux) | Co For full details on the system requirements for the drivers, see the [system requirements](https://docs.microsoft.com/sql/connect/php/system-requirements-for-the-php-sql-driver) on Microsoft Docs. On the client machine: -- 7.3.x, 7.4.x, 8.0.x -- [Microsoft ODBC Driver 17, Microsoft ODBC Driver 13, or Microsoft ODBC Driver 11][odbcdoc] +- 7.4.x, 8.0.x, 8.1.x +- [Microsoft ODBC Driver 17 or Microsoft ODBC Driver 13][odbcdoc] - If using a Web server such as Internet Information Services (IIS) or Apache, it must be configured to run PHP On the server side, Microsoft SQL Server 2012 and above on Windows are supported, as are Microsoft SQL Server 2016 and above on Linux. ## Building and Installing the Drivers on Windows -The drivers are distributed as pre-compiled extensions for PHP found on the [releases page][releases]. They are available in thread-safe and non thread-safe versions, and in 32-bit and 64-bit versions. The source code for the drivers is also available, and you can compile them as thread safe or non-thread safe versions. The thread safety configuration of your web server will determine which version you need. +The drivers are distributed as pre-compiled extensions for PHP found on the [releases page][releases]. They are available in thread-safe and non-thread-safe versions, and in 32-bit (Windows only) and 64-bit versions. The source code for the drivers is also available, and you can compile them as thread safe or non-thread-safe versions. The thread safety configuration of your web server will determine which version you need. -If you choose to build the drivers, you must be able to build PHP 7.* without including these extensions. For help building PHP on Windows, see the [official PHP website][phpbuild]. For details on compiling the drivers, see the [documentation](https://github.com/Microsoft/msphpsql/tree/dev/buildscripts#windows) -- an example buildscript is provided, but you can also compile the drivers manually. +If you choose to build the drivers, you must be able to build PHP 7.* or 8.* without including these extensions. For help building PHP on Windows, see the [official PHP website][phpbuild]. For details on compiling the drivers, see the [documentation](https://github.com/microsoft/msphpsql/blob/master/buildscripts/README.md) -- an example buildscript is provided, but you can also compile the drivers manually. -To load the drivers, make sure that the driver is in your PHP extension directory and enable it in your PHP installation's php.ini file by adding `extension=php_sqlsrv.dll` and/or `extension=php_pdo_sqlsrv.dll` to it. If necessary, specify the extension directory using `extension_dir`, for example: `extension_dir = "C:\PHP\ext"`. Note that the precompiled binaries have different names -- substitute accordingly in php.ini. For more details on loading the drivers, see [Loading the PHP SQL Driver](https://docs.microsoft.com/sql/connect/php/loading-the-php-sql-driver) on Microsoft Docs. +To load the drivers, make sure that the driver is in your PHP extension directory and enable it in your PHP installation's php.ini file by adding `extension=php_sqlsrv.dll` and/or `extension=php_pdo_sqlsrv.dll` to the ini file. If necessary, specify the extension directory using `extension_dir`, for example: `extension_dir = "C:\PHP\ext"`. Note that the precompiled binaries have different names -- substitute accordingly in php.ini. For more details on loading the drivers, see [Loading the PHP SQL Driver](https://docs.microsoft.com/sql/connect/php/loading-the-php-sql-driver) on Microsoft Docs. Finally, if running PHP in a Web server, restart the Web server. @@ -131,9 +123,9 @@ This project has adopted the Microsoft Open Source Code of Conduct. For more inf [sqldrivers]: https://techcommunity.microsoft.com/t5/SQL-Server/bg-p/SQLServer/label-name/SQLServerDrivers -[project]: https://github.com/Microsoft/msphpsql +[project]: https://github.com/microsoft/msphpsql -[issues]: https://github.com/Microsoft/msphpsql/issues +[issues]: https://github.com/microsoft/msphpsql/issues [releases]: https://github.com/microsoft/msphpsql/releases @@ -141,8 +133,8 @@ This project has adopted the Microsoft Open Source Code of Conduct. For more inf [phpbuild]: https://wiki.php.net/internals/windows/stepbystepbuild_sdk_2 -[phpdoc]: https://docs.microsoft.com/sql/connect/php/microsoft-php-driver-for-sql-server?view=sql-server-2017 +[phpdoc]: https://docs.microsoft.com/sql/connect/php/microsoft-php-driver-for-sql-server -[odbcdoc]: https://docs.microsoft.com/sql/connect/odbc/microsoft-odbc-driver-for-sql-server?view=sql-server-2017 +[odbcdoc]: https://docs.microsoft.com/sql/connect/odbc/microsoft-odbc-driver-for-sql-server [unixinstructions]: https://docs.microsoft.com/sql/connect/php/installation-tutorial-linux-mac diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 944cc954..c7b643f9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -2,7 +2,6 @@ # https://aka.ms/yaml variables: - phpVersion: 7.4 server: 'localhost,1433' host: 'sql1' sqlsrv_db: 'sqlsrv_testdb' @@ -19,7 +18,7 @@ pr: jobs: - job: macOS pool: - vmImage: 'macOS-10.14' + vmImage: 'macOS-10.15' steps: - checkout: self clean: true @@ -27,16 +26,15 @@ jobs: - task: UsePythonVersion@0 inputs: - versionSpec: '3.6' + versionSpec: '3.x' architecture: 'x64' - script: | brew tap brew tap homebrew/core brew reinstall autoconf automake libtool - brew reinstall php@$(phpVersion) php -v - displayName: 'Install PHP' + displayName: 'Install PHP prerequisites' - script: | echo ready to build extensions @@ -63,9 +61,9 @@ jobs: - job: Linux variables: - phpver: 7.4 + phpver: 8.0 pool: - vmImage: 'ubuntu-18.04' + vmImage: 'ubuntu-20.04' steps: - checkout: self clean: true @@ -73,7 +71,7 @@ jobs: - task: UsePythonVersion@0 inputs: - versionSpec: '3.6' + versionSpec: '3.x' architecture: 'x64' - script: | @@ -93,7 +91,7 @@ jobs: sudo apt-get purge unixodbc sudo apt autoremove sudo curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - - curl https://packages.microsoft.com/config/ubuntu/18.04/prod.list > mssql-release.list + curl https://packages.microsoft.com/config/ubuntu/20.04/prod.list > mssql-release.list sudo mv mssql-release.list /etc/apt/sources.list.d/ sudo apt-get update sudo ACCEPT_EULA=Y apt-get install msodbcsql17 mssql-tools @@ -186,7 +184,7 @@ jobs: sed -i -e 's/TARGET_PASSWORD/'"$(pwd)"'/g' MsSetup.inc export LC_ALL='en_US.UTF-8' - php run-tests.php -P ./*.phpt 2>&1 | tee ../sqlsrv.log + php run-tests.php -P ./*.phpt --no-color 2>&1 | tee ../sqlsrv.log displayName: 'Run sqlsrv functional tests' - script: | @@ -197,7 +195,7 @@ jobs: sed -i -e 's/TARGET_PASSWORD/'"$(pwd)"'/g' MsSetup.inc export LC_ALL='en_US.UTF-8' - php run-tests.php -P ./*.phpt 2>&1 | tee ../pdo_sqlsrv.log + php run-tests.php -P ./*.phpt --no-color 2>&1 | tee ../pdo_sqlsrv.log displayName: 'Run pdo_sqlsrv functional tests' - script: | @@ -235,8 +233,10 @@ jobs: condition: always() - job: Windows + variables: + phpVersion: 8.1 pool: - vmImage: 'vs2017-win2016' + vmImage: 'windows-2019' steps: - checkout: self clean: true @@ -244,7 +244,7 @@ jobs: - task: UsePythonVersion@0 inputs: - versionSpec: '3.6' + versionSpec: '3.x' architecture: 'x64' - script: | @@ -269,24 +269,19 @@ jobs: - powershell: | $client = New-Object Net.WebClient - $client.DownloadFile('https://download.microsoft.com/download/E/6/B/E6BFDC7A-5BCD-4C51-9912-635646DA801E/en-US/msodbcsql_17.3.1.1_x64.msi', 'msodbcsql_17.3.1.1_x64.msi') - $client.DownloadFile('https://download.microsoft.com/download/D/5/E/D5EEF288-A277-45C8-855B-8E2CB7E25B96/x64/msodbcsql.msi', 'msodbcsql_13.1.msi') - $client.DownloadFile('https://download.microsoft.com/download/4/C/C/4CC1A229-3C56-4A7F-A3BA-F903C73E5895/EN/x64/MsSqlCmdLnUtils.msi', 'MsSqlCmdLnUtils.msi') + $client.DownloadFile('https://download.microsoft.com/download/a/e/b/aeb7d4ff-ca20-45db-86b8-8a8f774ce97b/en-US/17.8.1.1/x64/msodbcsql.msi', 'c:\projects\msodbcsql.msi') + $client.DownloadFile('https://download.microsoft.com/download/0/e/6/0e63d835-3513-45a0-9cf0-0bc75fb4269e/EN/x64/MsSqlCmdLnUtils.msi', 'MsSqlCmdLnUtils.msi') dir *.msi displayName: 'Download ODBC msi and sql tools msi' condition: false - script: | - msiexec /i "msodbcsql_17.3.1.1_x64.msi" /q IACCEPTMSODBCSQLLICENSETERMS=YES ADDLOCAL=ALL + msiexec /i "msodbcsql.msi" /q IACCEPTMSODBCSQLLICENSETERMS=YES ADDLOCAL=ALL reg query "HKLM\SOFTWARE\ODBC\odbcinst.ini\ODBC Driver 17 for SQL Server" dir %WINDIR%\System32\msodbcsql*.dll displayName: 'Install ODBC driver' condition: false - # TOFIX: Install ODBC 13.1 because of SQLCMD 15 installation bug -- this step should be removed later - - script: msiexec /i "msodbcsql_13.1.msi" /q IACCEPTMSODBCSQLLICENSETERMS=YES ADDLOCAL=ALL - condition: false - # FOR SOME REASON the set up did not set the PATH - script: | msiexec /i "MsSqlCmdLnUtils.msi" /qn IACCEPTMSSQLCMDLNUTILSLICENSETERMS=YES @@ -296,15 +291,16 @@ jobs: - powershell: | $client = New-Object Net.WebClient $client.Headers.Add("user-agent", "azure pipeline build") - $client.DownloadFile("https://windows.php.net/downloads/releases/sha256sum.txt", "sha256sum.txt") - $env:VERSION=type sha256sum.txt | where { $_ -match "php-($(phpVersion)\.\d+)-src" } | foreach { $matches[1] } + $client.DownloadFile("http://windows.php.net/downloads/releases/releases.json", "releases.json"); + $jsondata = Get-Content -Path .\releases.json | ConvertFrom-Json + $env:VERSION = $jsondata.{$(phpVersion)}.version Write-Host "Latest PHP $(phpVersion) is ${env:VERSION}" - cd $(Build.SourcesDirectory)/buildscripts/ - python builddrivers.py --PHPVER=${env:VERSION} --DRIVER=sqlsrv --ARCH=x64 --THREAD=nts --SOURCE=$(Build.SourcesDirectory)/source --TESTING --NO_RENAME + cd $(Build.SourcesDirectory)\buildscripts\ + python builddrivers.py --PHPVER=${env:VERSION} --DRIVER=sqlsrv --ARCH=x64 --THREAD=nts --SOURCE=$(Build.SourcesDirectory)\source --TESTING --NO_RENAME dir *sqlsrv*.dll - python builddrivers.py --PHPVER=${env:VERSION} --DRIVER=pdo_sqlsrv --ARCH=x64 --THREAD=nts --SOURCE=$(Build.SourcesDirectory)/source --TESTING --NO_RENAME - cp php-sdk\phpdev\vc15\x64\php-${env:VERSION}-src\run-tests.php $(Build.SourcesDirectory)\test\functional\sqlsrv - cp php-sdk\phpdev\vc15\x64\php-${env:VERSION}-src\run-tests.php $(Build.SourcesDirectory)\test\functional\pdo_sqlsrv + python builddrivers.py --PHPVER=${env:VERSION} --DRIVER=pdo_sqlsrv --ARCH=x64 --THREAD=nts --SOURCE=$(Build.SourcesDirectory)\source --TESTING --NO_RENAME + cp $(Build.SourcesDirectory)\buildscripts\php-sdk\phpdev\vs16\x64\php-${env:VERSION}-src\run-tests.php $(Build.SourcesDirectory)\test\functional\sqlsrv + cp $(Build.SourcesDirectory)\buildscripts\php-sdk\phpdev\vs16\x64\php-${env:VERSION}-src\run-tests.php $(Build.SourcesDirectory)\test\functional\pdo_sqlsrv dir *sqlsrv*.dll cp *sqlsrv*.dll C:\tools\php\ext\ displayName: 'Build drivers (separately) for the latest version of PHP $(phpVersion)' diff --git a/buildscripts/README.md b/buildscripts/README.md index 3d1481b4..0c9a325e 100644 --- a/buildscripts/README.md +++ b/buildscripts/README.md @@ -14,7 +14,7 @@ To use the sample build scripts `builddrivers.py` and `buildtools.py`, install P You must first be able to build PHP source without including our PHP extensions. For help with building PHP 7.0* or PHP 7.1* in Windows, see the [official PHP website](https://wiki.php.net/internals/windows/stepbystepbuild). For PHP 7.2 or above, visit [PHP SDK page](https://github.com/OSTC/php-sdk-binary-tools) for new instructions. -The Microsoft Drivers for PHP for SQL Server have been compiled and tested with PHP 7.2+ using Visual Studio 2017 and PHP 8.0 previews using Visual Studio 2019. The drivers for Windows that are published for each release (including previews) are digitally signed. You are recommended to sign the binaries you have compiled locally for your own development or testing purposes, using tools like Authenticode. It verifies the publisher's identity and prevents malicious actors from posing as legitimate developers. +The Microsoft Drivers for PHP for SQL Server have been compiled and tested with PHP 7.3+ using Visual Studio 2017 and PHP 8.0+ using Visual Studio 2019. The drivers for Windows that are published for each release (including previews) are digitally signed. You are recommended to sign the binaries you have compiled locally for your own development or testing purposes, using tools like Authenticode. It verifies the publisher's identity and prevents malicious actors from posing as legitimate developers. ### Manually building from source @@ -26,7 +26,7 @@ The Microsoft Drivers for PHP for SQL Server have been compiled and tested with 4. Run `buildconf --force` to rebuild the configure.js script to include the *sqlsrv* and/or *pdo_sqlsrv* driver(s). -5. Run `configure.bat` with the desired driver options (as shown below) to generate the makefile. You can run `configure.bat --help` to see what other options are available. For example, for non-thread safe build, add this option `--disable-zts`. +5. Run `configure.bat` with the desired driver options (as shown below) to generate the makefile. You can run `configure.bat --help` to see what other options are available. For example, for non-thread safe build, add this option `--disable-zts`. * For SQLSRV add: `--enable-sqlsrv=shared` * For PDO_SQLSRV add: `--enable-pdo --with-pdo-sqlsrv=shared` @@ -45,7 +45,7 @@ The sample build scripts, `builddrivers.py` and `buildtools.py`, can be used to #### Overview -When asked to provide the PHP version, you should enter values like `7.3.17`. If it's alpha, beta, or RC version, make sure the name you provide matches the PHP tag name without the prefix `php-`. For example, for PHP 8.0.0 beta 3, the tag name is `php-8.0.0beta3`, so you will enter `8.0.0beta3`. Visit [PHP SRC]( https://github.com/php/php-src) to find the appropriate tag names. +When asked to provide the PHP version, you should enter values like `7.4.27`. If it's alpha, beta, or RC version, make sure the name you provide matches the PHP tag name without the prefix `php-`. For example, for PHP 8.0.0 beta 3, the tag name is `php-8.0.0beta3`, so you will enter `8.0.0beta3`. Visit [PHP SRC]( https://github.com/php/php-src) to find the appropriate tag names. PHP recommends to unzip the PHP SDK into the shortest possible path, preferrably somewhere near the root drive. Therefore, this script will, by default, create a `php-sdk` folder in the C:\ drive, and this `php-sdk` directory tree will remain unless you remove it yourself. For ongoing development, we suggest you keep it around. The build scripts will handle updating the PHP SDK if a new version is available. @@ -69,7 +69,7 @@ PHP recommends to unzip the PHP SDK into the shortest possible path, preferrably * Type `py builddrivers.py -h` to get a list of options and their descriptions * For example, * `py builddrivers.py --PHPVER=7.4.10 --ARCH=x64 --THREAD=nts --DRIVER=sqlsrv --SOURCE=C:\local\source` - * `py builddrivers.py --PHPVER=7.2.30 --ARCH=x86 --THREAD=ts --DEBUG` + * `py builddrivers.py --PHPVER=8.1.0 --ARCH=x86 --THREAD=ts --DEBUG` 5. Based on the given configuration, if the script detects the presence of the PHP source directory, you can choose whether to rebuild, clean or superclean: * `rebuild` to build again using the same configuration (32 bit, thread safe, etc.) diff --git a/issue_template.md b/issue_template.md deleted file mode 100644 index dc39a3db..00000000 --- a/issue_template.md +++ /dev/null @@ -1,20 +0,0 @@ -.+Please check the [FAQ (frequently-asked questions)](https://github.com/Microsoft/msphpsql/wiki/FAQ) first. If you have other questions or something to report, please address the following: - - +## PHP Driver version or file name - + - +## SQL Server version - + - +## Client operating system - + - +## PHP version - + - +## Microsoft ODBC Driver version - + - +## Table schema - + - +## Problem description - + - +## Expected behavior and actual behavior - + - +## Repro code or steps to reproduce - \ No newline at end of file diff --git a/media/os_development.PNG b/media/os_development.PNG index 6f2bd861..07bde7c3 100644 Binary files a/media/os_development.PNG and b/media/os_development.PNG differ diff --git a/media/os_production.PNG b/media/os_production.PNG index 4ee4e9a9..c90fdea5 100644 Binary files a/media/os_production.PNG and b/media/os_production.PNG differ diff --git a/media/php_versions.PNG b/media/php_versions.PNG index b241f3a3..7da55a9d 100644 Binary files a/media/php_versions.PNG and b/media/php_versions.PNG differ diff --git a/media/sql_server.PNG b/media/sql_server.PNG index 25224fe2..976c2dde 100644 Binary files a/media/sql_server.PNG and b/media/sql_server.PNG differ diff --git a/source/pdo_sqlsrv/pdo_dbh.cpp b/source/pdo_sqlsrv/pdo_dbh.cpp index a69127c1..a21686d5 100644 --- a/source/pdo_sqlsrv/pdo_dbh.cpp +++ b/source/pdo_sqlsrv/pdo_dbh.cpp @@ -68,6 +68,8 @@ const char TrustServerCertificate[] = "TrustServerCertificate"; const char TransactionIsolation[] = "TransactionIsolation"; const char TransparentNetworkIPResolution[] = "TransparentNetworkIPResolution"; const char WSID[] = "WSID"; +const char ComputePool[] = "ComputePool"; +const char HostNameInCertificate[] = "HostNameInCertificate"; } @@ -125,7 +127,7 @@ struct pdo_int_conn_str_func { static void func( _In_ connection_option const* option, _In_ zval* value, sqlsrv_conn* /*conn*/, _Out_ std::string& conn_str ) { - SQLSRV_ASSERT( Z_TYPE_P( value ) == IS_STRING, "Wrong zval type for this keyword" ) + SQLSRV_ASSERT(Z_TYPE_P(value) == IS_STRING, "Wrong zval type for this keyword"); std::string val_str = Z_STRVAL_P( value ); @@ -136,6 +138,42 @@ struct pdo_int_conn_str_func { } }; +struct pdo_encrypt_set_func +{ + static void func(_In_ connection_option const* option, _Inout_ zval* value_z, sqlsrv_conn* /*conn*/, _Out_ std::string& conn_str) + { + SQLSRV_ASSERT(Z_TYPE_P(value_z) == IS_STRING, "Wrong zval type for this keyword"); + std::string val_str = Z_STRVAL_P(value_z); + std::string whitespaces(" \t\f\v\n\r"); + + // Trim white spaces + std::size_t found = val_str.find_last_not_of(whitespaces); + if (found != std::string::npos) + val_str.erase(found + 1); + + const char TRUE_VALUE_1[] = "true"; + const char TRUE_VALUE_2[] = "1"; + const char FALSE_VALUE_1[] = "false"; + const char FALSE_VALUE_2[] = "0"; + + // For backward compatibility, convert true/1 to yes and false/0 to no + std::string attr; + if (!val_str.compare(TRUE_VALUE_1) || !val_str.compare(TRUE_VALUE_2)) { + attr = "yes"; + } else if (!val_str.compare(FALSE_VALUE_1) || !val_str.compare(FALSE_VALUE_2)) { + attr = "no"; + } else { + // simply pass the attribute value to ODBC driver + attr = val_str; + } + + conn_str += option->odbc_name; + conn_str += "={"; + conn_str += attr; + conn_str += "};"; + } +}; + template struct pdo_int_conn_attr_func { @@ -303,8 +341,8 @@ const connection_option PDO_CONN_OPTS[] = { SQLSRV_CONN_OPTION_ENCRYPT, ODBCConnOptions::Encrypt, sizeof( ODBCConnOptions::Encrypt ), - CONN_ATTR_BOOL, - pdo_bool_conn_str_func::func + CONN_ATTR_MIXED, + pdo_encrypt_set_func::func }, { PDOConnOptionNames::Failover_Partner, @@ -432,6 +470,24 @@ const connection_option PDO_CONN_OPTS[] = { CONN_ATTR_STRING, conn_str_append_func::func }, + { + PDOConnOptionNames::ComputePool, + sizeof(PDOConnOptionNames::ComputePool), + SQLSRV_CONN_OPTION_COMPUTE_POOL, + ODBCConnOptions::ComputePool, + sizeof(ODBCConnOptions::ComputePool), + CONN_ATTR_STRING, + conn_str_append_func::func + }, + { + PDOConnOptionNames::HostNameInCertificate, + sizeof(PDOConnOptionNames::HostNameInCertificate), + SQLSRV_CONN_OPTION_HOSTNAME_IN_CERT, + ODBCConnOptions::HostNameInCertificate, + sizeof(ODBCConnOptions::HostNameInCertificate), + CONN_ATTR_STRING, + conn_str_append_func::func + }, { NULL, 0, SQLSRV_CONN_OPTION_INVALID, NULL, 0 , CONN_ATTR_INVALID, NULL }, //terminate the table }; @@ -1569,7 +1625,6 @@ zend_string * pdo_sqlsrv_dbh_last_id(_Inout_ pdo_dbh_t *dbh, _In_ const zend_str #if PHP_VERSION_ID < 80100 snprintf(buffer, LAST_INSERT_ID_QUERY_MAX_LEN, SEQUENCE_CURRENT_VALUE_QUERY, name); #else - const char *name_str = ZSTR_VAL(name); snprintf(buffer, LAST_INSERT_ID_QUERY_MAX_LEN, SEQUENCE_CURRENT_VALUE_QUERY, ZSTR_VAL(name)); #endif wsql_string = utf16_string_from_mbcs_string(SQLSRV_ENCODING_CHAR, buffer, sizeof(buffer), &wsql_len); diff --git a/source/shared/core_conn.cpp b/source/shared/core_conn.cpp index 4fb2caff..b573e72a 100644 --- a/source/shared/core_conn.cpp +++ b/source/shared/core_conn.cpp @@ -48,9 +48,8 @@ const int INFO_BUFFER_LEN = 256; // length for name of keystore used in CEKeyStoreData const int MAX_CE_NAME_LEN = 260; -// ODBC driver names. -// the order of this list should match the order of DRIVER_VERSION enum -std::vector CONNECTION_STRING_DRIVER_NAME{ "Driver={ODBC Driver 17 for SQL Server};", "Driver={ODBC Driver 13 for SQL Server};", "Driver={ODBC Driver 11 for SQL Server};" }; +// ODBC driver name +const char ODBC_DRIVER_NAME[] = "ODBC Driver %d for SQL Server"; // default options if only the server is specified const char CONNECTION_STRING_DEFAULT_OPTIONS[] = "Mars_Connection={Yes};"; @@ -73,6 +72,11 @@ void common_conn_str_append_func( _In_z_ const char* odbc_name, _In_reads_(val_l void load_azure_key_vault( _Inout_ sqlsrv_conn* conn ); void configure_azure_key_vault( sqlsrv_conn* conn, BYTE config_attr, const DWORD config_value, size_t key_size); void configure_azure_key_vault( sqlsrv_conn* conn, BYTE config_attr, const char* config_value, size_t key_size); +std::string get_ODBC_driver_name(_In_ ODBC_DRIVER driver); +#ifndef _WIN32 +bool core_search_odbc_driver_unix(_In_ ODBC_DRIVER driver); +#endif + } // core_sqlsrv_connect @@ -151,93 +155,70 @@ sqlsrv_conn* core_sqlsrv_connect( _In_ sqlsrv_context& henv_cp, _In_ sqlsrv_cont build_connection_string_and_set_conn_attr( conn, server, uid, pwd, options_ht, valid_conn_opts, driver, conn_str ); - // If column encryption is enabled, must use ODBC driver 17 - if( conn->ce_option.enabled && conn->driver_version != ODBC_DRIVER_UNKNOWN) { - CHECK_CUSTOM_ERROR( conn->driver_version != ODBC_DRIVER_17, conn, SQLSRV_ERROR_CE_DRIVER_REQUIRED, get_processor_arch() ) { - throw core::CoreException(); - } - } - // In non-Windows environment, unixODBC 2.3.4 and unixODBC 2.3.1 return different error states when an ODBC driver exists or not // Therefore, it is unreliable to check for a certain sql state error + // In Windows, we try to connect with ODBC driver first and rely on the returned error code to try connecting with other supported ODBC drivers + if (conn->driver_version != ODBC_DRIVER::VER_UNKNOWN) { + // if column encryption is enabled, must use ODBC driver 17 or above + CHECK_CUSTOM_ERROR(conn->ce_option.enabled && conn->driver_version == ODBC_DRIVER::VER_13, conn, SQLSRV_ERROR_CE_DRIVER_REQUIRED, get_processor_arch()) { + throw core::CoreException(); + } + #ifndef _WIN32 - if( conn->driver_version != ODBC_DRIVER_UNKNOWN ) { // check if the ODBC driver actually exists, if not, throw an exception - CHECK_CUSTOM_ERROR( ! core_search_odbc_driver_unix( conn->driver_version ), conn, SQLSRV_ERROR_SPECIFIED_DRIVER_NOT_FOUND ) { + CHECK_CUSTOM_ERROR(!core_search_odbc_driver_unix(conn->driver_version), conn, SQLSRV_ERROR_SPECIFIED_DRIVER_NOT_FOUND) { throw core::CoreException(); } - - r = core_odbc_connect( conn, conn_str, is_pooled ); - } - else { - if( conn->ce_option.enabled ) { - // driver not specified, so check if ODBC 17 exists - CHECK_CUSTOM_ERROR( ! core_search_odbc_driver_unix( ODBC_DRIVER_17 ), conn, SQLSRV_ERROR_CE_DRIVER_REQUIRED, get_processor_arch()) { - throw core::CoreException(); - } - - conn_str = conn_str + CONNECTION_STRING_DRIVER_NAME[ODBC_DRIVER_17]; - r = core_odbc_connect( conn, conn_str, is_pooled ); - } - else { - // skip ODBC 11 in a non-Windows environment -- only available in Red Hat / SUSE (preview) - // https://docs.microsoft.com/en-us/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server#microsoft-odbc-driver-11-for-sql-server-on-linux - - DRIVER_VERSION odbc_version = ODBC_DRIVER_UNKNOWN; - if( core_search_odbc_driver_unix( ODBC_DRIVER_17 ) ) { - odbc_version = ODBC_DRIVER_17; - } - else if ( core_search_odbc_driver_unix( ODBC_DRIVER_13 ) ) { - odbc_version = ODBC_DRIVER_13; - } - - CHECK_CUSTOM_ERROR( odbc_version == ODBC_DRIVER_UNKNOWN, conn, SQLSRV_ERROR_DRIVER_NOT_INSTALLED, get_processor_arch() ) { - throw core::CoreException(); - } - std::string conn_str_driver = conn_str + CONNECTION_STRING_DRIVER_NAME[odbc_version]; - r = core_odbc_connect( conn, conn_str_driver, is_pooled ); - } // else ce_option enabled - } // else driver_version not unknown + // if the driver exists, connect + r = core_odbc_connect(conn, conn_str, is_pooled); #else - if( conn->driver_version != ODBC_DRIVER_UNKNOWN ) { - r = core_odbc_connect( conn, conn_str, is_pooled ); + // try to connect with the specified ODBC driver + r = core_odbc_connect(conn, conn_str, is_pooled); - // check if the specified ODBC driver is there - CHECK_CUSTOM_ERROR( core_compare_error_state( conn, r, "IM002" ), conn, SQLSRV_ERROR_SPECIFIED_DRIVER_NOT_FOUND ) { + // if the specified ODBC driver does not exist, the error code is "IM002" (i.e. Data source name not found) + CHECK_CUSTOM_ERROR(core_compare_error_state(conn, r, "IM002"), conn, SQLSRV_ERROR_SPECIFIED_DRIVER_NOT_FOUND) { throw core::CoreException(); } +#endif } else { - if( conn->ce_option.enabled ) { - // driver not specified, so connect using ODBC 17 - conn_str = conn_str + CONNECTION_STRING_DRIVER_NAME[ODBC_DRIVER_17]; - r = core_odbc_connect( conn, conn_str, is_pooled ); + // ODBC driver not specified, so check ODBC 17 first then ODBC 18 and/or ODBC 13 + // If column encryption is enabled, check up to ODBC 18 + ODBC_DRIVER drivers[] = { ODBC_DRIVER::VER_17, ODBC_DRIVER::VER_18, ODBC_DRIVER::VER_13 }; + ODBC_DRIVER last_version = (conn->ce_option.enabled) ? ODBC_DRIVER::VER_18 : ODBC_DRIVER::VER_13; + + ODBC_DRIVER version = ODBC_DRIVER::VER_UNKNOWN; + for (auto &d : drivers) { + std::string driver_name = get_ODBC_driver_name(d); +#ifndef _WIN32 + if (core_search_odbc_driver_unix(d)) { + // now append the driver name to the connection string + common_conn_str_append_func(ODBCConnOptions::Driver, driver_name.c_str(), driver_name.length(), conn_str); + r = core_odbc_connect(conn, conn_str, is_pooled); + break; + } +#else + std::string conn_str_driver = conn_str; // use a copy of conn_str instead + common_conn_str_append_func(ODBCConnOptions::Driver, driver_name.c_str(), driver_name.length(), conn_str_driver); + r = core_odbc_connect(conn, conn_str_driver, is_pooled); + if (SQL_SUCCEEDED(r) || !core_compare_error_state(conn, r, "IM002")) { + // something else went wrong, exit the loop now other than ODBC driver not found + break; + } +#endif + else if (d == last_version) { + // if column encryption is enabled, throw the exception related to column encryption + CHECK_CUSTOM_ERROR(conn->ce_option.enabled, conn, SQLSRV_ERROR_CE_DRIVER_REQUIRED, get_processor_arch()) { + throw core::CoreException(); + } - // check if the specified ODBC driver is there - CHECK_CUSTOM_ERROR( core_compare_error_state( conn, r, "IM002" ) , conn, SQLSRV_ERROR_CE_DRIVER_REQUIRED, get_processor_arch() ) { - throw core::CoreException(); - } + // here it means that none of the supported ODBC drivers is found + CHECK_CUSTOM_ERROR(true, conn, SQLSRV_ERROR_DRIVER_NOT_INSTALLED, get_processor_arch()) { + throw core::CoreException(); + } + } } - else { - bool done = false; - for( short i = DRIVER_VERSION::FIRST; i <= DRIVER_VERSION::LAST && ! done; ++i ) { - std::string conn_str_driver = conn_str + CONNECTION_STRING_DRIVER_NAME[i]; - r = core_odbc_connect( conn, conn_str_driver, is_pooled ); - - if( SQL_SUCCEEDED( r ) || ! core_compare_error_state( conn, r, "IM002" ) ) { - // something else went wrong, exit the loop now other than ODBC driver not found - done = true; - } - else { - // did it fail to find the last valid ODBC driver? - CHECK_CUSTOM_ERROR( ( i == DRIVER_VERSION::LAST ), conn, SQLSRV_ERROR_DRIVER_NOT_INSTALLED, get_processor_arch()) { - throw core::CoreException(); - } - } - } // for - } // else ce_option enabled - } // else driver_version not unknown -#endif // !_WIN32 + } // time to free the access token, if not null if (conn->azure_ad_access_token) { @@ -322,50 +303,6 @@ bool core_compare_error_state( _In_ sqlsrv_conn* conn, _In_ SQLRETURN rc, _In_ return ( SQL_SUCCEEDED(sr) && ! strcmp(error_state, reinterpret_cast( state ) ) ); } -// core_search_odbc_driver_unix -// This method is meant to be used in a non-Windows environment, -// searching for a particular ODBC driver name in the odbcinst.ini file -// Parameters: -// driver_version - a valid value in enum DRIVER_VERSION -// Return - a boolean flag that indicates if the specified driver version is found or not - -bool core_search_odbc_driver_unix( _In_ DRIVER_VERSION driver_version ) -{ -#ifndef _WIN32 - char szBuf[DEFAULT_CONN_STR_LEN+1] = {'\0'}; // use a large enough buffer size - WORD cbBufMax = DEFAULT_CONN_STR_LEN; - WORD cbBufOut; - char *pszBuf = szBuf; - - // get all the names of the installed drivers delimited by null characters - if(! SQLGetInstalledDrivers( szBuf, cbBufMax, &cbBufOut ) ) - { - return false; - } - - // extract the ODBC driver name - std::string driver = CONNECTION_STRING_DRIVER_NAME[driver_version]; - std::size_t pos1 = driver.find_first_of("{"); - std::size_t pos2 = driver.find_first_of("}"); - std::string driver_str = driver.substr( pos1 + 1, pos2 - pos1 - 1); - - // search for the ODBC driver... - const char* driver_name = driver_str.c_str(); - do - { - if( strstr( pszBuf, driver_name ) != 0 ) - { - return true; - } - // get the next driver - pszBuf = strchr( pszBuf, '\0' ) + 1; - } - while( pszBuf[1] != '\0' ); // end when there are two consecutive null characters -#endif // !_WIN32 - - return false; -} - // core_odbc_connect // calls odbc connect API to establish the connection to server // Parameters: @@ -1010,6 +947,48 @@ void common_conn_str_append_func( _In_z_ const char* odbc_name, _In_reads_(val_l conn_str += "};"; } +std::string get_ODBC_driver_name(_In_ ODBC_DRIVER driver) +{ + const short BUFFER_LEN = sizeof(ODBC_DRIVER_NAME); + char driver_name[BUFFER_LEN] = { '\0' }; + snprintf(driver_name, BUFFER_LEN, ODBC_DRIVER_NAME, static_cast(driver)); + + return driver_name; +} + +#ifndef _WIN32 +// core_search_odbc_driver_unix +// This method is meant to be used in a non-Windows environment, +// searching for a particular ODBC driver name in the odbcinst.ini file +// Parameters: +// driver - a valid value in enum ODBC_DRIVER +// Return - a boolean flag that indicates if the specified driver version is found or not +bool core_search_odbc_driver_unix(_In_ ODBC_DRIVER driver) +{ + char szBuf[DEFAULT_CONN_STR_LEN + 1] = { '\0' }; // use a large enough buffer size + WORD cbBufMax = DEFAULT_CONN_STR_LEN; + WORD cbBufOut; + char *pszBuf = szBuf; + + // get all the names of the installed drivers delimited by null characters + if (!SQLGetInstalledDrivers(szBuf, cbBufMax, &cbBufOut)) + return false; + + // search for the derived ODBC driver name based on the given version + std::string driver_name = get_ODBC_driver_name(driver); + do + { + if (strstr(pszBuf, driver_name.c_str()) != 0) + return true; + + // get the next driver + pszBuf = strchr(pszBuf, '\0') + 1; + } while (pszBuf[1] != '\0'); // end when there are two consecutive null characters + + return false; +} +#endif // !_WIN32 + } // namespace // simply add the parsed value to the connection string @@ -1026,27 +1005,36 @@ void conn_null_func::func( connection_option const* /*option*/, zval* /*value*/, { } -void driver_set_func::func( _In_ connection_option const* option, _In_ zval* value, _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str ) +void driver_set_func::func(_In_ connection_option const* option, _In_ zval* value, _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str) { - const char* val_str = Z_STRVAL_P( value ); - size_t val_len = Z_STRLEN_P( value ); - std::string driver_option( "" ); - common_conn_str_append_func( option->odbc_name, val_str, val_len, driver_option ); + const char* val_str = Z_STRVAL_P(value); + size_t val_len = Z_STRLEN_P(value); - conn->driver_version = ODBC_DRIVER_UNKNOWN; - for ( short i = DRIVER_VERSION::FIRST; i <= DRIVER_VERSION::LAST && conn->driver_version == ODBC_DRIVER_UNKNOWN; ++i ) { - std::string driver_name = CONNECTION_STRING_DRIVER_NAME[i]; - - if (! driver_name.compare( driver_option ) ) { - conn->driver_version = DRIVER_VERSION( i ); - } + // Check if curly brackets are used, if so, trim them for matching + if (val_len > 0 && val_str[0] == '{' && val_str[val_len - 1] == '}') { + ++val_str; + val_len -= 2; } - CHECK_CUSTOM_ERROR( conn->driver_version == ODBC_DRIVER_UNKNOWN, conn, SQLSRV_ERROR_CONNECT_INVALID_DRIVER, val_str) { + // Check if the user provided driver_option matches any of the acceptable driver names + std::string driver_option(val_str, val_len); + ODBC_DRIVER drivers[] = { ODBC_DRIVER::VER_17, ODBC_DRIVER::VER_18, ODBC_DRIVER::VER_13 }; + + conn->driver_version = ODBC_DRIVER::VER_UNKNOWN; + for (auto &d : drivers) { + std::string name = get_ODBC_driver_name(d); + if (!driver_option.compare(name)) { + conn->driver_version = d; + break; + } + } + + CHECK_CUSTOM_ERROR(conn->driver_version == ODBC_DRIVER::VER_UNKNOWN, conn, SQLSRV_ERROR_CONNECT_INVALID_DRIVER, Z_STRVAL_P(value)) { throw core::CoreException(); } - conn_str += driver_option; + // Append this driver option to the connection string + common_conn_str_append_func(ODBCConnOptions::Driver, driver_option.c_str(), driver_option.length(), conn_str); } void column_encryption_set_func::func( _In_ connection_option const* option, _In_ zval* value, _Inout_ sqlsrv_conn* conn, _Inout_ std::string& conn_str ) @@ -1124,34 +1112,22 @@ void ce_akv_str_set_func::func(_In_ connection_option const* option, _In_ zval* // Values = ("true" or "1") are treated as true values. Everything else is treated as false. // Returns 1 for true and 0 for false. -size_t core_str_zval_is_true( _Inout_ zval* value_z ) +size_t core_str_zval_is_true(_Inout_ zval* value_z) { SQLSRV_ASSERT( Z_TYPE_P( value_z ) == IS_STRING, "core_str_zval_is_true: This function only accepts zval of type string." ); + std::string val_str = Z_STRVAL_P(value_z); + std::string whitespaces(" \t\f\v\n\r"); - char* value_in = Z_STRVAL_P( value_z ); - size_t val_len = Z_STRLEN_P( value_z ); + // Trim white spaces + std::size_t found = val_str.find_last_not_of(whitespaces); + if (found != std::string::npos) + val_str.erase(found + 1); - // strip any whitespace at the end (whitespace is the same value in ASCII and UTF-8) - size_t last_char = val_len - 1; - while( isspace(( unsigned char )value_in[last_char] )) { - value_in[last_char] = '\0'; - val_len = last_char; - --last_char; + const char TRUE_VALUE_1[] = "true"; + const char TRUE_VALUE_2[] = "1"; + if (!val_str.compare(TRUE_VALUE_1) || !val_str.compare(TRUE_VALUE_2)) { + return 1; // true } - - // save adjustments to the value made by stripping whitespace at the end - Z_STRLEN_P( value_z ) = val_len; - - const char VALID_TRUE_VALUE_1[] = "true"; - const char VALID_TRUE_VALUE_2[] = "1"; - - if(( val_len == ( sizeof( VALID_TRUE_VALUE_1 ) - 1 ) && !strnicmp( value_in, VALID_TRUE_VALUE_1, val_len )) || - ( val_len == ( sizeof( VALID_TRUE_VALUE_2 ) - 1 ) && !strnicmp( value_in, VALID_TRUE_VALUE_2, val_len )) - ) { - - return 1; // true - } - return 0; // false } diff --git a/source/shared/core_sqlsrv.h b/source/shared/core_sqlsrv.h index 766b3f45..40da6988 100644 --- a/source/shared/core_sqlsrv.h +++ b/source/shared/core_sqlsrv.h @@ -374,6 +374,10 @@ inline void sqlsrv_free_trace( _Inout_ void* ptr, _In_ const char* file, _In_ in #else +// Unlike their C standard library's counterparts the Zend Engine's memory management functions +// emalloc or erealloc won't return NULL in case of an problem while allocating the requested +// memory but bail out and terminate the current request. +// Check www.phpinternalsbook.com/php7/memory_management/zend_memory_manager.html for details inline void* sqlsrv_malloc( _In_ size_t size ) { return emalloc( size ); @@ -1054,14 +1058,13 @@ enum SERVER_VERSION { }; // supported driver versions. -// the latest RTWed ODBC is the first one -enum DRIVER_VERSION { - ODBC_DRIVER_UNKNOWN = -1, - FIRST = 0, - ODBC_DRIVER_17 = FIRST, - ODBC_DRIVER_13 = 1, - ODBC_DRIVER_11 = 2, - LAST = ODBC_DRIVER_11 +// ODBC 17 is the default +enum class ODBC_DRIVER : int +{ + VER_17 = 17, + VER_18 = 18, + VER_13 = 13, + VER_UNKNOWN = 0 }; // forward decl @@ -1097,7 +1100,7 @@ struct sqlsrv_conn : public sqlsrv_context { SERVER_VERSION server_version; // version of the server that we're connected to col_encryption_option ce_option; // holds the details of what are required to enable column encryption - DRIVER_VERSION driver_version; // version of ODBC driver + ODBC_DRIVER driver_version; // version of ODBC driver sqlsrv_malloc_auto_ptr azure_ad_access_token; @@ -1106,7 +1109,7 @@ struct sqlsrv_conn : public sqlsrv_context { sqlsrv_context( h, SQL_HANDLE_DBC, e, drv, encoding ) { server_version = SERVER_VERSION_UNKNOWN; - driver_version = ODBC_DRIVER_UNKNOWN; + driver_version = ODBC_DRIVER::VER_UNKNOWN; } // sqlsrv_conn has no destructor since its allocated using placement new, which requires that the destructor be @@ -1164,6 +1167,8 @@ const char WSID[] = "WSID"; const char UID[] = "UID"; const char PWD[] = "PWD"; const char SERVER[] = "Server"; +const char ComputePool[] = "ComputePool"; +const char HostNameInCertificate[] = "HostNameInCertificate"; } @@ -1201,6 +1206,8 @@ enum SQLSRV_CONN_OPTIONS { SQLSRV_CONN_OPTION_TRANSPARENT_NETWORK_IP_RESOLUTION, SQLSRV_CONN_OPTION_CONN_RETRY_COUNT, SQLSRV_CONN_OPTION_CONN_RETRY_INTERVAL, + SQLSRV_CONN_OPTION_COMPUTE_POOL, + SQLSRV_CONN_OPTION_HOSTNAME_IN_CERT, // Driver specific connection options SQLSRV_CONN_OPTION_DRIVER_SPECIFIC = 1000, @@ -1215,6 +1222,7 @@ enum CONN_ATTR_TYPE { CONN_ATTR_INT, CONN_ATTR_BOOL, CONN_ATTR_STRING, + CONN_ATTR_MIXED, CONN_ATTR_INVALID, }; @@ -1283,7 +1291,6 @@ void core_sqlsrv_get_server_version( _Inout_ sqlsrv_conn* conn, _Inout_ zval *se void core_sqlsrv_get_client_info( _Inout_ sqlsrv_conn* conn, _Out_ zval *client_info ); bool core_is_conn_opt_value_escaped( _Inout_ const char* value, _Inout_ size_t value_len ); size_t core_str_zval_is_true( _Inout_ zval* str_zval ); -bool core_search_odbc_driver_unix( _In_ DRIVER_VERSION driver_version ); bool core_compare_error_state( _In_ sqlsrv_conn* conn, _In_ SQLRETURN r, _In_ const char* error_state ); //********************************************************************************************************************************* diff --git a/source/shared/core_stmt.cpp b/source/shared/core_stmt.cpp index 29511a82..92c7cfc7 100644 --- a/source/shared/core_stmt.cpp +++ b/source/shared/core_stmt.cpp @@ -3673,7 +3673,7 @@ bool sqlsrv_params_container::send_next_packet(_Inout_ sqlsrv_stmt* stmt) } // The helper method send_stream_packet() returns false when EOF is reached - if (current_param->send_data_packet(stmt) == false) { + if (current_param && current_param->send_data_packet(stmt) == false) { // Now that EOF has been reached, reset current_param for next round // Bear in mind that SQLParamData might request the same stream resource again current_param = NULL; diff --git a/source/shared/version.h b/source/shared/version.h index cf04824e..97407fe6 100644 --- a/source/shared/version.h +++ b/source/shared/version.h @@ -31,7 +31,7 @@ #define SQLVERSION_BUILD 0 // For previews, set this constant to 1, 2 and so on. Otherwise, set it to 0 -#define PREVIEW 2 +#define PREVIEW 0 #define SEMVER_PRERELEASE // Semantic versioning build metadata, build meta data is not counted in precedence order. @@ -59,7 +59,7 @@ #define _FILEVERSION SQLVERSION_MAJOR,SQLVERSION_MINOR,SQLVERSION_PATCH,SQLVERSION_BUILD // PECL package version ('-' or '+' is not allowed) - to support Pickle do not use macros below -#define PHP_SQLSRV_VERSION "5.10.0beta2" -#define PHP_PDO_SQLSRV_VERSION "5.10.0beta2" +#define PHP_SQLSRV_VERSION "5.10.0" +#define PHP_PDO_SQLSRV_VERSION "5.10.0" #endif // VERSION_H diff --git a/source/sqlsrv/conn.cpp b/source/sqlsrv/conn.cpp index d83f4458..4ae1a286 100644 --- a/source/sqlsrv/conn.cpp +++ b/source/sqlsrv/conn.cpp @@ -55,7 +55,6 @@ struct format_decimals_func struct decimal_places_func { - static void func(connection_option const* /*option*/, _In_ zval* value, _Inout_ sqlsrv_conn* conn, std::string& /*conn_str*/) { // first check if the input is an integer @@ -73,6 +72,33 @@ struct decimal_places_func } }; +struct srv_encrypt_set_func { + static void func(connection_option const* option, _In_ zval* value_z, _Inout_ sqlsrv_conn* conn, std::string& conn_str) + { + std::string attr; + + if (Z_TYPE_P(value_z) == IS_LONG) { + long val = Z_LVAL_P(value_z); + if (val == 1) { + attr = "yes"; + } else if (val == 0) { + attr = "no"; + } else { + attr = std::to_string(val); + } + } else if (Z_TYPE_P(value_z) == IS_TRUE || Z_TYPE_P(value_z) == IS_FALSE) { + attr = zend_is_true(value_z) ? "yes" : "no"; + } else { + attr = Z_STRVAL_P(value_z); + } + + char temp_str[MAX_CONN_VALSTRING_LEN]; + snprintf(temp_str, MAX_CONN_VALSTRING_LEN, "%s={%s};", option->odbc_name, attr.c_str()); + + conn_str += temp_str; + } +}; + struct conn_char_set_func { static void func( connection_option const* /*option*/, _Inout_ zval* value, _Inout_ sqlsrv_conn* conn, std::string& /*conn_str*/ ) @@ -232,6 +258,8 @@ const char TransactionIsolation[] = "TransactionIsolation"; const char TransparentNetworkIPResolution[] = "TransparentNetworkIPResolution"; const char UID[] = "UID"; const char WSID[] = "WSID"; +const char ComputePool[] = "ComputePool"; +const char HostNameInCertificate[] = "HostNameInCertificate"; } @@ -421,8 +449,8 @@ const connection_option SS_CONN_OPTS[] = { SQLSRV_CONN_OPTION_ENCRYPT, ODBCConnOptions::Encrypt, sizeof( ODBCConnOptions::Encrypt ), - CONN_ATTR_BOOL, - bool_conn_str_func::func + CONN_ATTR_MIXED, + srv_encrypt_set_func::func }, { SSConnOptionNames::Failover_Partner, @@ -577,6 +605,25 @@ const connection_option SS_CONN_OPTS[] = { CONN_ATTR_INT, decimal_places_func::func }, + { + SSConnOptionNames::ComputePool, + sizeof(SSConnOptionNames::ComputePool), + SQLSRV_CONN_OPTION_COMPUTE_POOL, + ODBCConnOptions::ComputePool, + sizeof(ODBCConnOptions::ComputePool), + CONN_ATTR_STRING, + conn_str_append_func::func + }, + { + SSConnOptionNames::HostNameInCertificate, + sizeof(SSConnOptionNames::HostNameInCertificate), + SQLSRV_CONN_OPTION_HOSTNAME_IN_CERT, + ODBCConnOptions::HostNameInCertificate, + sizeof(ODBCConnOptions::HostNameInCertificate), + CONN_ATTR_STRING, + conn_str_append_func::func + }, + { NULL, 0, SQLSRV_CONN_OPTION_INVALID, NULL, 0 , CONN_ATTR_INVALID, NULL }, //terminate the table }; @@ -1336,6 +1383,8 @@ int get_conn_option_key( _Inout_ sqlsrv_context& ctx, _In_ zend_string* key, _In // if we ever introduce a boolean connection option that maps to a string connection // attribute. break; + case CONN_ATTR_MIXED: + break; case CONN_ATTR_INT: { CHECK_CUSTOM_ERROR( (Z_TYPE_P( value_z ) != IS_LONG ), ctx, SQLSRV_ERROR_INVALID_OPTION_TYPE_INT, diff --git a/test/functional/pdo_sqlsrv/pdo_1063_test_locale.php b/test/functional/pdo_sqlsrv/pdo_1063_test_locale.php index 4140f80a..4e62cd61 100644 --- a/test/functional/pdo_sqlsrv/pdo_1063_test_locale.php +++ b/test/functional/pdo_sqlsrv/pdo_1063_test_locale.php @@ -48,30 +48,34 @@ $locale = ($_SERVER['argv'][2] ?? ''); echo "**Begin**" . PHP_EOL; -// Assuming LC_ALL is 'en_US.UTF-8', so is LC_CTYPE, except in PHP 8 (TODO) -// But default LC_MONETARY varies -$ctype = (PHP_MAJOR_VERSION == 8 && $setLocaleInfo == 0) ? 'C' : 'en_US.UTF-8'; +// Assuming LC_ALL is 'en_US.UTF-8', but default LC_CTYPE and LC_MONETARY vary in various +// platforms and PHP versions, so only check when $setLocaleInfo is 2 switch ($setLocaleInfo) { case 0: case 1: - $m = 'C'; $symbol = ''; $sep = ''; + $symbol = ''; $sep = ''; break; case 2: - $m = 'en_US.UTF-8'; $symbol = '$'; $sep = ','; + $symbol = '$'; $sep = ','; break; default: die("Unexpected $setLocaleInfo\n"); break; } -$m1 = setlocale(LC_MONETARY, 0); -if ($m !== $m1) { - echo "Unexpected LC_MONETARY: $m1" . PHP_EOL; -} -$c1 = setlocale(LC_CTYPE, 0); -if ($ctype !== $c1) { - echo "Unexpected LC_CTYPE: $c1" . PHP_EOL; - echo "LC_NUMERIC for $setLocaleInfo: " . setlocale(LC_NUMERIC, 0) . PHP_EOL; +if ($setLocaleInfo == 2) { + $ctype = 'en_US.UTF-8'; + $m = 'en_US.UTF-8'; + + $m1 = setlocale(LC_MONETARY, 0); + if ($m !== $m1) { + echo "Unexpected LC_MONETARY: $m1" . PHP_EOL; + } + $c1 = setlocale(LC_CTYPE, 0); + if ($ctype !== $c1) { + echo "Unexpected LC_CTYPE: $c1" . PHP_EOL; + echo "LC_NUMERIC for $setLocaleInfo: " . setlocale(LC_NUMERIC, 0) . PHP_EOL; + } } // Set a different locale, if the input is not empty diff --git a/test/functional/pdo_sqlsrv/pdo_connect_computepool.phpt b/test/functional/pdo_sqlsrv/pdo_connect_computepool.phpt new file mode 100644 index 00000000..bdc53801 --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_connect_computepool.phpt @@ -0,0 +1,23 @@ +--TEST-- +Test ComputePool keyword +--DESCRIPTION-- +This test does not test if any connection is successful but mainly test if the computepool keyword is recognized. +--SKIPIF-- + +--FILE-- + +--EXPECT-- +Done diff --git a/test/functional/pdo_sqlsrv/pdo_connect_driver.phpt b/test/functional/pdo_sqlsrv/pdo_connect_driver.phpt index a1a18144..620e74d9 100644 --- a/test/functional/pdo_sqlsrv/pdo_connect_driver.phpt +++ b/test/functional/pdo_sqlsrv/pdo_connect_driver.phpt @@ -23,20 +23,26 @@ testValidValues(); testInvalidValues(); testEncryptedWithODBC(); testWrongODBC(); -echo "Done"; +echo "Done" . PHP_EOL; // end test /////////////////////////// -function connectVerifyOutput($connectionOptions, $expected = '') +function connectVerifyOutput($connectionOptions, $testcase, $expected = null) { global $server, $uid, $pwd; - + try { $conn = new PDO("sqlsrv:server = $server ; $connectionOptions", $uid, $pwd); + if (!is_null($expected)) { + echo "'$testcase' is expected to fail!" . PHP_EOL; + } } catch(PDOException $e) { - if (strpos($e->getMessage(), $expected) === false) { - print_r($e->getMessage()); - echo "\n"; + if (is_null($expected)) { + echo "'$testcase' is expected to pass!" . PHP_EOL; + echo $e->getMessage() . PHP_EOL; + } elseif (strpos($e->getMessage(), $expected) === false) { + echo "The error returned for '$testcase' is unexpected:" . PHP_EOL; + echo $e->getMessage() . PHP_EOL; } } } @@ -44,90 +50,85 @@ function connectVerifyOutput($connectionOptions, $expected = '') function testValidValues() { global $msodbcsqlMaj; - + $value = ""; - // The major version number of ODBC 11 can be 11 or 12 + // The major version number of ODBC 13 can be 13 or 14 // Test with {} switch ($msodbcsqlMaj) { case 17: $value = "{ODBC Driver 17 for SQL Server}"; break; + case 18: + $value = "{ODBC Driver 18 for SQL Server}"; + break; case 14: case 13: $value = "{ODBC Driver 13 for SQL Server}"; break; - case 12: - case 11: - $value = "{ODBC Driver 11 for SQL Server}"; - break; default: $value = "invalid value $msodbcsqlMaj"; } $connectionOptions = "Driver = $value"; - connectVerifyOutput($connectionOptions); - + connectVerifyOutput($connectionOptions, "Driver with curly brackets"); + // Test without {} switch ($msodbcsqlMaj) { case 17: $value = "ODBC Driver 17 for SQL Server"; break; + case 18: + $value = "ODBC Driver 18 for SQL Server"; + break; case 14: case 13: $value = "ODBC Driver 13 for SQL Server"; break; - case 12: - case 11: - $value = "ODBC Driver 11 for SQL Server"; - break; default: $value = "invalid value $msodbcsqlMaj"; } - + $connectionOptions = "Driver = $value"; - connectVerifyOutput($connectionOptions); + connectVerifyOutput($connectionOptions, "Driver without curly brackets"); } function testInvalidValues() { - $values = array("{SQL Server Native Client 11.0}", - "SQL Server Native Client 11.0", - "ODBC Driver 00 for SQL Server", - 123, + $values = array("{SQL Server Native Client 11.0}", + "SQL Server Native Client 11.0", + "ODBC Driver 00 for SQL Server", + 123, false); - + foreach ($values as $value) { $connectionOptions = "Driver = $value"; $expected = "Invalid value $value was specified for Driver option."; - connectVerifyOutput($connectionOptions, $expected); + connectVerifyOutput($connectionOptions, "Invalid driver $value", $expected); } } -function testEncryptedWithODBC() +function testEncryptedWithODBC() { global $msodbcsqlMaj, $server, $uid, $pwd; - + $value = "ODBC Driver 13 for SQL Server"; - $connectionOptions = "Driver = $value; ColumnEncryption = Enabled;"; - + $connectionOptions = "Driver = $value; ColumnEncryption = Enabled;"; + $expected = "The Always Encrypted feature requires Microsoft ODBC Driver 17 for SQL Server"; - connectVerifyOutput($connectionOptions, $expected); + connectVerifyOutput($connectionOptions, "Using ODBC 13 for AE", $expected); } function testWrongODBC() { global $msodbcsqlMaj; - - $value = "ODBC Driver 11 for SQL Server"; - if ($msodbcsqlMaj == 17 || $msodbcsqlMaj < 13) { - $value = "ODBC Driver 13 for SQL Server"; - } + + $value = "ODBC Driver 18 for SQL Server"; $connectionOptions = "Driver = $value;"; $expected = "The specified ODBC Driver is not found."; - - connectVerifyOutput($connectionOptions, $expected); + + connectVerifyOutput($connectionOptions, "Connect with ODBC 18", $expected); } ?> --EXPECT-- -Done \ No newline at end of file +Done diff --git a/test/functional/pdo_sqlsrv/pdo_connect_encrypt_attributes.phpt b/test/functional/pdo_sqlsrv/pdo_connect_encrypt_attributes.phpt new file mode 100644 index 00000000..0f418ca1 --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_connect_encrypt_attributes.phpt @@ -0,0 +1,105 @@ +--TEST-- +Test various encrypt attributes +--DESCRIPTION-- +This test does not test if any connection is successful but mainly test if the Encrypt keyword takes +different attributes. +--SKIPIF-- + +--FILE-- +getMessage()); + echo PHP_EOL; +} + +unset($conn1); + +try { + $encrypt = ' 1 '; + $trust = 'true '; + $connectionInfo = "Database = $databaseName; Encrypt = $encrypt; TrustServerCertificate = $trust;"; + $conn2 = new PDO("sqlsrv:server = $server ; $connectionInfo", $uid, $pwd); + echo 'Test case 2' . PHP_EOL; +} catch (PDOException $e) { + echo 'Failed to connect (test case 2)' . PHP_EOL; + print_r($e->getMessage()); + echo PHP_EOL; +} + +unset($conn2); + +try { + $encrypt = ' yes '; + $trust = 'true'; + $connectionInfo = "Database = $databaseName; Encrypt = $encrypt; TrustServerCertificate = $trust;"; + $conn3 = new PDO("sqlsrv:server = $server ; $connectionInfo", $uid, $pwd); + echo 'Test case 3' . PHP_EOL; +} catch (PDOException $e) { + echo 'Failed to connect (test case 3)' . PHP_EOL; + print_r($e->getMessage()); + echo PHP_EOL; +} + +unset($conn3); + +try { + $encrypt = ' 0 '; + $trust = 'false '; + $connectionInfo = "Database = $databaseName; Encrypt = $encrypt; TrustServerCertificate = $trust;"; + $conn4 = new PDO("sqlsrv:server = $server ; $connectionInfo", $uid, $pwd); + echo 'Test case 4' . PHP_EOL; +} catch (PDOException $e) { + echo 'Failed to connect (test case 4)' . PHP_EOL; + print_r($e->getMessage()); + echo PHP_EOL; +} + +unset($conn4); + +try { + $encrypt = ' false '; + $trust = 'false '; + $connectionInfo = "Database = $databaseName; Encrypt = $encrypt; TrustServerCertificate = $trust;"; + $conn5 = new PDO("sqlsrv:server = $server ; $connectionInfo", $uid, $pwd); + echo 'Test case 5' . PHP_EOL; +} catch (PDOException $e) { + echo 'Failed to connect (test case 5)' . PHP_EOL; + print_r($e->getMessage()); + echo PHP_EOL; +} + +unset($conn5); + +try { + $encrypt = 'no '; + $trust = 'false '; + $connectionInfo = "Database = $databaseName; Encrypt = $encrypt; TrustServerCertificate = $trust;"; + $conn6 = new PDO("sqlsrv:server = $server ; $connectionInfo", $uid, $pwd); + echo 'Test case 6' . PHP_EOL; +} catch (PDOException $e) { + echo 'Failed to connect (test case 6)' . PHP_EOL; + print_r($e->getMessage()); + echo PHP_EOL; +} + +unset($conn6); +echo 'Done' . PHP_EOL; + +?> +--EXPECT-- +Test case 1 +Test case 2 +Test case 3 +Test case 4 +Test case 5 +Test case 6 +Done diff --git a/test/functional/pdo_sqlsrv/pdo_connect_hostname_cert.phpt b/test/functional/pdo_sqlsrv/pdo_connect_hostname_cert.phpt new file mode 100644 index 00000000..64daa58d --- /dev/null +++ b/test/functional/pdo_sqlsrv/pdo_connect_hostname_cert.phpt @@ -0,0 +1,23 @@ +--TEST-- +Test HostNameInCertificate keyword +--DESCRIPTION-- +This test does not test if any connection is successful but mainly test if the HostNameInCertificate keyword is recognized. +--SKIPIF-- + +--FILE-- + +--EXPECT-- +Done diff --git a/test/functional/sqlsrv/sqlsrv_connect_computepool.phpt b/test/functional/sqlsrv/sqlsrv_connect_computepool.phpt new file mode 100644 index 00000000..ca3fae5a --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_connect_computepool.phpt @@ -0,0 +1,21 @@ +--TEST-- +Test ComputePool keyword +--DESCRIPTION-- +This test does not test if any connection is successful but mainly test if the computepool keyword is recognized. +--SKIPIF-- + +--FILE-- + 'pool1'); +$conn = sqlsrv_connect($server, $connectionOptions); +if ($conn != false) { + sqlsrv_close($conn); +} + +echo 'Done' . PHP_EOL; + +?> +--EXPECT-- +Done diff --git a/test/functional/sqlsrv/sqlsrv_connect_driver.phpt b/test/functional/sqlsrv/sqlsrv_connect_driver.phpt index ee78f0a4..24ae97e8 100644 --- a/test/functional/sqlsrv/sqlsrv_connect_driver.phpt +++ b/test/functional/sqlsrv/sqlsrv_connect_driver.phpt @@ -21,62 +21,66 @@ testValidValues($msodbcsqlMaj, $server, $connectionOptions); testInvalidValues($msodbcsqlMaj, $server, $connectionOptions); testEncryptedWithODBC($msodbcsqlMaj, $server, $connectionOptions); testWrongODBC($msodbcsqlMaj, $server, $connectionOptions); -echo "Done"; +echo "Done\n"; // end test /////////////////////////// -function connectVerifyOutput($server, $connectionOptions, $expected = '') +function connectVerifyOutput($server, $connectionOptions, $testcase, $expected = null) { $conn = sqlsrv_connect($server, $connectionOptions); if ($conn === false) { - if (strpos(sqlsrv_errors($conn)[0]['message'], $expected) === false) { + if (is_null($expected)) { + echo "'$testcase' is expected to pass!\n"; + print_r(sqlsrv_errors()); + } elseif (strpos(sqlsrv_errors($conn)[0]['message'], $expected) === false) { + echo "The error returned for '$testcase' is unexpected:\n"; print_r(sqlsrv_errors()); } + } else if (!is_null($expected)) { + echo "'$testcase' is expected to fail!\n"; } } function testValidValues($msodbcsqlMaj, $server, $connectionOptions) { $value = ""; - // The major version number of ODBC 11 can be 11 or 12 + // The major version number of ODBC 13 can be 13 or 14 // Test with {} switch ($msodbcsqlMaj) { case 17: $value = "{ODBC Driver 17 for SQL Server}"; break; + case 18: + $value = "{ODBC Driver 18 for SQL Server}"; + break; case 14: case 13: $value = "{ODBC Driver 13 for SQL Server}"; break; - case 12: - case 11: - $value = "{ODBC Driver 11 for SQL Server}"; - break; default: $value = "invalid value $msodbcsqlMaj"; } $connectionOptions['Driver']=$value; - connectVerifyOutput($server, $connectionOptions); + connectVerifyOutput($server, $connectionOptions, "Driver with curly brackets"); // Test without {} switch ($msodbcsqlMaj) { case 17: $value = "ODBC Driver 17 for SQL Server"; break; + case 18: + $value = "ODBC Driver 18 for SQL Server"; + break; case 14: case 13: $value = "ODBC Driver 13 for SQL Server"; break; - case 12: - case 11: - $value = "ODBC Driver 11 for SQL Server"; - break; default: $value = "invalid value $msodbcsqlMaj"; } $connectionOptions['Driver']=$value; - connectVerifyOutput($server, $connectionOptions); + connectVerifyOutput($server, $connectionOptions, "Driver without curly brackets"); } function testInvalidValues($msodbcsqlMaj, $server, $connectionOptions) @@ -88,7 +92,7 @@ function testInvalidValues($msodbcsqlMaj, $server, $connectionOptions) foreach ($values as $value) { $connectionOptions['Driver']=$value; $expected = "Invalid value $value was specified for Driver option."; - connectVerifyOutput($server, $connectionOptions, $expected); + connectVerifyOutput($server, $connectionOptions, "Invalid driver $value", $expected); } $values = array(123, false); @@ -96,7 +100,7 @@ function testInvalidValues($msodbcsqlMaj, $server, $connectionOptions) foreach ($values as $value) { $connectionOptions['Driver']=$value; $expected = "Invalid value type for option Driver was specified. String type was expected."; - connectVerifyOutput($server, $connectionOptions, $expected); + connectVerifyOutput($server, $connectionOptions, "Invalid driver $value", $expected); } } @@ -108,22 +112,19 @@ function testEncryptedWithODBC($msodbcsqlMaj, $server, $connectionOptions) $expected = "The Always Encrypted feature requires Microsoft ODBC Driver 17 for SQL Server"; - connectVerifyOutput($server, $connectionOptions, $expected); + connectVerifyOutput($server, $connectionOptions, "Using ODBC 13 for AE", $expected); } function testWrongODBC($msodbcsqlMaj, $server, $connectionOptions) { - $value = "ODBC Driver 11 for SQL Server"; - if ($msodbcsqlMaj == 17 || $msodbcsqlMaj < 13) { - $value = "ODBC Driver 13 for SQL Server"; - } - + $value = "ODBC Driver 18 for SQL Server"; $connectionOptions['Driver']=$value; $expected = "The specified ODBC Driver is not found."; - connectVerifyOutput($server, $connectionOptions, $expected); + connectVerifyOutput($server, $connectionOptions, "Connect with ODBC 18", $expected); } ?> --EXPECT-- Done + diff --git a/test/functional/sqlsrv/sqlsrv_connect_encrypt_attributes.phpt b/test/functional/sqlsrv/sqlsrv_connect_encrypt_attributes.phpt new file mode 100644 index 00000000..8448e676 --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_connect_encrypt_attributes.phpt @@ -0,0 +1,72 @@ +--TEST-- +Test various encrypt attributes +--DESCRIPTION-- +This test does not test if any connection is successful but mainly test if the Encrypt keyword takes +different attributes. +--SKIPIF-- + +--FILE-- + true, 'TrustServerCertificate' => true); +$conn = sqlsrv_connect($server, $connectionOptions); +if ($conn != false) { + sqlsrv_close($conn); +} + +echo 'Test case 2' . PHP_EOL; +$connectionOptions = array('Encrypt' => 1, 'TrustServerCertificate' => true); +$conn = sqlsrv_connect($server, $connectionOptions); +if ($conn != false) { + sqlsrv_close($conn); +} + +echo 'Test case 3' . PHP_EOL; +$connectionOptions = array('Encrypt' => "yes", 'TrustServerCertificate' => true); +$conn = sqlsrv_connect($server, $connectionOptions); +if ($conn != false) { + sqlsrv_close($conn); +} + +echo 'Test case 4' . PHP_EOL; +$connectionOptions = array('Encrypt' => "no"); +$conn = sqlsrv_connect($server, $connectionOptions); +if ($conn != false) { + sqlsrv_close($conn); +} + +echo 'Test case 5' . PHP_EOL; +$connectionOptions = array('Encrypt' => false); +$conn = sqlsrv_connect($server, $connectionOptions); +if ($conn != false) { + sqlsrv_close($conn); +} + +echo 'Test case 6' . PHP_EOL; +$connectionOptions = array('Encrypt' => 0); +$conn = sqlsrv_connect($server, $connectionOptions); +if ($conn != false) { + sqlsrv_close($conn); +} + +echo 'Test case 7' . PHP_EOL; +$connectionOptions = array('Encrypt' => 3); +$conn = sqlsrv_connect($server, $connectionOptions); +if ($conn !== false) { + echo 'Expect this to fail' . PHP_EOL; +} + +echo 'Done' . PHP_EOL; + +?> +--EXPECT-- +Test case 1 +Test case 2 +Test case 3 +Test case 4 +Test case 5 +Test case 6 +Test case 7 +Done diff --git a/test/functional/sqlsrv/sqlsrv_connect_hostname_cert.phpt b/test/functional/sqlsrv/sqlsrv_connect_hostname_cert.phpt new file mode 100644 index 00000000..edd7915c --- /dev/null +++ b/test/functional/sqlsrv/sqlsrv_connect_hostname_cert.phpt @@ -0,0 +1,21 @@ +--TEST-- +Test HostNameInCertificate keyword +--DESCRIPTION-- +This test does not test if any connection is successful but mainly test if the HostNameInCertificate keyword is recognized. +--SKIPIF-- + +--FILE-- + 'dummy'); +$conn = sqlsrv_connect($server, $connectionOptions); +if ($conn != false) { + sqlsrv_close($conn); +} + +echo 'Done' . PHP_EOL; + +?> +--EXPECT-- +Done diff --git a/test/functional/sqlsrv/srv_1063_test_locale.php b/test/functional/sqlsrv/srv_1063_test_locale.php index b8fea4d5..2ee88f56 100644 --- a/test/functional/sqlsrv/srv_1063_test_locale.php +++ b/test/functional/sqlsrv/srv_1063_test_locale.php @@ -13,7 +13,7 @@ function fatalError($message) die($message); } -function printMoney($amt, $info) +function printMoney($amt, $info) { // The money_format() function is deprecated in PHP 7.4, so use intl NumberFormatter $loc = setlocale(LC_MONETARY, 0); @@ -53,30 +53,34 @@ $locale = ($_SERVER['argv'][2] ?? ''); echo "**Begin**" . PHP_EOL; -// Assuming LC_ALL is 'en_US.UTF-8', so is LC_CTYPE, except in PHP 8 (TODO) -// But default LC_MONETARY varies -$ctype = (PHP_MAJOR_VERSION == 8 && $setLocaleInfo == 0) ? 'C' : 'en_US.UTF-8'; +// Assuming LC_ALL is 'en_US.UTF-8', but default LC_CTYPE and LC_MONETARY vary in various +// platforms and PHP versions, so only check when $setLocaleInfo is 2 switch ($setLocaleInfo) { case 0: case 1: - $m = 'C'; $symbol = ''; $sep = ''; + $symbol = ''; $sep = ''; break; case 2: - $m = 'en_US.UTF-8'; $symbol = '$'; $sep = ','; + $symbol = '$'; $sep = ','; break; default: fatalError("Unexpected $setLocaleInfo\n"); break; } -$m1 = setlocale(LC_MONETARY, 0); -if ($m !== $m1) { - echo "Unexpected LC_MONETARY: $m1" . PHP_EOL; -} -$c1 = setlocale(LC_CTYPE, 0); -if ($ctype !== $c1) { - echo "Unexpected LC_CTYPE: $c1" . PHP_EOL; - echo "LC_NUMERIC for $setLocaleInfo: " . setlocale(LC_NUMERIC, 0) . PHP_EOL; +if ($setLocaleInfo == 2) { + $ctype = 'en_US.UTF-8'; + $m = 'en_US.UTF-8'; + + $m1 = setlocale(LC_MONETARY, 0); + if ($m !== $m1) { + echo "Unexpected LC_MONETARY: $m1" . PHP_EOL; + } + $c1 = setlocale(LC_CTYPE, 0); + if ($ctype !== $c1) { + echo "Unexpected LC_CTYPE: $c1" . PHP_EOL; + echo "LC_NUMERIC for $setLocaleInfo: " . setlocale(LC_NUMERIC, 0) . PHP_EOL; + } } // Set a different locale, if the input is not empty @@ -86,7 +90,7 @@ if (!empty($locale)) { if ($loc !== $locale) { echo "Unexpected $loc for LC_ALL " . PHP_EOL; } - + // Currency symbol and thousands separator in Linux and macOS may be different if ($loc === 'de_DE.UTF-8') { $symbol = strtoupper(PHP_OS) === 'LINUX' ? '€' : 'Eu';