Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added configurable options for setting locales #1069

Merged
merged 7 commits into from
Dec 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions Dockerfile-msphpsql
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,14 @@ ENV TEST_PHP_SQL_PWD Password123
# update PATH after ODBC driver and tools are installed
ENV PATH="/opt/mssql-tools/bin:${PATH}"

# add locale iso-8859-1
# add locales for testing
RUN sed -i 's/# en_US ISO-8859-1/en_US ISO-8859-1/g' /etc/locale.gen
RUN locale-gen en_US
RUN sed -i 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/g' /etc/locale.gen
RUN sed -i 's/# de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/g' /etc/locale.gen
RUN locale-gen

# set locale to utf-8
RUN locale-gen en_US.UTF-8
# RUN locale-gen en_US.UTF-8
ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' LC_ALL='en_US.UTF-8'

# install coveralls (upgrade both pip and requests first)
Expand All @@ -65,6 +67,10 @@ RUN /bin/bash -c "./packagize.sh"
RUN echo "; priority=20\nextension=sqlsrv.so\n" > /etc/php/7.3/mods-available/sqlsrv.ini
RUN echo "; priority=30\nextension=pdo_sqlsrv.so\n" > /etc/php/7.3/mods-available/pdo_sqlsrv.ini

# create a writable ini file for testing locales
RUN echo '' > `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/99-overrides.ini
RUN chmod 666 `php --ini | grep "Scan for additional .ini files" | sed -e "s|.*:\s*||"`/99-overrides.ini

WORKDIR $PHPSQLDIR/source/sqlsrv
RUN /usr/bin/phpize && ./configure LDFLAGS="-lgcov" CXXFLAGS="-O0 --coverage" && make && make install

Expand Down
10 changes: 8 additions & 2 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,9 @@ jobs:

- script: |
sudo sed -i 's/# en_US ISO-8859-1/en_US ISO-8859-1/g' /etc/locale.gen
sudo locale-gen en_US
sudo locale-gen en_US.UTF-8
sudo sed -i 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/g' /etc/locale.gen
sudo sed -i 's/# de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/g' /etc/locale.gen
sudo locale-gen
export LANG='en_US.UTF-8'
export LANGUAGE='en_US:en'
export LC_ALL='en_US.UTF-8'
Expand Down Expand Up @@ -151,6 +152,9 @@ jobs:
echo copying pdo_sqlsrv to $dest
sudo cp 30-pdo_sqlsrv.ini $dest

sudo touch $dest/99-overrides.ini
sudo chmod 666 $dest/99-overrides.ini

php --ri sqlsrv
php --ri pdo_sqlsrv
displayName: 'Build and install drivers'
Expand All @@ -162,6 +166,7 @@ jobs:
sed -i -e 's/TARGET_USERNAME/'"$(uid)"'/g' MsSetup.inc
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
displayName: 'Run sqlsrv functional tests'

Expand All @@ -172,6 +177,7 @@ jobs:
sed -i -e 's/TARGET_USERNAME/'"$(uid)"'/g' MsSetup.inc
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
displayName: 'Run pdo_sqlsrv functional tests'

Expand Down
16 changes: 16 additions & 0 deletions source/pdo_sqlsrv/pdo_init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,22 @@ PHP_RINIT_FUNCTION(pdo_sqlsrv)
ZEND_TSRMLS_CACHE_UPDATE();
#endif

#ifndef _WIN32
// if necessary, set locale from the environment for ODBC, which MUST be done before any connection
int set_locale = PDO_SQLSRV_G(set_locale_info);
if (set_locale == 2) {
setlocale(LC_ALL, "");
LOG(SEV_NOTICE, "pdo_sqlsrv: setlocale LC_ALL");
}
else if (set_locale == 1) {
setlocale(LC_CTYPE, "");
LOG(SEV_NOTICE, "pdo_sqlsrv: setlocale LC_CTYPE");
}
else {
LOG(SEV_NOTICE, "pdo_sqlsrv: setlocale NONE");
}
#endif

LOG( SEV_NOTICE, "pdo_sqlsrv: entering rinit" );

return SUCCESS;
Expand Down
4 changes: 4 additions & 0 deletions source/pdo_sqlsrv/php_pdo_sqlsrv.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ ZEND_BEGIN_MODULE_GLOBALS(pdo_sqlsrv)
unsigned int log_severity;
zend_long client_buffer_max_size;

#ifndef _WIN32
zend_long set_locale_info;
#endif

ZEND_END_MODULE_GLOBALS(pdo_sqlsrv)

ZEND_EXTERN_MODULE_GLOBALS(pdo_sqlsrv);
Expand Down
8 changes: 8 additions & 0 deletions source/pdo_sqlsrv/php_pdo_sqlsrv_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,19 @@ extern HMODULE g_sqlsrv_hmodule;
#define INI_PDO_SQLSRV_LOG "log_severity"
#define INI_PREFIX "pdo_sqlsrv."

#ifndef _WIN32
#define INI_PDO_SET_LOCALE_INFO "set_locale_info"
#endif

PHP_INI_BEGIN()
STD_PHP_INI_ENTRY( INI_PREFIX INI_PDO_SQLSRV_LOG , "0", PHP_INI_ALL, OnUpdateLong, log_severity,
zend_pdo_sqlsrv_globals, pdo_sqlsrv_globals )
STD_PHP_INI_ENTRY( INI_PREFIX INI_PDO_SQLSRV_CLIENT_BUFFER_MAX_SIZE , INI_BUFFERED_QUERY_LIMIT_DEFAULT, PHP_INI_ALL, OnUpdateLong,
client_buffer_max_size, zend_pdo_sqlsrv_globals, pdo_sqlsrv_globals )
#ifndef _WIN32
STD_PHP_INI_ENTRY(INI_PREFIX INI_PDO_SET_LOCALE_INFO, "2", PHP_INI_ALL, OnUpdateLong, set_locale_info,
zend_pdo_sqlsrv_globals, pdo_sqlsrv_globals)
#endif
PHP_INI_END()


Expand Down
6 changes: 0 additions & 6 deletions source/shared/core_init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,6 @@ void core_sqlsrv_minit( _Outptr_ sqlsrv_context** henv_cp, _Inout_ sqlsrv_contex
SQLSRV_STATIC_ASSERT( sizeof( sqlsrv_sqltype ) == sizeof( zend_long ) );
SQLSRV_STATIC_ASSERT( sizeof( sqlsrv_phptype ) == sizeof( zend_long ));

#ifndef _WIN32
// set locale from environment
// this is necessary for ODBC and MUST be done before connection
setlocale(LC_ALL, "");
#endif

*henv_cp = *henv_ncp = SQL_NULL_HANDLE; // initialize return values to NULL

try {
Expand Down
19 changes: 19 additions & 0 deletions source/sqlsrv/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,25 @@ PHP_RINIT_FUNCTION(sqlsrv)
SQLSRV_G( log_subsystems ) = INI_INT( subsystems );
SQLSRV_G( buffered_query_limit ) = INI_INT( buffered_limit );

#ifndef _WIN32
char set_locale_info[] = INI_PREFIX INI_SET_LOCALE_INFO;
SQLSRV_G(set_locale_info) = INI_INT(set_locale_info);

// if necessary, set locale from the environment for ODBC, which MUST be done before any connection
int set_locale = SQLSRV_G(set_locale_info);
if (set_locale == 2) {
setlocale(LC_ALL, "");
}
else if (set_locale == 1) {
setlocale(LC_CTYPE, "");
}
else {
// Do nothing
}

LOG(SEV_NOTICE, INI_PREFIX INI_SET_LOCALE_INFO " = %1!d!", set_locale);
#endif

LOG( SEV_NOTICE, INI_PREFIX INI_WARNINGS_RETURN_AS_ERRORS " = %1!s!", SQLSRV_G( warnings_return_as_errors ) ? "On" : "Off");
LOG( SEV_NOTICE, INI_PREFIX INI_LOG_SEVERITY " = %1!d!", SQLSRV_G( log_severity ));
LOG( SEV_NOTICE, INI_PREFIX INI_LOG_SUBSYSTEMS " = %1!d!", SQLSRV_G( log_subsystems ));
Expand Down
4 changes: 4 additions & 0 deletions source/sqlsrv/php_sqlsrv.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ zend_long current_subsystem;
zend_bool warnings_return_as_errors;
zend_long buffered_query_limit;

#ifndef _WIN32
zend_long set_locale_info;
#endif

ZEND_END_MODULE_GLOBALS(sqlsrv)

ZEND_EXTERN_MODULE_GLOBALS(sqlsrv);
Expand Down
9 changes: 9 additions & 0 deletions source/sqlsrv/php_sqlsrv_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
#define INI_BUFFERED_QUERY_LIMIT "ClientBufferMaxKBSize"
#define INI_PREFIX "sqlsrv."

#ifndef _WIN32
#define INI_SET_LOCALE_INFO "SetLocaleInfo"
#endif

PHP_INI_BEGIN()
STD_PHP_INI_BOOLEAN( INI_PREFIX INI_WARNINGS_RETURN_AS_ERRORS , "1", PHP_INI_ALL, OnUpdateBool, warnings_return_as_errors,
zend_sqlsrv_globals, sqlsrv_globals )
Expand All @@ -46,6 +50,11 @@ PHP_INI_BEGIN()
sqlsrv_globals )
STD_PHP_INI_ENTRY( INI_PREFIX INI_BUFFERED_QUERY_LIMIT, INI_BUFFERED_QUERY_LIMIT_DEFAULT, PHP_INI_ALL, OnUpdateLong, buffered_query_limit,
zend_sqlsrv_globals, sqlsrv_globals )
#ifndef _WIN32
STD_PHP_INI_ENTRY(INI_PREFIX INI_SET_LOCALE_INFO, "2", PHP_INI_ALL, OnUpdateLong, set_locale_info,
zend_sqlsrv_globals, sqlsrv_globals)
#endif

PHP_INI_END()


Expand Down
103 changes: 103 additions & 0 deletions test/functional/pdo_sqlsrv/pdo_1063_locale_configs.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
--TEST--
GitHub issue 1063 - make setting locale info configurable
--DESCRIPTION--
This test verifies that the users can configure using ini file to set application locale using the system locale or not. This test is valid for Linux and macOS systems only.
--ENV--
PHPT_EXEC=true
--SKIPIF--
<?php require('skipif_unix_locales.inc'); ?>
--FILE--
<?php
function runTest($val, $file, $locale)
{
print("\n***sqlsrv.SetLocaleInfo = $val\npdo_sqlsrv.set_locale_info = $val***\n\n");
shell_exec("echo 'sqlsrv.SetLocaleInfo = $val\npdo_sqlsrv.set_locale_info = $val' > $file");
print_r(shell_exec(PHP_BINARY." ".dirname(__FILE__)."/pdo_1063_test_locale.php "));
print_r(shell_exec(PHP_BINARY." ".dirname(__FILE__)."/pdo_1063_test_locale.php $locale"));
}

$inifile = PHP_CONFIG_FILE_SCAN_DIR."/99-overrides.ini";

$locale1 = strtoupper(PHP_OS) === 'LINUX' ? "en_US.ISO-8859-1" : "en_US.ISO8859-1";
$locale2 = 'de_DE.UTF-8';

runTest(0, $inifile, $locale1);
runTest(1, $inifile, $locale2);
runTest(2, $inifile, $locale2);
?>
--EXPECT--

***sqlsrv.SetLocaleInfo = 0
pdo_sqlsrv.set_locale_info = 0***

**Begin**
Current LC_MONETARY: C
Current LC_CTYPE: en_US.UTF-8
Currency symbol:
Thousands_sep:
Amount formatted: 10000.99
Friday
December
3.14159
**End**
**Begin**
Current LC_MONETARY: C
Current LC_CTYPE: en_US.UTF-8
Setting LC_ALL: en_US.ISO-8859-1
Currency symbol: $
Thousands_sep: ,
Amount formatted: USD 10,000.99
Friday
December
3.14159
**End**

***sqlsrv.SetLocaleInfo = 1
pdo_sqlsrv.set_locale_info = 1***

**Begin**
Current LC_MONETARY: C
Current LC_CTYPE: en_US.UTF-8
Currency symbol:
Thousands_sep:
Amount formatted: 10000.99
Friday
December
3.14159
**End**
**Begin**
Current LC_MONETARY: C
Current LC_CTYPE: en_US.UTF-8
Setting LC_ALL: de_DE.UTF-8
Currency symbol: €
Thousands_sep: .
Amount formatted: 10.000,99 EUR
Freitag
Dezember
3,14159
**End**

***sqlsrv.SetLocaleInfo = 2
pdo_sqlsrv.set_locale_info = 2***

**Begin**
Current LC_MONETARY: en_US.UTF-8
Current LC_CTYPE: en_US.UTF-8
Currency symbol: $
Thousands_sep: ,
Amount formatted: USD 10,000.99
Friday
December
3.14159
**End**
**Begin**
Current LC_MONETARY: en_US.UTF-8
Current LC_CTYPE: en_US.UTF-8
Setting LC_ALL: de_DE.UTF-8
Currency symbol: €
Thousands_sep: .
Amount formatted: 10.000,99 EUR
Freitag
Dezember
3,14159
**End**
61 changes: 61 additions & 0 deletions test/functional/pdo_sqlsrv/pdo_1063_test_locale.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

function dropTable($conn, $tableName)
{
$tsql = "IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'" . $tableName . "') AND type in (N'U')) DROP TABLE $tableName";
$conn->exec($tsql);
}


// This test is invoked by pdo_1063_locale_configs.phpt
require_once('MsSetup.inc');

$locale = ($_SERVER['argv'][1] ?? '');

echo "**Begin**" . PHP_EOL;
echo "Current LC_MONETARY: " . setlocale(LC_MONETARY, 0) . PHP_EOL;
echo "Current LC_CTYPE: " . setlocale(LC_CTYPE, 0) . PHP_EOL;

if (!empty($locale)) {
$loc = setlocale(LC_ALL, $locale);
echo "Setting LC_ALL: " . $loc . PHP_EOL;
}

$info = localeconv();
echo "Currency symbol: " . $info['currency_symbol'] . PHP_EOL;
echo "Thousands_sep: " . $info['thousands_sep'] . PHP_EOL;

$n1 = 10000.98765;
echo "Amount formatted: " . money_format("%i", $n1) . PHP_EOL;
echo strftime("%A", strtotime("12/25/2020")) . PHP_EOL;
echo strftime("%B", strtotime("12/25/2020")) . PHP_EOL;

try {
$conn = new PDO("sqlsrv:server = $server; database=$databaseName; driver=$driver", $uid, $pwd );

$tableName = "[" . "pdo1063" . $locale . "]";

dropTable($conn, $tableName);

$pi = "3.14159";

$stmt = $conn->query("CREATE TABLE $tableName (c1 FLOAT)");
$stmt = $conn->query("INSERT INTO $tableName (c1) VALUES ($pi)");

$sql = "SELECT c1 FROM $tableName";
$stmt = $conn->prepare($sql, array(PDO::SQLSRV_ATTR_FETCHES_NUMERIC_TYPE => true));
$stmt->execute();

$row = $stmt->fetch(PDO::FETCH_NUM);
echo ($row[0]) . PHP_EOL;
unset($stmt);

dropTable($conn, $tableName);

unset($conn);
} catch( PDOException $e ) {
print_r( $e->getMessage() );
}

echo "**End**" . PHP_EOL;
?>
29 changes: 29 additions & 0 deletions test/functional/pdo_sqlsrv/skipif_unix_locales.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
die("Skipped: Test for Linux and macOS");
}

if (!extension_loaded("sqlsrv")) {
die("skip extension not loaded");
}

// check if the required ini file exists
$inifile = PHP_CONFIG_FILE_SCAN_DIR."/99-overrides.ini";
if (!file_exists($inifile)) {
die("required ini file not exists");
}

// if the file exists, is it writable? '@' sign is used to suppress warnings
$file = @fopen($inifile, "w");
if (!$file) {
die("required ini file not writable");
}

fclose($file);

$loc = setlocale(LC_TIME, 'de_DE.UTF-8');
if (empty($loc)) {
die("required locale not available");
}
?>
Loading