8
8
*/
9
9
class Resque_Redis
10
10
{
11
- /**
12
- * Redis namespace
13
- * @var string
14
- */
15
- private static $ defaultNamespace = 'resque: ' ;
11
+ /**
12
+ * Redis namespace
13
+ * @var string
14
+ */
15
+ private static $ defaultNamespace = 'resque: ' ;
16
16
17
- private $ server ;
18
- private $ database ;
17
+ /**
18
+ * A default host to connect to
19
+ */
20
+ const DEFAULT_HOST = 'localhost ' ;
21
+
22
+ /**
23
+ * The default Redis port
24
+ */
25
+ const DEFAULT_PORT = 6379 ;
26
+
27
+ /**
28
+ * The default Redis Database number
29
+ */
30
+ const DEFAULT_DATABASE = 0 ;
19
31
20
32
/**
21
33
* @var array List of all commands in Redis that supply a key as their
@@ -92,47 +104,106 @@ public static function prefix($namespace)
92
104
self ::$ defaultNamespace = $ namespace ;
93
105
}
94
106
95
- public function __construct ($ server , $ database = null )
107
+ /**
108
+ * @param string|array $server A DSN or array
109
+ * @param int $database A database number to select. However, if we find a valid database number in the DSN the
110
+ * DSN-supplied value will be used instead and this parameter is ignored.
111
+ */
112
+ public function __construct ($ server , $ database = null )
96
113
{
97
- $ this ->server = $ server ;
98
- $ this ->database = $ database ;
99
-
100
- if (is_array ($ this ->server )) {
114
+ if (is_array ($ server )) {
101
115
$ this ->driver = new Credis_Cluster ($ server );
102
116
}
103
117
else {
104
- $ port = null ;
105
- $ password = null ;
106
- $ host = $ server ;
107
-
108
- // If not a UNIX socket path or tcp:// formatted connections string
109
- // assume host:port combination.
110
- if (strpos ($ server , '/ ' ) === false ) {
111
- $ parts = explode (': ' , $ server );
112
- if (isset ($ parts [1 ])) {
113
- $ port = $ parts [1 ];
114
- }
115
- $ host = $ parts [0 ];
116
- }else if (strpos ($ server , 'redis:// ' ) !== false ){
117
- // Redis format is:
118
- // redis://[user]:[password]@[host]:[port]
119
- list ($ userpwd ,$ hostport ) = explode ('@ ' , $ server );
120
- $ userpwd = substr ($ userpwd , strpos ($ userpwd , 'redis:// ' )+8 );
121
- list ($ host , $ port ) = explode (': ' , $ hostport );
122
- list ($ user , $ password ) = explode (': ' , $ userpwd );
123
- }
124
-
125
- $ this ->driver = new Credis_Client ($ host , $ port );
126
- if (isset ($ password )){
118
+
119
+ list ($ host , $ port , $ dsnDatabase , $ user , $ password , $ options ) = self ::parseDsn ($ server );
120
+ // $user is not used, only $password
121
+
122
+ // Look for known Credis_Client options
123
+ $ timeout = isset ($ options ['timeout ' ]) ? intval ($ options ['timeout ' ]) : null ;
124
+ $ persistent = isset ($ options ['persistent ' ]) ? $ options ['persistent ' ] : '' ;
125
+
126
+ $ this ->driver = new Credis_Client ($ host , $ port , $ timeout , $ persistent );
127
+ if ($ password ){
127
128
$ this ->driver ->auth ($ password );
128
129
}
130
+
131
+ // If we have found a database in our DSN, use it instead of the `$database`
132
+ // value passed into the constructor.
133
+ if ($ dsnDatabase !== false ) {
134
+ $ database = $ dsnDatabase ;
135
+ }
129
136
}
130
137
131
- if ($ this -> database !== null ) {
138
+ if ($ database !== null ) {
132
139
$ this ->driver ->select ($ database );
133
140
}
134
141
}
135
142
143
+ /**
144
+ * Parse a DSN string, which can have one of the following formats:
145
+ *
146
+ * - host:port
147
+ * - redis://user:pass@host:port/db?option1=val1&option2=val2
148
+ * - tcp://user:pass@host:port/db?option1=val1&option2=val2
149
+ *
150
+ * Note: the 'user' part of the DSN is not used.
151
+ *
152
+ * @param string $dsn A DSN string
153
+ * @return array An array of DSN compotnents, with 'false' values for any unknown components. e.g.
154
+ * [host, port, db, user, pass, options]
155
+ */
156
+ public static function parseDsn ($ dsn )
157
+ {
158
+ if ($ dsn == '' ) {
159
+ // Use a sensible default for an empty DNS string
160
+ $ dsn = 'redis:// ' . self ::DEFAULT_HOST ;
161
+ }
162
+ $ parts = parse_url ($ dsn );
163
+
164
+ // Check the URI scheme
165
+ $ validSchemes = array ('redis ' , 'tcp ' );
166
+ if (isset ($ parts ['scheme ' ]) && ! in_array ($ parts ['scheme ' ], $ validSchemes )) {
167
+ throw new \InvalidArgumentException ("Invalid DSN. Supported schemes are " . implode (', ' , $ validSchemes ));
168
+ }
169
+
170
+ // Allow simple 'hostname' format, which `parse_url` treats as a path, not host.
171
+ if ( ! isset ($ parts ['host ' ]) && isset ($ parts ['path ' ])) {
172
+ $ parts ['host ' ] = $ parts ['path ' ];
173
+ unset($ parts ['path ' ]);
174
+ }
175
+
176
+ // Extract the port number as an integer
177
+ $ port = isset ($ parts ['port ' ]) ? intval ($ parts ['port ' ]) : self ::DEFAULT_PORT ;
178
+
179
+ // Get the database from the 'path' part of the URI
180
+ $ database = false ;
181
+ if (isset ($ parts ['path ' ])) {
182
+ // Strip non-digit chars from path
183
+ $ database = intval (preg_replace ('/[^0-9]/ ' , '' , $ parts ['path ' ]));
184
+ }
185
+
186
+ // Extract any 'user' and 'pass' values
187
+ $ user = isset ($ parts ['user ' ]) ? $ parts ['user ' ] : false ;
188
+ $ pass = isset ($ parts ['pass ' ]) ? $ parts ['pass ' ] : false ;
189
+
190
+ // Convert the query string into an associative array
191
+ $ options = array ();
192
+ if (isset ($ parts ['query ' ])) {
193
+ // Parse the query string into an array
194
+ parse_str ($ parts ['query ' ], $ options );
195
+ }
196
+
197
+ return array (
198
+ $ parts ['host ' ],
199
+ $ port ,
200
+ $ database ,
201
+ $ user ,
202
+ $ pass ,
203
+ $ options ,
204
+ );
205
+ }
206
+
136
207
/**
137
208
* Magic method to handle all function requests and prefix key based
138
209
* operations with the {self::$defaultNamespace} key prefix.
@@ -141,37 +212,38 @@ public function __construct($server, $database = null)
141
212
* @param array $args Array of supplied arguments to the method.
142
213
* @return mixed Return value from Resident::call() based on the command.
143
214
*/
144
- public function __call ($ name , $ args ) {
145
- if (in_array ($ name , $ this ->keyCommands )) {
146
- if (is_array ($ args [0 ])) {
147
- foreach ($ args [0 ] AS $ i => $ v ) {
148
- $ args [0 ][$ i ] = self ::$ defaultNamespace . $ v ;
149
- }
150
- } else {
151
- $ args [0 ] = self ::$ defaultNamespace . $ args [0 ];
152
- }
215
+ public function __call ($ name , $ args )
216
+ {
217
+ if (in_array ($ name , $ this ->keyCommands )) {
218
+ if (is_array ($ args [0 ])) {
219
+ foreach ($ args [0 ] AS $ i => $ v ) {
220
+ $ args [0 ][$ i ] = self ::$ defaultNamespace . $ v ;
221
+ }
222
+ }
223
+ else {
224
+ $ args [0 ] = self ::$ defaultNamespace . $ args [0 ];
225
+ }
153
226
}
154
227
try {
155
228
return $ this ->driver ->__call ($ name , $ args );
156
229
}
157
- catch (CredisException $ e ) {
230
+ catch (CredisException $ e ) {
158
231
return false ;
159
232
}
160
233
}
161
234
162
- public static function getPrefix ()
163
- {
164
- return self ::$ defaultNamespace ;
165
- }
235
+ public static function getPrefix ()
236
+ {
237
+ return self ::$ defaultNamespace ;
238
+ }
166
239
167
- public static function removePrefix ($ string )
168
- {
169
- $ prefix =self ::getPrefix ();
240
+ public static function removePrefix ($ string )
241
+ {
242
+ $ prefix =self ::getPrefix ();
170
243
171
- if (substr ($ string , 0 , strlen ($ prefix )) == $ prefix ) {
172
- $ string = substr ($ string , strlen ($ prefix ), strlen ($ string ) );
173
- }
174
- return $ string ;
175
- }
244
+ if (substr ($ string , 0 , strlen ($ prefix )) == $ prefix ) {
245
+ $ string = substr ($ string , strlen ($ prefix ), strlen ($ string ) );
246
+ }
247
+ return $ string ;
248
+ }
176
249
}
177
- ?>
0 commit comments