Browse Source

Improve URI parsing for connection parameters.

Using PHP's "parse_str()" to parse the query string is slightly more
efficient then our own code especially when the number of fields in
the query string grows, with the additional benefit of supporting
arrays for values when brackets are present in fieldnames.

So after this commit, providing this URI string:

  $string = 'tcp://127.0.0.1?metavars[]=foo&metavars[]=hoge';

Is equivalent to providing the following named array:

  $array = [
    'scheme' => 'tcp',
    'host' => '127.0.0.1',
    'metavars' => ['foo', 'hoge'],
  ];

Other improvements are that parsing does not break when the value of a
field contains one or more "=" and empty or incomplete "key=value"
pairs result in an empty string for "key".
Daniele Alessandri 11 years ago
parent
commit
09cb6677e2

+ 7 - 0
CHANGELOG.md

@@ -19,6 +19,13 @@ v0.8.5 (2013-xx-xx)
   responses are not parsed, which means arguments must follow the signature of
   the command as defined by Redis and complex responses are left untouched.
 
+- URI parsing for connection parameters has been improved and has slightly less
+  overhead when the number of fields in the querystring grows. New features are:
+
+    - Parsing does not break when value of a field contains one or more "=".
+    - Repeated fieldnames using [] produce an array of values.
+    - Empty or incomplete "key=value" pairs result in an empty string for "key".
+
 - Various improvements and fixes to the redis-cluster connection backend:
 
     - __FIX__: the `ASKING` command is sent upon -ASK redirections.

+ 3 - 5
lib/Predis/Connection/ConnectionParameters.php

@@ -119,12 +119,10 @@ class ConnectionParameters implements ConnectionParametersInterface
         }
 
         if (isset($parsed['query'])) {
-            foreach (explode('&', $parsed['query']) as $kv) {
-                @list($k, $v) = explode('=', $kv);
-                $parsed[$k] = $v;
-            }
-
+            parse_str($parsed['query'], $queryarray);
             unset($parsed['query']);
+
+            $parsed = array_merge($parsed, $queryarray);
         }
 
         return $parsed;

+ 52 - 0
tests/Predis/Connection/ConnectionParametersTest.php

@@ -158,6 +158,58 @@ class ParametersTest extends PredisTestCase
         $this->assertSame($expected, ConnectionParameters::parseURI($uri));
     }
 
+    /**
+     * @group disconnected
+     */
+    public function testParsingURIWithIncompletePairInQueryString()
+    {
+        $uri = 'tcp://10.10.10.10?persistent=1&foo=&bar';
+
+        $expected = array(
+            'scheme' => 'tcp',
+            'host' => '10.10.10.10',
+            'persistent' => '1',
+            'foo' => '',
+            'bar' => '',
+        );
+
+        $this->assertSame($expected, ConnectionParameters::parseURI($uri));
+    }
+
+    /**
+     * @group disconnected
+     */
+    public function testParsingURIWithMoreThanOneEqualSignInQueryStringPairValue()
+    {
+        $uri = 'tcp://10.10.10.10?foobar=a=b=c&persistent=1';
+
+        $expected = array(
+            'scheme' => 'tcp',
+            'host' => '10.10.10.10',
+            'foobar' => 'a=b=c',
+            'persistent' => '1',
+        );
+
+        $this->assertSame($expected, ConnectionParameters::parseURI($uri));
+    }
+
+    /**
+     * @group disconnected
+     */
+    public function testParsingURIWhenQueryStringHasBracketsInFieldnames()
+    {
+        $uri = 'tcp://10.10.10.10?persistent=1&metavars[]=foo&metavars[]=hoge';
+
+        $expected = array(
+            'scheme' => 'tcp',
+            'host' => '10.10.10.10',
+            'persistent' => '1',
+            'metavars' => array('foo', 'hoge'),
+        );
+
+        $this->assertSame($expected, ConnectionParameters::parseURI($uri));
+    }
+
     /**
      * @group disconnected
      * @expectedException Predis\ClientException