TextProtocol.php 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. <?php
  2. /*
  3. * This file is part of the Predis package.
  4. *
  5. * (c) Daniele Alessandri <suppakilla@gmail.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Predis\Protocol\Text;
  11. use Predis\Helpers;
  12. use Predis\ResponseError;
  13. use Predis\ResponseQueued;
  14. use Predis\ServerException;
  15. use Predis\Commands\ICommand;
  16. use Predis\Protocol\IProtocolProcessor;
  17. use Predis\Protocol\ProtocolException;
  18. use Predis\Network\IConnectionComposable;
  19. use Predis\Iterators\MultiBulkResponseSimple;
  20. class TextProtocol implements IProtocolProcessor
  21. {
  22. const NEWLINE = "\r\n";
  23. const OK = 'OK';
  24. const ERROR = 'ERR';
  25. const QUEUED = 'QUEUED';
  26. const NULL = 'nil';
  27. const PREFIX_STATUS = '+';
  28. const PREFIX_ERROR = '-';
  29. const PREFIX_INTEGER = ':';
  30. const PREFIX_BULK = '$';
  31. const PREFIX_MULTI_BULK = '*';
  32. const BUFFER_SIZE = 4096;
  33. private $_mbiterable;
  34. private $_throwErrors;
  35. private $_serializer;
  36. public function __construct()
  37. {
  38. $this->_mbiterable = false;
  39. $this->_throwErrors = true;
  40. $this->_serializer = new TextCommandSerializer();
  41. }
  42. public function write(IConnectionComposable $connection, ICommand $command)
  43. {
  44. $connection->writeBytes($this->_serializer->serialize($command));
  45. }
  46. public function read(IConnectionComposable $connection)
  47. {
  48. $chunk = $connection->readLine();
  49. $prefix = $chunk[0];
  50. $payload = substr($chunk, 1);
  51. switch ($prefix) {
  52. case '+': // inline
  53. switch ($payload) {
  54. case 'OK':
  55. return true;
  56. case 'QUEUED':
  57. return new ResponseQueued();
  58. default:
  59. return $payload;
  60. }
  61. case '$': // bulk
  62. $size = (int) $payload;
  63. if ($size === -1) {
  64. return null;
  65. }
  66. return substr($connection->readBytes($size + 2), 0, -2);
  67. case '*': // multi bulk
  68. $count = (int) $payload;
  69. if ($count === -1) {
  70. return null;
  71. }
  72. if ($this->_mbiterable == true) {
  73. return new MultiBulkResponseSimple($connection, $count);
  74. }
  75. $multibulk = array();
  76. for ($i = 0; $i < $count; $i++) {
  77. $multibulk[$i] = $this->read($connection);
  78. }
  79. return $multibulk;
  80. case ':': // integer
  81. return (int) $payload;
  82. case '-': // error
  83. if ($this->_throwErrors) {
  84. throw new ServerException($payload);
  85. }
  86. return new ResponseError($payload);
  87. default:
  88. Helpers::onCommunicationException(new ProtocolException(
  89. $connection, "Unknown prefix: '$prefix'"
  90. ));
  91. }
  92. }
  93. public function setOption($option, $value)
  94. {
  95. switch ($option) {
  96. case 'iterable_multibulk':
  97. $this->_mbiterable = (bool) $value;
  98. break;
  99. case 'throw_errors':
  100. $this->_throwErrors = (bool) $value;
  101. break;
  102. }
  103. }
  104. }