Version Notes
1.9.2.0
Download this release
Release Info
Developer | Magento Core Team |
Extension | Lib_Credis |
Version | 1.9.2.0 |
Comparing to | |
See all releases |
Code changes from version 1.8.0.0 to 1.9.2.0
- lib/Credis/Client.php +412 -55
- package.xml +5 -5
lib/Credis/Client.php
CHANGED
@@ -25,7 +25,20 @@ if( ! defined('CRLF')) define('CRLF', sprintf('%s%s', chr(13), chr(10)));
|
|
25 |
/**
|
26 |
* Credis-specific errors, wraps native Redis errors
|
27 |
*/
|
28 |
-
class CredisException extends Exception
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
}
|
30 |
|
31 |
/**
|
@@ -126,12 +139,13 @@ class CredisException extends Exception {
|
|
126 |
* TODO
|
127 |
*
|
128 |
* Pub/Sub
|
129 |
-
*
|
|
|
130 |
*
|
131 |
* Scripting:
|
132 |
* @method string|int script(string $command, string $arg1 = null)
|
133 |
-
* @method string|int|array|bool eval(string $script,
|
134 |
-
* @method string|int|array|bool evalSha(string $
|
135 |
*/
|
136 |
class Credis_Client {
|
137 |
|
@@ -155,7 +169,7 @@ class Credis_Client {
|
|
155 |
* @var string
|
156 |
*/
|
157 |
protected $host;
|
158 |
-
|
159 |
/**
|
160 |
* Port on which the Redis server is running
|
161 |
* @var integer
|
@@ -244,7 +258,23 @@ class Credis_Client {
|
|
244 |
* Aliases for backwards compatibility with phpredis
|
245 |
* @var array
|
246 |
*/
|
247 |
-
protected $
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
248 |
|
249 |
/**
|
250 |
* Creates a Redisent connection to the Redis server on host {@link $host} and port {@link $port}.
|
@@ -254,14 +284,19 @@ class Credis_Client {
|
|
254 |
* @param integer $port The port number of the Redis server
|
255 |
* @param float $timeout Timeout period in seconds
|
256 |
* @param string $persistent Flag to establish persistent connection
|
|
|
|
|
257 |
*/
|
258 |
-
public function __construct($host = '127.0.0.1', $port = 6379, $timeout = null, $persistent = '')
|
259 |
{
|
260 |
$this->host = (string) $host;
|
261 |
$this->port = (int) $port;
|
262 |
$this->timeout = $timeout;
|
263 |
$this->persistent = (string) $persistent;
|
264 |
$this->standalone = ! extension_loaded('redis');
|
|
|
|
|
|
|
265 |
}
|
266 |
|
267 |
public function __destruct()
|
@@ -270,7 +305,47 @@ class Credis_Client {
|
|
270 |
$this->close();
|
271 |
}
|
272 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
273 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
274 |
/**
|
275 |
* @throws CredisException
|
276 |
* @return Credis_Client
|
@@ -303,24 +378,16 @@ class Credis_Client {
|
|
303 |
$this->closeOnDestruct = $flag;
|
304 |
return $this;
|
305 |
}
|
306 |
-
|
307 |
-
/**
|
308 |
-
* @throws CredisException
|
309 |
-
* @return Credis_Client
|
310 |
-
*/
|
311 |
-
public function connect()
|
312 |
{
|
313 |
-
if ($this->connected) {
|
314 |
-
return $this;
|
315 |
-
}
|
316 |
if (preg_match('#^(tcp|unix)://(.*)$#', $this->host, $matches)) {
|
317 |
if($matches[1] == 'tcp') {
|
318 |
-
if ( ! preg_match('#^(
|
319 |
-
throw new CredisException('Invalid host format; expected tcp://host[:port][/
|
320 |
}
|
321 |
$this->host = $matches[1];
|
322 |
-
$this->port = (int) (isset($matches[
|
323 |
-
$this->persistent = isset($matches[
|
324 |
} else {
|
325 |
$this->host = $matches[2];
|
326 |
$this->port = NULL;
|
@@ -332,6 +399,16 @@ class Credis_Client {
|
|
332 |
if ($this->port !== NULL && substr($this->host,0,1) == '/') {
|
333 |
$this->port = NULL;
|
334 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
335 |
if ($this->standalone) {
|
336 |
$flags = STREAM_CLIENT_CONNECT;
|
337 |
$remote_socket = $this->port === NULL
|
@@ -363,7 +440,7 @@ class Credis_Client {
|
|
363 |
}
|
364 |
$failures = $this->connectFailures;
|
365 |
$this->connectFailures = 0;
|
366 |
-
throw new CredisException("Connection to Redis failed after $failures failures.");
|
367 |
}
|
368 |
|
369 |
$this->connectFailures = 0;
|
@@ -374,28 +451,44 @@ class Credis_Client {
|
|
374 |
$this->setReadTimeout($this->readTimeout);
|
375 |
}
|
376 |
|
|
|
|
|
|
|
|
|
|
|
|
|
377 |
return $this;
|
378 |
}
|
379 |
-
|
380 |
/**
|
381 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
382 |
*
|
383 |
-
* @param $timeout
|
384 |
* @throws CredisException
|
385 |
* @return Credis_Client
|
386 |
*/
|
387 |
public function setReadTimeout($timeout)
|
388 |
{
|
389 |
-
if ($timeout <
|
390 |
-
throw new CredisException('
|
391 |
}
|
392 |
$this->readTimeout = $timeout;
|
393 |
if ($this->connected) {
|
394 |
if ($this->standalone) {
|
|
|
|
|
395 |
stream_set_timeout($this->redis, (int) floor($timeout), ($timeout - floor($timeout)) * 1000000);
|
396 |
} else if (defined('Redis::OPT_READ_TIMEOUT')) {
|
397 |
-
//
|
398 |
-
//
|
|
|
399 |
$this->redis->setOption(Redis::OPT_READ_TIMEOUT, $timeout);
|
400 |
}
|
401 |
}
|
@@ -419,14 +512,81 @@ class Credis_Client {
|
|
419 |
return $result;
|
420 |
}
|
421 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
422 |
/**
|
423 |
* @param string $password
|
424 |
* @return bool
|
425 |
*/
|
426 |
public function auth($password)
|
427 |
{
|
|
|
428 |
$this->authPassword = $password;
|
429 |
-
$response = $this->__call('auth', array($this->authPassword));
|
430 |
return $response;
|
431 |
}
|
432 |
|
@@ -436,10 +596,128 @@ class Credis_Client {
|
|
436 |
*/
|
437 |
public function select($index)
|
438 |
{
|
|
|
439 |
$this->selectedDb = (int) $index;
|
440 |
-
$response = $this->__call('select', array($this->selectedDb));
|
441 |
return $response;
|
442 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
443 |
|
444 |
public function __call($name, $args)
|
445 |
{
|
@@ -451,6 +729,15 @@ class Credis_Client {
|
|
451 |
// Send request via native PHP
|
452 |
if($this->standalone)
|
453 |
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
454 |
// Flatten arguments
|
455 |
$argsFlat = NULL;
|
456 |
foreach($args as $index => $arg) {
|
@@ -459,12 +746,12 @@ class Credis_Client {
|
|
459 |
$argsFlat = array_slice($args, 0, $index);
|
460 |
}
|
461 |
if($name == 'mset' || $name == 'msetnx' || $name == 'hmset') {
|
462 |
-
|
463 |
-
|
464 |
-
|
465 |
-
|
466 |
} else {
|
467 |
-
|
468 |
}
|
469 |
} else if($argsFlat !== NULL) {
|
470 |
$argsFlat[] = $arg;
|
@@ -484,7 +771,7 @@ class Credis_Client {
|
|
484 |
else if($name == 'exec') {
|
485 |
if($this->isMulti) {
|
486 |
$this->commandNames[] = $name;
|
487 |
-
$this->commands .= self::_prepare_command(array($name));
|
488 |
}
|
489 |
|
490 |
// Write request
|
@@ -510,7 +797,7 @@ class Credis_Client {
|
|
510 |
if($name == 'multi') {
|
511 |
$this->isMulti = TRUE;
|
512 |
}
|
513 |
-
array_unshift($args, $name);
|
514 |
$this->commandNames[] = $name;
|
515 |
$this->commands .= self::_prepare_command($args);
|
516 |
return $this;
|
@@ -532,7 +819,7 @@ class Credis_Client {
|
|
532 |
}
|
533 |
|
534 |
// Non-pipeline mode
|
535 |
-
array_unshift($args, $name);
|
536 |
$command = self::_prepare_command($args);
|
537 |
$this->write_command($command);
|
538 |
$response = $this->read_reply($name);
|
@@ -576,6 +863,27 @@ class Credis_Client {
|
|
576 |
case 'lrem':
|
577 |
$args = array($args[0], $args[2], $args[1]);
|
578 |
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
579 |
default:
|
580 |
// Flatten arguments
|
581 |
$argsFlat = NULL;
|
@@ -614,8 +922,8 @@ class Credis_Client {
|
|
614 |
}
|
615 |
|
616 |
// Use aliases to be compatible with phpredis wrapper
|
617 |
-
if(isset($this->
|
618 |
-
$name = $this->
|
619 |
}
|
620 |
|
621 |
// Multi and pipeline return self for chaining
|
@@ -624,11 +932,28 @@ class Credis_Client {
|
|
624 |
return $this;
|
625 |
}
|
626 |
|
627 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
628 |
}
|
629 |
-
|
630 |
catch(RedisException $e) {
|
631 |
-
|
|
|
|
|
|
|
|
|
|
|
632 |
}
|
633 |
|
634 |
#echo "> $name : ".substr(print_r($response, TRUE),0,100)."\n";
|
@@ -639,17 +964,38 @@ class Credis_Client {
|
|
639 |
case 'hmget':
|
640 |
$response = array_values($response);
|
641 |
break;
|
|
|
642 |
case 'type':
|
643 |
$typeMap = array(
|
644 |
-
|
645 |
-
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
);
|
651 |
$response = $typeMap[$response];
|
652 |
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
653 |
}
|
654 |
}
|
655 |
|
@@ -681,6 +1027,7 @@ class Credis_Client {
|
|
681 |
for ($written = 0; $written < $commandLen; $written += $fwrite) {
|
682 |
$fwrite = fwrite($this->redis, substr($command, $written));
|
683 |
if ($fwrite === FALSE || $fwrite == 0 ) {
|
|
|
684 |
throw new CredisException('Failed to write entire command to stream');
|
685 |
}
|
686 |
}
|
@@ -690,7 +1037,13 @@ class Credis_Client {
|
|
690 |
{
|
691 |
$reply = fgets($this->redis);
|
692 |
if($reply === FALSE) {
|
693 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
694 |
}
|
695 |
$reply = rtrim($reply, CRLF);
|
696 |
#echo "> $name: $reply\n";
|
@@ -700,15 +1053,17 @@ class Credis_Client {
|
|
700 |
case '-':
|
701 |
if($this->isMulti || $this->usePipeline) {
|
702 |
$response = FALSE;
|
|
|
|
|
703 |
} else {
|
704 |
-
throw new CredisException(substr($reply,
|
705 |
}
|
706 |
break;
|
707 |
/* Inline reply */
|
708 |
case '+':
|
709 |
$response = substr($reply, 1);
|
710 |
if($response == 'OK' || $response == 'QUEUED') {
|
711 |
-
|
712 |
}
|
713 |
break;
|
714 |
/* Bulk reply */
|
@@ -716,8 +1071,10 @@ class Credis_Client {
|
|
716 |
if ($reply == '$-1') return FALSE;
|
717 |
$size = (int) substr($reply, 1);
|
718 |
$response = stream_get_contents($this->redis, $size + 2);
|
719 |
-
if( ! $response)
|
|
|
720 |
throw new CredisException('Error reading reply.');
|
|
|
721 |
$response = substr($response, 0, $size);
|
722 |
break;
|
723 |
/* Multi-bulk reply */
|
@@ -727,7 +1084,7 @@ class Credis_Client {
|
|
727 |
|
728 |
$response = array();
|
729 |
for ($i = 0; $i < $count; $i++) {
|
730 |
-
|
731 |
}
|
732 |
break;
|
733 |
/* Integer reply */
|
@@ -758,7 +1115,7 @@ class Credis_Client {
|
|
758 |
$response = array();
|
759 |
foreach($lines as $line) {
|
760 |
if ( ! $line || substr($line, 0, 1) == '#') {
|
761 |
-
|
762 |
}
|
763 |
list($key, $value) = explode(':', $line, 2);
|
764 |
$response[$key] = $value;
|
25 |
/**
|
26 |
* Credis-specific errors, wraps native Redis errors
|
27 |
*/
|
28 |
+
class CredisException extends Exception
|
29 |
+
{
|
30 |
+
|
31 |
+
const CODE_TIMED_OUT = 1;
|
32 |
+
const CODE_DISCONNECTED = 2;
|
33 |
+
|
34 |
+
public function __construct($message, $code = 0, $exception = NULL)
|
35 |
+
{
|
36 |
+
if ($exception && get_class($exception) == 'RedisException' && $message == 'read error on connection') {
|
37 |
+
$code = CredisException::CODE_DISCONNECTED;
|
38 |
+
}
|
39 |
+
parent::__construct($message, $code, $exception);
|
40 |
+
}
|
41 |
+
|
42 |
}
|
43 |
|
44 |
/**
|
139 |
* TODO
|
140 |
*
|
141 |
* Pub/Sub
|
142 |
+
* @method int publish(string $channel, string $message)
|
143 |
+
* @method int|array pubsub(string $subCommand, $arg = NULL)
|
144 |
*
|
145 |
* Scripting:
|
146 |
* @method string|int script(string $command, string $arg1 = null)
|
147 |
+
* @method string|int|array|bool eval(string $script, array $keys = NULL, array $args = NULL)
|
148 |
+
* @method string|int|array|bool evalSha(string $script, array $keys = NULL, array $args = NULL)
|
149 |
*/
|
150 |
class Credis_Client {
|
151 |
|
169 |
* @var string
|
170 |
*/
|
171 |
protected $host;
|
172 |
+
|
173 |
/**
|
174 |
* Port on which the Redis server is running
|
175 |
* @var integer
|
258 |
* Aliases for backwards compatibility with phpredis
|
259 |
* @var array
|
260 |
*/
|
261 |
+
protected $wrapperMethods = array('delete' => 'del', 'getkeys' => 'keys', 'sremove' => 'srem');
|
262 |
+
|
263 |
+
/**
|
264 |
+
* @var array
|
265 |
+
*/
|
266 |
+
protected $renamedCommands;
|
267 |
+
|
268 |
+
/**
|
269 |
+
* @var int
|
270 |
+
*/
|
271 |
+
protected $requests = 0;
|
272 |
+
|
273 |
+
/**
|
274 |
+
* @var bool
|
275 |
+
*/
|
276 |
+
protected $subscribed = false;
|
277 |
+
|
278 |
|
279 |
/**
|
280 |
* Creates a Redisent connection to the Redis server on host {@link $host} and port {@link $port}.
|
284 |
* @param integer $port The port number of the Redis server
|
285 |
* @param float $timeout Timeout period in seconds
|
286 |
* @param string $persistent Flag to establish persistent connection
|
287 |
+
* @param int $db The selected datbase of the Redis server
|
288 |
+
* @param string $password The authentication password of the Redis server
|
289 |
*/
|
290 |
+
public function __construct($host = '127.0.0.1', $port = 6379, $timeout = null, $persistent = '', $db = 0, $password = null)
|
291 |
{
|
292 |
$this->host = (string) $host;
|
293 |
$this->port = (int) $port;
|
294 |
$this->timeout = $timeout;
|
295 |
$this->persistent = (string) $persistent;
|
296 |
$this->standalone = ! extension_loaded('redis');
|
297 |
+
$this->authPassword = $password;
|
298 |
+
$this->selectedDb = (int)$db;
|
299 |
+
$this->convertHost();
|
300 |
}
|
301 |
|
302 |
public function __destruct()
|
305 |
$this->close();
|
306 |
}
|
307 |
}
|
308 |
+
|
309 |
+
/**
|
310 |
+
* @return bool
|
311 |
+
*/
|
312 |
+
public function isSubscribed()
|
313 |
+
{
|
314 |
+
return $this->subscribed;
|
315 |
+
}
|
316 |
+
|
317 |
+
/**
|
318 |
+
* Return the host of the Redis instance
|
319 |
+
* @return string
|
320 |
+
*/
|
321 |
+
public function getHost()
|
322 |
+
{
|
323 |
+
return $this->host;
|
324 |
+
}
|
325 |
+
/**
|
326 |
+
* Return the port of the Redis instance
|
327 |
+
* @return int
|
328 |
+
*/
|
329 |
+
public function getPort()
|
330 |
+
{
|
331 |
+
return $this->port;
|
332 |
+
}
|
333 |
|
334 |
+
/**
|
335 |
+
* Return the selected database
|
336 |
+
* @return int
|
337 |
+
*/
|
338 |
+
public function getSelectedDb()
|
339 |
+
{
|
340 |
+
return $this->selectedDb;
|
341 |
+
}
|
342 |
+
/**
|
343 |
+
* @return string
|
344 |
+
*/
|
345 |
+
public function getPersistence()
|
346 |
+
{
|
347 |
+
return $this->persistent;
|
348 |
+
}
|
349 |
/**
|
350 |
* @throws CredisException
|
351 |
* @return Credis_Client
|
378 |
$this->closeOnDestruct = $flag;
|
379 |
return $this;
|
380 |
}
|
381 |
+
protected function convertHost()
|
|
|
|
|
|
|
|
|
|
|
382 |
{
|
|
|
|
|
|
|
383 |
if (preg_match('#^(tcp|unix)://(.*)$#', $this->host, $matches)) {
|
384 |
if($matches[1] == 'tcp') {
|
385 |
+
if ( ! preg_match('#^([^:]+)(:([0-9]+))?(/(.+))?$#', $matches[2], $matches)) {
|
386 |
+
throw new CredisException('Invalid host format; expected tcp://host[:port][/persistence_identifier]');
|
387 |
}
|
388 |
$this->host = $matches[1];
|
389 |
+
$this->port = (int) (isset($matches[3]) ? $matches[3] : 6379);
|
390 |
+
$this->persistent = isset($matches[5]) ? $matches[5] : '';
|
391 |
} else {
|
392 |
$this->host = $matches[2];
|
393 |
$this->port = NULL;
|
399 |
if ($this->port !== NULL && substr($this->host,0,1) == '/') {
|
400 |
$this->port = NULL;
|
401 |
}
|
402 |
+
}
|
403 |
+
/**
|
404 |
+
* @throws CredisException
|
405 |
+
* @return Credis_Client
|
406 |
+
*/
|
407 |
+
public function connect()
|
408 |
+
{
|
409 |
+
if ($this->connected) {
|
410 |
+
return $this;
|
411 |
+
}
|
412 |
if ($this->standalone) {
|
413 |
$flags = STREAM_CLIENT_CONNECT;
|
414 |
$remote_socket = $this->port === NULL
|
440 |
}
|
441 |
$failures = $this->connectFailures;
|
442 |
$this->connectFailures = 0;
|
443 |
+
throw new CredisException("Connection to Redis failed after $failures failures." . (isset($errno) && isset($errstr) ? "Last Error : ({$errno}) {$errstr}" : ""));
|
444 |
}
|
445 |
|
446 |
$this->connectFailures = 0;
|
451 |
$this->setReadTimeout($this->readTimeout);
|
452 |
}
|
453 |
|
454 |
+
if($this->authPassword !== null) {
|
455 |
+
$this->auth($this->authPassword);
|
456 |
+
}
|
457 |
+
if($this->selectedDb !== 0) {
|
458 |
+
$this->select($this->selectedDb);
|
459 |
+
}
|
460 |
return $this;
|
461 |
}
|
|
|
462 |
/**
|
463 |
+
* @return bool
|
464 |
+
*/
|
465 |
+
public function isConnected()
|
466 |
+
{
|
467 |
+
return $this->connected;
|
468 |
+
}
|
469 |
+
/**
|
470 |
+
* Set the read timeout for the connection. Use 0 to disable timeouts entirely (or use a very long timeout
|
471 |
+
* if not supported).
|
472 |
*
|
473 |
+
* @param int $timeout 0 (or -1) for no timeout, otherwise number of seconds
|
474 |
* @throws CredisException
|
475 |
* @return Credis_Client
|
476 |
*/
|
477 |
public function setReadTimeout($timeout)
|
478 |
{
|
479 |
+
if ($timeout < -1) {
|
480 |
+
throw new CredisException('Timeout values less than -1 are not accepted.');
|
481 |
}
|
482 |
$this->readTimeout = $timeout;
|
483 |
if ($this->connected) {
|
484 |
if ($this->standalone) {
|
485 |
+
$timeout = $timeout <= 0 ? 315360000 : $timeout; // Ten-year timeout
|
486 |
+
stream_set_blocking($this->redis, TRUE);
|
487 |
stream_set_timeout($this->redis, (int) floor($timeout), ($timeout - floor($timeout)) * 1000000);
|
488 |
} else if (defined('Redis::OPT_READ_TIMEOUT')) {
|
489 |
+
// supported in phpredis 2.2.3
|
490 |
+
// a timeout value of -1 means reads will not timeout
|
491 |
+
$timeout = $timeout == 0 ? -1 : $timeout;
|
492 |
$this->redis->setOption(Redis::OPT_READ_TIMEOUT, $timeout);
|
493 |
}
|
494 |
}
|
512 |
return $result;
|
513 |
}
|
514 |
|
515 |
+
/**
|
516 |
+
* Enabled command renaming and provide mapping method. Supported methods are:
|
517 |
+
*
|
518 |
+
* 1. renameCommand('foo') // Salted md5 hash for all commands -> md5('foo'.$command)
|
519 |
+
* 2. renameCommand(function($command){ return 'my'.$command; }); // Callable
|
520 |
+
* 3. renameCommand('get', 'foo') // Single command -> alias
|
521 |
+
* 4. renameCommand(['get' => 'foo', 'set' => 'bar']) // Full map of [command -> alias]
|
522 |
+
*
|
523 |
+
* @param string|callable|array $command
|
524 |
+
* @param string|null $alias
|
525 |
+
* @return $this
|
526 |
+
*/
|
527 |
+
public function renameCommand($command, $alias = NULL)
|
528 |
+
{
|
529 |
+
if ( ! $this->standalone) {
|
530 |
+
$this->forceStandalone();
|
531 |
+
}
|
532 |
+
if ($alias === NULL) {
|
533 |
+
$this->renamedCommands = $command;
|
534 |
+
} else {
|
535 |
+
if ( ! $this->renamedCommands) {
|
536 |
+
$this->renamedCommands = array();
|
537 |
+
}
|
538 |
+
$this->renamedCommands[$command] = $alias;
|
539 |
+
}
|
540 |
+
return $this;
|
541 |
+
}
|
542 |
+
|
543 |
+
/**
|
544 |
+
* @param $command
|
545 |
+
*/
|
546 |
+
public function getRenamedCommand($command)
|
547 |
+
{
|
548 |
+
static $map;
|
549 |
+
|
550 |
+
// Command renaming not enabled
|
551 |
+
if ($this->renamedCommands === NULL) {
|
552 |
+
return $command;
|
553 |
+
}
|
554 |
+
|
555 |
+
// Initialize command map
|
556 |
+
if ($map === NULL) {
|
557 |
+
if (is_array($this->renamedCommands)) {
|
558 |
+
$map = $this->renamedCommands;
|
559 |
+
} else {
|
560 |
+
$map = array();
|
561 |
+
}
|
562 |
+
}
|
563 |
+
|
564 |
+
// Generate and return cached result
|
565 |
+
if ( ! isset($map[$command])) {
|
566 |
+
// String means all commands are hashed with salted md5
|
567 |
+
if (is_string($this->renamedCommands)) {
|
568 |
+
$map[$command] = md5($this->renamedCommands.$command);
|
569 |
+
}
|
570 |
+
// Would already be set in $map if it was intended to be renamed
|
571 |
+
else if (is_array($this->renamedCommands)) {
|
572 |
+
return $command;
|
573 |
+
}
|
574 |
+
// User-supplied function
|
575 |
+
else if (is_callable($this->renamedCommands)) {
|
576 |
+
$map[$command] = call_user_func($this->renamedCommands, $command);
|
577 |
+
}
|
578 |
+
}
|
579 |
+
return $map[$command];
|
580 |
+
}
|
581 |
+
|
582 |
/**
|
583 |
* @param string $password
|
584 |
* @return bool
|
585 |
*/
|
586 |
public function auth($password)
|
587 |
{
|
588 |
+
$response = $this->__call('auth', array($password));
|
589 |
$this->authPassword = $password;
|
|
|
590 |
return $response;
|
591 |
}
|
592 |
|
596 |
*/
|
597 |
public function select($index)
|
598 |
{
|
599 |
+
$response = $this->__call('select', array($index));
|
600 |
$this->selectedDb = (int) $index;
|
|
|
601 |
return $response;
|
602 |
}
|
603 |
+
|
604 |
+
/**
|
605 |
+
* @param string|array $pattern
|
606 |
+
* @return array
|
607 |
+
*/
|
608 |
+
public function pUnsubscribe()
|
609 |
+
{
|
610 |
+
list($command, $channel, $subscribedChannels) = $this->__call('punsubscribe', func_get_args());
|
611 |
+
$this->subscribed = $subscribedChannels > 0;
|
612 |
+
return array($command, $channel, $subscribedChannels);
|
613 |
+
}
|
614 |
+
|
615 |
+
/**
|
616 |
+
* @param string|array $patterns
|
617 |
+
* @param $callback
|
618 |
+
* @return $this|array|bool|Credis_Client|mixed|null|string
|
619 |
+
* @throws CredisException
|
620 |
+
*/
|
621 |
+
public function pSubscribe($patterns, $callback)
|
622 |
+
{
|
623 |
+
if ( ! $this->standalone) {
|
624 |
+
return $this->__call('pSubscribe', array((array)$patterns, $callback));
|
625 |
+
}
|
626 |
+
|
627 |
+
// Standalone mode: use infinite loop to subscribe until timeout
|
628 |
+
$patternCount = is_array($patterns) ? count($patterns) : 1;
|
629 |
+
while ($patternCount--) {
|
630 |
+
if (isset($status)) {
|
631 |
+
list($command, $pattern, $status) = $this->read_reply();
|
632 |
+
} else {
|
633 |
+
list($command, $pattern, $status) = $this->__call('psubscribe', array($patterns));
|
634 |
+
}
|
635 |
+
$this->subscribed = $status > 0;
|
636 |
+
if ( ! $status) {
|
637 |
+
throw new CredisException('Invalid pSubscribe response.');
|
638 |
+
}
|
639 |
+
}
|
640 |
+
try {
|
641 |
+
while ($this->subscribed) {
|
642 |
+
list($type, $pattern, $channel, $message) = $this->read_reply();
|
643 |
+
if ($type != 'pmessage') {
|
644 |
+
throw new CredisException('Received non-pmessage reply.');
|
645 |
+
}
|
646 |
+
$callback($this, $pattern, $channel, $message);
|
647 |
+
}
|
648 |
+
} catch (CredisException $e) {
|
649 |
+
if ($e->getCode() == CredisException::CODE_TIMED_OUT) {
|
650 |
+
try {
|
651 |
+
list($command, $pattern, $status) = $this->pUnsubscribe($patterns);
|
652 |
+
while ($status !== 0) {
|
653 |
+
list($command, $pattern, $status) = $this->read_reply();
|
654 |
+
}
|
655 |
+
} catch (CredisException $e2) {
|
656 |
+
throw $e2;
|
657 |
+
}
|
658 |
+
}
|
659 |
+
throw $e;
|
660 |
+
}
|
661 |
+
}
|
662 |
+
|
663 |
+
/**
|
664 |
+
* @param string|array $pattern
|
665 |
+
* @return array
|
666 |
+
*/
|
667 |
+
public function unsubscribe()
|
668 |
+
{
|
669 |
+
list($command, $channel, $subscribedChannels) = $this->__call('unsubscribe', func_get_args());
|
670 |
+
$this->subscribed = $subscribedChannels > 0;
|
671 |
+
return array($command, $channel, $subscribedChannels);
|
672 |
+
}
|
673 |
+
|
674 |
+
/**
|
675 |
+
* @param string|array $channels
|
676 |
+
* @param $callback
|
677 |
+
* @throws CredisException
|
678 |
+
* @return $this|array|bool|Credis_Client|mixed|null|string
|
679 |
+
*/
|
680 |
+
public function subscribe($channels, $callback)
|
681 |
+
{
|
682 |
+
if ( ! $this->standalone) {
|
683 |
+
return $this->__call('subscribe', array((array)$channels, $callback));
|
684 |
+
}
|
685 |
+
|
686 |
+
// Standalone mode: use infinite loop to subscribe until timeout
|
687 |
+
$channelCount = is_array($channels) ? count($channels) : 1;
|
688 |
+
while ($channelCount--) {
|
689 |
+
if (isset($status)) {
|
690 |
+
list($command, $channel, $status) = $this->read_reply();
|
691 |
+
} else {
|
692 |
+
list($command, $channel, $status) = $this->__call('subscribe', array($channels));
|
693 |
+
}
|
694 |
+
$this->subscribed = $status > 0;
|
695 |
+
if ( ! $status) {
|
696 |
+
throw new CredisException('Invalid subscribe response.');
|
697 |
+
}
|
698 |
+
}
|
699 |
+
try {
|
700 |
+
while ($this->subscribed) {
|
701 |
+
list($type, $channel, $message) = $this->read_reply();
|
702 |
+
if ($type != 'message') {
|
703 |
+
throw new CredisException('Received non-message reply.');
|
704 |
+
}
|
705 |
+
$callback($this, $channel, $message);
|
706 |
+
}
|
707 |
+
} catch (CredisException $e) {
|
708 |
+
if ($e->getCode() == CredisException::CODE_TIMED_OUT) {
|
709 |
+
try {
|
710 |
+
list($command, $channel, $status) = $this->unsubscribe($channels);
|
711 |
+
while ($status !== 0) {
|
712 |
+
list($command, $channel, $status) = $this->read_reply();
|
713 |
+
}
|
714 |
+
} catch (CredisException $e2) {
|
715 |
+
throw $e2;
|
716 |
+
}
|
717 |
+
}
|
718 |
+
throw $e;
|
719 |
+
}
|
720 |
+
}
|
721 |
|
722 |
public function __call($name, $args)
|
723 |
{
|
729 |
// Send request via native PHP
|
730 |
if($this->standalone)
|
731 |
{
|
732 |
+
switch ($name) {
|
733 |
+
case 'eval':
|
734 |
+
case 'evalsha':
|
735 |
+
$script = array_shift($args);
|
736 |
+
$keys = (array) array_shift($args);
|
737 |
+
$eArgs = (array) array_shift($args);
|
738 |
+
$args = array($script, count($keys), $keys, $eArgs);
|
739 |
+
break;
|
740 |
+
}
|
741 |
// Flatten arguments
|
742 |
$argsFlat = NULL;
|
743 |
foreach($args as $index => $arg) {
|
746 |
$argsFlat = array_slice($args, 0, $index);
|
747 |
}
|
748 |
if($name == 'mset' || $name == 'msetnx' || $name == 'hmset') {
|
749 |
+
foreach($arg as $key => $value) {
|
750 |
+
$argsFlat[] = $key;
|
751 |
+
$argsFlat[] = $value;
|
752 |
+
}
|
753 |
} else {
|
754 |
+
$argsFlat = array_merge($argsFlat, $arg);
|
755 |
}
|
756 |
} else if($argsFlat !== NULL) {
|
757 |
$argsFlat[] = $arg;
|
771 |
else if($name == 'exec') {
|
772 |
if($this->isMulti) {
|
773 |
$this->commandNames[] = $name;
|
774 |
+
$this->commands .= self::_prepare_command(array($this->getRenamedCommand($name)));
|
775 |
}
|
776 |
|
777 |
// Write request
|
797 |
if($name == 'multi') {
|
798 |
$this->isMulti = TRUE;
|
799 |
}
|
800 |
+
array_unshift($args, $this->getRenamedCommand($name));
|
801 |
$this->commandNames[] = $name;
|
802 |
$this->commands .= self::_prepare_command($args);
|
803 |
return $this;
|
819 |
}
|
820 |
|
821 |
// Non-pipeline mode
|
822 |
+
array_unshift($args, $this->getRenamedCommand($name));
|
823 |
$command = self::_prepare_command($args);
|
824 |
$this->write_command($command);
|
825 |
$response = $this->read_reply($name);
|
863 |
case 'lrem':
|
864 |
$args = array($args[0], $args[2], $args[1]);
|
865 |
break;
|
866 |
+
case 'eval':
|
867 |
+
case 'evalsha':
|
868 |
+
if (isset($args[1]) && is_array($args[1])) {
|
869 |
+
$cKeys = $args[1];
|
870 |
+
} elseif (isset($args[1]) && is_string($args[1])) {
|
871 |
+
$cKeys = array($args[1]);
|
872 |
+
} else {
|
873 |
+
$cKeys = array();
|
874 |
+
}
|
875 |
+
if (isset($args[2]) && is_array($args[2])) {
|
876 |
+
$cArgs = $args[2];
|
877 |
+
} elseif (isset($args[2]) && is_string($args[2])) {
|
878 |
+
$cArgs = array($args[2]);
|
879 |
+
} else {
|
880 |
+
$cArgs = array();
|
881 |
+
}
|
882 |
+
$args = array($args[0], array_merge($cKeys, $cArgs), count($cKeys));
|
883 |
+
break;
|
884 |
+
case 'subscribe':
|
885 |
+
case 'psubscribe':
|
886 |
+
break;
|
887 |
default:
|
888 |
// Flatten arguments
|
889 |
$argsFlat = NULL;
|
922 |
}
|
923 |
|
924 |
// Use aliases to be compatible with phpredis wrapper
|
925 |
+
if(isset($this->wrapperMethods[$name])) {
|
926 |
+
$name = $this->wrapperMethods[$name];
|
927 |
}
|
928 |
|
929 |
// Multi and pipeline return self for chaining
|
932 |
return $this;
|
933 |
}
|
934 |
|
935 |
+
// Send request, retry one time when using persistent connections on the first request only
|
936 |
+
$this->requests++;
|
937 |
+
try {
|
938 |
+
$response = call_user_func_array(array($this->redis, $name), $args);
|
939 |
+
} catch (RedisException $e) {
|
940 |
+
if ($this->persistent && $this->requests == 1 && $e->getMessage() == 'read error on connection') {
|
941 |
+
$this->connected = FALSE;
|
942 |
+
$this->connect();
|
943 |
+
$response = call_user_func_array(array($this->redis, $name), $args);
|
944 |
+
} else {
|
945 |
+
throw $e;
|
946 |
+
}
|
947 |
+
}
|
948 |
}
|
949 |
+
// Wrap exceptions
|
950 |
catch(RedisException $e) {
|
951 |
+
$code = 0;
|
952 |
+
if ( ! ($result = $this->redis->IsConnected())) {
|
953 |
+
$this->connected = FALSE;
|
954 |
+
$code = CredisException::CODE_DISCONNECTED;
|
955 |
+
}
|
956 |
+
throw new CredisException($e->getMessage(), $code, $e);
|
957 |
}
|
958 |
|
959 |
#echo "> $name : ".substr(print_r($response, TRUE),0,100)."\n";
|
964 |
case 'hmget':
|
965 |
$response = array_values($response);
|
966 |
break;
|
967 |
+
|
968 |
case 'type':
|
969 |
$typeMap = array(
|
970 |
+
self::TYPE_NONE,
|
971 |
+
self::TYPE_STRING,
|
972 |
+
self::TYPE_SET,
|
973 |
+
self::TYPE_LIST,
|
974 |
+
self::TYPE_ZSET,
|
975 |
+
self::TYPE_HASH,
|
976 |
);
|
977 |
$response = $typeMap[$response];
|
978 |
break;
|
979 |
+
|
980 |
+
// Handle scripting errors
|
981 |
+
case 'eval':
|
982 |
+
case 'evalsha':
|
983 |
+
case 'script':
|
984 |
+
$error = $this->redis->getLastError();
|
985 |
+
$this->redis->clearLastError();
|
986 |
+
if ($error && substr($error,0,8) == 'NOSCRIPT') {
|
987 |
+
$response = NULL;
|
988 |
+
} else if ($error) {
|
989 |
+
throw new CredisException($error);
|
990 |
+
}
|
991 |
+
break;
|
992 |
+
default:
|
993 |
+
$error = $this->redis->getLastError();
|
994 |
+
$this->redis->clearLastError();
|
995 |
+
if ($error) {
|
996 |
+
throw new CredisException($error);
|
997 |
+
}
|
998 |
+
break;
|
999 |
}
|
1000 |
}
|
1001 |
|
1027 |
for ($written = 0; $written < $commandLen; $written += $fwrite) {
|
1028 |
$fwrite = fwrite($this->redis, substr($command, $written));
|
1029 |
if ($fwrite === FALSE || $fwrite == 0 ) {
|
1030 |
+
$this->connected = FALSE;
|
1031 |
throw new CredisException('Failed to write entire command to stream');
|
1032 |
}
|
1033 |
}
|
1037 |
{
|
1038 |
$reply = fgets($this->redis);
|
1039 |
if($reply === FALSE) {
|
1040 |
+
$info = stream_get_meta_data($this->redis);
|
1041 |
+
if ($info['timed_out']) {
|
1042 |
+
throw new CredisException('Read operation timed out.', CredisException::CODE_TIMED_OUT);
|
1043 |
+
} else {
|
1044 |
+
$this->connected = FALSE;
|
1045 |
+
throw new CredisException('Lost connection to Redis server.', CredisException::CODE_DISCONNECTED);
|
1046 |
+
}
|
1047 |
}
|
1048 |
$reply = rtrim($reply, CRLF);
|
1049 |
#echo "> $name: $reply\n";
|
1053 |
case '-':
|
1054 |
if($this->isMulti || $this->usePipeline) {
|
1055 |
$response = FALSE;
|
1056 |
+
} else if ($name == 'evalsha' && substr($reply,0,9) == '-NOSCRIPT') {
|
1057 |
+
$response = NULL;
|
1058 |
} else {
|
1059 |
+
throw new CredisException(substr($reply,0,4) == '-ERR' ? substr($reply, 5) : substr($reply,1));
|
1060 |
}
|
1061 |
break;
|
1062 |
/* Inline reply */
|
1063 |
case '+':
|
1064 |
$response = substr($reply, 1);
|
1065 |
if($response == 'OK' || $response == 'QUEUED') {
|
1066 |
+
return TRUE;
|
1067 |
}
|
1068 |
break;
|
1069 |
/* Bulk reply */
|
1071 |
if ($reply == '$-1') return FALSE;
|
1072 |
$size = (int) substr($reply, 1);
|
1073 |
$response = stream_get_contents($this->redis, $size + 2);
|
1074 |
+
if( ! $response) {
|
1075 |
+
$this->connected = FALSE;
|
1076 |
throw new CredisException('Error reading reply.');
|
1077 |
+
}
|
1078 |
$response = substr($response, 0, $size);
|
1079 |
break;
|
1080 |
/* Multi-bulk reply */
|
1084 |
|
1085 |
$response = array();
|
1086 |
for ($i = 0; $i < $count; $i++) {
|
1087 |
+
$response[] = $this->read_reply();
|
1088 |
}
|
1089 |
break;
|
1090 |
/* Integer reply */
|
1115 |
$response = array();
|
1116 |
foreach($lines as $line) {
|
1117 |
if ( ! $line || substr($line, 0, 1) == '#') {
|
1118 |
+
continue;
|
1119 |
}
|
1120 |
list($key, $value) = explode(':', $line, 2);
|
1121 |
$response[$key] = $value;
|
package.xml
CHANGED
@@ -1,18 +1,18 @@
|
|
1 |
<?xml version="1.0"?>
|
2 |
<package>
|
3 |
<name>Lib_Credis</name>
|
4 |
-
<version>1.
|
5 |
<stability>stable</stability>
|
6 |
<license uri="http://opensource.org/licenses/osl-3.0.php">OSL v3.0</license>
|
7 |
<channel>community</channel>
|
8 |
<extends/>
|
9 |
<summary>Credis Library</summary>
|
10 |
<description>Credis Library</description>
|
11 |
-
<notes>1.
|
12 |
<authors><author><name>Magento Core Team</name><user>core</user><email>core@magentocommerce.com</email></author></authors>
|
13 |
-
<date>
|
14 |
-
<time>
|
15 |
-
<contents><target name="magelib"><dir name="Credis"><file name="Client.php" hash="
|
16 |
<compatible/>
|
17 |
<dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies>
|
18 |
</package>
|
1 |
<?xml version="1.0"?>
|
2 |
<package>
|
3 |
<name>Lib_Credis</name>
|
4 |
+
<version>1.9.2.0</version>
|
5 |
<stability>stable</stability>
|
6 |
<license uri="http://opensource.org/licenses/osl-3.0.php">OSL v3.0</license>
|
7 |
<channel>community</channel>
|
8 |
<extends/>
|
9 |
<summary>Credis Library</summary>
|
10 |
<description>Credis Library</description>
|
11 |
+
<notes>1.9.2.0</notes>
|
12 |
<authors><author><name>Magento Core Team</name><user>core</user><email>core@magentocommerce.com</email></author></authors>
|
13 |
+
<date>2015-06-26</date>
|
14 |
+
<time>13:48:52</time>
|
15 |
+
<contents><target name="magelib"><dir name="Credis"><file name="Client.php" hash="1fde64fdcd768d51758ec437d5952861"/></dir></target></contents>
|
16 |
<compatible/>
|
17 |
<dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies>
|
18 |
</package>
|