![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/old/vendor/php-amqplib/php-amqplib/PhpAmqpLib/Wire/ |
<?php namespace PhpAmqpLib\Wire; use PhpAmqpLib\Channel\AbstractChannel; use PhpAmqpLib\Exception; use PhpAmqpLib\Wire; /** * Iterator implemented for transparent integration with AMQPWriter::write_[array|table]() */ abstract class AMQPAbstractCollection implements \Iterator, \ArrayAccess { //protocol defines available field types and their corresponding symbols const PROTOCOL_RBT = 'rabbit'; //pseudo proto //Abstract data types const T_INT_SHORTSHORT = 1; const T_INT_SHORTSHORT_U = 2; const T_INT_SHORT = 3; const T_INT_SHORT_U = 4; const T_INT_LONG = 5; const T_INT_LONG_U = 6; const T_INT_LONGLONG = 7; const T_INT_LONGLONG_U = 8; const T_DECIMAL = 9; const T_TIMESTAMP = 10; const T_VOID = 11; const T_BOOL = 12; const T_STRING_SHORT = 13; const T_STRING_LONG = 14; const T_ARRAY = 15; const T_TABLE = 16; const T_BYTES = 17; const T_FLOAT = 18; const T_DOUBLE = 19; /** * @var string */ private static $protocol; /* * Field types messy mess http://www.rabbitmq.com/amqp-0-9-1-errata.html#section_3 * Default behaviour is to use rabbitMQ compatible field-set * Define AMQP_STRICT_FLD_TYPES=true to use strict AMQP instead * @var array<int, string> */ private static $types_080 = array( self::T_INT_LONG => 'I', self::T_DECIMAL => 'D', self::T_TIMESTAMP => 'T', self::T_STRING_LONG => 'S', self::T_TABLE => 'F' ); /** * @var array<int, string> */ private static $types_091 = array( self::T_INT_SHORTSHORT => 'b', self::T_INT_SHORTSHORT_U => 'B', self::T_INT_SHORT => 'U', self::T_INT_SHORT_U => 'u', self::T_INT_LONG => 'I', self::T_INT_LONG_U => 'i', self::T_INT_LONGLONG => 'L', self::T_INT_LONGLONG_U => 'l', self::T_FLOAT => 'f', self::T_DOUBLE => 'd', self::T_DECIMAL => 'D', self::T_TIMESTAMP => 'T', self::T_VOID => 'V', self::T_BOOL => 't', self::T_STRING_SHORT => 's', self::T_STRING_LONG => 'S', self::T_ARRAY => 'A', self::T_TABLE => 'F', self::T_BYTES => 'x', ); /** * @var array<int, string> */ private static $types_rabbit = array( self::T_INT_SHORTSHORT => 'b', self::T_INT_SHORTSHORT_U => 'B', self::T_INT_SHORT => 's', self::T_INT_SHORT_U => 'u', self::T_INT_LONG => 'I', self::T_INT_LONG_U => 'i', self::T_INT_LONGLONG => 'l', self::T_FLOAT => 'f', self::T_DOUBLE => 'd', self::T_DECIMAL => 'D', self::T_TIMESTAMP => 'T', self::T_VOID => 'V', self::T_BOOL => 't', self::T_STRING_LONG => 'S', self::T_ARRAY => 'A', self::T_TABLE => 'F', self::T_BYTES => 'x', ); /** * @var array */ protected $data = array(); public function __construct(array $data = null) { if (!empty($data)) { $this->data = $this->encodeCollection($data); } } /** * @return int */ abstract public function getType(); /** * @param mixed $val * @param int|null $type * @param string $key */ final protected function setValue($val, $type = null, $key = null) { if ($val instanceof self) { if ($type && ($type !== $val->getType())) { throw new Exception\AMQPInvalidArgumentException( sprintf( 'Attempted to add instance of %s representing type [%s] as mismatching type [%s]', get_class($val), $val->getType(), $type ) ); } $type = $val->getType(); } elseif ($type) { //ensuring data integrity and that all members are properly validated switch ($type) { case self::T_ARRAY: throw new Exception\AMQPInvalidArgumentException('Arrays must be passed as AMQPArray instance'); case self::T_TABLE: throw new Exception\AMQPInvalidArgumentException('Tables must be passed as AMQPTable instance'); case self::T_DECIMAL: if (!($val instanceof AMQPDecimal)) { throw new Exception\AMQPInvalidArgumentException( 'Decimal values must be instance of AMQPDecimal' ); } break; } } if ($type) { self::checkDataTypeIsSupported($type, false); $val = array($type, $val); } else { $val = $this->encodeValue($val); } if ($key === null) { $this->data[] = $val; } else { $this->data[$key] = $val; } } /** * @return array */ final public function getNativeData() { return $this->decodeCollection($this->data); } /** * @param array $val * @return array */ final protected function encodeCollection(array $val) { foreach ($val as $k => $v) { $val[$k] = $this->encodeValue($v); } return $val; } /** * @param array $val * @return array */ final protected function decodeCollection(array $val) { foreach ($val as $k => $v) { $val[$k] = $this->decodeValue($v[1], $v[0]); } return $val; } public function offsetExists($offset): bool { return isset($this->data[$offset]); } /** * @param mixed $offset * @return mixed */ #[\ReturnTypeWillChange] public function offsetGet($offset) { $value = isset($this->data[$offset]) ? $this->data[$offset] : null; return is_array($value) ? $value[1] : $value; } public function offsetSet($offset, $value): void { $this->setValue($value, null, $offset); } public function offsetUnset($offset): void { unset($this->data[$offset]); } /** * @param mixed $val * @return mixed * @throws Exception\AMQPOutOfBoundsException */ protected function encodeValue($val) { if (is_string($val)) { $val = $this->encodeString($val); } elseif (is_float($val)) { $val = $this->encodeFloat($val); } elseif (is_int($val)) { $val = $this->encodeInt($val); } elseif (is_bool($val)) { $val = $this->encodeBool($val); } elseif (is_null($val)) { $val = $this->encodeVoid(); } elseif ($val instanceof \DateTimeInterface) { $val = array(self::T_TIMESTAMP, $val->getTimestamp()); } elseif ($val instanceof AMQPDecimal) { $val = array(self::T_DECIMAL, $val); } elseif ($val instanceof self) { //avoid silent type correction of strictly typed values self::checkDataTypeIsSupported($val->getType(), false); $val = array($val->getType(), $val); } elseif (is_array($val)) { //AMQP specs says "Field names MUST start with a letter, '$' or '#'" //so beware, some servers may raise an exception with 503 code in cases when indexed // array is encoded as table if (self::isProtocol(Wire\Constants080::VERSION)) { //080 doesn't support arrays, forcing table $val = array(self::T_TABLE, new AMQPTable($val)); } elseif (empty($val) || (array_keys($val) === range(0, count($val) - 1))) { $val = array(self::T_ARRAY, new AMQPArray($val)); } else { $val = array(self::T_TABLE, new AMQPTable($val)); } } else { throw new Exception\AMQPOutOfBoundsException( sprintf('Encountered value of unsupported type: %s', gettype($val)) ); } return $val; } /** * @param mixed $val * @param int $type * @return array|bool|\DateTime|null */ protected function decodeValue($val, $type) { if ($val instanceof self) { //covering arrays and tables $val = $val->getNativeData(); } else { switch ($type) { case self::T_BOOL: $val = (bool) $val; break; case self::T_TIMESTAMP: $val = \DateTime::createFromFormat('U', $val); break; case self::T_VOID: $val = null; break; case self::T_ARRAY: case self::T_TABLE: throw new Exception\AMQPLogicException( sprintf( '%s %s', 'Encountered an array/table struct which is not an instance of AMQPCollection.', 'This is considered a bug and should be fixed, please report' ) ); } } return $val; } /** * @param string $val * @return array */ protected function encodeString($val) { return array(self::T_STRING_LONG, $val); } /** * @param int $val * @return array */ protected function encodeInt($val) { if (($val >= -2147483648) && ($val <= 2147483647)) { $ev = array(self::T_INT_LONG, $val); } elseif (self::isProtocol(Wire\Constants080::VERSION)) { //080 doesn't support longlong $ev = $this->encodeString((string) $val); } else { $ev = array(self::T_INT_LONGLONG, $val); } return $ev; } /** * @param float $val * @return array */ protected function encodeFloat($val) { return $this->encodeString((string) $val); } /** * @param bool $val * @return array */ protected function encodeBool($val) { $val = (bool) $val; return self::isProtocol(Wire\Constants080::VERSION) ? array(self::T_INT_LONG, (int) $val) : array(self::T_BOOL, $val); } /** * @return array */ protected function encodeVoid() { return self::isProtocol(Wire\Constants080::VERSION) ? $this->encodeString('') : array(self::T_VOID, null); } /** * @return string */ final public static function getProtocol() { if (self::$protocol === null) { self::$protocol = defined('AMQP_STRICT_FLD_TYPES') && AMQP_STRICT_FLD_TYPES ? AbstractChannel::getProtocolVersion() : self::PROTOCOL_RBT; } return self::$protocol; } /** * @param string $proto * @return bool */ final public static function isProtocol($proto) { return self::getProtocol() === $proto; } /** * @return array [dataTypeConstant => dataTypeSymbol] */ final public static function getSupportedDataTypes() { switch ($proto = self::getProtocol()) { case Wire\Constants080::VERSION: $types = self::$types_080; break; case Wire\Constants091::VERSION: $types = self::$types_091; break; case self::PROTOCOL_RBT: $types = self::$types_rabbit; break; default: throw new Exception\AMQPOutOfRangeException(sprintf('Unknown protocol: %s', $proto)); } return $types; } /** * @param string $type * @param bool $return Whether to return or raise AMQPOutOfRangeException * @return boolean */ final public static function checkDataTypeIsSupported($type, $return = true) { try { $supported = self::getSupportedDataTypes(); if (!isset($supported[$type])) { throw new Exception\AMQPOutOfRangeException(sprintf( 'AMQP-%s doesn\'t support data of type [%s]', self::getProtocol(), $type )); } return true; } catch (Exception\AMQPOutOfRangeException $ex) { if (!$return) { throw $ex; } return false; } } /** * @param int $type * @return string */ final public static function getSymbolForDataType($type) { $types = self::getSupportedDataTypes(); if (!isset($types[$type])) { throw new Exception\AMQPOutOfRangeException(sprintf( 'AMQP-%s doesn\'t support data of type [%s]', self::getProtocol(), $type )); } return $types[$type]; } /** * @param string $symbol * @return integer */ final public static function getDataTypeForSymbol($symbol) { $symbols = array_flip(self::getSupportedDataTypes()); if (!isset($symbols[$symbol])) { throw new Exception\AMQPOutOfRangeException(sprintf( 'AMQP-%s doesn\'t define data of type [%s]', self::getProtocol(), $symbol )); } return $symbols[$symbol]; } /** * @return mixed */ #[\ReturnTypeWillChange] public function current() { return current($this->data); } /** * @return mixed */ #[\ReturnTypeWillChange] public function key() { return key($this->data); } public function next(): void { next($this->data); } public function rewind(): void { reset($this->data); } public function valid(): bool { return key($this->data) !== null; } }