Merge pull request #1366 from microsoft/dev

Dev - 5.10.0
This commit is contained in:
Sicong 2022-01-31 14:47:52 -08:00 committed by GitHub
commit 376dc05401
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 818 additions and 394 deletions

19
.github/ISSUE_TEMPLATE/bug-report.md vendored Normal file
View file

@ -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

View file

@ -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.

0
.github/ISSUE_TEMPLATE/other.md vendored Normal file
View file

View file

@ -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:

View file

@ -1,4 +1,4 @@
Copyright(c) 2021 Microsoft Corporation
Copyright(c) 2022 Microsoft Corporation
All rights reserved.
MIT License

View file

@ -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 `<SuseVersion>` 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 `<SuseVersion>` 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/<SuseVersion>/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/<SuseVersion>/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 `<mirror>` 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 "<FilesMatch .php$>"; echo "SetHandler application/x-httpd-php"; echo "</FilesMatch>";) >> /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

View file

@ -13,28 +13,20 @@ Thank you for taking the time to participate in the [sentiment survey](https://g
<a href="https://aka.ms/mssqlphpsurvey"><img style="float: right;" height="67" width="156" src="https://sqlchoice.blob.core.windows.net/sqlchoice/static/images/survey.png"></a>
### 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

View file

@ -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)'

View file

@ -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.)

View file

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 67 KiB

View file

@ -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 <unsigned int Attr>
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);

View file

@ -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<std::string> 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<char*>( 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<int>(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
}

View file

@ -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<ACCESSTOKEN> 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 );
//*********************************************************************************************************************************

View file

@ -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;

View file

@ -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

View file

@ -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,

View file

@ -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

View file

@ -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--
<?php require('skipif.inc');?>
--FILE--
<?php
require_once 'MsSetup.inc';
try {
$connectionInfo = "ComputePool = pool1;";
$conn1 = new PDO("sqlsrv:server = $server; $connectionInfo", $uid, $pwd);
} catch (PDOException $e) {
// do nothing
}
unset($conn1);
echo 'Done' . PHP_EOL;
?>
--EXPECT--
Done

View file

@ -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
Done

View file

@ -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--
<?php require('skipif.inc');?>
--FILE--
<?php
require_once 'MsSetup.inc';
try {
$encrypt = ' true ';
$trust = 'true ';
$connectionInfo = "Database = $databaseName; Encrypt = $encrypt; TrustServerCertificate = $trust;";
$conn1 = new PDO("sqlsrv:server = $server ; $connectionInfo", $uid, $pwd);
echo 'Test case 1' . PHP_EOL;
} catch (PDOException $e) {
echo 'Failed to connect (test case 1)' . PHP_EOL;
print_r($e->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

View file

@ -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--
<?php require('skipif.inc');?>
--FILE--
<?php
require_once 'MsSetup.inc';
try {
$connectionInfo = "HostNameInCertificate = dummy;";
$conn1 = new PDO("sqlsrv:server = $server; $connectionInfo", $uid, $pwd);
} catch (PDOException $e) {
// do nothing
}
unset($conn1);
echo 'Done' . PHP_EOL;
?>
--EXPECT--
Done

View file

@ -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--
<?php require('skipif.inc');?>
--FILE--
<?php
require_once 'MsSetup.inc';
$connectionOptions = array('ComputePool' => 'pool1');
$conn = sqlsrv_connect($server, $connectionOptions);
if ($conn != false) {
sqlsrv_close($conn);
}
echo 'Done' . PHP_EOL;
?>
--EXPECT--
Done

View file

@ -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

View file

@ -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--
<?php require('skipif.inc');?>
--FILE--
<?php
require_once 'MsSetup.inc';
echo 'Test case 1' . PHP_EOL;
$connectionOptions = array('Encrypt' => 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

View file

@ -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--
<?php require('skipif.inc');?>
--FILE--
<?php
require_once 'MsSetup.inc';
$connectionOptions = array('HostNameInCertificate' => 'dummy');
$conn = sqlsrv_connect($server, $connectionOptions);
if ($conn != false) {
sqlsrv_close($conn);
}
echo 'Done' . PHP_EOL;
?>
--EXPECT--
Done

View file

@ -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';