pierrick Sun, 06 Dec 2009 21:32:58 +0000 Revision: http://svn.php.net/viewvc?view=revision&revision=291781
Log: Fixed bug #50323 (Allow use of ; in values via ;; in PDO DSN even in the middle of a string). Bug: http://bugs.php.net/50323 (Closed) No ability to connect to database named 't;', no chance to escape semicolon Changed paths: U php/php-src/branches/PHP_5_2/NEWS U php/php-src/branches/PHP_5_2/ext/pdo/pdo.c A php/php-src/branches/PHP_5_2/ext/pdo_mysql/tests/bug_50323.phpt U php/php-src/branches/PHP_5_3/NEWS U php/php-src/branches/PHP_5_3/ext/pdo/pdo.c A php/php-src/branches/PHP_5_3/ext/pdo_mysql/tests/bug_50323.phpt U php/php-src/trunk/ext/pdo/pdo.c A php/php-src/trunk/ext/pdo_mysql/tests/bug_50323.phpt
Modified: php/php-src/branches/PHP_5_2/NEWS =================================================================== --- php/php-src/branches/PHP_5_2/NEWS 2009-12-06 21:03:55 UTC (rev 291780) +++ php/php-src/branches/PHP_5_2/NEWS 2009-12-06 21:32:58 UTC (rev 291781) @@ -10,7 +10,8 @@ - Fixed bug #50345 (nanosleep not detected properly on some solaris versions). (Jani) -- Fixed bug #50323 (Allow use of ; in values via ;; in PDO DSN). (Ilia) +- Fixed bug #50323 (Allow use of ; in values via ;; in PDO DSN). + (Ilia, Pierrick) - Fixed bug #50266 (conflicting types for llabs). (Jani) - Fixed bug #50168 (FastCGI fails with wrong error on HEAD request to non-existent file). (Dmitry) Modified: php/php-src/branches/PHP_5_2/ext/pdo/pdo.c =================================================================== --- php/php-src/branches/PHP_5_2/ext/pdo/pdo.c 2009-12-06 21:03:55 UTC (rev 291780) +++ php/php-src/branches/PHP_5_2/ext/pdo/pdo.c 2009-12-06 21:32:58 UTC (rev 291781) @@ -217,6 +217,7 @@ int optstart = 0; int nlen; int n_matches = 0; + int n_semicolumns = 0; i = 0; while (i < data_source_len) { @@ -235,14 +236,21 @@ /* 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; } @@ -259,7 +267,31 @@ 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; Added: php/php-src/branches/PHP_5_2/ext/pdo_mysql/tests/bug_50323.phpt =================================================================== --- php/php-src/branches/PHP_5_2/ext/pdo_mysql/tests/bug_50323.phpt (rev 0) +++ php/php-src/branches/PHP_5_2/ext/pdo_mysql/tests/bug_50323.phpt 2009-12-06 21:32:58 UTC (rev 291781) @@ -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! + Modified: php/php-src/branches/PHP_5_3/NEWS =================================================================== --- php/php-src/branches/PHP_5_3/NEWS 2009-12-06 21:03:55 UTC (rev 291780) +++ php/php-src/branches/PHP_5_3/NEWS 2009-12-06 21:32:58 UTC (rev 291781) @@ -33,7 +33,8 @@ - Fixed bug #50345 (nanosleep not detected properly on some solaris versions). (Jani) - Fixed bug #50340 (php.ini parser does not allow spaces in ini keys). (Jani) -- Fixed bug #50323 (Allow use of ; in values via ;; in PDO DSN). (Ilia) +- Fixed bug #50323 (Allow use of ; in values via ;; in PDO DSN). + (Ilia, Pierrick) - Fixed bug #50285 (xmlrpc does not preserve keys in encoded indexed arrays). (Felipe) - Fixed bug #50282 (xmlrpc_encode_request() changes object into array in Modified: php/php-src/branches/PHP_5_3/ext/pdo/pdo.c =================================================================== --- php/php-src/branches/PHP_5_3/ext/pdo/pdo.c 2009-12-06 21:03:55 UTC (rev 291780) +++ php/php-src/branches/PHP_5_3/ext/pdo/pdo.c 2009-12-06 21:32:58 UTC (rev 291781) @@ -222,6 +222,7 @@ int optstart = 0; int nlen; int n_matches = 0; + int n_semicolumns = 0; i = 0; while (i < data_source_len) { @@ -240,14 +241,21 @@ /* 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 @@ 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; Added: php/php-src/branches/PHP_5_3/ext/pdo_mysql/tests/bug_50323.phpt =================================================================== --- php/php-src/branches/PHP_5_3/ext/pdo_mysql/tests/bug_50323.phpt (rev 0) +++ php/php-src/branches/PHP_5_3/ext/pdo_mysql/tests/bug_50323.phpt 2009-12-06 21:32:58 UTC (rev 291781) @@ -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! + Modified: php/php-src/trunk/ext/pdo/pdo.c =================================================================== --- php/php-src/trunk/ext/pdo/pdo.c 2009-12-06 21:03:55 UTC (rev 291780) +++ php/php-src/trunk/ext/pdo/pdo.c 2009-12-06 21:32:58 UTC (rev 291781) @@ -222,6 +222,7 @@ int optstart = 0; int nlen; int n_matches = 0; + int n_semicolumns = 0; i = 0; while (i < data_source_len) { @@ -240,14 +241,21 @@ /* 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 @@ 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; Added: php/php-src/trunk/ext/pdo_mysql/tests/bug_50323.phpt =================================================================== --- php/php-src/trunk/ext/pdo_mysql/tests/bug_50323.phpt (rev 0) +++ php/php-src/trunk/ext/pdo_mysql/tests/bug_50323.phpt 2009-12-06 21:32:58 UTC (rev 291781) @@ -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! +
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php