diff options
author | Pierrick Charron <pierrick@php.net> | 2009-12-06 21:32:58 +0000 |
---|---|---|
committer | Pierrick Charron <pierrick@php.net> | 2009-12-06 21:32:58 +0000 |
commit | 99ba48dc60baeb3692ec05c0f6947fc7d732fa51 (patch) | |
tree | 7585d258a4b6c55fd8486ff6cb163d3a5f0ff2e4 /ext | |
parent | bf550fe8da6d9c302b64bdb1ff308ee989bd4fd3 (diff) | |
download | php-git-99ba48dc60baeb3692ec05c0f6947fc7d732fa51.tar.gz |
Fixed bug #50323 (Allow use of ; in values via ;; in PDO DSN even in the middle of a string).
Diffstat (limited to 'ext')
-rwxr-xr-x | ext/pdo/pdo.c | 40 | ||||
-rw-r--r-- | ext/pdo_mysql/tests/bug_50323.phpt | 61 |
2 files changed, 97 insertions, 4 deletions
diff --git a/ext/pdo/pdo.c b/ext/pdo/pdo.c index e986aaa225..0143d93e8a 100755 --- a/ext/pdo/pdo.c +++ b/ext/pdo/pdo.c @@ -222,6 +222,7 @@ PDO_API int php_pdo_parse_data_source(const char *data_source, int optstart = 0; int nlen; int n_matches = 0; + int n_semicolumns = 0; i = 0; while (i < data_source_len) { @@ -240,14 +241,21 @@ PDO_API int php_pdo_parse_data_source(const char *data_source, /* now we're looking for VALUE; or just VALUE<NUL> */ semi = -1; + n_semicolumns = 0; while (i < data_source_len) { if (data_source[i] == '\0') { semi = i++; break; } - if (data_source[i] == ';' && ((i + 1 >= data_source_len) || data_source[i+1] != ';')) { - semi = i++; - break; + if (data_source[i] == ';') { + if ((i + 1 >= data_source_len) || data_source[i+1] != ';') { + semi = i++; + break; + } else { + n_semicolumns++; + i += 2; + continue; + } } ++i; } @@ -264,7 +272,31 @@ PDO_API int php_pdo_parse_data_source(const char *data_source, if (parsed[j].freeme) { efree(parsed[j].optval); } - parsed[j].optval = estrndup(data_source + valstart, semi - valstart); + + if (n_semicolumns == 0) { + parsed[j].optval = estrndup(data_source + valstart, semi - valstart - n_semicolumns); + } else { + int vlen = semi - valstart; + char *orig_val = data_source + valstart; + char *new_val = (char *) emalloc(vlen - n_semicolumns + 1); + + parsed[j].optval = new_val; + + while (vlen && *orig_val) { + *new_val = *orig_val; + new_val++; + + if (*orig_val == ';') { + orig_val+=2; + vlen-=2; + } else { + orig_val++; + vlen--; + } + } + *new_val = '\0'; + } + parsed[j].freeme = 1; ++n_matches; break; diff --git a/ext/pdo_mysql/tests/bug_50323.phpt b/ext/pdo_mysql/tests/bug_50323.phpt new file mode 100644 index 0000000000..02050fac5d --- /dev/null +++ b/ext/pdo_mysql/tests/bug_50323.phpt @@ -0,0 +1,61 @@ +--TEST-- +Bug #50323 (No ability to connect to database named 't;', no chance to escape semicolon) +--SKIPIF-- +<?php +if (!extension_loaded('pdo') || !extension_loaded('pdo_mysql')) die('skip not loaded'); +require dirname(__FILE__) . '/config.inc'; +require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc'; +PDOTest::skip(); +?> +--FILE-- +<?php +require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc'; +$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt'); + + function changeDSN($original, $new_options) { + $old_options = array(); + $dsn = substr($original, + strpos($original, ':') + 1, + strlen($original)); + + // no real parser - any excotic setting can fool us + $parts = explode(';', $dsn); + foreach ($parts as $k => $v) { + $tmp = explode('=', $v); + if (count($tmp) == 2) + $old_options[$tmp[0]] = $tmp[1]; + } + + $options = $old_options; + foreach ($new_options as $k => $v) + $options[$k] = $v; + + $dsn = 'mysql:'; + foreach ($options as $k => $v) + $dsn .= sprintf('%s=%s;', $k, $v); + + $dsn = substr($dsn, 0, strlen($dsn) -1); + + return $dsn; + } + + +if (1 === @$db->exec('CREATE DATABASE `crazy;dbname`')) { + $dsn = changeDSN(getenv('PDOTEST_DSN'), array('dbname' => 'crazy;;dbname')); + $user = getenv('PDOTEST_USER'); + $pass = getenv('PDOTEST_PASS'); + + new PDO($dsn, $user, $pass); +} +echo 'done!'; +?> +--CLEAN-- +<?php +require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc'; +$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt'); + +@$db->exec('DROP DATABASE IF EXISTS `crazy;dbname`'); +?> +--EXPECTF-- +done! + |