mirror of
https://github.com/php/php-src.git
synced 2024-11-26 19:33:55 +08:00
Quote when adding to connection string in (PDO_)ODBC
Because the UID= and PWD= values are appended to the SQLDriverConnect case when credentials are passed, we have to append them to the string in case users are relying on this behaviour. However, they must be quoted, or the arguments will be invalid (or possibly more injected). This means users had to quote arguments or append credentials to the raw connection string themselves. It seems that ODBC quoting rules are consistent enough (and that Microsoft trusts them enough to encode into the .NET BCL) that we can actually check if the string is already quoted (in case a user is already quoting because of this not being fixed), and if not, apply the appropriate ODBC quoting rules. This is because the code exists in main/, and are shared between both ODBC extensions, so it doesn't make sense for it to only exist in one or the other. There may be a better spot for it. Closes GH-8307.
This commit is contained in:
parent
1400aa4fb5
commit
2920a26636
4
NEWS
4
NEWS
@ -42,9 +42,13 @@ PHP NEWS
|
||||
. Support for building against Oracle Client libraries 10.1 and 10.2 has been
|
||||
dropped. Oracle Client libraries 11.2 or newer are now required.
|
||||
|
||||
- ODBC:
|
||||
. Automatically quote username and password when needed. (Calvin Buckley)
|
||||
|
||||
- PDO_ODBC:
|
||||
. Fixed bug #80909 (crash with persistent connections in PDO_ODBC). (Calvin
|
||||
Buckley)
|
||||
. Automatically quote username and password when needed. (Calvin Buckley)
|
||||
|
||||
- Reflection:
|
||||
. Added ReflectionFunction::isAnonymous(). (Nicolas Grekas)
|
||||
|
20
UPGRADING
20
UPGRADING
@ -25,6 +25,19 @@ PHP 8.2 UPGRADE NOTES
|
||||
. DateTimeImmutable::createFromMutable() now has a tentative return type of static,
|
||||
previously it was DateTimeImmutable.
|
||||
|
||||
- ODBC:
|
||||
. The ODBC extension now escapes the username and password for the case when
|
||||
both a connection string and username/password are passed, and the string
|
||||
must be appended to. Before, user values containing values needing escaping
|
||||
could have created a malformed connection string, or injected values from
|
||||
user-provided data. The escaping rules should be identical to the .NET BCL
|
||||
DbConnectionOptions behaviour.
|
||||
|
||||
- PDO_ODBC:
|
||||
. The PDO_ODBC extension also escapes the username and password when a
|
||||
connection string is passed. See the change to the ODBC extension for
|
||||
further details.
|
||||
|
||||
- Standard:
|
||||
. strtolower() and strtoupper() are no longer locale-sensitive. They now
|
||||
perform ASCII case conversion, as if the locale were "C". Use
|
||||
@ -70,6 +83,13 @@ PHP 8.2 UPGRADE NOTES
|
||||
round-trips between PHP and Oracle Database when fetching LOBS. This is
|
||||
usable with Oracle Database 12.2 or later.
|
||||
|
||||
- ODBC:
|
||||
. Added odbc_connection_string_is_quoted, odbc_connection_string_should_quote,
|
||||
and odbc_connection_string_quote. These are primarily used behind the scenes
|
||||
in the ODBC and PDO_ODBC extensions, but is exposed to userland for easier
|
||||
unit testing, and for user applications and libraries to perform quoting
|
||||
themselves.
|
||||
|
||||
- PCRE:
|
||||
. Added support for the "n" (NO_AUTO_CAPTURE) modifier, which makes simple
|
||||
`(xyz)` groups non-capturing. Only named groups like `(?<name>xyz)` are
|
||||
|
@ -1614,7 +1614,7 @@ PHP_ADD_SOURCES(main, main.c snprintf.c spprintf.c \
|
||||
php_ini_builder.c \
|
||||
php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \
|
||||
strlcat.c explicit_bzero.c reentrancy.c php_variables.c php_ticks.c \
|
||||
network.c php_open_temporary_file.c \
|
||||
network.c php_open_temporary_file.c php_odbc_utils.c \
|
||||
output.c getopt.c php_syslog.c, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
|
||||
|
||||
PHP_ADD_SOURCES_X(main, fastcgi.c, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1, PHP_FASTCGI_OBJS, no)
|
||||
|
@ -461,7 +461,7 @@ if test -n "$ODBC_TYPE"; then
|
||||
PHP_SUBST_OLD(ODBC_LFLAGS)
|
||||
PHP_SUBST_OLD(ODBC_TYPE)
|
||||
|
||||
PHP_NEW_EXTENSION(odbc, php_odbc.c, $ext_shared,, [$ODBC_CFLAGS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1])
|
||||
PHP_NEW_EXTENSION(odbc, php_odbc.c odbc_utils.c, $ext_shared,, [$ODBC_CFLAGS -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1])
|
||||
else
|
||||
AC_MSG_CHECKING([for any ODBC driver support])
|
||||
AC_MSG_RESULT(no)
|
||||
|
@ -7,7 +7,7 @@ if (PHP_ODBC == "yes") {
|
||||
if (CHECK_LIB("odbc32.lib", "odbc") && CHECK_LIB("odbccp32.lib", "odbc")
|
||||
&& CHECK_HEADER_ADD_INCLUDE("sql.h", "CFLAGS_ODBC")
|
||||
&& CHECK_HEADER_ADD_INCLUDE("sqlext.h", "CFLAGS_ODBC")) {
|
||||
EXTENSION("odbc", "php_odbc.c", PHP_ODBC_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
|
||||
EXTENSION("odbc", "php_odbc.c odbc_utils.c", PHP_ODBC_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
|
||||
AC_DEFINE("HAVE_UODBC", 1, "ODBC support");
|
||||
if ("no" == PHP_ODBCVER) {
|
||||
AC_DEFINE("ODBCVER", "0x0350", "The highest supported ODBC version", false);
|
||||
|
@ -197,3 +197,11 @@ function odbc_tableprivileges($odbc, ?string $catalog, string $schema, string $t
|
||||
*/
|
||||
function odbc_columnprivileges($odbc, ?string $catalog, string $schema, string $table, string $column) {}
|
||||
#endif
|
||||
|
||||
/* odbc_utils.c */
|
||||
|
||||
function odbc_connection_string_is_quoted(string $str): bool {}
|
||||
|
||||
function odbc_connection_string_should_quote(string $str): bool {}
|
||||
|
||||
function odbc_connection_string_quote(string $str): string {}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 27a50ba79ed632721ee458527ef543e4b44ee897 */
|
||||
* Stub hash: 298e48377c2d18c532d91a9ed97886b49a64c096 */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_close_all, 0, 0, IS_VOID, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
@ -245,6 +245,16 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_odbc_columnprivileges, 0, 0, 5)
|
||||
ZEND_END_ARG_INFO()
|
||||
#endif
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_connection_string_is_quoted, 0, 1, _IS_BOOL, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
#define arginfo_odbc_connection_string_should_quote arginfo_odbc_connection_string_is_quoted
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_connection_string_quote, 0, 1, IS_STRING, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
|
||||
ZEND_FUNCTION(odbc_close_all);
|
||||
ZEND_FUNCTION(odbc_binmode);
|
||||
@ -307,6 +317,9 @@ ZEND_FUNCTION(odbc_tableprivileges);
|
||||
#if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) &&!defined(HAVE_SOLID_35)
|
||||
ZEND_FUNCTION(odbc_columnprivileges);
|
||||
#endif
|
||||
ZEND_FUNCTION(odbc_connection_string_is_quoted);
|
||||
ZEND_FUNCTION(odbc_connection_string_should_quote);
|
||||
ZEND_FUNCTION(odbc_connection_string_quote);
|
||||
|
||||
|
||||
static const zend_function_entry ext_functions[] = {
|
||||
@ -373,5 +386,8 @@ static const zend_function_entry ext_functions[] = {
|
||||
#if !defined(HAVE_DBMAKER) && !defined(HAVE_SOLID) && !defined(HAVE_SOLID_30) &&!defined(HAVE_SOLID_35)
|
||||
ZEND_FE(odbc_columnprivileges, arginfo_odbc_columnprivileges)
|
||||
#endif
|
||||
ZEND_FE(odbc_connection_string_is_quoted, arginfo_odbc_connection_string_is_quoted)
|
||||
ZEND_FE(odbc_connection_string_should_quote, arginfo_odbc_connection_string_should_quote)
|
||||
ZEND_FE(odbc_connection_string_quote, arginfo_odbc_connection_string_quote)
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
68
ext/odbc/odbc_utils.c
Normal file
68
ext/odbc/odbc_utils.c
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| https://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Calvin Buckley <calvin@cmpct.info> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "php.h"
|
||||
#include "php_odbc_utils.h"
|
||||
|
||||
/*
|
||||
* Utility functions for dealing with ODBC connection strings and other common
|
||||
* functionality.
|
||||
*
|
||||
* While useful for PDO_ODBC too, this lives in ext/odbc because there isn't a
|
||||
* better place for it.
|
||||
*/
|
||||
|
||||
PHP_FUNCTION(odbc_connection_string_is_quoted)
|
||||
{
|
||||
zend_string *str;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||
Z_PARAM_STR(str)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
bool is_quoted = php_odbc_connstr_is_quoted(ZSTR_VAL(str));
|
||||
|
||||
RETURN_BOOL(is_quoted);
|
||||
}
|
||||
|
||||
PHP_FUNCTION(odbc_connection_string_should_quote)
|
||||
{
|
||||
zend_string *str;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||
Z_PARAM_STR(str)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
bool should_quote = php_odbc_connstr_should_quote(ZSTR_VAL(str));
|
||||
|
||||
RETURN_BOOL(should_quote);
|
||||
}
|
||||
|
||||
PHP_FUNCTION(odbc_connection_string_quote)
|
||||
{
|
||||
zend_string *str;
|
||||
|
||||
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||
Z_PARAM_STR(str)
|
||||
ZEND_PARSE_PARAMETERS_END();
|
||||
|
||||
size_t new_size = php_odbc_connstr_estimate_quote_length(ZSTR_VAL(str));
|
||||
zend_string *new_string = zend_string_alloc(new_size, 0);
|
||||
php_odbc_connstr_quote(ZSTR_VAL(new_string), ZSTR_VAL(str), new_size);
|
||||
/* reset length */
|
||||
ZSTR_LEN(new_string) = strlen(ZSTR_VAL(new_string));
|
||||
RETURN_STR(new_string);
|
||||
}
|
@ -34,6 +34,9 @@
|
||||
#include "php_globals.h"
|
||||
#include "odbc_arginfo.h"
|
||||
|
||||
/* actually lives in main/ */
|
||||
#include "php_odbc_utils.h"
|
||||
|
||||
#ifdef HAVE_UODBC
|
||||
|
||||
#include <fcntl.h>
|
||||
@ -2169,8 +2172,38 @@ int odbc_sqlconnect(odbc_connection **conn, char *db, char *uid, char *pwd, int
|
||||
|
||||
if (strstr((char*)db, ";")) {
|
||||
direct = 1;
|
||||
if (uid && !strstr ((char*)db, "uid") && !strstr((char*)db, "UID")) {
|
||||
spprintf(&ldb, 0, "%s;UID=%s;PWD=%s", db, uid, pwd);
|
||||
/* Force UID and PWD to be set in the DSN */
|
||||
bool is_uid_set = uid && *uid
|
||||
&& !strstr(db, "uid=")
|
||||
&& !strstr(db, "UID=");
|
||||
bool is_pwd_set = pwd && *pwd
|
||||
&& !strstr(db, "pwd=")
|
||||
&& !strstr(db, "PWD=");
|
||||
if (is_uid_set && is_pwd_set) {
|
||||
char *uid_quoted = NULL, *pwd_quoted = NULL;
|
||||
bool should_quote_uid = !php_odbc_connstr_is_quoted(uid) && php_odbc_connstr_should_quote(uid);
|
||||
bool should_quote_pwd = !php_odbc_connstr_is_quoted(pwd) && php_odbc_connstr_should_quote(pwd);
|
||||
if (should_quote_uid) {
|
||||
size_t estimated_length = php_odbc_connstr_estimate_quote_length(uid);
|
||||
uid_quoted = emalloc(estimated_length);
|
||||
php_odbc_connstr_quote(uid_quoted, uid, estimated_length);
|
||||
} else {
|
||||
uid_quoted = uid;
|
||||
}
|
||||
if (should_quote_pwd) {
|
||||
size_t estimated_length = php_odbc_connstr_estimate_quote_length(pwd);
|
||||
pwd_quoted = emalloc(estimated_length);
|
||||
php_odbc_connstr_quote(pwd_quoted, pwd, estimated_length);
|
||||
} else {
|
||||
pwd_quoted = pwd;
|
||||
}
|
||||
spprintf(&ldb, 0, "%s;UID=%s;PWD=%s", db, uid_quoted, pwd_quoted);
|
||||
if (uid_quoted && should_quote_uid) {
|
||||
efree(uid_quoted);
|
||||
}
|
||||
if (pwd_quoted && should_quote_pwd) {
|
||||
efree(pwd_quoted);
|
||||
}
|
||||
} else {
|
||||
ldb_len = strlen(db)+1;
|
||||
ldb = (char*) emalloc(ldb_len);
|
||||
|
81
ext/odbc/tests/odbc_utils.phpt
Normal file
81
ext/odbc/tests/odbc_utils.phpt
Normal file
@ -0,0 +1,81 @@
|
||||
--TEST--
|
||||
Test common ODBC string functionality
|
||||
--EXTENSIONS--
|
||||
odbc
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
// 1. No, it's not quoted.
|
||||
// 2. Yes, it should be quoted because of the special character in the middle.
|
||||
$with_end_curly1 = "foo}bar";
|
||||
// 1. No, the unescaped special character in the middle breaks what would be quoted.
|
||||
// 2. Yes, it should be quoted because of the special character in the middle.
|
||||
// Note that should_quote doesn't care about if the string is already quoted.
|
||||
// That's why you should check if it is quoted first.
|
||||
$with_end_curly2 = "{foo}bar}";
|
||||
// 1. Yes, the special characters are escaped, so it's quoted.
|
||||
// 2. See $with_end_curly2; should_quote doesn't care about if the string is already quoted.
|
||||
$with_end_curly3 = "{foo}}bar}";
|
||||
// 1. No, it's not quoted.
|
||||
// 2. It doesn't need to be quoted because of no s
|
||||
$with_no_end_curly1 = "foobar";
|
||||
// 1. Yes, it is quoted and any characters are properly escaped.
|
||||
// 2. See $with_end_curly2.
|
||||
$with_no_end_curly2 = "{foobar}";
|
||||
|
||||
echo "# Is quoted?\n";
|
||||
echo "With end curly brace 1: ";
|
||||
var_dump(odbc_connection_string_is_quoted($with_end_curly1));
|
||||
echo "With end curly brace 2: ";
|
||||
var_dump(odbc_connection_string_is_quoted($with_end_curly2));
|
||||
echo "With end curly brace 3: ";
|
||||
var_dump(odbc_connection_string_is_quoted($with_end_curly3));
|
||||
echo "Without end curly brace 1: ";
|
||||
var_dump(odbc_connection_string_is_quoted($with_no_end_curly1));
|
||||
echo "Without end curly brace 2: ";
|
||||
var_dump(odbc_connection_string_is_quoted($with_no_end_curly2));
|
||||
|
||||
echo "# Should quote?\n";
|
||||
echo "With end curly brace 1: ";
|
||||
var_dump(odbc_connection_string_should_quote($with_end_curly1));
|
||||
echo "With end curly brace 2: ";
|
||||
var_dump(odbc_connection_string_should_quote($with_end_curly2));
|
||||
echo "With end curly brace 3: ";
|
||||
var_dump(odbc_connection_string_should_quote($with_end_curly3));
|
||||
echo "Without end curly brace 1: ";
|
||||
var_dump(odbc_connection_string_should_quote($with_no_end_curly1));
|
||||
echo "Without end curly brace 2: ";
|
||||
var_dump(odbc_connection_string_should_quote($with_no_end_curly2));
|
||||
|
||||
echo "# Quote?\n";
|
||||
echo "With end curly brace 1: ";
|
||||
var_dump(odbc_connection_string_quote($with_end_curly1));
|
||||
echo "With end curly brace 2: ";
|
||||
var_dump(odbc_connection_string_quote($with_end_curly2));
|
||||
echo "With end curly brace 3: ";
|
||||
var_dump(odbc_connection_string_quote($with_end_curly3));
|
||||
echo "Without end curly brace 1: ";
|
||||
var_dump(odbc_connection_string_quote($with_no_end_curly1));
|
||||
echo "Without end curly brace 2: ";
|
||||
var_dump(odbc_connection_string_quote($with_no_end_curly2));
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
# Is quoted?
|
||||
With end curly brace 1: bool(false)
|
||||
With end curly brace 2: bool(false)
|
||||
With end curly brace 3: bool(true)
|
||||
Without end curly brace 1: bool(false)
|
||||
Without end curly brace 2: bool(true)
|
||||
# Should quote?
|
||||
With end curly brace 1: bool(true)
|
||||
With end curly brace 2: bool(true)
|
||||
With end curly brace 3: bool(true)
|
||||
Without end curly brace 1: bool(false)
|
||||
Without end curly brace 2: bool(true)
|
||||
# Quote?
|
||||
With end curly brace 1: string(10) "{foo}}bar}"
|
||||
With end curly brace 2: string(13) "{{foo}}bar}}}"
|
||||
With end curly brace 3: string(15) "{{foo}}}}bar}}}"
|
||||
Without end curly brace 1: string(8) "{foobar}"
|
||||
Without end curly brace 2: string(11) "{{foobar}}}"
|
@ -23,6 +23,8 @@
|
||||
#include "ext/standard/info.h"
|
||||
#include "pdo/php_pdo.h"
|
||||
#include "pdo/php_pdo_driver.h"
|
||||
/* this file actually lives in main/ */
|
||||
#include "php_odbc_utils.h"
|
||||
#include "php_pdo_odbc.h"
|
||||
#include "php_pdo_odbc_int.h"
|
||||
#include "zend_exceptions.h"
|
||||
@ -485,20 +487,43 @@ static int pdo_odbc_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /* {{{
|
||||
use_direct = 1;
|
||||
|
||||
/* Force UID and PWD to be set in the DSN */
|
||||
if (dbh->username && *dbh->username && !strstr(dbh->data_source, "uid")
|
||||
&& !strstr(dbh->data_source, "UID")) {
|
||||
/* XXX: Do we check if password is null? */
|
||||
bool is_uid_set = dbh->username && *dbh->username
|
||||
&& !strstr(dbh->data_source, "uid=")
|
||||
&& !strstr(dbh->data_source, "UID=");
|
||||
bool is_pwd_set = dbh->password && *dbh->password
|
||||
&& !strstr(dbh->data_source, "pwd=")
|
||||
&& !strstr(dbh->data_source, "PWD=");
|
||||
if (is_uid_set && is_pwd_set) {
|
||||
char *uid = NULL, *pwd = NULL;
|
||||
bool should_quote_uid = !php_odbc_connstr_is_quoted(dbh->username) && php_odbc_connstr_should_quote(dbh->username);
|
||||
bool should_quote_pwd = !php_odbc_connstr_is_quoted(dbh->password) && php_odbc_connstr_should_quote(dbh->password);
|
||||
if (should_quote_uid) {
|
||||
size_t estimated_length = php_odbc_connstr_estimate_quote_length(dbh->username);
|
||||
uid = emalloc(estimated_length);
|
||||
php_odbc_connstr_quote(uid, dbh->username, estimated_length);
|
||||
} else {
|
||||
uid = dbh->username;
|
||||
}
|
||||
if (should_quote_pwd) {
|
||||
size_t estimated_length = php_odbc_connstr_estimate_quote_length(dbh->password);
|
||||
pwd = emalloc(estimated_length);
|
||||
php_odbc_connstr_quote(pwd, dbh->password, estimated_length);
|
||||
} else {
|
||||
pwd = dbh->password;
|
||||
}
|
||||
size_t new_dsn_size = strlen(dbh->data_source)
|
||||
+ strlen(dbh->username) + strlen(dbh->password)
|
||||
+ strlen(uid) + strlen(pwd)
|
||||
+ strlen(";UID=;PWD=") + 1;
|
||||
char *dsn = pemalloc(new_dsn_size, dbh->is_persistent);
|
||||
if (dsn == NULL) {
|
||||
/* XXX: Do we inform the caller? */
|
||||
goto fail;
|
||||
}
|
||||
snprintf(dsn, new_dsn_size, "%s;UID=%s;PWD=%s", dbh->data_source, dbh->username, dbh->password);
|
||||
snprintf(dsn, new_dsn_size, "%s;UID=%s;PWD=%s", dbh->data_source, uid, pwd);
|
||||
pefree((char*)dbh->data_source, dbh->is_persistent);
|
||||
dbh->data_source = dsn;
|
||||
if (uid && should_quote_uid) {
|
||||
efree(uid);
|
||||
}
|
||||
if (pwd && should_quote_pwd) {
|
||||
efree(pwd);
|
||||
}
|
||||
}
|
||||
|
||||
rc = SQLDriverConnect(H->dbc, NULL, (SQLCHAR *) dbh->data_source, strlen(dbh->data_source),
|
||||
|
117
main/php_odbc_utils.c
Normal file
117
main/php_odbc_utils.c
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| https://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Calvin Buckley <calvin@cmpct.info> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "php.h"
|
||||
|
||||
/*
|
||||
* This files contains functions shared between ext/pdo_odbc and ext/odbc,
|
||||
* relating to i.e. connection string quoting rules.
|
||||
*
|
||||
* The declarations are PHPAPI due to being available for shared/static
|
||||
* versions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Determines if a string matches the ODBC quoting rules.
|
||||
*
|
||||
* A valid quoted string begins with a '{', ends with a '}', and has no '}'
|
||||
* inside of the string that aren't repeated (as to be escaped).
|
||||
*
|
||||
* These rules are what .NET also follows.
|
||||
*/
|
||||
PHPAPI bool php_odbc_connstr_is_quoted(const char *str)
|
||||
{
|
||||
/* ODBC quotes are curly braces */
|
||||
if (str[0] != '{') {
|
||||
return false;
|
||||
}
|
||||
/* Check for } that aren't doubled up or at the end of the string */
|
||||
size_t length = strlen(str);
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
if (str[i] == '}' && str[i + 1] == '}') {
|
||||
/* Skip over so we don't count it again */
|
||||
i++;
|
||||
} else if (str[i] == '}' && str[i + 1] != '\0') {
|
||||
/* If not at the end, not quoted */
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a value for a connection string should be quoted.
|
||||
*
|
||||
* The ODBC specification mentions:
|
||||
* "Because of connection string and initialization file grammar, keywords and
|
||||
* and attribute values that contain the characters []{}(),;?*=!@ not enclosed
|
||||
* with braces should be avoided."
|
||||
*
|
||||
* Note that it assumes that the string is *not* already quoted. You should
|
||||
* check beforehand.
|
||||
*/
|
||||
PHPAPI bool php_odbc_connstr_should_quote(const char *str)
|
||||
{
|
||||
return strpbrk(str, "[]{}(),;?*=!@") != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Estimates the worst-case scenario for a quoted version of a string's size.
|
||||
*/
|
||||
PHPAPI size_t php_odbc_connstr_estimate_quote_length(const char *in_str)
|
||||
{
|
||||
/* Assume all '}'. Include '{,' '}', and the null terminator too */
|
||||
return (strlen(in_str) * 2) + 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Quotes a string with ODBC rules.
|
||||
*
|
||||
* Some characters (curly braces, semicolons) are special and must be quoted.
|
||||
* In the case of '}' in a quoted string, they must be escaped SQL style; that
|
||||
* is, repeated.
|
||||
*/
|
||||
PHPAPI size_t php_odbc_connstr_quote(char *out_str, const char *in_str, size_t out_str_size)
|
||||
{
|
||||
*out_str++ = '{';
|
||||
out_str_size--;
|
||||
while (out_str_size > 2) {
|
||||
if (*in_str == '\0') {
|
||||
break;
|
||||
} else if (*in_str == '}' && out_str_size - 1 > 2) {
|
||||
/* enough room to append */
|
||||
*out_str++ = '}';
|
||||
*out_str++ = *in_str++;
|
||||
out_str_size -= 2;
|
||||
} else if (*in_str == '}') {
|
||||
/* not enough, truncate here */
|
||||
break;
|
||||
} else {
|
||||
*out_str++ = *in_str++;
|
||||
out_str_size--;
|
||||
}
|
||||
}
|
||||
/* append termination */
|
||||
*out_str++ = '}';
|
||||
*out_str++ = '\0';
|
||||
out_str_size -= 2;
|
||||
/* return how many characters were left */
|
||||
return strlen(in_str);
|
||||
}
|
22
main/php_odbc_utils.h
Normal file
22
main/php_odbc_utils.h
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| https://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Calvin Buckley <calvin@cmpct.info> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "php.h"
|
||||
|
||||
PHPAPI bool php_odbc_connstr_is_quoted(const char *str);
|
||||
PHPAPI bool php_odbc_connstr_should_quote(const char *str);
|
||||
PHPAPI size_t php_odbc_connstr_estimate_quote_length(const char *in_str);
|
||||
PHPAPI size_t php_odbc_connstr_quote(char *out_str, const char *in_str, size_t out_str_size);
|
@ -265,7 +265,7 @@ ADD_SOURCES("main", "main.c snprintf.c spprintf.c getopt.c fopen_wrappers.c \
|
||||
php_scandir.c php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \
|
||||
strlcat.c reentrancy.c php_variables.c php_ticks.c network.c \
|
||||
php_open_temporary_file.c output.c internal_functions.c \
|
||||
php_syslog.c");
|
||||
php_syslog.c php_odbc_utils.c");
|
||||
ADD_FLAG("CFLAGS_BD_MAIN", "/D ZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
|
||||
if (VS_TOOLSET && VCVERS >= 1914) {
|
||||
ADD_FLAG("CFLAGS_BD_MAIN", "/d2FuncCache1");
|
||||
|
Loading…
Reference in New Issue
Block a user