Redis.php 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. <?php
  2. /**
  3. * This file is part of workerman.
  4. *
  5. * Licensed under The MIT License
  6. * For full copyright and license information, please see the LICENSE
  7. * Redistributions of files must retain the above copyright notice.
  8. *
  9. * @author walkor<walkor@workerman.net>
  10. * @copyright walkor<walkor@workerman.net>
  11. * @link http://www.workerman.net/
  12. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  13. */
  14. namespace Workerman\Redis\Protocols;
  15. use Workerman\Connection\ConnectionInterface;
  16. use Workerman\Redis\Exception;
  17. /**
  18. * Redis Protocol.
  19. */
  20. class Redis
  21. {
  22. /**
  23. * Check the integrity of the package.
  24. *
  25. * @param string $buffer
  26. * @param ConnectionInterface $connection
  27. * @return int
  28. */
  29. public static function input($buffer, ConnectionInterface $connection) {
  30. $type = $buffer[0];
  31. $pos = \strpos($buffer, "\r\n");
  32. if (false === $pos) {
  33. return 0;
  34. }
  35. switch ($type) {
  36. case ':':
  37. case '+':
  38. case '-':
  39. return $pos + 2;
  40. case '$':
  41. if(0 === strpos($buffer, '$-1')) {
  42. return 5;
  43. }
  44. return $pos + 4 + (int)substr($buffer, 1, $pos);
  45. case '*':
  46. if(0 === strpos($buffer, '*-1')) {
  47. return 5;
  48. }
  49. $count = (int)substr($buffer, 1, $pos - 1);
  50. while ($count --) {
  51. if (strlen($buffer) < $pos + 2) {
  52. return 0;
  53. }
  54. $next_pos = strpos($buffer, "\r\n", $pos + 2);
  55. if (!$next_pos) {
  56. return 0;
  57. }
  58. $sub_type = $buffer[$pos + 2];
  59. switch ($sub_type) {
  60. case ':':
  61. case '+':
  62. case '-':
  63. $pos = $next_pos;
  64. break;
  65. case '$':
  66. if($pos + 2 === strpos($buffer, '$-1', $pos)) {
  67. $pos = $next_pos;
  68. break;
  69. }
  70. $length = (int)substr($buffer, $pos + 3, $next_pos - $pos -3);
  71. $pos = $next_pos + $length + 2;
  72. if (strlen($buffer) < $pos) {
  73. return 0;
  74. }
  75. break;
  76. default:
  77. return \strlen($buffer);
  78. }
  79. }
  80. return $pos + 2;
  81. default:
  82. return \strlen($buffer);
  83. }
  84. }
  85. /**
  86. * Encode.
  87. *
  88. * @param array $data
  89. * @return string
  90. */
  91. public static function encode(array $data)
  92. {
  93. $cmd = '';
  94. $count = \count($data);
  95. foreach ($data as $item)
  96. {
  97. if (\is_array($item)) {
  98. $count += \count($item) - 1;
  99. foreach ($item as $str)
  100. {
  101. $cmd .= '$' . \strlen($str) . "\r\n$str\r\n";
  102. }
  103. continue;
  104. }
  105. $cmd .= '$' . \strlen($item) . "\r\n$item\r\n";
  106. }
  107. return "*$count\r\n$cmd";
  108. }
  109. /**
  110. * Decode.
  111. *
  112. * @param string $buffer
  113. * @return string
  114. */
  115. public static function decode($buffer)
  116. {
  117. $type = $buffer[0];
  118. switch ($type) {
  119. case ':':
  120. return [$type ,(int) substr($buffer, 1)];
  121. case '+':
  122. return [$type, \substr($buffer, 1, strlen($buffer) - 3)];
  123. case '-':
  124. return [$type, \substr($buffer, 1, strlen($buffer) - 3)];
  125. case '$':
  126. if(0 === strpos($buffer, '$-1')) {
  127. return [$type, null];
  128. }
  129. $pos = \strpos($buffer, "\r\n");
  130. return [$type, \substr($buffer, $pos + 2, (int)substr($buffer, 1, $pos))];
  131. case '*':
  132. if(0 === strpos($buffer, '*-1')) {
  133. return [$type, null];
  134. }
  135. $pos = \strpos($buffer, "\r\n");
  136. $value = [];
  137. $count = (int)substr($buffer, 1, $pos - 1);
  138. while ($count --) {
  139. if (strlen($buffer) < $pos + 2) {
  140. return 0;
  141. }
  142. $next_pos = strpos($buffer, "\r\n", $pos + 2);
  143. if (!$next_pos) {
  144. return 0;
  145. }
  146. $sub_type = $buffer[$pos + 2];
  147. switch ($sub_type) {
  148. case ':':
  149. $value[] = (int) substr($buffer, $pos + 3, $next_pos - $pos - 3);
  150. $pos = $next_pos;
  151. break;
  152. case '+':
  153. $value[] = substr($buffer, $pos + 3, $next_pos - $pos - 3);
  154. $pos = $next_pos;
  155. break;
  156. case '-':
  157. $value[] = substr($buffer, $pos + 3, $next_pos - $pos - 3);
  158. $pos = $next_pos;
  159. break;
  160. case '$':
  161. if($pos + 2 === strpos($buffer, '$-1', $pos)) {
  162. $pos = $next_pos;
  163. $value[] = null;
  164. break;
  165. }
  166. $length = (int)substr($buffer, $pos + 3, $next_pos - $pos -3);
  167. $value[] = substr($buffer, $next_pos + 2, $length);
  168. $pos = $next_pos + $length + 2;
  169. break;
  170. default:
  171. return ['!', "protocol error, got '$sub_type' as reply type byte. buffer:".bin2hex($buffer)." pos:$pos"];
  172. }
  173. }
  174. return [$type, $value];
  175. default:
  176. return ['!', "protocol error, got '$type' as reply type byte. buffer:".bin2hex($buffer)];
  177. }
  178. }
  179. }