/lib/Redisent/Redisent.php

https://github.com/d11wtq/php-resque · PHP · 147 lines · 91 code · 14 blank · 42 comment · 14 complexity · 7f7cae2704839058b2e67d4fff394af1 MD5 · raw file

  1. <?php
  2. /**
  3. * Redisent, a Redis interface for the modest
  4. * @author Justin Poliey <jdp34@njit.edu>
  5. * @copyright 2009 Justin Poliey <jdp34@njit.edu>
  6. * @license http://www.opensource.org/licenses/mit-license.php The MIT License
  7. * @package Redisent
  8. */
  9. define('CRLF', sprintf('%s%s', chr(13), chr(10)));
  10. /**
  11. * Wraps native Redis errors in friendlier PHP exceptions
  12. */
  13. class RedisException extends Exception {
  14. }
  15. /**
  16. * Redisent, a Redis interface for the modest among us
  17. */
  18. class Redisent {
  19. /**
  20. * Socket connection to the Redis server
  21. * @var resource
  22. * @access private
  23. */
  24. private $__sock;
  25. /**
  26. * Host of the Redis server
  27. * @var string
  28. * @access public
  29. */
  30. public $host;
  31. /**
  32. * Port on which the Redis server is running
  33. * @var integer
  34. * @access public
  35. */
  36. public $port;
  37. /**
  38. * Creates a Redisent connection to the Redis server on host {@link $host} and port {@link $port}.
  39. * @param string $host The hostname of the Redis server
  40. * @param integer $port The port number of the Redis server
  41. */
  42. function __construct($host, $port = 6379) {
  43. $this->host = $host;
  44. $this->port = $port;
  45. $this->establishConnection();
  46. }
  47. function establishConnection() {
  48. $this->__sock = fsockopen($this->host, $this->port, $errno, $errstr);
  49. if (!$this->__sock) {
  50. throw new Exception("{$errno} - {$errstr}");
  51. }
  52. }
  53. function __destruct() {
  54. fclose($this->__sock);
  55. }
  56. function __call($name, $args) {
  57. /* Build the Redis unified protocol command */
  58. array_unshift($args, strtoupper($name));
  59. $command = sprintf('*%d%s%s%s', count($args), CRLF, implode(array_map(array($this, 'formatArgument'), $args), CRLF), CRLF);
  60. /* Open a Redis connection and execute the command */
  61. for ($written = 0; $written < strlen($command); $written += $fwrite) {
  62. $fwrite = fwrite($this->__sock, substr($command, $written));
  63. if ($fwrite === FALSE) {
  64. throw new Exception('Failed to write entire command to stream');
  65. }
  66. }
  67. /* Parse the response based on the reply identifier */
  68. $reply = trim(fgets($this->__sock, 512));
  69. switch (substr($reply, 0, 1)) {
  70. /* Error reply */
  71. case '-':
  72. throw new RedisException(substr(trim($reply), 4));
  73. break;
  74. /* Inline reply */
  75. case '+':
  76. $response = substr(trim($reply), 1);
  77. break;
  78. /* Bulk reply */
  79. case '$':
  80. $response = null;
  81. if ($reply == '$-1') {
  82. break;
  83. }
  84. $read = 0;
  85. $size = substr($reply, 1);
  86. do {
  87. $block_size = ($size - $read) > 1024 ? 1024 : ($size - $read);
  88. $response .= fread($this->__sock, $block_size);
  89. $read += $block_size;
  90. } while ($read < $size);
  91. fread($this->__sock, 2); /* discard crlf */
  92. break;
  93. /* Multi-bulk reply */
  94. case '*':
  95. $count = substr($reply, 1);
  96. if ($count == '-1') {
  97. return null;
  98. }
  99. $response = array();
  100. for ($i = 0; $i < $count; $i++) {
  101. $bulk_head = trim(fgets($this->__sock, 512));
  102. $size = substr($bulk_head, 1);
  103. if ($size == '-1') {
  104. $response[] = null;
  105. }
  106. else {
  107. $read = 0;
  108. $block = "";
  109. do {
  110. $block_size = ($size - $read) > 1024 ? 1024 : ($size - $read);
  111. $block .= fread($this->__sock, $block_size);
  112. $read += $block_size;
  113. } while ($read < $size);
  114. fread($this->__sock, 2); /* discard crlf */
  115. $response[] = $block;
  116. }
  117. }
  118. break;
  119. /* Integer reply */
  120. case ':':
  121. $response = intval(substr(trim($reply), 1));
  122. break;
  123. default:
  124. throw new RedisException("invalid server response: {$reply}");
  125. break;
  126. }
  127. /* Party on */
  128. return $response;
  129. }
  130. private function formatArgument($arg) {
  131. return sprintf('$%d%s%s', strlen($arg), CRLF, $arg);
  132. }
  133. }