Skip to content

Commit 1517d45

Browse files
committed
Merge branch 'master' of github.com:chrisboulton/php-resque
2 parents 3cca631 + 4442e1b commit 1517d45

File tree

7 files changed

+331
-67
lines changed

7 files changed

+331
-67
lines changed

bin/resque

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,15 @@ if(empty($QUEUE)) {
3030
die("Set QUEUE env var containing the list of queues to work.\n");
3131
}
3232

33+
/**
34+
* REDIS_BACKEND can have simple 'host:port' format or use a DSN-style format like this:
35+
* - redis://user:pass@host:port
36+
*
37+
* Note: the 'user' part of the DSN URI is required but is not used.
38+
*/
3339
$REDIS_BACKEND = getenv('REDIS_BACKEND');
40+
41+
// A redis database number
3442
$REDIS_BACKEND_DB = getenv('REDIS_BACKEND_DB');
3543
if(!empty($REDIS_BACKEND)) {
3644
if (empty($REDIS_BACKEND_DB))

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"require": {
2121
"php": ">=5.3.0",
2222
"ext-pcntl": "*",
23-
"colinmollenhour/credis": "1.2.*",
23+
"colinmollenhour/credis": "~1.2",
2424
"psr/log": "1.0.0"
2525
},
2626
"suggest": {

demo/check_status.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77

88
date_default_timezone_set('GMT');
99
Resque::setBackend('127.0.0.1:6379');
10+
// You can also use a DSN-style format:
11+
//Resque::setBackend('redis://user:[email protected]:6379');
12+
//Resque::setBackend('redis://user:[email protected]:3432/2');
1013

1114
$status = new Resque_Job_Status($argv[1]);
1215
if(!$status->isTracking()) {

demo/queue.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
date_default_timezone_set('GMT');
88
Resque::setBackend('127.0.0.1:6379');
99

10+
// You can also use a DSN-style format:
11+
//Resque::setBackend('redis://user:[email protected]:6379');
12+
//Resque::setBackend('redis://user:[email protected]:3432/2');
13+
1014
$args = array(
1115
'time' => time(),
1216
'array' => array(

lib/Resque.php

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class Resque
3232
* Given a host/port combination separated by a colon, set it as
3333
* the redis server that Resque will talk to.
3434
*
35-
* @param mixed $server Host/port combination separated by a colon, or
35+
* @param mixed $server Host/port combination separated by a colon, DSN-formatted URI, or
3636
* a nested array of servers with host/port pairs.
3737
* @param int $database
3838
*/
@@ -54,12 +54,7 @@ public static function redis()
5454
return self::$redis;
5555
}
5656

57-
$server = self::$redisServer;
58-
if (empty($server)) {
59-
$server = 'localhost:6379';
60-
}
61-
62-
self::$redis = new Resque_Redis($server, self::$redisDatabase);
57+
self::$redis = new Resque_Redis(self::$redisServer, self::$redisDatabase);
6358
return self::$redis;
6459
}
6560

lib/Resque/Redis.php

Lines changed: 131 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,26 @@
88
*/
99
class Resque_Redis
1010
{
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:';
1616

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;
1931

2032
/**
2133
* @var array List of all commands in Redis that supply a key as their
@@ -92,47 +104,106 @@ public static function prefix($namespace)
92104
self::$defaultNamespace = $namespace;
93105
}
94106

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)
96113
{
97-
$this->server = $server;
98-
$this->database = $database;
99-
100-
if (is_array($this->server)) {
114+
if (is_array($server)) {
101115
$this->driver = new Credis_Cluster($server);
102116
}
103117
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){
127128
$this->driver->auth($password);
128129
}
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+
}
129136
}
130137

131-
if ($this->database !== null) {
138+
if ($database !== null) {
132139
$this->driver->select($database);
133140
}
134141
}
135142

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+
136207
/**
137208
* Magic method to handle all function requests and prefix key based
138209
* operations with the {self::$defaultNamespace} key prefix.
@@ -141,37 +212,38 @@ public function __construct($server, $database = null)
141212
* @param array $args Array of supplied arguments to the method.
142213
* @return mixed Return value from Resident::call() based on the command.
143214
*/
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+
}
153226
}
154227
try {
155228
return $this->driver->__call($name, $args);
156229
}
157-
catch(CredisException $e) {
230+
catch (CredisException $e) {
158231
return false;
159232
}
160233
}
161234

162-
public static function getPrefix()
163-
{
164-
return self::$defaultNamespace;
165-
}
235+
public static function getPrefix()
236+
{
237+
return self::$defaultNamespace;
238+
}
166239

167-
public static function removePrefix($string)
168-
{
169-
$prefix=self::getPrefix();
240+
public static function removePrefix($string)
241+
{
242+
$prefix=self::getPrefix();
170243

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+
}
176249
}
177-
?>

0 commit comments

Comments
 (0)