]> granicus.if.org Git - php/commitdiff
Fixed bug #50323 (Allow use of ; in values via ;; in PDO DSN even in the middle of...
authorPierrick Charron <pierrick@php.net>
Sun, 6 Dec 2009 21:32:58 +0000 (21:32 +0000)
committerPierrick Charron <pierrick@php.net>
Sun, 6 Dec 2009 21:32:58 +0000 (21:32 +0000)
NEWS
ext/pdo/pdo.c
ext/pdo_mysql/tests/bug_50323.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 438d62473d96a4144785140715434901e6684a70..5c6503a3fcec373def37c2f4c4635d6810dffdaf 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -33,7 +33,8 @@ PHP                                                                        NEWS
 - 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 
index e986aaa22553d3c2a619d3a4bb6239fd5b6f2848..0143d93e8a0d07a637007812ac105d99c1d9fa15 100755 (executable)
@@ -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 (file)
index 0000000..02050fa
--- /dev/null
@@ -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!
+