10
10
use React \Socket \ConnectionInterface ;
11
11
use React \Socket \Connector ;
12
12
use React \Socket \ConnectorInterface ;
13
- use InvalidArgumentException ;
14
13
15
14
class Factory
16
15
{
@@ -38,18 +37,39 @@ public function __construct(LoopInterface $loop = null, ConnectorInterface $conn
38
37
/**
39
38
* Create Redis client connected to address of given redis instance
40
39
*
41
- * @param string $target Redis server URI to connect to
42
- * @return \React\Promise\PromiseInterface<Client> resolves with Client or rejects with \Exception
40
+ * @param string $uri Redis server URI to connect to
41
+ * @return \React\Promise\PromiseInterface<Client,\Exception> Promise that will
42
+ * be fulfilled with `Client` on success or rejects with `\Exception` on error.
43
43
*/
44
- public function createClient ($ target )
44
+ public function createClient ($ uri )
45
45
{
46
- try {
47
- $ parts = $ this ->parseUrl ($ target );
48
- } catch (InvalidArgumentException $ e ) {
49
- return \React \Promise \reject ($ e );
46
+ // support `redis+unix://` scheme for Unix domain socket (UDS) paths
47
+ if (preg_match ('/^(redis\+unix:\/\/(?:[^:]*:[^@]*@)?)(.+?)?$/ ' , $ uri , $ match )) {
48
+ $ parts = parse_url ($ match [1 ] . 'localhost/ ' . $ match [2 ]);
49
+ } else {
50
+ if (strpos ($ uri , ':// ' ) === false ) {
51
+ $ uri = 'redis:// ' . $ uri ;
52
+ }
53
+
54
+ $ parts = parse_url ($ uri );
55
+ }
56
+
57
+ if ($ parts === false || !isset ($ parts ['scheme ' ], $ parts ['host ' ]) || !in_array ($ parts ['scheme ' ], array ('redis ' , 'rediss ' , 'redis+unix ' ))) {
58
+ return \React \Promise \reject (new \InvalidArgumentException ('Given URL can not be parsed ' ));
50
59
}
51
60
52
- $ connecting = $ this ->connector ->connect ($ parts ['authority ' ]);
61
+ $ args = array ();
62
+ parse_str (isset ($ parts ['query ' ]) ? $ parts ['query ' ] : '' , $ args );
63
+
64
+ $ authority = $ parts ['host ' ] . ': ' . (isset ($ parts ['port ' ]) ? $ parts ['port ' ] : 6379 );
65
+ if ($ parts ['scheme ' ] === 'rediss ' ) {
66
+ $ authority = 'tls:// ' . $ authority ;
67
+ } elseif ($ parts ['scheme ' ] === 'redis+unix ' ) {
68
+ $ authority = 'unix:// ' . substr ($ parts ['path ' ], 1 );
69
+ unset($ parts ['path ' ]);
70
+ }
71
+ $ connecting = $ this ->connector ->connect ($ authority );
72
+
53
73
$ deferred = new Deferred (function ($ _ , $ reject ) use ($ connecting ) {
54
74
// connection cancelled, start with rejecting attempt, then clean up
55
75
$ reject (new \RuntimeException ('Connection to Redis server cancelled ' ));
@@ -72,9 +92,12 @@ public function createClient($target)
72
92
);
73
93
});
74
94
75
- if (isset ($ parts ['auth ' ])) {
76
- $ promise = $ promise ->then (function (StreamingClient $ client ) use ($ parts ) {
77
- return $ client ->auth ($ parts ['auth ' ])->then (
95
+ // use `?password=secret` query or `user:secret@host` password form URL
96
+ $ pass = isset ($ args ['password ' ]) ? $ args ['password ' ] : (isset ($ parts ['pass ' ]) ? rawurldecode ($ parts ['pass ' ]) : null );
97
+ if (isset ($ args ['password ' ]) || isset ($ parts ['pass ' ])) {
98
+ $ pass = isset ($ args ['password ' ]) ? $ args ['password ' ] : rawurldecode ($ parts ['pass ' ]);
99
+ $ promise = $ promise ->then (function (StreamingClient $ client ) use ($ pass ) {
100
+ return $ client ->auth ($ pass )->then (
78
101
function () use ($ client ) {
79
102
return $ client ;
80
103
},
@@ -91,9 +114,11 @@ function ($error) use ($client) {
91
114
});
92
115
}
93
116
94
- if (isset ($ parts ['db ' ])) {
95
- $ promise = $ promise ->then (function (StreamingClient $ client ) use ($ parts ) {
96
- return $ client ->select ($ parts ['db ' ])->then (
117
+ // use `?db=1` query or `/1` path (skip first slash)
118
+ if (isset ($ args ['db ' ]) || (isset ($ parts ['path ' ]) && $ parts ['path ' ] !== '/ ' )) {
119
+ $ db = isset ($ args ['db ' ]) ? $ args ['db ' ] : substr ($ parts ['path ' ], 1 );
120
+ $ promise = $ promise ->then (function (StreamingClient $ client ) use ($ db ) {
121
+ return $ client ->select ($ db )->then (
97
122
function () use ($ client ) {
98
123
return $ client ;
99
124
},
@@ -113,7 +138,7 @@ function ($error) use ($client) {
113
138
$ promise ->then (array ($ deferred , 'resolve ' ), array ($ deferred , 'reject ' ));
114
139
115
140
// use timeout from explicit ?timeout=x parameter or default to PHP's default_socket_timeout (60)
116
- $ timeout = isset ($ parts ['timeout ' ]) ? $ parts ['timeout ' ] : (int ) ini_get ("default_socket_timeout " );
141
+ $ timeout = isset ($ args ['timeout ' ]) ? ( float ) $ args ['timeout ' ] : (int ) ini_get ("default_socket_timeout " );
117
142
if ($ timeout < 0 ) {
118
143
return $ deferred ->promise ();
119
144
}
@@ -138,63 +163,4 @@ public function createLazyClient($target)
138
163
{
139
164
return new LazyClient ($ target , $ this , $ this ->loop );
140
165
}
141
-
142
- /**
143
- * @param string $target
144
- * @return array with keys authority, auth and db
145
- * @throws InvalidArgumentException
146
- */
147
- private function parseUrl ($ target )
148
- {
149
- $ ret = array ();
150
- // support `redis+unix://` scheme for Unix domain socket (UDS) paths
151
- if (preg_match ('/^redis\+unix:\/\/([^:]*:[^@]*@)?(.+?)(\?.*)?$/ ' , $ target , $ match )) {
152
- $ ret ['authority ' ] = 'unix:// ' . $ match [2 ];
153
- $ target = 'redis:// ' . (isset ($ match [1 ]) ? $ match [1 ] : '' ) . 'localhost ' . (isset ($ match [3 ]) ? $ match [3 ] : '' );
154
- }
155
-
156
- if (strpos ($ target , ':// ' ) === false ) {
157
- $ target = 'redis:// ' . $ target ;
158
- }
159
-
160
- $ parts = parse_url ($ target );
161
- if ($ parts === false || !isset ($ parts ['scheme ' ], $ parts ['host ' ]) || !in_array ($ parts ['scheme ' ], array ('redis ' , 'rediss ' ))) {
162
- throw new InvalidArgumentException ('Given URL can not be parsed ' );
163
- }
164
-
165
- if (isset ($ parts ['pass ' ])) {
166
- $ ret ['auth ' ] = rawurldecode ($ parts ['pass ' ]);
167
- }
168
-
169
- if (isset ($ parts ['path ' ]) && $ parts ['path ' ] !== '' ) {
170
- // skip first slash
171
- $ ret ['db ' ] = substr ($ parts ['path ' ], 1 );
172
- }
173
-
174
- if (!isset ($ ret ['authority ' ])) {
175
- $ ret ['authority ' ] =
176
- ($ parts ['scheme ' ] === 'rediss ' ? 'tls:// ' : '' ) .
177
- $ parts ['host ' ] . ': ' .
178
- (isset ($ parts ['port ' ]) ? $ parts ['port ' ] : 6379 );
179
- }
180
-
181
- if (isset ($ parts ['query ' ])) {
182
- $ args = array ();
183
- parse_str ($ parts ['query ' ], $ args );
184
-
185
- if (isset ($ args ['password ' ])) {
186
- $ ret ['auth ' ] = $ args ['password ' ];
187
- }
188
-
189
- if (isset ($ args ['db ' ])) {
190
- $ ret ['db ' ] = $ args ['db ' ];
191
- }
192
-
193
- if (isset ($ args ['timeout ' ])) {
194
- $ ret ['timeout ' ] = (float ) $ args ['timeout ' ];
195
- }
196
- }
197
-
198
- return $ ret ;
199
- }
200
166
}
0 commit comments