The response has been limited to 50k tokens of the smallest files in the repo. You can remove this limitation by removing the max tokens filter.
├── CHANGELOG.md
├── History.md
├── LICENSE
├── PhpAmqpLib
    ├── Channel
    │   ├── AMQPChannel.php
    │   ├── AbstractChannel.php
    │   ├── Frame.php
    │   └── Method.php
    ├── Connection
    │   ├── AMQPConnectionConfig.php
    │   ├── AMQPConnectionFactory.php
    │   ├── AMQPLazyConnection.php
    │   ├── AMQPLazySSLConnection.php
    │   ├── AMQPLazySocketConnection.php
    │   ├── AMQPSSLConnection.php
    │   ├── AMQPSocketConnection.php
    │   ├── AMQPStreamConnection.php
    │   ├── AbstractConnection.php
    │   └── Heartbeat
    │   │   ├── AbstractSignalHeartbeatSender.php
    │   │   ├── PCNTLHeartbeatSender.php
    │   │   └── SIGHeartbeatSender.php
    ├── Exception
    │   ├── AMQPBasicCancelException.php
    │   ├── AMQPChannelClosedException.php
    │   ├── AMQPConnectionBlockedException.php
    │   ├── AMQPConnectionClosedException.php
    │   ├── AMQPDataReadException.php
    │   ├── AMQPEmptyDeliveryTagException.php
    │   ├── AMQPExceptionInterface.php
    │   ├── AMQPHeartbeatMissedException.php
    │   ├── AMQPIOException.php
    │   ├── AMQPIOWaitException.php
    │   ├── AMQPInvalidArgumentException.php
    │   ├── AMQPInvalidFrameException.php
    │   ├── AMQPLogicException.php
    │   ├── AMQPNoDataException.php
    │   ├── AMQPNotImplementedException.php
    │   ├── AMQPOutOfBoundsException.php
    │   ├── AMQPOutOfRangeException.php
    │   ├── AMQPProtocolChannelException.php
    │   ├── AMQPProtocolException.php
    │   ├── AMQPRuntimeException.php
    │   ├── AMQPSocketException.php
    │   └── AMQPTimeoutException.php
    ├── Exchange
    │   └── AMQPExchangeType.php
    ├── Helper
    │   ├── Assert.php
    │   ├── BigInteger.php
    │   ├── DebugHelper.php
    │   ├── MiscHelper.php
    │   ├── Protocol
    │   │   ├── MethodMap080.php
    │   │   ├── MethodMap091.php
    │   │   ├── Protocol080.php
    │   │   ├── Protocol091.php
    │   │   ├── Wait080.php
    │   │   └── Wait091.php
    │   └── SocketConstants.php
    ├── Message
    │   └── AMQPMessage.php
    ├── Package.php
    └── Wire
    │   ├── AMQPAbstractCollection.php
    │   ├── AMQPArray.php
    │   ├── AMQPBufferReader.php
    │   ├── AMQPByteStream.php
    │   ├── AMQPDecimal.php
    │   ├── AMQPIOReader.php
    │   ├── AMQPReader.php
    │   ├── AMQPTable.php
    │   ├── AMQPWriter.php
    │   ├── Constants.php
    │   ├── Constants080.php
    │   ├── Constants091.php
    │   └── IO
    │       ├── AbstractIO.php
    │       ├── SocketIO.php
    │       └── StreamIO.php
├── README.md
├── codecov.yml
├── composer.json
├── phpcs.xml.dist
└── test.env


/History.md:
--------------------------------------------------------------------------------
  1 | # Previous releases
  2 | 
  3 | ## 2.7.2 - 2018-02-11
  4 | 
  5 | [GitHub Milestone](https://github.com/php-amqplib/php-amqplib/milestone/5?closed=1)
  6 | 
  7 | - PHP `5.3` compatibility [PR](https://github.com/php-amqplib/php-amqplib/issues/539)
  8 | 
  9 | ## 2.7.1 - 2018-02-01
 10 | 
 11 | - Support PHPUnit 6 [PR](https://github.com/php-amqplib/php-amqplib/pull/530)
 12 | - Use `tcp_nodelay` for `StreamIO` [PR](https://github.com/php-amqplib/php-amqplib/pull/517)
 13 | - Pass connection timeout to `wait` method [PR](https://github.com/php-amqplib/php-amqplib/pull/512)
 14 | - Fix possible indefinite waiting for data in StreamIO [PR](https://github.com/php-amqplib/php-amqplib/pull/423), [PR](https://github.com/php-amqplib/php-amqplib/pull/534)
 15 | - Change protected method check_heartbeat to public [PR](https://github.com/php-amqplib/php-amqplib/pull/520)
 16 | - Ensure access levels are consistent for calling `check_heartbeat` [PR](https://github.com/php-amqplib/php-amqplib/pull/535)
 17 | 
 18 | ## 2.7.0 - 2017-09-20
 19 | 
 20 | ### Added
 21 | - Increased overall test coverage
 22 | - Bring heartbeat support to socket connection
 23 | - Add message delivery tag for publisher confirms
 24 | - Add support for serializing DateTimeImmutable objects
 25 | 
 26 | ### Fixed
 27 | - Fixed infinite loop on reconnect - check_heartbeat
 28 | - Fixed signal handling exit example
 29 | - Fixed exchange_unbind arguments
 30 | - Fixed invalid annotation for channel_id
 31 | - Fixed socket null error on php 5.3 version
 32 | - Fixed timeout parameters on HHVM before calling stream_select
 33 | 
 34 | ### Changed
 35 | - declare(ticks=1) no longer needed after PHP5.3 / amqplib 2.4.1
 36 | - Minor DebugHelper improvements
 37 | 
 38 | ### Enhancements
 39 | - Add extensions requirements to README.md
 40 | - Add PHP 7.1 to Travis build
 41 | - Reduce memory usage in StreamIO::write()
 42 | - Re-enable heartbeats after reconnection
 43 | 
 44 | ## 2.6.3 - 2016-04-11
 45 | 
 46 | ### Added
 47 | - Added the ability to set timeout as float
 48 | 
 49 | ### Fixed
 50 | - Fixed restoring of error_handler on connection error
 51 | 
 52 | ### Enhancements
 53 | - Verify read_write_timeout is at least 2x the heartbeat (if set)
 54 | - Many PHPDoc fixes
 55 | - Throw exception when trying to create an exchange on a closed connection
 56 | 
 57 | ## 2.6.2 - 2016-03-02
 58 | 
 59 | ### Added
 60 | - Added AMQPLazySocketConnection
 61 | - AbstractConnection::getServerProperties method to retrieve server properties.
 62 | - AMQPReader::wait() will throw IOWaitException on stream_select failure
 63 | - Add PHPDocs to Auto-generated Protocol Classes
 64 | 
 65 | ### Fixed
 66 | - Disable heartbeat when closing connection
 67 | - Fix for when the default error handler is not restored in StreamIO
 68 | 
 69 | ### Enhancements
 70 | - Cleanup tests and improve testing performance
 71 | - Confirm received valid frame type on wait_frame in AbstractConnection
 72 | - Update DEMO files closer to PSR-2 standards
 73 | 
 74 | ## 2.6.1 - 2016-02-12
 75 | 
 76 | ### Added
 77 | - Add constants for delivery modes to AMQPMessage
 78 | 
 79 | ### Fixed
 80 | - Fix some PHPDoc problems
 81 | - AbstractCollection value de/encoding on PHP7
 82 | - StreamIO: fix "bad write retry" in SSL mode
 83 | 
 84 | ### Enhancements
 85 | - Update PHPUnit configuration
 86 | - Add scrutinizer-ci configuration
 87 | - Organizational changes from videlalvaro to php-amqplib org
 88 | - Minor complexity optimizations, code organization, and code cleanup
 89 | 
 90 | ## 2.6.0 - 2015-09-23
 91 | 
 92 | ### BC Breaking Changes
 93 | - The `AMQPStreamConnection` class now throws `ErrorExceptions` when errors happen while reading/writing to the network.
 94 | 
 95 | ### Added
 96 | - Heartbeat frames will decrease the timeout used when calling wait_channel - heartbeat frames do not reset the timeout
 97 | 
 98 | ### Fixed
 99 | - Declared the class AbstractChannel as being an abstract class
100 | - Reads, writes and signals respond immediately instead of waiting for a timeout
101 | - Fatal error in some cases on Channel.wait with timeout when RabbitMQ restarted
102 | - Remove warning when trying to push a deferred frame
103 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Channel/Frame.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | namespace PhpAmqpLib\Channel;
 4 | use PhpAmqpLib\Wire\AMQPReader;
 5 | 
 6 | /**
 7 |  * @link https://livebook.manning.com/book/rabbitmq-in-depth/chapter-2/v-13/22
 8 |  * @link https://www.rabbitmq.com/resources/specs/amqp0-9-1.pdf 4.2.6 Content Framing
 9 |  */
10 | final class Frame
11 | {
12 |     public const FRAME_HEADER_SIZE = AMQPReader::OCTET + AMQPReader::SHORT + AMQPReader::LONG;
13 |     public const END = 0xCE;
14 | 
15 |     public const TYPE_METHOD = 1;
16 |     public const TYPE_HEADER = 2;
17 |     public const TYPE_BODY = 3;
18 |     public const TYPE_HEARTBEAT = 8;
19 | 
20 |     /** @var int */
21 |     private $type;
22 | 
23 |     /** @var int */
24 |     private $channel;
25 | 
26 |     /** @var int */
27 |     private $size;
28 | 
29 |     /** @var string|null */
30 |     private $payload;
31 | 
32 |     public function __construct(int $type, int $channel, int $size, ?string $payload = null)
33 |     {
34 |         $this->type = $type;
35 |         $this->channel = $channel;
36 |         $this->size = $size;
37 |         $this->payload = $payload;
38 |     }
39 | 
40 |     /**
41 |      * @return int
42 |      */
43 |     public function getType(): int
44 |     {
45 |         return $this->type;
46 |     }
47 | 
48 |     /**
49 |      * @return int
50 |      */
51 |     public function getChannel(): int
52 |     {
53 |         return $this->channel;
54 |     }
55 | 
56 |     /**
57 |      * @return int
58 |      */
59 |     public function getSize(): int
60 |     {
61 |         return $this->size;
62 |     }
63 | 
64 |     public function getPayload(): ?string
65 |     {
66 |         return $this->payload;
67 |     }
68 | 
69 |     public function isMethod(): bool
70 |     {
71 |         return $this->type === self::TYPE_METHOD;
72 |     }
73 | 
74 |     public function isHeartbeat(): bool
75 |     {
76 |         return $this->type === self::TYPE_HEARTBEAT;
77 |     }
78 | }
79 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Channel/Method.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | namespace PhpAmqpLib\Channel;
 4 | 
 5 | final class Method
 6 | {
 7 |     /** @var int */
 8 |     private $class;
 9 | 
10 |     /** @var int */
11 |     private $method;
12 | 
13 |     /** @var string */
14 |     private $arguments;
15 | 
16 |     public function __construct(int $class, int $method, string $arguments)
17 |     {
18 |         $this->class = $class;
19 |         $this->method = $method;
20 |         $this->arguments = $arguments;
21 |     }
22 | 
23 |     public function getClass(): int
24 |     {
25 |         return $this->class;
26 |     }
27 | 
28 |     public function getMethod(): int
29 |     {
30 |         return $this->method;
31 |     }
32 | 
33 |     public function getArguments(): string
34 |     {
35 |         return $this->arguments;
36 |     }
37 | 
38 |     public function getSignature(): string
39 |     {
40 |         return $this->class . ',' . $this->method;
41 |     }
42 | }
43 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Connection/AMQPConnectionConfig.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | 
  3 | namespace PhpAmqpLib\Connection;
  4 | 
  5 | use InvalidArgumentException;
  6 | use PhpAmqpLib\Wire;
  7 | 
  8 | /**
  9 |  * @since 3.2.0
 10 |  */
 11 | final class AMQPConnectionConfig
 12 | {
 13 |     public const AUTH_PLAIN = 'PLAIN';
 14 |     public const AUTH_AMQPPLAIN = 'AMQPLAIN';
 15 |     public const AUTH_EXTERNAL = 'EXTERNAL';
 16 |     public const IO_TYPE_STREAM = 'stream';
 17 |     public const IO_TYPE_SOCKET = 'socket';
 18 | 
 19 |     /** @var string */
 20 |     private $ioType = self::IO_TYPE_STREAM;
 21 | 
 22 |     /** @var bool */
 23 |     private $isLazy = false;
 24 | 
 25 |     /** @var string */
 26 |     private $host = '127.0.0.1';
 27 | 
 28 |     /** @var int */
 29 |     private $port = 5672;
 30 | 
 31 |     /** @var string */
 32 |     private $user = 'guest';
 33 | 
 34 |     /** @var string */
 35 |     private $password = 'guest';
 36 | 
 37 |     /** @var string */
 38 |     private $vhost = '/';
 39 | 
 40 |     /** @var bool */
 41 |     private $insist = false;
 42 | 
 43 |     /** @var string */
 44 |     private $loginMethod = self::AUTH_AMQPPLAIN;
 45 | 
 46 |     /** @var string|null */
 47 |     private $loginResponse;
 48 | 
 49 |     /** @var string */
 50 |     private $locale = 'en_US';
 51 | 
 52 |     /** @var float */
 53 |     private $connectionTimeout = 3.0;
 54 | 
 55 |     /** @var float */
 56 |     private $readTimeout = 3.0;
 57 | 
 58 |     /** @var float */
 59 |     private $writeTimeout = 3.0;
 60 | 
 61 |     /** @var float */
 62 |     private $channelRPCTimeout = 0.0;
 63 | 
 64 |     /** @var int */
 65 |     private $heartbeat = 0;
 66 | 
 67 |     /** @var bool */
 68 |     private $keepalive = false;
 69 | 
 70 |     /** @var bool */
 71 |     private $isSecure = false;
 72 | 
 73 |     /**
 74 |      * @deprecated Use sslCryptoMethod
 75 |      * @var string
 76 |      */
 77 |     private $networkProtocol = 'tcp';
 78 | 
 79 |     /** @var resource|null */
 80 |     private $streamContext;
 81 | 
 82 |     /** @var int */
 83 |     private $sendBufferSize = 0;
 84 | 
 85 |     /** @var bool */
 86 |     private $dispatchSignals = true;
 87 | 
 88 |     /**
 89 |      * @var string
 90 |      * @deprecated
 91 |      */
 92 |     private $amqpProtocol = Wire\Constants091::VERSION;
 93 | 
 94 |     /**
 95 |      * Whether to use strict AMQP0.9.1 field types. RabbitMQ does not support that.
 96 |      * @var bool
 97 |      */
 98 |     private $protocolStrictFields = false;
 99 | 
100 |     /** @var string|null */
101 |     private $sslCaCert;
102 | 
103 |     /**
104 |      * @var string|null
105 |      */
106 |     private $sslCaPath;
107 | 
108 |     /** @var string|null */
109 |     private $sslCert;
110 | 
111 |     /** @var string|null */
112 |     private $sslKey;
113 | 
114 |     /** @var bool|null */
115 |     private $sslVerify;
116 | 
117 |     /** @var bool|null */
118 |     private $sslVerifyName;
119 | 
120 |     /** @var string|null */
121 |     private $sslPassPhrase;
122 | 
123 |     /** @var string|null */
124 |     private $sslCiphers;
125 | 
126 |     /** @var int|null */
127 |     private $sslSecurityLevel;
128 | 
129 |     /** @var int|null */
130 |     private $sslCryptoMethod;
131 | 
132 |     /** @var string */
133 |     private $connectionName = '';
134 | 
135 |     /**
136 |      * Output all networks packets for debug purposes.
137 |      * @var bool
138 |      */
139 |     private $debugPackets = false;
140 | 
141 |     public function getIoType(): string
142 |     {
143 |         return $this->ioType;
144 |     }
145 | 
146 |     /**
147 |      * Set which IO type will be used, stream or socket.
148 |      * @param string $ioType
149 |      */
150 |     public function setIoType(string $ioType): void
151 |     {
152 |         if ($ioType !== self::IO_TYPE_STREAM && $ioType !== self::IO_TYPE_SOCKET) {
153 |             throw new InvalidArgumentException('IO type can be either "stream" or "socket"');
154 |         }
155 |         $this->ioType = $ioType;
156 |     }
157 | 
158 |     public function isLazy(): bool
159 |     {
160 |         return $this->isLazy;
161 |     }
162 | 
163 |     public function setIsLazy(bool $isLazy): void
164 |     {
165 |         $this->isLazy = $isLazy;
166 |     }
167 | 
168 |     public function getHost(): string
169 |     {
170 |         return $this->host;
171 |     }
172 | 
173 |     public function setHost(string $host): void
174 |     {
175 |         $this->host = $host;
176 |     }
177 | 
178 |     public function getPort(): int
179 |     {
180 |         return $this->port;
181 |     }
182 | 
183 |     public function setPort(int $port): void
184 |     {
185 |         if ($port <= 0) {
186 |             throw new InvalidArgumentException('Port number must be greater than 0');
187 |         }
188 |         $this->port = $port;
189 |     }
190 | 
191 |     public function getUser(): string
192 |     {
193 |         return $this->user;
194 |     }
195 | 
196 |     public function setUser(string $user): void
197 |     {
198 |         $this->user = $user;
199 |     }
200 | 
201 |     public function getPassword(): string
202 |     {
203 |         return $this->password;
204 |     }
205 | 
206 |     public function setPassword(string $password): void
207 |     {
208 |         $this->password = $password;
209 |     }
210 | 
211 |     public function getVhost(): string
212 |     {
213 |         return $this->vhost;
214 |     }
215 | 
216 |     public function setVhost(string $vhost): void
217 |     {
218 |         self::assertStringNotEmpty($vhost, 'vhost');
219 |         $this->vhost = $vhost;
220 |     }
221 | 
222 |     public function isInsist(): bool
223 |     {
224 |         return $this->insist;
225 |     }
226 | 
227 |     public function setInsist(bool $insist): void
228 |     {
229 |         $this->insist = $insist;
230 |     }
231 | 
232 |     public function getLoginMethod(): string
233 |     {
234 |         return $this->loginMethod;
235 |     }
236 | 
237 |     public function setLoginMethod(string $loginMethod): void
238 |     {
239 |         if (
240 |             $loginMethod !== self::AUTH_PLAIN
241 |             && $loginMethod !== self::AUTH_AMQPPLAIN
242 |             && $loginMethod !== self::AUTH_EXTERNAL
243 |         ) {
244 |             throw new InvalidArgumentException('Unknown login method: ' . $loginMethod);
245 |         }
246 |         if ($loginMethod === self::AUTH_EXTERNAL && (!empty($this->user) || !empty($this->password))) {
247 |             throw new InvalidArgumentException('External auth method cannot be used together with user credentials.');
248 |         }
249 |         $this->loginMethod = $loginMethod;
250 |     }
251 | 
252 |     public function getLoginResponse(): ?string
253 |     {
254 |         return $this->loginResponse;
255 |     }
256 | 
257 |     public function setLoginResponse(string $loginResponse): void
258 |     {
259 |         $this->loginResponse = $loginResponse;
260 |     }
261 | 
262 |     public function getLocale(): string
263 |     {
264 |         return $this->locale;
265 |     }
266 | 
267 |     public function setLocale(string $locale): void
268 |     {
269 |         self::assertStringNotEmpty($locale, 'locale');
270 |         $this->locale = $locale;
271 |     }
272 | 
273 |     public function getConnectionTimeout(): float
274 |     {
275 |         return $this->connectionTimeout;
276 |     }
277 | 
278 |     public function setConnectionTimeout(float $connectionTimeout): void
279 |     {
280 |         $this->connectionTimeout = $connectionTimeout;
281 |     }
282 | 
283 |     public function getReadTimeout(): float
284 |     {
285 |         return $this->readTimeout;
286 |     }
287 | 
288 |     public function setReadTimeout(float $readTimeout): void
289 |     {
290 |         self::assertGreaterOrEq($readTimeout, 0, 'read timeout');
291 |         $this->readTimeout = $readTimeout;
292 |     }
293 | 
294 |     public function getWriteTimeout(): float
295 |     {
296 |         return $this->writeTimeout;
297 |     }
298 | 
299 |     public function setWriteTimeout(float $writeTimeout): void
300 |     {
301 |         self::assertGreaterOrEq($writeTimeout, 0, 'write timeout');
302 |         $this->writeTimeout = $writeTimeout;
303 |     }
304 | 
305 |     public function getChannelRPCTimeout(): float
306 |     {
307 |         return $this->channelRPCTimeout;
308 |     }
309 | 
310 |     public function setChannelRPCTimeout(float $channelRPCTimeout): void
311 |     {
312 |         self::assertGreaterOrEq($channelRPCTimeout, 0, 'channel RPC timeout');
313 |         $this->channelRPCTimeout = $channelRPCTimeout;
314 |     }
315 | 
316 |     public function getHeartbeat(): int
317 |     {
318 |         return $this->heartbeat;
319 |     }
320 | 
321 |     public function setHeartbeat(int $heartbeat): void
322 |     {
323 |         self::assertGreaterOrEq($heartbeat, 0, 'heartbeat');
324 |         $this->heartbeat = $heartbeat;
325 |     }
326 | 
327 |     public function isKeepalive(): bool
328 |     {
329 |         return $this->keepalive;
330 |     }
331 | 
332 |     public function setKeepalive(bool $keepalive): void
333 |     {
334 |         $this->keepalive = $keepalive;
335 |     }
336 | 
337 |     public function isSecure(): bool
338 |     {
339 |         return $this->isSecure;
340 |     }
341 | 
342 |     public function setIsSecure(bool $isSecure): void
343 |     {
344 |         $this->isSecure = $isSecure;
345 | 
346 |         if ($this->isSecure) {
347 |             $this->networkProtocol = 'tls';
348 |             $this->sslCryptoMethod = STREAM_CRYPTO_METHOD_ANY_CLIENT;
349 |         } else {
350 |             $this->networkProtocol = 'tcp';
351 |             $this->sslCryptoMethod = null;
352 |         }
353 |     }
354 | 
355 |     /**
356 |      * @deprecated Use getSslCryptoMethod()
357 |      */
358 |     public function getNetworkProtocol(): string
359 |     {
360 |         return $this->networkProtocol;
361 |     }
362 | 
363 |     /**
364 |      * @deprecated Use setIsSecure() and setSslCryptoMethod()
365 |      */
366 |     public function setNetworkProtocol(string $networkProtocol): void
367 |     {
368 |         self::assertStringNotEmpty($networkProtocol, 'network protocol');
369 |         $this->networkProtocol = $networkProtocol;
370 |     }
371 | 
372 |     /**
373 |      * @return resource|null
374 |      */
375 |     public function getStreamContext()
376 |     {
377 |         return $this->streamContext;
378 |     }
379 | 
380 |     /**
381 |      * @param resource|null $streamContext
382 |      */
383 |     public function setStreamContext($streamContext): void
384 |     {
385 |         if ($streamContext === null) {
386 |             $this->streamContext = null;
387 |             return;
388 |         }
389 | 
390 |         if (!is_resource($streamContext) || get_resource_type($streamContext) !== 'stream-context') {
391 |             throw new InvalidArgumentException('Resource must be valid stream context');
392 |         }
393 |         $this->streamContext = $streamContext;
394 |     }
395 | 
396 |     /**
397 |      * @return int
398 |      * @since 3.2.1
399 |      */
400 |     public function getSendBufferSize(): int
401 |     {
402 |         return $this->sendBufferSize;
403 |     }
404 | 
405 |     /**
406 |      * Socket send buffer size. Set 0 to keep system default.
407 |      * @param int $sendBufferSize
408 |      * @return void
409 |      * @since 3.2.1
410 |      */
411 |     public function setSendBufferSize(int $sendBufferSize): void
412 |     {
413 |         self::assertGreaterOrEq($sendBufferSize, 0, 'sendBufferSize');
414 |         $this->sendBufferSize = $sendBufferSize;
415 |     }
416 | 
417 |     public function isSignalsDispatchEnabled(): bool
418 |     {
419 |         return $this->dispatchSignals;
420 |     }
421 | 
422 |     public function enableSignalDispatch(bool $dispatchSignals): void
423 |     {
424 |         $this->dispatchSignals = $dispatchSignals;
425 |     }
426 | 
427 |     /**
428 |      * @return string
429 |      * @deprecated
430 |      */
431 |     public function getAMQPProtocol(): string
432 |     {
433 |         return $this->amqpProtocol;
434 |     }
435 | 
436 |     /**
437 |      * @param string $protocol
438 |      * @deprecated
439 |      */
440 |     public function setAMQPProtocol(string $protocol): void
441 |     {
442 |         if ($protocol !== Wire\Constants091::VERSION && $protocol !== Wire\Constants080::VERSION) {
443 |             throw new InvalidArgumentException('AMQP protocol can be either "0.9.1" or "8.0"');
444 |         }
445 |         $this->amqpProtocol = $protocol;
446 |     }
447 | 
448 |     public function isProtocolStrictFieldsEnabled(): bool
449 |     {
450 |         return $this->protocolStrictFields;
451 |     }
452 | 
453 |     public function setProtocolStrictFields(bool $protocolStrictFields): void
454 |     {
455 |         $this->protocolStrictFields = $protocolStrictFields;
456 |     }
457 | 
458 |     public function getSslCaCert(): ?string
459 |     {
460 |         return $this->sslCaCert;
461 |     }
462 | 
463 |     public function setSslCaCert(?string $sslCaCert): void
464 |     {
465 |         $this->sslCaCert = $sslCaCert;
466 |     }
467 | 
468 |     public function getSslCaPath(): ?string
469 |     {
470 |         return $this->sslCaPath;
471 |     }
472 | 
473 |     public function setSslCaPath(?string $sslCaPath): void
474 |     {
475 |         $this->sslCaPath = $sslCaPath;
476 |     }
477 | 
478 |     public function getSslCert(): ?string
479 |     {
480 |         return $this->sslCert;
481 |     }
482 | 
483 |     public function setSslCert(?string $sslCert): void
484 |     {
485 |         $this->sslCert = $sslCert;
486 |     }
487 | 
488 |     public function getSslKey(): ?string
489 |     {
490 |         return $this->sslKey;
491 |     }
492 | 
493 |     public function setSslKey(?string $sslKey): void
494 |     {
495 |         $this->sslKey = $sslKey;
496 |     }
497 | 
498 |     public function getSslVerify(): ?bool
499 |     {
500 |         return $this->sslVerify;
501 |     }
502 | 
503 |     public function setSslVerify(?bool $sslVerify): void
504 |     {
505 |         $this->sslVerify = $sslVerify;
506 | 
507 |         if (!$this->sslVerify) {
508 |             $this->setSslVerifyName(false);
509 |         }
510 |     }
511 | 
512 |     public function getSslVerifyName(): ?bool
513 |     {
514 |         return $this->sslVerifyName;
515 |     }
516 | 
517 |     public function setSslVerifyName(?bool $sslVerifyName): void
518 |     {
519 |         $this->sslVerifyName = $sslVerifyName;
520 |     }
521 | 
522 |     public function getSslPassPhrase(): ?string
523 |     {
524 |         return $this->sslPassPhrase;
525 |     }
526 | 
527 |     public function setSslPassPhrase(?string $sslPassPhrase): void
528 |     {
529 |         $this->sslPassPhrase = $sslPassPhrase;
530 |     }
531 | 
532 |     public function getSslCiphers(): ?string
533 |     {
534 |         return $this->sslCiphers;
535 |     }
536 | 
537 |     public function setSslCiphers(?string $sslCiphers): void
538 |     {
539 |         $this->sslCiphers = $sslCiphers;
540 |     }
541 | 
542 |     public function getSslSecurityLevel(): ?int
543 |     {
544 |         return $this->sslSecurityLevel;
545 |     }
546 | 
547 |     public function setSslSecurityLevel(?int $sslSecurityLevel): void
548 |     {
549 |         $this->sslSecurityLevel = $sslSecurityLevel;
550 |     }
551 | 
552 |     public function getSslCryptoMethod(): ?int
553 |     {
554 |         return $this->sslCryptoMethod;
555 |     }
556 | 
557 |     public function setSslCryptoMethod(?int $sslCryptoMethod): void
558 |     {
559 |         $this->sslCryptoMethod = $sslCryptoMethod;
560 |     }
561 | 
562 |     public function isDebugPackets(): bool
563 |     {
564 |         return $this->debugPackets;
565 |     }
566 | 
567 |     public function setDebugPackets(bool $debugPackets): void
568 |     {
569 |         $this->debugPackets = $debugPackets;
570 |     }
571 | 
572 |     private static function assertStringNotEmpty($value, string $param): void
573 |     {
574 |         $value = trim($value);
575 |         if (empty($value)) {
576 |             throw new InvalidArgumentException(sprintf('Parameter "%s" must be non empty string', $param));
577 |         }
578 |     }
579 | 
580 |     /**
581 |      * @param int|float $value
582 |      * @param int $limit
583 |      * @param string $param
584 |      */
585 |     private static function assertGreaterOrEq($value, int $limit, string $param): void
586 |     {
587 |         if ($value < $limit) {
588 |             throw new InvalidArgumentException(sprintf('Parameter "%s" must be greater than zero', $param));
589 |         }
590 |     }
591 | 
592 |     /**
593 |      * @return string
594 |      */
595 |     public function getConnectionName(): string
596 |     {
597 |         return $this->connectionName;
598 |     }
599 | 
600 |     /**
601 |      * @param string $connectionName
602 |      */
603 |     public function setConnectionName(string $connectionName): void
604 |     {
605 |         $this->connectionName = $connectionName;
606 |     }
607 | }
608 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Connection/AMQPConnectionFactory.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | 
  3 | namespace PhpAmqpLib\Connection;
  4 | 
  5 | use LogicException;
  6 | 
  7 | /**
  8 |  * @since 3.2.0
  9 |  */
 10 | class AMQPConnectionFactory
 11 | {
 12 |     public static function create(AMQPConnectionConfig $config): AbstractConnection
 13 |     {
 14 |         if ($config->getIoType() === AMQPConnectionConfig::IO_TYPE_STREAM) {
 15 |             $connection = new AMQPStreamConnection(
 16 |                 $config->getHost(),
 17 |                 $config->getPort(),
 18 |                 $config->getUser(),
 19 |                 $config->getPassword(),
 20 |                 $config->getVhost(),
 21 |                 $config->isInsist(),
 22 |                 $config->getLoginMethod(),
 23 |                 $config->getLoginResponse(),
 24 |                 $config->getLocale(),
 25 |                 $config->getConnectionTimeout(),
 26 |                 self::getReadWriteTimeout($config),
 27 |                 self::getStreamContext($config),
 28 |                 $config->isKeepalive(),
 29 |                 $config->getHeartbeat(),
 30 |                 $config->getChannelRPCTimeout(),
 31 |                 $config
 32 |             );
 33 |         } else {
 34 |             if ($config->isSecure()) {
 35 |                 throw new LogicException('The socket connection implementation does not support secure connections.');
 36 |             }
 37 | 
 38 |             $connection = new AMQPSocketConnection(
 39 |                 $config->getHost(),
 40 |                 $config->getPort(),
 41 |                 $config->getUser(),
 42 |                 $config->getPassword(),
 43 |                 $config->getVhost(),
 44 |                 $config->isInsist(),
 45 |                 $config->getLoginMethod(),
 46 |                 $config->getLoginResponse(),
 47 |                 $config->getLocale(),
 48 |                 $config->getReadTimeout(),
 49 |                 $config->isKeepalive(),
 50 |                 $config->getWriteTimeout(),
 51 |                 $config->getHeartbeat(),
 52 |                 $config->getChannelRPCTimeout(),
 53 |                 $config
 54 |             );
 55 |         }
 56 | 
 57 |         return $connection;
 58 |     }
 59 | 
 60 |     private static function getReadWriteTimeout(AMQPConnectionConfig $config): float
 61 |     {
 62 |         return min($config->getReadTimeout(), $config->getWriteTimeout());
 63 |     }
 64 | 
 65 |     /**
 66 |      * @param AMQPConnectionConfig $config
 67 |      * @return string[]
 68 |      */
 69 |     private static function getSslOptions(AMQPConnectionConfig $config): array
 70 |     {
 71 |         return array_filter([
 72 |             'cafile' => $config->getSslCaCert(),
 73 |             'capath' => $config->getSslCaPath(),
 74 |             'local_cert' => $config->getSslCert(),
 75 |             'local_pk' => $config->getSslKey(),
 76 |             'verify_peer' => $config->getSslVerify(),
 77 |             'verify_peer_name' => $config->getSslVerifyName(),
 78 |             'passphrase' => $config->getSslPassPhrase(),
 79 |             'ciphers' => $config->getSslCiphers(),
 80 |             'security_level' => $config->getSslSecurityLevel(),
 81 |             'crypto_method' => $config->getSslCryptoMethod(),
 82 |         ], static function ($value) {
 83 |             return null !== $value;
 84 |         });
 85 |     }
 86 | 
 87 |     /**
 88 |      * @param AMQPConnectionConfig $config
 89 |      * @return resource|null
 90 |      */
 91 |     private static function getStreamContext(AMQPConnectionConfig $config)
 92 |     {
 93 |         $context = $config->getStreamContext();
 94 | 
 95 |         if ($config->isSecure()) {
 96 |             if (!$context) {
 97 |                 $context = stream_context_create();
 98 |             }
 99 |             $options = self::getSslOptions($config);
100 |             foreach ($options as $k => $v) {
101 |                 // Note: 'ssl' applies to 'tls' as well
102 |                 // https://www.php.net/manual/en/context.ssl.php
103 |                 stream_context_set_option($context, 'ssl', $k, $v);
104 |             }
105 |         }
106 | 
107 |         return $context;
108 |     }
109 | }
110 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Connection/AMQPLazyConnection.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | namespace PhpAmqpLib\Connection;
 4 | 
 5 | /**
 6 |  * @deprecated AMQPStreamConnection can be lazy too. Use AMQPConnectionFactory with AMQPConnectionConfig::setIsLazy(true)
 7 |  */
 8 | class AMQPLazyConnection extends AMQPStreamConnection
 9 | {
10 |     /**
11 |      * @inheritDoc
12 |      */
13 |     public function connectOnConstruct(): bool
14 |     {
15 |         return false;
16 |     }
17 | 
18 |     /**
19 |      * @param string[][] $hosts
20 |      * @param string[] $options
21 |      * @return self
22 |      * @throws \Exception
23 |      * @deprecated Use ConnectionFactory
24 |      */
25 |     public static function create_connection($hosts, $options = array())
26 |     {
27 |         if (count($hosts) > 1) {
28 |             throw new \RuntimeException('Lazy connection does not support multiple hosts');
29 |         }
30 | 
31 |         return parent::create_connection($hosts, $options);
32 |     }
33 | }
34 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Connection/AMQPLazySSLConnection.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | namespace PhpAmqpLib\Connection;
 4 | 
 5 | /**
 6 |  * @deprecated AMQPLazySSLConnection can be lazy too. Use AMQPConnectionFactory with AMQPConnectionConfig::setIsLazy(true)
 7 |  */
 8 | class AMQPLazySSLConnection extends AMQPSSLConnection
 9 | {
10 |     /**
11 |      * @inheritDoc
12 |      */
13 |     public function connectOnConstruct(): bool
14 |     {
15 |         return false;
16 |     }
17 | 
18 |     /**
19 |      * @param string[][] $hosts
20 |      * @param string[] $options
21 |      * @return self
22 |      * @throws \Exception
23 |      * @deprecated Use ConnectionFactory
24 |      */
25 |     public static function create_connection($hosts, $options = array())
26 |     {
27 |         if (count($hosts) > 1) {
28 |             throw new \RuntimeException('Lazy connection does not support multiple hosts');
29 |         }
30 | 
31 |         return parent::create_connection($hosts, $options);
32 |     }
33 | }
34 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Connection/AMQPLazySocketConnection.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | namespace PhpAmqpLib\Connection;
 4 | 
 5 | /**
 6 |  * @deprecated AMQPSocketConnection can be lazy too. Use AMQPConnectionFactory with AMQPConnectionConfig::setIsLazy(true)
 7 |  */
 8 | class AMQPLazySocketConnection extends AMQPSocketConnection
 9 | {
10 |     /**
11 |      * @inheritDoc
12 |      */
13 |     public function connectOnConstruct(): bool
14 |     {
15 |         return false;
16 |     }
17 | 
18 |     /**
19 |      * @param string[][] $hosts
20 |      * @param string[] $options
21 |      * @return self
22 |      * @throws \Exception
23 |      * @deprecated Use ConnectionFactory
24 |      */
25 |     public static function create_connection($hosts, $options = array())
26 |     {
27 |         if (count($hosts) > 1) {
28 |             throw new \RuntimeException('Lazy connection does not support multiple hosts');
29 |         }
30 | 
31 |         return parent::create_connection($hosts, $options);
32 |     }
33 | }
34 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Connection/AMQPSSLConnection.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | namespace PhpAmqpLib\Connection;
 4 | 
 5 | /**
 6 |  * @deprecated Use AMQPConnectionFactory with AMQPConnectionConfig::setIsSecure(true) and AMQPConnectionConfig::setSsl* methods.
 7 |  */
 8 | class AMQPSSLConnection extends AMQPStreamConnection
 9 | {
10 |     /**
11 |      * @param string $host
12 |      * @param int $port
13 |      * @param string $user
14 |      * @param string $password
15 |      * @param string $vhost
16 |      * @param array $ssl_options
17 |      * @param array $options
18 |      * @param AMQPConnectionConfig|null $config
19 |      * @throws \Exception
20 |      */
21 |     public function __construct(
22 |         $host,
23 |         $port,
24 |         $user,
25 |         $password,
26 |         $vhost = '/',
27 |         $ssl_options = array(),
28 |         $options = array(),
29 |         ?AMQPConnectionConfig $config = null
30 |     ) {
31 |         trigger_error('AMQPSSLConnection is deprecated and will be removed in version 4 of php-amqplib', E_USER_DEPRECATED);
32 |         $ssl_context = null;
33 |         if (!empty($ssl_options)) {
34 |             $ssl_context = $this->createSslContext($ssl_options);
35 |         }
36 | 
37 |         parent::__construct(
38 |             $host,
39 |             $port,
40 |             $user,
41 |             $password,
42 |             $vhost,
43 |             isset($options['insist']) ? $options['insist'] : false,
44 |             isset($options['login_method']) ? $options['login_method'] : 'AMQPLAIN',
45 |             isset($options['login_response']) ? $options['login_response'] : null,
46 |             isset($options['locale']) ? $options['locale'] : 'en_US',
47 |             isset($options['connection_timeout']) ? $options['connection_timeout'] : 3,
48 |             isset($options['read_write_timeout']) ? $options['read_write_timeout'] : 130,
49 |             $ssl_context,
50 |             isset($options['keepalive']) ? $options['keepalive'] : false,
51 |             isset($options['heartbeat']) ? $options['heartbeat'] : 0,
52 |             isset($options['channel_rpc_timeout']) ? $options['channel_rpc_timeout'] : 0.0,
53 |             $config
54 |         );
55 |     }
56 | 
57 |     /**
58 |      * @deprecated Use AmqpConnectionFactory
59 |      * @throws \Exception
60 |      */
61 |     public static function try_create_connection($host, $port, $user, $password, $vhost, $options)
62 |     {
63 |         $ssl_options = isset($options['ssl_options']) ? $options['ssl_options'] : [];
64 |         return new static($host, $port, $user, $password, $vhost, $ssl_options, $options);
65 |     }
66 | 
67 |     /**
68 |      * @param array $options
69 |      * @return resource
70 |      */
71 |     private function createSslContext($options)
72 |     {
73 |         $ssl_context = stream_context_create();
74 |         foreach ($options as $k => $v) {
75 |             // Note: 'ssl' applies to 'tls' as well
76 |             // https://www.php.net/manual/en/context.ssl.php
77 |             stream_context_set_option($ssl_context, 'ssl', $k, $v);
78 |         }
79 | 
80 |         return $ssl_context;
81 |     }
82 | }
83 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Connection/AMQPSocketConnection.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | 
  3 | namespace PhpAmqpLib\Connection;
  4 | 
  5 | use PhpAmqpLib\Wire\IO\SocketIO;
  6 | 
  7 | class AMQPSocketConnection extends AbstractConnection
  8 | {
  9 |     /**
 10 |      * @param string $host
 11 |      * @param int $port
 12 |      * @param string $user
 13 |      * @param string $password
 14 |      * @param string $vhost
 15 |      * @param bool $insist
 16 |      * @param string $login_method
 17 |      * @param null $login_response @deprecated
 18 |      * @param string $locale
 19 |      * @param int|float $read_timeout
 20 |      * @param bool $keepalive
 21 |      * @param int $write_timeout
 22 |      * @param int $heartbeat
 23 |      * @param float $channel_rpc_timeout
 24 |      * @param AMQPConnectionConfig|null $config
 25 |      * @throws \Exception
 26 |      */
 27 |     public function __construct(
 28 |         $host,
 29 |         $port,
 30 |         $user,
 31 |         $password,
 32 |         $vhost = '/',
 33 |         $insist = false,
 34 |         $login_method = 'AMQPLAIN',
 35 |         $login_response = null,
 36 |         $locale = 'en_US',
 37 |         $read_timeout = 3,
 38 |         $keepalive = false,
 39 |         $write_timeout = 3,
 40 |         $heartbeat = 0,
 41 |         $channel_rpc_timeout = 0.0,
 42 |         ?AMQPConnectionConfig $config = null
 43 |     ) {
 44 |         if ($channel_rpc_timeout > $read_timeout) {
 45 |             throw new \InvalidArgumentException('channel RPC timeout must not be greater than I/O read timeout');
 46 |         }
 47 | 
 48 |         $io = new SocketIO($host, $port, $read_timeout, $keepalive, $write_timeout, $heartbeat, $config);
 49 | 
 50 |         parent::__construct(
 51 |             $user,
 52 |             $password,
 53 |             $vhost,
 54 |             $insist,
 55 |             $login_method,
 56 |             $login_response,
 57 |             $locale,
 58 |             $io,
 59 |             $heartbeat,
 60 |             max($read_timeout, $write_timeout),
 61 |             $channel_rpc_timeout,
 62 |             $config
 63 |         );
 64 |     }
 65 | 
 66 |     /**
 67 |      * @deprecated Use AmqpConnectionFactory
 68 |      * @throws \Exception
 69 |      */
 70 |     protected static function try_create_connection($host, $port, $user, $password, $vhost, $options)
 71 |     {
 72 |         $insist = isset($options['insist']) ?
 73 |                         $options['insist'] : false;
 74 |         $login_method = isset($options['login_method']) ?
 75 |                               $options['login_method'] : 'AMQPLAIN';
 76 |         $login_response = isset($options['login_response']) ?
 77 |                                 $options['login_response'] : null;
 78 |         $locale = isset($options['locale']) ?
 79 |                         $options['locale'] : 'en_US';
 80 |         $read_timeout = isset($options['read_timeout']) ?
 81 |                               $options['read_timeout'] : 3;
 82 |         $keepalive = isset($options['keepalive']) ?
 83 |                            $options['keepalive'] : false;
 84 |         $write_timeout = isset($options['write_timeout']) ?
 85 |                                $options['write_timeout'] : 3;
 86 |         $heartbeat = isset($options['heartbeat']) ?
 87 |                            $options['heartbeat'] : 0;
 88 |         $channel_rpc_timeout = isset($options['channel_rpc_timeout']) ?
 89 |                                     $options['channel_rpc_timeout'] : 0.0;
 90 |         return new static(
 91 |             $host,
 92 |             $port,
 93 |             $user,
 94 |             $password,
 95 |             $vhost,
 96 |             $insist,
 97 |             $login_method,
 98 |             $login_response,
 99 |             $locale,
100 |             $read_timeout,
101 |             $keepalive,
102 |             $write_timeout,
103 |             $heartbeat,
104 |             $channel_rpc_timeout
105 |         );
106 |     }
107 | }
108 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Connection/AMQPStreamConnection.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | 
  3 | namespace PhpAmqpLib\Connection;
  4 | 
  5 | use PhpAmqpLib\Wire\IO\StreamIO;
  6 | 
  7 | class AMQPStreamConnection extends AbstractConnection
  8 | {
  9 |     /**
 10 |      * @param string $host
 11 |      * @param int $port
 12 |      * @param string $user
 13 |      * @param string $password
 14 |      * @param string $vhost
 15 |      * @param bool $insist
 16 |      * @param string $login_method
 17 |      * @param null $login_response @deprecated
 18 |      * @param string $locale
 19 |      * @param float $connection_timeout
 20 |      * @param float $read_write_timeout
 21 |      * @param resource|array|null $context
 22 |      * @param bool $keepalive
 23 |      * @param int $heartbeat
 24 |      * @param float $channel_rpc_timeout
 25 |      * @param string|AMQPConnectionConfig|null $ssl_protocol @deprecated
 26 |      * @param AMQPConnectionConfig|null $config
 27 |      * @throws \Exception
 28 |      */
 29 |     public function __construct(
 30 |         $host,
 31 |         $port,
 32 |         $user,
 33 |         $password,
 34 |         $vhost = '/',
 35 |         $insist = false,
 36 |         $login_method = 'AMQPLAIN',
 37 |         $login_response = null,
 38 |         $locale = 'en_US',
 39 |         $connection_timeout = 3.0,
 40 |         $read_write_timeout = 3.0,
 41 |         $context = null,
 42 |         $keepalive = false,
 43 |         $heartbeat = 0,
 44 |         $channel_rpc_timeout = 0.0,
 45 |         $ssl_protocol = null,
 46 |         ?AMQPConnectionConfig $config = null
 47 |     ) {
 48 |         if ($ssl_protocol !== null && $ssl_protocol instanceof AMQPConnectionConfig === false) {
 49 |             trigger_error(
 50 |                 '$ssl_protocol parameter is deprecated, use stream_context_set_option($context, \'ssl\', \'crypto_method\', $ssl_protocol) instead (see https://www.php.net/manual/en/function.stream-socket-enable-crypto.php for possible values)',
 51 |                 E_USER_DEPRECATED
 52 |             );
 53 |         } elseif ($ssl_protocol instanceof AMQPConnectionConfig) {
 54 |             $config = $ssl_protocol;
 55 |         }
 56 | 
 57 |         if ($channel_rpc_timeout > $read_write_timeout) {
 58 |             throw new \InvalidArgumentException('channel RPC timeout must not be greater than I/O read-write timeout');
 59 |         }
 60 | 
 61 |         $io = new StreamIO(
 62 |             $host,
 63 |             $port,
 64 |             $connection_timeout,
 65 |             $read_write_timeout,
 66 |             $context,
 67 |             $keepalive,
 68 |             $heartbeat
 69 |         );
 70 | 
 71 |         parent::__construct(
 72 |             $user,
 73 |             $password,
 74 |             $vhost,
 75 |             $insist,
 76 |             $login_method,
 77 |             $login_response,
 78 |             $locale,
 79 |             $io,
 80 |             $heartbeat,
 81 |             $connection_timeout,
 82 |             $channel_rpc_timeout,
 83 |             $config
 84 |         );
 85 | 
 86 |         // save the params for the use of __clone, this will overwrite the parent
 87 |         $this->construct_params = func_get_args();
 88 |     }
 89 | 
 90 |     /**
 91 |      * @deprecated Use AmqpConnectionFactory
 92 |      * @throws \Exception
 93 |      */
 94 |     protected static function try_create_connection($host, $port, $user, $password, $vhost, $options)
 95 |     {
 96 |         $insist = isset($options['insist']) ?
 97 |                         $options['insist'] : false;
 98 |         $login_method = isset($options['login_method']) ?
 99 |                               $options['login_method'] : 'AMQPLAIN';
100 |         $login_response = isset($options['login_response']) ?
101 |                                 $options['login_response'] : null;
102 |         $locale = isset($options['locale']) ?
103 |                         $options['locale'] : 'en_US';
104 |         $connection_timeout = isset($options['connection_timeout']) ?
105 |                                     $options['connection_timeout'] : 3.0;
106 |         $read_write_timeout = isset($options['read_write_timeout']) ?
107 |                                     $options['read_write_timeout'] : 3.0;
108 |         $context = isset($options['context']) ?
109 |                          $options['context'] : null;
110 |         $keepalive = isset($options['keepalive']) ?
111 |                            $options['keepalive'] : false;
112 |         $heartbeat = isset($options['heartbeat']) ?
113 |                            $options['heartbeat'] : 60;
114 |         $channel_rpc_timeout = isset($options['channel_rpc_timeout']) ?
115 |                                     $options['channel_rpc_timeout'] : 0.0;
116 |         return new static(
117 |             $host,
118 |             $port,
119 |             $user,
120 |             $password,
121 |             $vhost,
122 |             $insist,
123 |             $login_method,
124 |             $login_response,
125 |             $locale,
126 |             $connection_timeout,
127 |             $read_write_timeout,
128 |             $context,
129 |             $keepalive,
130 |             $heartbeat,
131 |             $channel_rpc_timeout
132 |         );
133 |     }
134 | }
135 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Connection/Heartbeat/AbstractSignalHeartbeatSender.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | namespace PhpAmqpLib\Connection\Heartbeat;
 4 | 
 5 | use PhpAmqpLib\Connection\AbstractConnection;
 6 | use PhpAmqpLib\Exception\AMQPRuntimeException;
 7 | 
 8 | /**
 9 |  * Manages pcntl-based heartbeat sending for a {@link AbstractConnection}.
10 |  */
11 | abstract class AbstractSignalHeartbeatSender
12 | {
13 |     /**
14 |      * @var AbstractConnection|null
15 |      */
16 |     protected $connection;
17 | 
18 |     /**
19 |      * @var bool
20 |      */
21 |     protected $wasActive = false;
22 | 
23 |     /**
24 |      * @param AbstractConnection $connection
25 |      * @throws AMQPRuntimeException
26 |      */
27 |     public function __construct(AbstractConnection $connection)
28 |     {
29 |         if (!$this->isSupported()) {
30 |             throw new AMQPRuntimeException('Signal-based heartbeat sender is unsupported');
31 |         }
32 | 
33 |         $this->connection = $connection;
34 |     }
35 | 
36 |     public function __destruct()
37 |     {
38 |         $this->unregister();
39 |     }
40 | 
41 |     /**
42 |      * @return bool
43 |      */
44 |     protected function isSupported(): bool
45 |     {
46 |         return extension_loaded('pcntl')
47 |                && function_exists('pcntl_async_signals')
48 |                && (defined('AMQP_WITHOUT_SIGNALS') ? !AMQP_WITHOUT_SIGNALS : true);
49 |     }
50 | 
51 |     /**
52 |      * Starts the heartbeats
53 |      */
54 |     abstract public function register(): void;
55 | 
56 |     /**
57 |      * Stops the heartbeats.
58 |      */
59 |     abstract public function unregister(): void;
60 | 
61 |     /**
62 |      * Handles the heartbeat when a signal interrupt is received
63 |      *
64 |      * @param int $interval
65 |      */
66 |     protected function handleSignal(int $interval): void
67 |     {
68 |         if (!$this->connection) {
69 |             return;
70 |         }
71 | 
72 |         // Support for lazy connections
73 |         if (!$this->wasActive && $this->connection->isConnected()) {
74 |             $this->wasActive = true;
75 |         }
76 | 
77 |         if (!$this->wasActive) {
78 |             return;
79 |         }
80 | 
81 |         if (!$this->connection->isConnected()) {
82 |             $this->unregister();
83 |             return;
84 |         }
85 | 
86 |         if ($this->connection->isWriting()) {
87 |             return;
88 |         }
89 | 
90 |         if (time() > ($this->connection->getLastActivity() + $interval)) {
91 |             $this->connection->checkHeartBeat();
92 |         }
93 |     }
94 | }
95 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Connection/Heartbeat/PCNTLHeartbeatSender.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | namespace PhpAmqpLib\Connection\Heartbeat;
 4 | 
 5 | use PhpAmqpLib\Exception\AMQPRuntimeException;
 6 | 
 7 | /**
 8 |  * @see AbstractSignalHeartbeatSender
 9 |  *
10 |  * This version of a signal based heartbeat sendler relies on using SIGALRM and uses the OS to trigger an alarm
11 |  * after a given time.
12 |  */
13 | final class PCNTLHeartbeatSender extends AbstractSignalHeartbeatSender
14 | {
15 |     public function register(): void
16 |     {
17 |         if (!$this->connection) {
18 |             throw new AMQPRuntimeException('Unable to re-register heartbeat sender');
19 |         }
20 | 
21 |         $timeout = $this->connection->getHeartbeat();
22 | 
23 |         if ($timeout > 0) {
24 |             $interval = (int)ceil($timeout / 2);
25 |             pcntl_async_signals(true);
26 |             $this->registerListener($interval);
27 |             pcntl_alarm($interval);
28 |         }
29 |     }
30 | 
31 |     public function unregister(): void
32 |     {
33 |         $this->connection = null;
34 |         // restore default signal handler
35 |         pcntl_signal(SIGALRM, SIG_IGN);
36 |     }
37 | 
38 |     private function registerListener(int $interval): void
39 |     {
40 |         pcntl_signal(SIGALRM, function () use ($interval) {
41 |             $this->handleSignal($interval);
42 |             if ($this->connection) {
43 |                 pcntl_alarm($interval);
44 |             }
45 |         }, true);
46 |     }
47 | }
48 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Connection/Heartbeat/SIGHeartbeatSender.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | namespace PhpAmqpLib\Connection\Heartbeat;
 3 | 
 4 | use PhpAmqpLib\Connection\AbstractConnection;
 5 | use PhpAmqpLib\Exception\AMQPRuntimeException;
 6 | 
 7 | /**
 8 |  * @see AbstractSignalHeartbeatSender
 9 |  * @since 3.2.0
10 |  *
11 |  * This version of a signal based heartbeat sender allows using any signal number. It forks the current process
12 |  * to create a child process that periodically sends a signal to the parent process.
13 |  * The default signal used is SIGUSR1
14 |  */
15 | final class SIGHeartbeatSender extends AbstractSignalHeartbeatSender
16 | {
17 |     /**
18 |      * @var int the UNIX signal to be used for managing heartbeats
19 |      */
20 |     private $signal;
21 | 
22 |     /**
23 |      * @var int the PID (process ID) of the child process sending regular signals to manage heartbeats
24 |      */
25 |     private $childPid;
26 | 
27 |     /**
28 |      * @param AbstractConnection $connection
29 |      * @param int $signal
30 |      * @throws AMQPRuntimeException
31 |      */
32 |     public function __construct(AbstractConnection $connection, int $signal = SIGUSR1)
33 |     {
34 |         parent::__construct($connection);
35 |         $this->signal = $signal;
36 |     }
37 | 
38 |     public function register(): void
39 |     {
40 |         if (!$this->connection) {
41 |             throw new AMQPRuntimeException('Unable to re-register heartbeat sender');
42 |         }
43 | 
44 |         $timeout = $this->connection->getHeartbeat();
45 | 
46 |         if ($timeout > 0) {
47 |             $interval = (int)ceil($timeout / 2);
48 |             $this->registerListener($interval);
49 |         }
50 |     }
51 | 
52 |     public function unregister(): void
53 |     {
54 |         $this->connection = null;
55 |         // restore default signal handler
56 |         pcntl_signal($this->signal, SIG_IGN);
57 |         if ($this->childPid > 0) {
58 |             posix_kill($this->childPid, SIGKILL);
59 |             pcntl_waitpid($this->childPid, $status);
60 |         }
61 |         $this->childPid = 0;
62 |     }
63 | 
64 |     private function registerListener(int $interval): void
65 |     {
66 |         pcntl_async_signals(true);
67 |         $this->periodicAlarm($interval);
68 |         pcntl_signal($this->signal, function () use ($interval) {
69 |             $this->handleSignal($interval);
70 |         });
71 |     }
72 | 
73 |     /**
74 |      * Forks the current process to create a child process that will send periodic signals to the parent
75 |      *
76 |      * @param int $interval
77 |      */
78 |     private function periodicAlarm(int $interval): void
79 |     {
80 |         $parent = getmypid();
81 |         $pid = pcntl_fork();
82 |         if(!$pid) {
83 |             while (true){
84 |                 $slept = sleep($interval);
85 |                 if ($slept !== 0) {
86 |                     // interupted by signal from parent, exit immediately
87 |                     die;
88 |                 }
89 |                 posix_kill($parent, $this->signal);
90 |             }
91 |         } else {
92 |             $this->childPid = $pid;
93 |         }
94 |     }
95 | }
96 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Exception/AMQPBasicCancelException.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | namespace PhpAmqpLib\Exception;
 4 | 
 5 | class AMQPBasicCancelException extends \Exception implements AMQPExceptionInterface
 6 | {
 7 |     /**
 8 |      * @var string
 9 |      * @internal Use getter getConsumerTag()
10 |      */
11 |     public $consumerTag;
12 | 
13 |     /**
14 |      * @param string $consumerTag
15 |      */
16 |     public function __construct($consumerTag)
17 |     {
18 |         parent::__construct('Channel was canceled');
19 |         $this->consumerTag = $consumerTag;
20 |     }
21 | 
22 |     /**
23 |      * @return string
24 |      */
25 |     public function getConsumerTag()
26 |     {
27 |         return $this->consumerTag;
28 |     }
29 | }
30 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Exception/AMQPChannelClosedException.php:
--------------------------------------------------------------------------------
1 | <?php
2 | 
3 | namespace PhpAmqpLib\Exception;
4 | 
5 | class AMQPChannelClosedException extends AMQPRuntimeException
6 | {
7 | }
8 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Exception/AMQPConnectionBlockedException.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | namespace PhpAmqpLib\Exception;
 4 | 
 5 | class AMQPConnectionBlockedException extends AMQPRuntimeException
 6 | {
 7 |     public function __construct($message = '', $code = 0, $previous = null)
 8 |     {
 9 |         if (empty($message)) {
10 |             $message = 'Connection is blocked due to low resources';
11 |         }
12 |         parent::__construct($message, $code, $previous);
13 |     }
14 | }
15 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Exception/AMQPConnectionClosedException.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | namespace PhpAmqpLib\Exception;
 4 | 
 5 | /**
 6 |  * When connection was closed by server, proxy or some tunnel due to timeout or network issue.
 7 |  */
 8 | class AMQPConnectionClosedException extends AMQPRuntimeException
 9 | {
10 | }
11 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Exception/AMQPDataReadException.php:
--------------------------------------------------------------------------------
1 | <?php
2 | 
3 | namespace PhpAmqpLib\Exception;
4 | 
5 | class AMQPDataReadException extends AMQPRuntimeException
6 | {
7 | }
8 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Exception/AMQPEmptyDeliveryTagException.php:
--------------------------------------------------------------------------------
1 | <?php
2 | 
3 | namespace PhpAmqpLib\Exception;
4 | 
5 | class AMQPEmptyDeliveryTagException extends AMQPRuntimeException
6 | {
7 | }
8 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Exception/AMQPExceptionInterface.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | namespace PhpAmqpLib\Exception;
 4 | 
 5 | use Throwable;
 6 | 
 7 | interface AMQPExceptionInterface extends Throwable
 8 | {
 9 | }
10 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Exception/AMQPHeartbeatMissedException.php:
--------------------------------------------------------------------------------
1 | <?php
2 | 
3 | namespace PhpAmqpLib\Exception;
4 | 
5 | class AMQPHeartbeatMissedException extends AMQPConnectionClosedException
6 | {
7 | }
8 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Exception/AMQPIOException.php:
--------------------------------------------------------------------------------
1 | <?php
2 | 
3 | namespace PhpAmqpLib\Exception;
4 | 
5 | class AMQPIOException extends \Exception implements AMQPExceptionInterface
6 | {
7 | }
8 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Exception/AMQPIOWaitException.php:
--------------------------------------------------------------------------------
1 | <?php
2 | 
3 | namespace PhpAmqpLib\Exception;
4 | 
5 | class AMQPIOWaitException extends AMQPRuntimeException
6 | {
7 | }
8 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Exception/AMQPInvalidArgumentException.php:
--------------------------------------------------------------------------------
1 | <?php
2 | 
3 | namespace PhpAmqpLib\Exception;
4 | 
5 | class AMQPInvalidArgumentException extends \RuntimeException implements AMQPExceptionInterface
6 | {
7 | }
8 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Exception/AMQPInvalidFrameException.php:
--------------------------------------------------------------------------------
1 | <?php
2 | 
3 | namespace PhpAmqpLib\Exception;
4 | 
5 | class AMQPInvalidFrameException extends AMQPRuntimeException
6 | {
7 | }
8 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Exception/AMQPLogicException.php:
--------------------------------------------------------------------------------
1 | <?php
2 | 
3 | namespace PhpAmqpLib\Exception;
4 | 
5 | class AMQPLogicException extends \LogicException implements AMQPExceptionInterface
6 | {
7 | 
8 | }
9 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Exception/AMQPNoDataException.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | namespace PhpAmqpLib\Exception;
 4 | 
 5 | /**
 6 |  * Used mostly in non-blocking methods when no data is ready for processing.
 7 |  */
 8 | class AMQPNoDataException extends AMQPRuntimeException
 9 | {
10 | }
11 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Exception/AMQPNotImplementedException.php:
--------------------------------------------------------------------------------
1 | <?php
2 | 
3 | namespace PhpAmqpLib\Exception;
4 | 
5 | class AMQPNotImplementedException extends AMQPRuntimeException
6 | {
7 | }
8 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Exception/AMQPOutOfBoundsException.php:
--------------------------------------------------------------------------------
1 | <?php
2 | 
3 | namespace PhpAmqpLib\Exception;
4 | 
5 | class AMQPOutOfBoundsException extends \OutOfBoundsException implements AMQPExceptionInterface
6 | {
7 | }
8 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Exception/AMQPOutOfRangeException.php:
--------------------------------------------------------------------------------
1 | <?php
2 | 
3 | namespace PhpAmqpLib\Exception;
4 | 
5 | class AMQPOutOfRangeException extends \OutOfRangeException implements AMQPExceptionInterface
6 | {
7 | 
8 | }
9 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Exception/AMQPProtocolChannelException.php:
--------------------------------------------------------------------------------
1 | <?php
2 | 
3 | namespace PhpAmqpLib\Exception;
4 | 
5 | class AMQPProtocolChannelException extends AMQPProtocolException
6 | {
7 | }
8 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Exception/AMQPProtocolException.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | namespace PhpAmqpLib\Exception;
 4 | 
 5 | class AMQPProtocolException extends \Exception implements AMQPExceptionInterface
 6 | {
 7 |     /** @var int */
 8 |     public $amqp_reply_code;
 9 | 
10 |     /** @var string */
11 |     public $amqp_reply_text;
12 | 
13 |     /** @var int[] */
14 |     public $amqp_method_sig;
15 | 
16 |     /** @var array */
17 |     public $args;
18 | 
19 |     /**
20 |      * @param int $reply_code
21 |      * @param string $reply_text
22 |      * @param int[] $method_sig
23 |      */
24 |     public function __construct($reply_code, $reply_text, $method_sig)
25 |     {
26 |         parent::__construct($reply_text, $reply_code);
27 | 
28 |         $this->amqp_reply_code = $reply_code; // redundant, but kept for BC
29 |         $this->amqp_reply_text = $reply_text; // redundant, but kept for BC
30 |         $this->amqp_method_sig = $method_sig;
31 | 
32 |         $this->args = array($reply_code, $reply_text, $method_sig);
33 |     }
34 | }
35 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Exception/AMQPRuntimeException.php:
--------------------------------------------------------------------------------
1 | <?php
2 | 
3 | namespace PhpAmqpLib\Exception;
4 | 
5 | class AMQPRuntimeException extends \RuntimeException implements AMQPExceptionInterface
6 | {
7 | }
8 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Exception/AMQPSocketException.php:
--------------------------------------------------------------------------------
1 | <?php
2 | 
3 | namespace PhpAmqpLib\Exception;
4 | 
5 | class AMQPSocketException extends AMQPRuntimeException
6 | {
7 | }
8 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Exception/AMQPTimeoutException.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | namespace PhpAmqpLib\Exception;
 4 | 
 5 | class AMQPTimeoutException extends \RuntimeException implements AMQPExceptionInterface
 6 | {
 7 |     /**
 8 |      * @var int|float|null
 9 |      */
10 |     private $timeout;
11 | 
12 |     public function __construct($message = '', $timeout = 0, $code = 0, ?\Exception $previous = null)
13 |     {
14 |         parent::__construct($message, $code, $previous);
15 |         $this->timeout = $timeout;
16 |     }
17 | 
18 |     /**
19 |      * @param int|float|null $timeout
20 |      * @param int $code
21 |      * @return self
22 |      */
23 |     public static function writeTimeout($timeout, $code = 0)
24 |     {
25 |         return new self('Error sending data. Connection timed out.', $timeout, $code);
26 |     }
27 | 
28 |     /**
29 |      * @return int|float|null
30 |      */
31 |     public function getTimeout()
32 |     {
33 |         return $this->timeout;
34 |     }
35 | }
36 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Exchange/AMQPExchangeType.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | namespace PhpAmqpLib\Exchange;
 4 | 
 5 | final class AMQPExchangeType
 6 | {
 7 |     const DIRECT = 'direct';
 8 |     const FANOUT = 'fanout';
 9 |     const TOPIC = 'topic';
10 |     const HEADERS = 'headers';
11 | }
12 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Helper/Assert.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | namespace PhpAmqpLib\Helper;
 4 | 
 5 | use InvalidArgumentException;
 6 | 
 7 | class Assert
 8 | {
 9 |     /**
10 |      * @param mixed $argument
11 |      * @throws \InvalidArgumentException
12 |      */
13 |     public static function isCallable($argument)
14 |     {
15 |         if (!is_callable($argument)) {
16 |             throw new InvalidArgumentException(sprintf(
17 |                 'Given argument "%s" should be callable. %s type was given.',
18 |                 $argument,
19 |                 gettype($argument)
20 |             ));
21 |         }
22 |     }
23 | }
24 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Helper/BigInteger.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | namespace PhpAmqpLib\Helper;
 4 | 
 5 | if (class_exists('phpseclib\Math\BigInteger')) {
 6 |     class BigInteger extends \phpseclib\Math\BigInteger
 7 |     {
 8 |     }
 9 | } elseif (class_exists('phpseclib3\Math\BigInteger')) {
10 |     class BigInteger extends \phpseclib3\Math\BigInteger
11 |     {
12 |     }
13 | } else {
14 |     throw new \RuntimeException('Cannot find supported phpseclib/phpseclib library');
15 | }
16 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Helper/DebugHelper.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | 
  3 | namespace PhpAmqpLib\Helper;
  4 | 
  5 | use PhpAmqpLib\Wire\Constants;
  6 | 
  7 | class DebugHelper
  8 | {
  9 |     /**
 10 |      * @var bool
 11 |      */
 12 |     protected $debug;
 13 | 
 14 |     /**
 15 |      * @var resource
 16 |      */
 17 |     protected $debug_output;
 18 | 
 19 |     /**
 20 |      * @var Constants
 21 |      */
 22 |     protected $constants;
 23 | 
 24 |     /**
 25 |      * @param Constants $constants
 26 |      */
 27 |     public function __construct(Constants $constants)
 28 |     {
 29 |         $this->debug = defined('AMQP_DEBUG') ? AMQP_DEBUG : false;
 30 |         if (defined('AMQP_DEBUG_OUTPUT')) {
 31 |             $this->debug_output = AMQP_DEBUG_OUTPUT;
 32 |         } else {
 33 |             $this->debug_output = fopen('php://output', 'wb');
 34 |         }
 35 |         $this->constants = $constants;
 36 |     }
 37 | 
 38 |     /**
 39 |      * @param string $msg
 40 |      */
 41 |     public function debug_msg($msg)
 42 |     {
 43 |         if ($this->debug) {
 44 |             $this->print_msg($msg);
 45 |         }
 46 |     }
 47 | 
 48 |     /**
 49 |      * @param array|null $allowed_methods
 50 |      */
 51 |     public function debug_allowed_methods($allowed_methods)
 52 |     {
 53 |         if ($this->debug) {
 54 |             if ($allowed_methods) {
 55 |                 $msg = 'waiting for ' . implode(', ', $allowed_methods);
 56 |             } else {
 57 |                 $msg = 'waiting for any method';
 58 |             }
 59 |             $this->debug_msg($msg);
 60 |         }
 61 |     }
 62 | 
 63 |     /**
 64 |      * @param string|array $method_sig
 65 |      */
 66 |     public function debug_method_signature1($method_sig)
 67 |     {
 68 |         $this->debug_method_signature('< %s:', $method_sig);
 69 |     }
 70 | 
 71 |     /**
 72 |      * @param string $msg
 73 |      * @param string|array $method_sig
 74 |      */
 75 |     public function debug_method_signature($msg, $method_sig)
 76 |     {
 77 |         if ($this->debug) {
 78 |             $constants = $this->constants;
 79 |             $methods = $constants::$GLOBAL_METHOD_NAMES;
 80 |             $key = MiscHelper::methodSig($method_sig);
 81 |             $this->debug_msg(sprintf($msg . ': %s', $key, $methods[$key]));
 82 |         }
 83 |     }
 84 | 
 85 |     /**
 86 |      * @param string $data
 87 |      */
 88 |     public function debug_hexdump($data)
 89 |     {
 90 |         if ($this->debug) {
 91 |             $this->debug_msg(
 92 |                 sprintf(
 93 |                     '< [hex]: %s%s',
 94 |                     PHP_EOL,
 95 |                     MiscHelper::hexdump($data, $htmloutput = false, $uppercase = true, $return = true)
 96 |                 )
 97 |             );
 98 |         }
 99 |     }
100 | 
101 |     /**
102 |      * @param int $version_major
103 |      * @param int $version_minor
104 |      * @param array $server_properties
105 |      * @param array $mechanisms
106 |      * @param array $locales
107 |      */
108 |     public function debug_connection_start($version_major, $version_minor, $server_properties, $mechanisms, $locales)
109 |     {
110 |         if ($this->debug) {
111 |             $this->debug_msg(
112 |                 sprintf(
113 |                     'Start from server, version: %d.%d, properties: %s, mechanisms: %s, locales: %s',
114 |                     $version_major,
115 |                     $version_minor,
116 |                     MiscHelper::dump_table($server_properties),
117 |                     implode(', ', $mechanisms),
118 |                     implode(', ', $locales)
119 |                 )
120 |             );
121 |         }
122 |     }
123 | 
124 |     /**
125 |      * @param string $s
126 |      */
127 |     protected function print_msg($s)
128 |     {
129 |         fwrite($this->debug_output, $s . PHP_EOL);
130 |     }
131 | }
132 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Helper/MiscHelper.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | 
  3 | namespace PhpAmqpLib\Helper;
  4 | 
  5 | class MiscHelper
  6 | {
  7 |     /**
  8 |      * @param string|array $a
  9 |      * @return string
 10 |      */
 11 |     public static function methodSig($a)
 12 |     {
 13 |         if (is_string($a)) {
 14 |             return $a;
 15 |         }
 16 | 
 17 |         return sprintf('%d,%d', $a[0], $a[1]);
 18 |     }
 19 | 
 20 |     /**
 21 |      * Gets a number (either int or float) and returns an array containing its integer part as first element and its
 22 |      * decimal part multiplied by 10^6. Useful for some PHP stream functions that need seconds and microseconds as
 23 |      * different arguments
 24 |      *
 25 |      * @param int|float $number
 26 |      * @return int[]
 27 |      */
 28 |     public static function splitSecondsMicroseconds($number)
 29 |     {
 30 |         return array((int)floor($number), (int)(fmod($number, 1) * 1000000));
 31 |     }
 32 | 
 33 |     /**
 34 |      * View any string as a hexdump.
 35 |      *
 36 |      * This is most commonly used to view binary data from streams
 37 |      * or sockets while debugging, but can be used to view any string
 38 |      * with non-viewable characters.
 39 |      *
 40 |      * @version     1.3.2
 41 |      * @author      Aidan Lister <aidan@php.net>
 42 |      * @author      Peter Waller <iridum@php.net>
 43 |      * @link        http://aidanlister.com/repos/v/function.hexdump.php
 44 |      *
 45 |      * @param string $data The string to be dumped
 46 |      * @param bool $htmloutput Set to false for non-HTML output
 47 |      * @param bool $uppercase Set to true for uppercase hex
 48 |      * @param bool $return Set to true to return the dump
 49 |      * @return string|null
 50 |      */
 51 |     public static function hexdump($data, $htmloutput = true, $uppercase = false, $return = false)
 52 |     {
 53 |         // Init
 54 |         $hexi = '';
 55 |         $ascii = '';
 56 |         $dump = $htmloutput ? '<pre>' : '';
 57 |         $offset = 0;
 58 |         $len = mb_strlen($data, 'ASCII');
 59 | 
 60 |         // Upper or lower case hexidecimal
 61 |         $hexFormat = $uppercase ? 'X' : 'x';
 62 | 
 63 |         // Iterate string
 64 |         for ($i = $j = 0; $i < $len; $i++) {
 65 |             // Convert to hexidecimal
 66 |             // We must use concatenation here because the $hexFormat value
 67 |             // is needed for sprintf() to parse the format
 68 |             $hexi .= sprintf('%02' .  $hexFormat . ' ', ord($data[$i]));
 69 | 
 70 |             // Replace non-viewable bytes with '.'
 71 |             if (ord($data[$i]) >= 32) {
 72 |                 $ascii .= $htmloutput ? htmlentities($data[$i]) : $data[$i];
 73 |             } else {
 74 |                 $ascii .= '.';
 75 |             }
 76 | 
 77 |             // Add extra column spacing
 78 |             if ($j === 7) {
 79 |                 $hexi .= ' ';
 80 |                 $ascii .= ' ';
 81 |             }
 82 | 
 83 |             // Add row
 84 |             if (++$j === 16 || $i === $len - 1) {
 85 |                 // Join the hexi / ascii output
 86 |                 // We must use concatenation here because the $hexFormat value
 87 |                 // is needed for sprintf() to parse the format
 88 |                 $dump .= sprintf('%04' . $hexFormat . '  %-49s  %s', $offset, $hexi, $ascii);
 89 | 
 90 |                 // Reset vars
 91 |                 $hexi = $ascii = '';
 92 |                 $offset += 16;
 93 |                 $j = 0;
 94 | 
 95 |                 // Add newline
 96 |                 if ($i !== $len - 1) {
 97 |                     $dump .= PHP_EOL;
 98 |                 }
 99 |             }
100 |         }
101 | 
102 |         // Finish dump
103 |         $dump .= $htmloutput ? '</pre>' : '';
104 |         $dump .= PHP_EOL;
105 | 
106 |         if ($return) {
107 |             return $dump;
108 |         }
109 | 
110 |         echo $dump;
111 | 
112 |         return null;
113 |     }
114 | 
115 |     /**
116 |      * @param array $table
117 |      * @return string
118 |      */
119 |     public static function dump_table($table)
120 |     {
121 |         $tokens = array();
122 |         foreach ($table as $name => $value) {
123 |             switch ($value[0]) {
124 |                 case 'D':
125 |                     $val = $value[1]->n . 'E' . $value[1]->e;
126 |                     break;
127 |                 case 'F':
128 |                     $val = '(' . self::dump_table($value[1]) . ')';
129 |                     break;
130 |                 case 'T':
131 |                     $val = date('Y-m-d H:i:s', $value[1]);
132 |                     break;
133 |                 default:
134 |                     $val = $value[1];
135 |             }
136 |             $tokens[] = $name . '=' . $val;
137 |         }
138 | 
139 |         return implode(', ', $tokens);
140 |     }
141 | }
142 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Helper/Protocol/MethodMap080.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | 
  3 | /* This file was autogenerated by spec/parser.php - Do not modify */
  4 | 
  5 | namespace PhpAmqpLib\Helper\Protocol;
  6 | 
  7 | class MethodMap080
  8 | {
  9 |     /**
 10 |      * @var array
 11 |      */
 12 |     protected $method_map = array(
 13 |         '10,10' => 'connection_start',
 14 |         '10,11' => 'connection_start_ok',
 15 |         '10,20' => 'connection_secure',
 16 |         '10,21' => 'connection_secure_ok',
 17 |         '10,30' => 'connection_tune',
 18 |         '10,31' => 'connection_tune_ok',
 19 |         '10,40' => 'connection_open',
 20 |         '10,41' => 'connection_open_ok',
 21 |         '10,50' => 'connection_redirect',
 22 |         '10,60' => 'connection_close',
 23 |         '10,61' => 'connection_close_ok',
 24 |         '20,10' => 'channel_open',
 25 |         '20,11' => 'channel_open_ok',
 26 |         '20,20' => 'channel_flow',
 27 |         '20,21' => 'channel_flow_ok',
 28 |         '20,30' => 'channel_alert',
 29 |         '20,40' => 'channel_close',
 30 |         '20,41' => 'channel_close_ok',
 31 |         '30,10' => 'access_request',
 32 |         '30,11' => 'access_request_ok',
 33 |         '40,10' => 'exchange_declare',
 34 |         '40,11' => 'exchange_declare_ok',
 35 |         '40,20' => 'exchange_delete',
 36 |         '40,21' => 'exchange_delete_ok',
 37 |         '50,10' => 'queue_declare',
 38 |         '50,11' => 'queue_declare_ok',
 39 |         '50,20' => 'queue_bind',
 40 |         '50,21' => 'queue_bind_ok',
 41 |         '50,30' => 'queue_purge',
 42 |         '50,31' => 'queue_purge_ok',
 43 |         '50,40' => 'queue_delete',
 44 |         '50,41' => 'queue_delete_ok',
 45 |         '50,50' => 'queue_unbind',
 46 |         '50,51' => 'queue_unbind_ok',
 47 |         '60,10' => 'basic_qos',
 48 |         '60,11' => 'basic_qos_ok',
 49 |         '60,20' => 'basic_consume',
 50 |         '60,21' => 'basic_consume_ok',
 51 |         '60,30' => 'basic_cancel',
 52 |         '60,31' => 'basic_cancel_ok',
 53 |         '60,40' => 'basic_publish',
 54 |         '60,50' => 'basic_return',
 55 |         '60,60' => 'basic_deliver',
 56 |         '60,70' => 'basic_get',
 57 |         '60,71' => 'basic_get_ok',
 58 |         '60,72' => 'basic_get_empty',
 59 |         '60,80' => 'basic_ack',
 60 |         '60,90' => 'basic_reject',
 61 |         '60,100' => 'basic_recover_async',
 62 |         '60,110' => 'basic_recover',
 63 |         '60,111' => 'basic_recover_ok',
 64 |         '70,10' => 'file_qos',
 65 |         '70,11' => 'file_qos_ok',
 66 |         '70,20' => 'file_consume',
 67 |         '70,21' => 'file_consume_ok',
 68 |         '70,30' => 'file_cancel',
 69 |         '70,31' => 'file_cancel_ok',
 70 |         '70,40' => 'file_open',
 71 |         '70,41' => 'file_open_ok',
 72 |         '70,50' => 'file_stage',
 73 |         '70,60' => 'file_publish',
 74 |         '70,70' => 'file_return',
 75 |         '70,80' => 'file_deliver',
 76 |         '70,90' => 'file_ack',
 77 |         '70,100' => 'file_reject',
 78 |         '80,10' => 'stream_qos',
 79 |         '80,11' => 'stream_qos_ok',
 80 |         '80,20' => 'stream_consume',
 81 |         '80,21' => 'stream_consume_ok',
 82 |         '80,30' => 'stream_cancel',
 83 |         '80,31' => 'stream_cancel_ok',
 84 |         '80,40' => 'stream_publish',
 85 |         '80,50' => 'stream_return',
 86 |         '80,60' => 'stream_deliver',
 87 |         '90,10' => 'tx_select',
 88 |         '90,11' => 'tx_select_ok',
 89 |         '90,20' => 'tx_commit',
 90 |         '90,21' => 'tx_commit_ok',
 91 |         '90,30' => 'tx_rollback',
 92 |         '90,31' => 'tx_rollback_ok',
 93 |         '100,10' => 'dtx_select',
 94 |         '100,11' => 'dtx_select_ok',
 95 |         '100,20' => 'dtx_start',
 96 |         '100,21' => 'dtx_start_ok',
 97 |         '110,10' => 'tunnel_request',
 98 |         '120,10' => 'test_integer',
 99 |         '120,11' => 'test_integer_ok',
100 |         '120,20' => 'test_string',
101 |         '120,21' => 'test_string_ok',
102 |         '120,30' => 'test_table',
103 |         '120,31' => 'test_table_ok',
104 |         '120,40' => 'test_content',
105 |         '120,41' => 'test_content_ok',
106 |     );
107 | 
108 |     /**
109 |      * @var string $method_sig
110 |      * @return string
111 |      */
112 |     public function get_method($method_sig)
113 |     {
114 |         return $this->method_map[$method_sig];
115 |     }
116 | 
117 |     /**
118 |      * @var string $method_sig
119 |      * @return bool
120 |      */
121 |     public function valid_method($method_sig)
122 |     {
123 |         return array_key_exists($method_sig, $this->method_map);
124 |     }
125 | }
126 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Helper/Protocol/MethodMap091.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | /* This file was autogenerated by spec/parser.php - Do not modify */
 4 | 
 5 | namespace PhpAmqpLib\Helper\Protocol;
 6 | 
 7 | class MethodMap091
 8 | {
 9 |     /**
10 |      * @var array
11 |      */
12 |     protected $method_map = array(
13 |         '10,10' => 'connection_start',
14 |         '10,11' => 'connection_start_ok',
15 |         '10,20' => 'connection_secure',
16 |         '10,21' => 'connection_secure_ok',
17 |         '10,30' => 'connection_tune',
18 |         '10,31' => 'connection_tune_ok',
19 |         '10,40' => 'connection_open',
20 |         '10,41' => 'connection_open_ok',
21 |         '10,50' => 'connection_close',
22 |         '10,51' => 'connection_close_ok',
23 |         '10,60' => 'connection_blocked',
24 |         '10,61' => 'connection_unblocked',
25 |         '20,10' => 'channel_open',
26 |         '20,11' => 'channel_open_ok',
27 |         '20,20' => 'channel_flow',
28 |         '20,21' => 'channel_flow_ok',
29 |         '20,40' => 'channel_close',
30 |         '20,41' => 'channel_close_ok',
31 |         '30,10' => 'access_request',
32 |         '30,11' => 'access_request_ok',
33 |         '40,10' => 'exchange_declare',
34 |         '40,11' => 'exchange_declare_ok',
35 |         '40,20' => 'exchange_delete',
36 |         '40,21' => 'exchange_delete_ok',
37 |         '40,30' => 'exchange_bind',
38 |         '40,31' => 'exchange_bind_ok',
39 |         '40,40' => 'exchange_unbind',
40 |         '40,51' => 'exchange_unbind_ok',
41 |         '50,10' => 'queue_declare',
42 |         '50,11' => 'queue_declare_ok',
43 |         '50,20' => 'queue_bind',
44 |         '50,21' => 'queue_bind_ok',
45 |         '50,30' => 'queue_purge',
46 |         '50,31' => 'queue_purge_ok',
47 |         '50,40' => 'queue_delete',
48 |         '50,41' => 'queue_delete_ok',
49 |         '50,50' => 'queue_unbind',
50 |         '50,51' => 'queue_unbind_ok',
51 |         '60,10' => 'basic_qos',
52 |         '60,11' => 'basic_qos_ok',
53 |         '60,20' => 'basic_consume',
54 |         '60,21' => 'basic_consume_ok',
55 |         '60,30' => 'basic_cancel_from_server',
56 |         '60,31' => 'basic_cancel_ok',
57 |         '60,40' => 'basic_publish',
58 |         '60,50' => 'basic_return',
59 |         '60,60' => 'basic_deliver',
60 |         '60,70' => 'basic_get',
61 |         '60,71' => 'basic_get_ok',
62 |         '60,72' => 'basic_get_empty',
63 |         '60,80' => 'basic_ack_from_server',
64 |         '60,90' => 'basic_reject',
65 |         '60,100' => 'basic_recover_async',
66 |         '60,110' => 'basic_recover',
67 |         '60,111' => 'basic_recover_ok',
68 |         '60,120' => 'basic_nack_from_server',
69 |         '90,10' => 'tx_select',
70 |         '90,11' => 'tx_select_ok',
71 |         '90,20' => 'tx_commit',
72 |         '90,21' => 'tx_commit_ok',
73 |         '90,30' => 'tx_rollback',
74 |         '90,31' => 'tx_rollback_ok',
75 |         '85,10' => 'confirm_select',
76 |         '85,11' => 'confirm_select_ok',
77 |     );
78 | 
79 |     /**
80 |      * @var string $method_sig
81 |      * @return string
82 |      */
83 |     public function get_method($method_sig)
84 |     {
85 |         return $this->method_map[$method_sig];
86 |     }
87 | 
88 |     /**
89 |      * @var string $method_sig
90 |      * @return bool
91 |      */
92 |     public function valid_method($method_sig)
93 |     {
94 |         return array_key_exists($method_sig, $this->method_map);
95 |     }
96 | }
97 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Helper/Protocol/Wait080.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | 
  3 | /* This file was autogenerated by spec/parser.php - Do not modify */
  4 | 
  5 | namespace PhpAmqpLib\Helper\Protocol;
  6 | 
  7 | class Wait080
  8 | {
  9 |     /**
 10 |      * @var array
 11 |      */
 12 |     protected $wait = array(
 13 |         'connection.start' => '10,10',
 14 |         'connection.start_ok' => '10,11',
 15 |         'connection.secure' => '10,20',
 16 |         'connection.secure_ok' => '10,21',
 17 |         'connection.tune' => '10,30',
 18 |         'connection.tune_ok' => '10,31',
 19 |         'connection.open' => '10,40',
 20 |         'connection.open_ok' => '10,41',
 21 |         'connection.redirect' => '10,50',
 22 |         'connection.close' => '10,60',
 23 |         'connection.close_ok' => '10,61',
 24 |         'channel.open' => '20,10',
 25 |         'channel.open_ok' => '20,11',
 26 |         'channel.flow' => '20,20',
 27 |         'channel.flow_ok' => '20,21',
 28 |         'channel.alert' => '20,30',
 29 |         'channel.close' => '20,40',
 30 |         'channel.close_ok' => '20,41',
 31 |         'access.request' => '30,10',
 32 |         'access.request_ok' => '30,11',
 33 |         'exchange.declare' => '40,10',
 34 |         'exchange.declare_ok' => '40,11',
 35 |         'exchange.delete' => '40,20',
 36 |         'exchange.delete_ok' => '40,21',
 37 |         'queue.declare' => '50,10',
 38 |         'queue.declare_ok' => '50,11',
 39 |         'queue.bind' => '50,20',
 40 |         'queue.bind_ok' => '50,21',
 41 |         'queue.purge' => '50,30',
 42 |         'queue.purge_ok' => '50,31',
 43 |         'queue.delete' => '50,40',
 44 |         'queue.delete_ok' => '50,41',
 45 |         'queue.unbind' => '50,50',
 46 |         'queue.unbind_ok' => '50,51',
 47 |         'basic.qos' => '60,10',
 48 |         'basic.qos_ok' => '60,11',
 49 |         'basic.consume' => '60,20',
 50 |         'basic.consume_ok' => '60,21',
 51 |         'basic.cancel' => '60,30',
 52 |         'basic.cancel_ok' => '60,31',
 53 |         'basic.publish' => '60,40',
 54 |         'basic.return' => '60,50',
 55 |         'basic.deliver' => '60,60',
 56 |         'basic.get' => '60,70',
 57 |         'basic.get_ok' => '60,71',
 58 |         'basic.get_empty' => '60,72',
 59 |         'basic.ack' => '60,80',
 60 |         'basic.reject' => '60,90',
 61 |         'basic.recover_async' => '60,100',
 62 |         'basic.recover' => '60,110',
 63 |         'basic.recover_ok' => '60,111',
 64 |         'file.qos' => '70,10',
 65 |         'file.qos_ok' => '70,11',
 66 |         'file.consume' => '70,20',
 67 |         'file.consume_ok' => '70,21',
 68 |         'file.cancel' => '70,30',
 69 |         'file.cancel_ok' => '70,31',
 70 |         'file.open' => '70,40',
 71 |         'file.open_ok' => '70,41',
 72 |         'file.stage' => '70,50',
 73 |         'file.publish' => '70,60',
 74 |         'file.return' => '70,70',
 75 |         'file.deliver' => '70,80',
 76 |         'file.ack' => '70,90',
 77 |         'file.reject' => '70,100',
 78 |         'stream.qos' => '80,10',
 79 |         'stream.qos_ok' => '80,11',
 80 |         'stream.consume' => '80,20',
 81 |         'stream.consume_ok' => '80,21',
 82 |         'stream.cancel' => '80,30',
 83 |         'stream.cancel_ok' => '80,31',
 84 |         'stream.publish' => '80,40',
 85 |         'stream.return' => '80,50',
 86 |         'stream.deliver' => '80,60',
 87 |         'tx.select' => '90,10',
 88 |         'tx.select_ok' => '90,11',
 89 |         'tx.commit' => '90,20',
 90 |         'tx.commit_ok' => '90,21',
 91 |         'tx.rollback' => '90,30',
 92 |         'tx.rollback_ok' => '90,31',
 93 |         'dtx.select' => '100,10',
 94 |         'dtx.select_ok' => '100,11',
 95 |         'dtx.start' => '100,20',
 96 |         'dtx.start_ok' => '100,21',
 97 |         'tunnel.request' => '110,10',
 98 |         'test.integer' => '120,10',
 99 |         'test.integer_ok' => '120,11',
100 |         'test.string' => '120,20',
101 |         'test.string_ok' => '120,21',
102 |         'test.table' => '120,30',
103 |         'test.table_ok' => '120,31',
104 |         'test.content' => '120,40',
105 |         'test.content_ok' => '120,41',
106 |     );
107 | 
108 |     /**
109 |      * @var string $method
110 |      * @return string
111 |      */
112 |     public function get_wait($method)
113 |     {
114 |         return $this->wait[$method];
115 |     }
116 | }
117 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Helper/Protocol/Wait091.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | /* This file was autogenerated by spec/parser.php - Do not modify */
 4 | 
 5 | namespace PhpAmqpLib\Helper\Protocol;
 6 | 
 7 | class Wait091
 8 | {
 9 |     /**
10 |      * @var array
11 |      */
12 |     protected $wait = array(
13 |         'connection.start' => '10,10',
14 |         'connection.start_ok' => '10,11',
15 |         'connection.secure' => '10,20',
16 |         'connection.secure_ok' => '10,21',
17 |         'connection.tune' => '10,30',
18 |         'connection.tune_ok' => '10,31',
19 |         'connection.open' => '10,40',
20 |         'connection.open_ok' => '10,41',
21 |         'connection.close' => '10,50',
22 |         'connection.close_ok' => '10,51',
23 |         'connection.blocked' => '10,60',
24 |         'connection.unblocked' => '10,61',
25 |         'channel.open' => '20,10',
26 |         'channel.open_ok' => '20,11',
27 |         'channel.flow' => '20,20',
28 |         'channel.flow_ok' => '20,21',
29 |         'channel.close' => '20,40',
30 |         'channel.close_ok' => '20,41',
31 |         'access.request' => '30,10',
32 |         'access.request_ok' => '30,11',
33 |         'exchange.declare' => '40,10',
34 |         'exchange.declare_ok' => '40,11',
35 |         'exchange.delete' => '40,20',
36 |         'exchange.delete_ok' => '40,21',
37 |         'exchange.bind' => '40,30',
38 |         'exchange.bind_ok' => '40,31',
39 |         'exchange.unbind' => '40,40',
40 |         'exchange.unbind_ok' => '40,51',
41 |         'queue.declare' => '50,10',
42 |         'queue.declare_ok' => '50,11',
43 |         'queue.bind' => '50,20',
44 |         'queue.bind_ok' => '50,21',
45 |         'queue.purge' => '50,30',
46 |         'queue.purge_ok' => '50,31',
47 |         'queue.delete' => '50,40',
48 |         'queue.delete_ok' => '50,41',
49 |         'queue.unbind' => '50,50',
50 |         'queue.unbind_ok' => '50,51',
51 |         'basic.qos' => '60,10',
52 |         'basic.qos_ok' => '60,11',
53 |         'basic.consume' => '60,20',
54 |         'basic.consume_ok' => '60,21',
55 |         'basic.cancel' => '60,30',
56 |         'basic.cancel_ok' => '60,31',
57 |         'basic.publish' => '60,40',
58 |         'basic.return' => '60,50',
59 |         'basic.deliver' => '60,60',
60 |         'basic.get' => '60,70',
61 |         'basic.get_ok' => '60,71',
62 |         'basic.get_empty' => '60,72',
63 |         'basic.ack' => '60,80',
64 |         'basic.reject' => '60,90',
65 |         'basic.recover_async' => '60,100',
66 |         'basic.recover' => '60,110',
67 |         'basic.recover_ok' => '60,111',
68 |         'basic.nack' => '60,120',
69 |         'tx.select' => '90,10',
70 |         'tx.select_ok' => '90,11',
71 |         'tx.commit' => '90,20',
72 |         'tx.commit_ok' => '90,21',
73 |         'tx.rollback' => '90,30',
74 |         'tx.rollback_ok' => '90,31',
75 |         'confirm.select' => '85,10',
76 |         'confirm.select_ok' => '85,11',
77 |     );
78 | 
79 |     /**
80 |      * @var string $method
81 |      * @return string
82 |      */
83 |     public function get_wait($method)
84 |     {
85 |         return $this->wait[$method];
86 |     }
87 | }
88 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Helper/SocketConstants.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | namespace PhpAmqpLib\Helper;
 4 | 
 5 | /**
 6 |  * @property-read int $SOCKET_EPIPE
 7 |  * @property-read int $SOCKET_ENETDOWN
 8 |  * @property-read int $SOCKET_ENETUNREACH
 9 |  * @property-read int $SOCKET_ENETRESET
10 |  * @property-read int $SOCKET_ECONNABORTED
11 |  * @property-read int $SOCKET_ECONNRESET
12 |  * @property-read int $SOCKET_ECONNREFUSED
13 |  * @property-read int $SOCKET_ETIMEDOUT
14 |  * @property-read int $SOCKET_EWOULDBLOCK
15 |  * @property-read int $SOCKET_EINTR
16 |  * @property-read int $SOCKET_EAGAIN
17 |  */
18 | final class SocketConstants
19 | {
20 |     /**
21 |      * @var int[]
22 |      */
23 |     private $constants;
24 | 
25 |     /** @var self */
26 |     private static $instance;
27 | 
28 |     public function __construct()
29 |     {
30 |         $constants = get_defined_constants(true);
31 |         if (isset($constants['sockets'])) {
32 |             $this->constants = $constants['sockets'];
33 |         } else {
34 |             trigger_error('Sockets extension is not enabled', E_USER_WARNING);
35 |             $this->constants = array();
36 |         }
37 |     }
38 | 
39 |     /**
40 |      * @param string $name
41 |      * @return int
42 |      */
43 |     public function __get($name)
44 |     {
45 |         return isset($this->constants[$name]) ? $this->constants[$name] : 0;
46 |     }
47 | 
48 |     /**
49 |      * @param string $name
50 |      * @param int $value
51 |      * @internal
52 |      */
53 |     public function __set($name, $value)
54 |     {
55 |     }
56 | 
57 |     /**
58 |      * @param string $name
59 |      * @return bool
60 |      */
61 |     public function __isset($name)
62 |     {
63 |         return isset($this->constants[$name]);
64 |     }
65 | 
66 |     /**
67 |      * @return self
68 |      */
69 |     public static function getInstance()
70 |     {
71 |         if (!self::$instance) {
72 |             self::$instance = new self();
73 |         }
74 | 
75 |         return self::$instance;
76 |     }
77 | }
78 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Message/AMQPMessage.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | 
  3 | namespace PhpAmqpLib\Message;
  4 | 
  5 | use PhpAmqpLib\Channel\AMQPChannel;
  6 | use PhpAmqpLib\Exception\AMQPEmptyDeliveryTagException;
  7 | use PhpAmqpLib\Wire\AMQPReader;
  8 | use PhpAmqpLib\Wire\AMQPWriter;
  9 | 
 10 | /**
 11 |  * A Message for use with the Channnel.basic_* methods.
 12 |  */
 13 | class AMQPMessage
 14 | {
 15 |     const DELIVERY_MODE_NON_PERSISTENT = 1;
 16 |     const DELIVERY_MODE_PERSISTENT = 2;
 17 | 
 18 |     /**
 19 |      * @var string
 20 |      * @deprecated Will be removed in version 4.0, use getBody() instead.
 21 |      */
 22 |     public $body;
 23 | 
 24 |     /**
 25 |      * @var int
 26 |      * @deprecated Will be removed in version 4.0, use getBodySize() instead.
 27 |      */
 28 |     public $body_size;
 29 | 
 30 |     /**
 31 |      * @var bool
 32 |      * @deprecated Will be removed in version 4.0, use isTruncated() instead.
 33 |      */
 34 |     public $is_truncated = false;
 35 | 
 36 |     /**
 37 |      * @var string
 38 |      * @deprecated Will be removed in version 4.0, use getContentEncoding() instead.
 39 |      */
 40 |     public $content_encoding;
 41 | 
 42 |     /** @var int */
 43 |     private $deliveryTag;
 44 | 
 45 |     /** @var string|null */
 46 |     private $consumerTag;
 47 | 
 48 |     /** @var bool|null */
 49 |     private $redelivered;
 50 | 
 51 |     /** @var string|null */
 52 |     private $exchange;
 53 | 
 54 |     /** @var string|null */
 55 |     private $routingKey;
 56 | 
 57 |     /** @var int|null */
 58 |     private $messageCount;
 59 | 
 60 |     /** @var AMQPChannel|null */
 61 |     private $channel;
 62 | 
 63 |     /** @var bool */
 64 |     private $responded = false;
 65 | 
 66 |     /**
 67 |      * @var array
 68 |      * @internal
 69 |      * @deprecated Will be removed in version 4.0, use one of getters to get delivery info.
 70 |      */
 71 |     public $delivery_info = array();
 72 | 
 73 |     /** @var array Properties content */
 74 |     protected $properties = array();
 75 | 
 76 |     /** @var null|string Compiled properties */
 77 |     protected $serialized_properties;
 78 | 
 79 |     /** @var array */
 80 |     protected static $propertyDefinitions = array(
 81 |         'content_type' => 'shortstr',
 82 |         'content_encoding' => 'shortstr',
 83 |         'application_headers' => 'table_object',
 84 |         'delivery_mode' => 'octet',
 85 |         'priority' => 'octet',
 86 |         'correlation_id' => 'shortstr',
 87 |         'reply_to' => 'shortstr',
 88 |         'expiration' => 'shortstr',
 89 |         'message_id' => 'shortstr',
 90 |         'timestamp' => 'timestamp',
 91 |         'type' => 'shortstr',
 92 |         'user_id' => 'shortstr',
 93 |         'app_id' => 'shortstr',
 94 |         'cluster_id' => 'shortstr',
 95 |     );
 96 | 
 97 |     /**
 98 |      * @param string $body
 99 |      * @param array $properties
100 |      */
101 |     public function __construct($body = '', $properties = array())
102 |     {
103 |         $this->setBody($body);
104 | 
105 |         if (!empty($properties) && is_array($properties)) {
106 |             $this->properties = array_intersect_key($properties, self::$propertyDefinitions);
107 |         }
108 |     }
109 | 
110 |     /**
111 |      * Acknowledge one or more messages.
112 |      *
113 |      * @param bool $multiple If true, the delivery tag is treated as "up to and including",
114 |      *                       so that multiple messages can be acknowledged with a single method.
115 |      * @since 2.12.0
116 |      * @link https://www.rabbitmq.com/amqp-0-9-1-reference.html#basic.ack
117 |      */
118 |     public function ack($multiple = false)
119 |     {
120 |         $this->assertUnacked();
121 |         $this->channel->basic_ack($this->deliveryTag, $multiple);
122 |         $this->onResponse();
123 |     }
124 | 
125 |     /**
126 |      * Reject one or more incoming messages.
127 |      *
128 |      * @param bool $requeue If true, the server will attempt to requeue the message. If requeue is false or the requeue
129 |      *                       attempt fails the messages are discarded or dead-lettered.
130 |      * @param bool $multiple If true, the delivery tag is treated as "up to and including",
131 |      *                       so that multiple messages can be rejected with a single method.
132 |      * @since 2.12.0
133 |      * @link https://www.rabbitmq.com/amqp-0-9-1-reference.html#basic.nack
134 |      */
135 |     public function nack($requeue = false, $multiple = false)
136 |     {
137 |         $this->assertUnacked();
138 |         $this->channel->basic_nack($this->deliveryTag, $multiple, $requeue);
139 |         $this->onResponse();
140 |     }
141 | 
142 |     /**
143 |      * Reject an incoming message.
144 |      *
145 |      * @param bool $requeue If requeue is true, the server will attempt to requeue the message.
146 |      *                     If requeue is false or the requeue attempt fails the messages are discarded or dead-lettered.
147 |      * @since 2.12.0
148 |      * @link https://www.rabbitmq.com/amqp-0-9-1-reference.html#basic.reject
149 |      */
150 |     public function reject($requeue = true)
151 |     {
152 |         $this->assertUnacked();
153 |         $this->channel->basic_reject($this->deliveryTag, $requeue);
154 |         $this->onResponse();
155 |     }
156 | 
157 |     /**
158 |      * @throws \LogicException When response to broker was already sent.
159 |      */
160 |     protected function assertUnacked()
161 |     {
162 |         if (!$this->channel || $this->responded) {
163 |             throw new \LogicException('Message is not published or response was already sent');
164 |         }
165 |     }
166 | 
167 |     protected function onResponse()
168 |     {
169 |         $this->responded = true;
170 |     }
171 | 
172 |     /**
173 |      * @return AMQPChannel|null
174 |      * @since 2.12.0
175 |      */
176 |     public function getChannel()
177 |     {
178 |         return $this->channel;
179 |     }
180 | 
181 |     /**
182 |      * @param AMQPChannel $channel
183 |      * @return $this
184 |      * @throws \RuntimeException
185 |      * @since 2.12.0
186 |      */
187 |     public function setChannel($channel)
188 |     {
189 |         if ($this->channel) {
190 |             throw new \RuntimeException('A message is already assigned to channel');
191 |         }
192 |         $this->channel = $channel;
193 |         $this->delivery_info['channel'] = $channel;
194 | 
195 |         return $this;
196 |     }
197 | 
198 |     /**
199 |      * @param int $deliveryTag
200 |      * @param bool $redelivered
201 |      * @param string $exchange
202 |      * @param string $routingKey
203 |      * @return $this
204 |      * @since 2.12.0
205 |      */
206 |     public function setDeliveryInfo($deliveryTag, $redelivered, $exchange, $routingKey)
207 |     {
208 |         $this->deliveryTag = $this->delivery_info['delivery_tag'] = $deliveryTag;
209 |         $this->redelivered = $this->delivery_info['redelivered'] = $redelivered;
210 |         $this->exchange = $this->delivery_info['exchange'] = $exchange;
211 |         $this->routingKey = $this->delivery_info['routing_key'] = $routingKey;
212 | 
213 |         return $this;
214 |     }
215 | 
216 |     /**
217 |      * @return bool|null
218 |      * @since 2.12.0
219 |      */
220 |     public function isRedelivered()
221 |     {
222 |         return $this->redelivered;
223 |     }
224 | 
225 |     /**
226 |      * @return string|null
227 |      * @since 2.12.0
228 |      */
229 |     public function getExchange()
230 |     {
231 |         return $this->exchange;
232 |     }
233 | 
234 |     /**
235 |      * @return string|null
236 |      * @since 2.12.0
237 |      */
238 |     public function getRoutingKey()
239 |     {
240 |         return $this->routingKey;
241 |     }
242 | 
243 |     /**
244 |      * @return string|null
245 |      * @since 2.12.0
246 |      */
247 |     public function getConsumerTag()
248 |     {
249 |         return $this->consumerTag;
250 |     }
251 | 
252 |     /**
253 |      * @param string $consumerTag
254 |      * @return $this
255 |      * @since 2.12.0
256 |      */
257 |     public function setConsumerTag($consumerTag)
258 |     {
259 |         $this->consumerTag = $consumerTag;
260 |         $this->delivery_info['consumer_tag'] = $consumerTag;
261 | 
262 |         return $this;
263 |     }
264 | 
265 |     /**
266 |      * @return int|null
267 |      * @since 2.12.0
268 |      */
269 |     public function getMessageCount()
270 |     {
271 |         return $this->messageCount;
272 |     }
273 | 
274 |     /**
275 |      * @param int $messageCount
276 |      * @return $this
277 |      * @since 2.12.0
278 |      */
279 |     public function setMessageCount($messageCount)
280 |     {
281 |         $this->messageCount = (int)$messageCount;
282 |         $this->delivery_info['message_count'] = $this->messageCount;
283 | 
284 |         return $this;
285 |     }
286 | 
287 |     /**
288 |      * @return string
289 |      */
290 |     public function getBody()
291 |     {
292 |         return $this->body;
293 |     }
294 | 
295 |     /**
296 |      * Sets the message payload
297 |      *
298 |      * @param string $body
299 |      * @return $this
300 |      */
301 |     public function setBody($body)
302 |     {
303 |         $this->body = $body;
304 | 
305 |         return $this;
306 |     }
307 | 
308 |     /**
309 |      * @return string
310 |      */
311 |     public function getContentEncoding()
312 |     {
313 |         return $this->content_encoding;
314 |     }
315 | 
316 |     /**
317 |      * @return int
318 |      */
319 |     public function getBodySize()
320 |     {
321 |         return $this->body_size;
322 |     }
323 | 
324 |     /**
325 |      * @param int $body_size Message body size in byte(s)
326 |      * @return AMQPMessage
327 |      */
328 |     public function setBodySize($body_size)
329 |     {
330 |         $this->body_size = (int)$body_size;
331 | 
332 |         return $this;
333 |     }
334 | 
335 |     /**
336 |      * @return boolean
337 |      */
338 |     public function isTruncated()
339 |     {
340 |         return $this->is_truncated;
341 |     }
342 | 
343 |     /**
344 |      * @param bool $is_truncated
345 |      * @return AMQPMessage
346 |      */
347 |     public function setIsTruncated($is_truncated)
348 |     {
349 |         $this->is_truncated = (bool)$is_truncated;
350 | 
351 |         return $this;
352 |     }
353 | 
354 |     /**
355 |      * @param int|string $deliveryTag
356 |      * @return $this
357 |      * @since 2.12.0
358 |      */
359 |     public function setDeliveryTag($deliveryTag)
360 |     {
361 |         if (!empty($this->deliveryTag)) {
362 |             throw new \LogicException('Delivery tag cannot be changed');
363 |         }
364 |         $this->deliveryTag = $deliveryTag;
365 |         $this->delivery_info['delivery_tag'] = $deliveryTag;
366 | 
367 |         return $this;
368 |     }
369 | 
370 |     /**
371 |      * @return int
372 |      *
373 |      * @throws AMQPEmptyDeliveryTagException
374 |      */
375 |     public function getDeliveryTag()
376 |     {
377 |         if (empty($this->deliveryTag)) {
378 |             throw new AMQPEmptyDeliveryTagException('This message was not delivered yet');
379 |         }
380 | 
381 |         return $this->deliveryTag;
382 |     }
383 | 
384 |     /**
385 |      * Check whether a property exists in the 'properties' dictionary
386 |      * or if present - in the 'delivery_info' dictionary.
387 |      *
388 |      * @param string $name
389 |      * @return bool
390 |      */
391 |     public function has($name)
392 |     {
393 |         return isset($this->properties[$name]) || isset($this->delivery_info[$name]);
394 |     }
395 | 
396 |     /**
397 |      * Look for additional properties in the 'properties' dictionary,
398 |      * and if present - the 'delivery_info' dictionary.
399 |      *
400 |      * @param string $name
401 |      * @return mixed|AMQPChannel
402 |      * @throws \OutOfBoundsException
403 |      */
404 |     public function get($name)
405 |     {
406 |         if (isset($this->properties[$name])) {
407 |             return $this->properties[$name];
408 |         }
409 | 
410 |         if (isset($this->delivery_info[$name])) {
411 |             return $this->delivery_info[$name];
412 |         }
413 | 
414 |         throw new \OutOfBoundsException(sprintf(
415 |             'No "%s" property',
416 |             $name
417 |         ));
418 |     }
419 | 
420 |     /**
421 |      * Returns the properties content
422 |      *
423 |      * @return array
424 |      */
425 |     public function get_properties()
426 |     {
427 |         return $this->properties;
428 |     }
429 | 
430 |     /**
431 |      * Sets a property value
432 |      *
433 |      * @param string $name The property name (one of the property definition)
434 |      * @param mixed $value The property value
435 |      * @throws \OutOfBoundsException
436 |      */
437 |     public function set($name, $value)
438 |     {
439 |         if (!array_key_exists($name, self::$propertyDefinitions)) {
440 |             throw new \OutOfBoundsException(sprintf(
441 |                 'No "%s" property',
442 |                 $name
443 |             ));
444 |         }
445 | 
446 |         if (isset($this->properties[$name]) && $this->properties[$name] === $value) {
447 |             // same value, nothing to do
448 |             return;
449 |         }
450 | 
451 |         $this->properties[$name] = $value;
452 |         $this->serialized_properties = null;
453 |     }
454 | 
455 |     /**
456 |      * Given the raw bytes containing the property-flags and
457 |      * property-list from a content-frame-header, parse and insert
458 |      * into a dictionary stored in this object as an attribute named
459 |      * 'properties'.
460 |      *
461 |      * @param AMQPReader $reader
462 |      * NOTE: do not mutate $reader
463 |      * @return $this
464 |      */
465 |     public function load_properties(AMQPReader $reader)
466 |     {
467 |         // Read 16-bit shorts until we get one with a low bit set to zero
468 |         $flags = array();
469 | 
470 |         while (true) {
471 |             $flag_bits = $reader->read_short();
472 |             $flags[] = $flag_bits;
473 | 
474 |             if (($flag_bits & 1) === 0) {
475 |                 break;
476 |             }
477 |         }
478 | 
479 |         $shift = 0;
480 |         $data = array();
481 | 
482 |         foreach (self::$propertyDefinitions as $key => $proptype) {
483 |             if ($shift === 0) {
484 |                 if (!$flags) {
485 |                     break;
486 |                 }
487 |                 $flag_bits = array_shift($flags);
488 |                 $shift = 15;
489 |             }
490 | 
491 |             if ($flag_bits & (1 << $shift)) {
492 |                 $data[$key] = $reader->{'read_' . $proptype}();
493 |             }
494 | 
495 |             $shift -= 1;
496 |         }
497 | 
498 |         $this->properties = $data;
499 | 
500 |         return $this;
501 |     }
502 | 
503 | 
504 |     /**
505 |      * Serializes the 'properties' attribute (a dictionary) into the
506 |      * raw bytes making up a set of property flags and a property
507 |      * list, suitable for putting into a content frame header.
508 |      *
509 |      * @return string
510 |      * @todo Inject the AMQPWriter to make the method easier to test
511 |      */
512 |     public function serialize_properties()
513 |     {
514 |         if (!empty($this->serialized_properties)) {
515 |             return $this->serialized_properties;
516 |         }
517 | 
518 |         $shift = 15;
519 |         $flag_bits = 0;
520 |         $flags = array();
521 |         $raw_bytes = new AMQPWriter();
522 | 
523 |         foreach (self::$propertyDefinitions as $key => $prototype) {
524 |             $val = isset($this->properties[$key]) ? $this->properties[$key] : null;
525 | 
526 |             // Very important: PHP type eval is weak, use the === to test the
527 |             // value content. Zero or false value should not be removed
528 |             if ($val === null) {
529 |                 $shift -= 1;
530 |                 continue;
531 |             }
532 | 
533 |             if ($shift === 0) {
534 |                 $flags[] = $flag_bits;
535 |                 $flag_bits = 0;
536 |                 $shift = 15;
537 |             }
538 | 
539 |             $flag_bits |= (1 << $shift);
540 |             if ($prototype !== 'bit') {
541 |                 $raw_bytes->{'write_' . $prototype}($val);
542 |             }
543 | 
544 |             $shift -= 1;
545 |         }
546 | 
547 |         $flags[] = $flag_bits;
548 |         $result = new AMQPWriter();
549 |         foreach ($flags as $flag_bits) {
550 |             $result->write_short($flag_bits);
551 |         }
552 | 
553 |         $result->write($raw_bytes->getvalue());
554 | 
555 |         $this->serialized_properties = $result->getvalue();
556 | 
557 |         return $this->serialized_properties;
558 |     }
559 | }
560 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Package.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | namespace PhpAmqpLib;
 4 | 
 5 | final class Package
 6 | {
 7 |     public const NAME = 'AMQPLib';
 8 |     public const VERSION = '3.7.3';
 9 | }
10 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Wire/AMQPAbstractCollection.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | 
  3 | namespace PhpAmqpLib\Wire;
  4 | 
  5 | use PhpAmqpLib\Channel\AbstractChannel;
  6 | use PhpAmqpLib\Exception;
  7 | use PhpAmqpLib\Wire;
  8 | 
  9 | /**
 10 |  * Iterator implemented for transparent integration with AMQPWriter::write_[array|table]()
 11 |  */
 12 | abstract class AMQPAbstractCollection implements \Iterator, \ArrayAccess
 13 | {
 14 |     //protocol defines available field types and their corresponding symbols
 15 |     const PROTOCOL_RBT = 'rabbit'; //pseudo proto
 16 | 
 17 |     //Abstract data types
 18 |     const T_INT_SHORTSHORT = 1;
 19 |     const T_INT_SHORTSHORT_U = 2;
 20 |     const T_INT_SHORT = 3;
 21 |     const T_INT_SHORT_U = 4;
 22 |     const T_INT_LONG = 5;
 23 |     const T_INT_LONG_U = 6;
 24 |     const T_INT_LONGLONG = 7;
 25 |     const T_INT_LONGLONG_U = 8;
 26 | 
 27 |     const T_DECIMAL = 9;
 28 |     const T_TIMESTAMP = 10;
 29 |     const T_VOID = 11;
 30 | 
 31 |     const T_BOOL = 12;
 32 | 
 33 |     const T_STRING_SHORT = 13;
 34 |     const T_STRING_LONG = 14;
 35 | 
 36 |     const T_ARRAY = 15;
 37 |     const T_TABLE = 16;
 38 | 
 39 |     const T_BYTES = 17;
 40 | 
 41 |     const T_FLOAT = 18;
 42 |     const T_DOUBLE = 19;
 43 | 
 44 |     /**
 45 |      * @var string
 46 |      */
 47 |     private static $protocol;
 48 | 
 49 |     /*
 50 |      * Field types messy mess http://www.rabbitmq.com/amqp-0-9-1-errata.html#section_3
 51 |      * Default behaviour is to use rabbitMQ compatible field-set
 52 |      * Define AMQP_STRICT_FLD_TYPES=true to use strict AMQP instead
 53 |      * @var array<int, string>
 54 |      * @deprecated
 55 |      */
 56 |     private static $types_080 = array(
 57 |         self::T_INT_LONG => 'I',
 58 |         self::T_DECIMAL => 'D',
 59 |         self::T_TIMESTAMP => 'T',
 60 |         self::T_STRING_LONG => 'S',
 61 |         self::T_TABLE => 'F'
 62 |     );
 63 | 
 64 |     /**
 65 |      * @var array<int, string>
 66 |      */
 67 |     private static $types_091 = array(
 68 |         self::T_INT_SHORTSHORT => 'b',
 69 |         self::T_INT_SHORTSHORT_U => 'B',
 70 |         self::T_INT_SHORT => 'U',
 71 |         self::T_INT_SHORT_U => 'u',
 72 |         self::T_INT_LONG => 'I',
 73 |         self::T_INT_LONG_U => 'i',
 74 |         self::T_INT_LONGLONG => 'L',
 75 |         self::T_INT_LONGLONG_U => 'l',
 76 |         self::T_FLOAT => 'f',
 77 |         self::T_DOUBLE => 'd',
 78 |         self::T_DECIMAL => 'D',
 79 |         self::T_TIMESTAMP => 'T',
 80 |         self::T_VOID => 'V',
 81 |         self::T_BOOL => 't',
 82 |         self::T_STRING_SHORT => 's',
 83 |         self::T_STRING_LONG => 'S',
 84 |         self::T_ARRAY => 'A',
 85 |         self::T_TABLE => 'F',
 86 |         self::T_BYTES => 'x',
 87 |     );
 88 | 
 89 |     /**
 90 |      * @var array<int, string>
 91 |      */
 92 |     private static $types_rabbit = array(
 93 |         self::T_INT_SHORTSHORT => 'b',
 94 |         self::T_INT_SHORTSHORT_U => 'B',
 95 |         self::T_INT_SHORT => 's',
 96 |         self::T_INT_SHORT_U => 'u',
 97 |         self::T_INT_LONG => 'I',
 98 |         self::T_INT_LONG_U => 'i',
 99 |         self::T_INT_LONGLONG => 'l',
100 |         self::T_FLOAT => 'f',
101 |         self::T_DOUBLE => 'd',
102 |         self::T_DECIMAL => 'D',
103 |         self::T_TIMESTAMP => 'T',
104 |         self::T_VOID => 'V',
105 |         self::T_BOOL => 't',
106 |         self::T_STRING_LONG => 'S',
107 |         self::T_ARRAY => 'A',
108 |         self::T_TABLE => 'F',
109 |         self::T_BYTES => 'x',
110 |     );
111 | 
112 |     /**
113 |      * @var array
114 |      */
115 |     protected $data = array();
116 | 
117 |     public function __construct(?array $data = null)
118 |     {
119 |         if (!empty($data)) {
120 |             $this->data = $this->encodeCollection($data);
121 |         }
122 |     }
123 | 
124 |     /**
125 |      * @return int
126 |      */
127 |     abstract public function getType();
128 | 
129 |     /**
130 |      * @param mixed $val
131 |      * @param int|null $type
132 |      * @param string $key
133 |      */
134 |     final protected function setValue($val, $type = null, $key = null)
135 |     {
136 |         if ($val instanceof self) {
137 |             if ($type && ($type !== $val->getType())) {
138 |                 throw new Exception\AMQPInvalidArgumentException(
139 |                     sprintf(
140 |                         'Attempted to add instance of %s representing type [%s] as mismatching type [%s]',
141 |                         get_class($val),
142 |                         $val->getType(),
143 |                         $type
144 |                     )
145 |                 );
146 |             }
147 |             $type = $val->getType();
148 |         } elseif ($type) { //ensuring data integrity and that all members are properly validated
149 |             switch ($type) {
150 |                 case self::T_ARRAY:
151 |                     throw new Exception\AMQPInvalidArgumentException('Arrays must be passed as AMQPArray instance');
152 |                 case self::T_TABLE:
153 |                     throw new Exception\AMQPInvalidArgumentException('Tables must be passed as AMQPTable instance');
154 |                 case self::T_DECIMAL:
155 |                     if (!($val instanceof AMQPDecimal)) {
156 |                         throw new Exception\AMQPInvalidArgumentException(
157 |                             'Decimal values must be instance of AMQPDecimal'
158 |                         );
159 |                     }
160 |                     break;
161 |             }
162 |         }
163 | 
164 |         if ($type) {
165 |             self::checkDataTypeIsSupported($type, false);
166 |             $val = array($type, $val);
167 |         } else {
168 |             $val = $this->encodeValue($val);
169 |         }
170 | 
171 |         if ($key === null) {
172 |             $this->data[] = $val;
173 |         } else {
174 |             $this->data[$key] = $val;
175 |         }
176 |     }
177 | 
178 |     /**
179 |      * @return array
180 |      */
181 |     final public function getNativeData()
182 |     {
183 |         return $this->decodeCollection($this->data);
184 |     }
185 | 
186 |     /**
187 |      * @param array $val
188 |      * @return array
189 |      */
190 |     final protected function encodeCollection(array $val)
191 |     {
192 |         foreach ($val as $k => $v) {
193 |             $val[$k] = $this->encodeValue($v);
194 |         }
195 | 
196 |         return $val;
197 |     }
198 | 
199 |     /**
200 |      * @param array $val
201 |      * @return array
202 |      */
203 |     final protected function decodeCollection(array $val)
204 |     {
205 |         foreach ($val as $k => $v) {
206 |             $val[$k] = $this->decodeValue($v[1], $v[0]);
207 |         }
208 | 
209 |         return $val;
210 |     }
211 | 
212 |     public function offsetExists($offset): bool
213 |     {
214 |         return isset($this->data[$offset]);
215 |     }
216 | 
217 |     /**
218 |      * @param mixed $offset
219 |      * @return mixed
220 |      */
221 |     #[\ReturnTypeWillChange]
222 |     public function offsetGet($offset)
223 |     {
224 |         $value = isset($this->data[$offset]) ? $this->data[$offset] : null;
225 | 
226 |         return is_array($value) ? $value[1] : $value;
227 |     }
228 | 
229 |     public function offsetSet($offset, $value): void
230 |     {
231 |         $this->setValue($value, null, $offset);
232 |     }
233 | 
234 |     public function offsetUnset($offset): void
235 |     {
236 |         unset($this->data[$offset]);
237 |     }
238 | 
239 |     /**
240 |      * @param mixed $val
241 |      * @return mixed
242 |      * @throws Exception\AMQPOutOfBoundsException
243 |      */
244 |     protected function encodeValue($val)
245 |     {
246 |         if (is_string($val)) {
247 |             $val = $this->encodeString($val);
248 |         } elseif (is_float($val)) {
249 |             $val = $this->encodeFloat($val);
250 |         } elseif (is_int($val)) {
251 |             $val = $this->encodeInt($val);
252 |         } elseif (is_bool($val)) {
253 |             $val = $this->encodeBool($val);
254 |         } elseif (is_null($val)) {
255 |             $val = $this->encodeVoid();
256 |         } elseif ($val instanceof \DateTimeInterface) {
257 |             $val = array(self::T_TIMESTAMP, $val->getTimestamp());
258 |         } elseif ($val instanceof AMQPDecimal) {
259 |             $val = array(self::T_DECIMAL, $val);
260 |         } elseif ($val instanceof self) {
261 |             //avoid silent type correction of strictly typed values
262 |             self::checkDataTypeIsSupported($val->getType(), false);
263 |             $val = array($val->getType(), $val);
264 |         } elseif (is_array($val)) {
265 |             //AMQP specs says "Field names MUST start with a letter, '
#39; or '#'"
266 |             //so beware, some servers may raise an exception with 503 code in cases when indexed
267 |             // array is encoded as table
268 |             if (self::isProtocol(Wire\Constants080::VERSION)) {
269 |                 //080 doesn't support arrays, forcing table
270 |                 $val = array(self::T_TABLE, new AMQPTable($val));
271 |             } elseif (empty($val) || (array_keys($val) === range(0, count($val) - 1))) {
272 |                 $val = array(self::T_ARRAY, new AMQPArray($val));
273 |             } else {
274 |                 $val = array(self::T_TABLE, new AMQPTable($val));
275 |             }
276 |         } else {
277 |             throw new Exception\AMQPOutOfBoundsException(
278 |                 sprintf('Encountered value of unsupported type: %s', gettype($val))
279 |             );
280 |         }
281 | 
282 |         return $val;
283 |     }
284 | 
285 |     /**
286 |      * @param mixed $val
287 |      * @param int $type
288 |      * @return array|bool|\DateTime|null
289 |      */
290 |     protected function decodeValue($val, $type)
291 |     {
292 |         if ($val instanceof self) {
293 |             //covering arrays and tables
294 |             $val = $val->getNativeData();
295 |         } else {
296 |             switch ($type) {
297 |                 case self::T_BOOL:
298 |                     $val = (bool) $val;
299 |                     break;
300 |                 case self::T_TIMESTAMP:
301 |                     $val = \DateTime::createFromFormat('U', $val);
302 |                     break;
303 |                 case self::T_VOID:
304 |                     $val = null;
305 |                     break;
306 |                 case self::T_ARRAY:
307 |                 case self::T_TABLE:
308 |                     throw new Exception\AMQPLogicException(
309 |                         sprintf(
310 |                             '%s %s',
311 |                             'Encountered an array/table struct which is not an instance of AMQPCollection.',
312 |                             'This is considered a bug and should be fixed, please report'
313 |                         )
314 |                     );
315 |             }
316 |         }
317 | 
318 |         return $val;
319 |     }
320 | 
321 |     /**
322 |      * @param string $val
323 |      * @return array
324 |      */
325 |     protected function encodeString($val)
326 |     {
327 |         return array(self::T_STRING_LONG, $val);
328 |     }
329 | 
330 |     /**
331 |      * @param int $val
332 |      * @return array
333 |      */
334 |     protected function encodeInt($val)
335 |     {
336 |         if (($val >= -2147483648) && ($val <= 2147483647)) {
337 |             $ev = array(self::T_INT_LONG, $val);
338 |         } elseif (self::isProtocol(Wire\Constants080::VERSION)) {
339 |             //080 doesn't support longlong
340 |             $ev = $this->encodeString((string) $val);
341 |         } else {
342 |             $ev = array(self::T_INT_LONGLONG, $val);
343 |         }
344 | 
345 |         return $ev;
346 |     }
347 | 
348 |     /**
349 |      * @param float $val
350 |      * @return array
351 |      */
352 |     protected function encodeFloat($val)
353 |     {
354 |         return $this->encodeString((string) $val);
355 |     }
356 | 
357 |     /**
358 |      * @param bool $val
359 |      * @return array
360 |      */
361 |     protected function encodeBool($val)
362 |     {
363 |         $val = (bool) $val;
364 | 
365 |         return self::isProtocol(Wire\Constants080::VERSION)
366 |             ? array(self::T_INT_LONG, (int) $val)
367 |             : array(self::T_BOOL, $val);
368 |     }
369 | 
370 |     /**
371 |      * @return array
372 |      */
373 |     protected function encodeVoid()
374 |     {
375 |         return self::isProtocol(Wire\Constants080::VERSION) ? $this->encodeString('') : array(self::T_VOID, null);
376 |     }
377 | 
378 |     /**
379 |      * @return string
380 |      * @deprecated
381 |      */
382 |     final public static function getProtocol()
383 |     {
384 |         if (self::$protocol === null) {
385 |             self::$protocol = defined('AMQP_STRICT_FLD_TYPES') && AMQP_STRICT_FLD_TYPES ?
386 |                 AbstractChannel::getProtocolVersion() :
387 |                 self::PROTOCOL_RBT;
388 |         }
389 | 
390 |         return self::$protocol;
391 |     }
392 | 
393 |     /**
394 |      * @param string $proto
395 |      * @return bool
396 |      */
397 |     final public static function isProtocol($proto)
398 |     {
399 |         return self::getProtocol() === $proto;
400 |     }
401 | 
402 |     /**
403 |      * @return array  [dataTypeConstant => dataTypeSymbol]
404 |      */
405 |     final public static function getSupportedDataTypes()
406 |     {
407 |         switch ($proto = self::getProtocol()) {
408 |             case Wire\Constants080::VERSION:
409 |                 $types = self::$types_080;
410 |                 break;
411 |             case Wire\Constants091::VERSION:
412 |                 $types = self::$types_091;
413 |                 break;
414 |             case self::PROTOCOL_RBT:
415 |                 $types = self::$types_rabbit;
416 |                 break;
417 |             default:
418 |                 throw new Exception\AMQPOutOfRangeException(sprintf('Unknown protocol: %s', $proto));
419 |         }
420 | 
421 |         return $types;
422 |     }
423 | 
424 |     /**
425 |      * @param string $type
426 |      * @param bool $return Whether to return or raise AMQPOutOfRangeException
427 |      * @return boolean
428 |      */
429 |     final public static function checkDataTypeIsSupported($type, $return = true)
430 |     {
431 |         try {
432 |             $supported = self::getSupportedDataTypes();
433 |             if (!isset($supported[$type])) {
434 |                 throw new Exception\AMQPOutOfRangeException(sprintf(
435 |                     'AMQP-%s doesn\'t support data of type [%s]',
436 |                     self::getProtocol(),
437 |                     $type
438 |                 ));
439 |             }
440 |             return true;
441 |         } catch (Exception\AMQPOutOfRangeException $ex) {
442 |             if (!$return) {
443 |                 throw $ex;
444 |             }
445 | 
446 |             return false;
447 |         }
448 |     }
449 | 
450 |     /**
451 |      * @param int $type
452 |      * @return string
453 |      */
454 |     final public static function getSymbolForDataType($type)
455 |     {
456 |         $types = self::getSupportedDataTypes();
457 |         if (!isset($types[$type])) {
458 |             throw new Exception\AMQPOutOfRangeException(sprintf(
459 |                 'AMQP-%s doesn\'t support data of type [%s]',
460 |                 self::getProtocol(),
461 |                 $type
462 |             ));
463 |         }
464 | 
465 |         return $types[$type];
466 |     }
467 | 
468 |     /**
469 |      * @param string $symbol
470 |      * @return integer
471 |      */
472 |     final public static function getDataTypeForSymbol($symbol)
473 |     {
474 |         $symbols = array_flip(self::getSupportedDataTypes());
475 |         if (!isset($symbols[$symbol])) {
476 |             throw new Exception\AMQPOutOfRangeException(sprintf(
477 |                 'AMQP-%s doesn\'t define data of type [%s]',
478 |                 self::getProtocol(),
479 |                 $symbol
480 |             ));
481 |         }
482 | 
483 |         return $symbols[$symbol];
484 |     }
485 | 
486 |     /**
487 |      * @return mixed
488 |      */
489 |     #[\ReturnTypeWillChange]
490 |     public function current()
491 |     {
492 |         return current($this->data);
493 |     }
494 | 
495 |     /**
496 |      * @return mixed
497 |      */
498 |     #[\ReturnTypeWillChange]
499 |     public function key()
500 |     {
501 |         return key($this->data);
502 |     }
503 | 
504 |     public function next(): void
505 |     {
506 |         next($this->data);
507 |     }
508 | 
509 |     public function rewind(): void
510 |     {
511 |         reset($this->data);
512 |     }
513 | 
514 |     public function valid(): bool
515 |     {
516 |         return key($this->data) !== null;
517 |     }
518 | }
519 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Wire/AMQPArray.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | namespace PhpAmqpLib\Wire;
 4 | 
 5 | class AMQPArray extends AMQPAbstractCollection
 6 | {
 7 | 
 8 |     /**
 9 |      * @param array|null $data
10 |      */
11 |     public function __construct(?array $data = null)
12 |     {
13 |         parent::__construct(empty($data) ? null : array_values($data));
14 |     }
15 | 
16 |     /**
17 |      * @return int
18 |      */
19 |     final public function getType()
20 |     {
21 |         return self::T_ARRAY;
22 |     }
23 | 
24 |     /**
25 |      * @param mixed $val
26 |      * @param int|null $type
27 |      * @return $this
28 |      */
29 |     public function push($val, $type = null)
30 |     {
31 |         $this->setValue($val, $type);
32 | 
33 |         return $this;
34 |     }
35 | }
36 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Wire/AMQPBufferReader.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | namespace PhpAmqpLib\Wire;
 4 | 
 5 | use PhpAmqpLib\Exception\AMQPDataReadException;
 6 | 
 7 | class AMQPBufferReader extends AMQPReader
 8 | {
 9 |     /**
10 |      * @var string
11 |      */
12 |     private $buffer;
13 | 
14 |     /**
15 |      * @var int
16 |      */
17 |     private $length;
18 | 
19 |     public function __construct(string $buffer)
20 |     {
21 |         $this->buffer = $buffer;
22 |         $this->length = mb_strlen($buffer, 'ASCII');
23 |     }
24 | 
25 |     public function close(): void
26 |     {
27 |     }
28 | 
29 |     /**
30 |      * Resets the object from the injected param
31 |      *
32 |      * Used to not need to create a new AMQPBufferReader instance every time.
33 |      * when we can just pass a string and reset the object state.
34 |      * NOTE: since we are working with strings we don't need to pass an AbstractIO
35 |      *       or a timeout.
36 |      *
37 |      * @param string $str
38 |      */
39 |     public function reset(string $str): void
40 |     {
41 |         $this->buffer = $str;
42 |         $this->length = mb_strlen($this->buffer, 'ASCII');
43 |         $this->offset = 0;
44 |         $this->resetCounters();
45 |     }
46 | 
47 |     protected function rawread(int $n): string
48 |     {
49 |         if ($this->length < $n) {
50 |             throw new AMQPDataReadException(sprintf(
51 |                                                 'Error reading data. Requested %s bytes while string buffer has only %s',
52 |                                                 $n,
53 |                                                 $this->length
54 |                                             ));
55 |         }
56 | 
57 |         $res = mb_substr($this->buffer, 0, $n, 'ASCII');
58 |         $this->buffer = mb_substr($this->buffer, $n, null, 'ASCII');
59 |         $this->length -= $n;
60 |         $this->offset += $n;
61 | 
62 |         return $res;
63 |     }
64 | 
65 | }
66 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Wire/AMQPByteStream.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | 
  3 | namespace PhpAmqpLib\Wire;
  4 | 
  5 | use PhpAmqpLib\Helper\BigInteger;
  6 | 
  7 | abstract class AMQPByteStream
  8 | {
  9 |     public const BIT = 1;
 10 |     public const OCTET = 1;
 11 |     public const SHORTSTR = 1;
 12 |     public const SHORT = 2;
 13 |     public const LONG = 4;
 14 |     public const SIGNED_LONG = 4;
 15 |     public const READ_PHP_INT = 4; // use READ_ to avoid possible clashes with PHP
 16 |     public const LONGLONG = 8;
 17 |     public const TIMESTAMP = 8;
 18 | 
 19 |     /** @var bool */
 20 |     protected const PLATFORM_64BIT = PHP_INT_SIZE === 8;
 21 | 
 22 |     /** @var BigInteger[][] */
 23 |     protected static $bigIntegers = array();
 24 | 
 25 |     /**
 26 |      * @var bool
 27 |      */
 28 |     protected static $isLittleEndian;
 29 | 
 30 |     /**
 31 |      * Converts byte-string between native and network byte order, in both directions
 32 |      *
 33 |      * @param string $bytes
 34 |      * @return string
 35 |      */
 36 |     protected function correctEndianness($bytes)
 37 |     {
 38 |         return self::isLittleEndian() ? $this->convertByteOrder($bytes) : $bytes;
 39 |     }
 40 | 
 41 |     /**
 42 |      * @param string $bytes
 43 |      * @return string
 44 |      */
 45 |     protected function convertByteOrder($bytes)
 46 |     {
 47 |         return strrev($bytes);
 48 |     }
 49 | 
 50 |     /**
 51 |      * @param int $longInt
 52 |      * @return bool
 53 |      */
 54 |     protected function getLongMSB($longInt)
 55 |     {
 56 |         return (bool) ($longInt & 0x80000000);
 57 |     }
 58 | 
 59 |     /**
 60 |      * @param string $bytes
 61 |      * @return bool
 62 |      */
 63 |     protected function getMSB($bytes)
 64 |     {
 65 |         return ord($bytes[0]) > 127;
 66 |     }
 67 | 
 68 |     /**
 69 |      * @return bool
 70 |      */
 71 |     protected static function isLittleEndian()
 72 |     {
 73 |         if (self::$isLittleEndian === null) {
 74 |             $tmp = unpack('S', "\x01\x00"); // to maintain 5.3 compatibility
 75 |             self::$isLittleEndian = $tmp[1] === 1;
 76 |         }
 77 | 
 78 |         return self::$isLittleEndian;
 79 |     }
 80 | 
 81 |     /**
 82 |      * @param string $value
 83 |      * @param int $base
 84 |      * @return BigInteger
 85 |      */
 86 |     protected static function getBigInteger($value, $base = 10)
 87 |     {
 88 |         if (!isset(self::$bigIntegers[$base])) {
 89 |             self::$bigIntegers[$base] = array();
 90 |         }
 91 |         if (isset(self::$bigIntegers[$base][$value])) {
 92 |             return self::$bigIntegers[$base][$value];
 93 |         }
 94 | 
 95 |         $integer = new BigInteger($value, $base);
 96 |         self::$bigIntegers[$base][$value] = $integer;
 97 | 
 98 |         return $integer;
 99 |     }
100 | }
101 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Wire/AMQPDecimal.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | namespace PhpAmqpLib\Wire;
 4 | 
 5 | use PhpAmqpLib\Exception\AMQPOutOfBoundsException;
 6 | use PhpAmqpLib\Helper\BigInteger;
 7 | 
 8 | /**
 9 |  * AMQP protocol decimal value.
10 |  *
11 |  * Values are represented as (n,e) pairs. The actual value
12 |  * is n * 10^(-e).
13 |  *
14 |  * From 0.8 spec: Decimal values are
15 |  * not intended to support floating point values, but rather
16 |  * business values such as currency rates and amounts. The
17 |  * 'decimals' octet is not signed.
18 |  */
19 | class AMQPDecimal
20 | {
21 |     /** @var int */
22 |     protected $n;
23 | 
24 |     /** @var int */
25 |     protected $e;
26 | 
27 |     /**
28 |      * @param int $n
29 |      * @param int $e
30 |      * @throws \PhpAmqpLib\Exception\AMQPOutOfBoundsException
31 |      */
32 |     public function __construct($n, $e)
33 |     {
34 |         if ($e < 0) {
35 |             throw new AMQPOutOfBoundsException('Decimal exponent value must be unsigned!');
36 |         }
37 | 
38 |         $this->n = $n;
39 |         $this->e = $e;
40 |     }
41 | 
42 |     /**
43 |      * @return string
44 |      */
45 |     public function asBCvalue()
46 |     {
47 |         $n = new BigInteger($this->n);
48 |         $e = new BigInteger('1' . str_repeat('0', $this->e));
49 |         list($q) = $n->divide($e);
50 |         return $q->toString();
51 |     }
52 | 
53 |     /**
54 |      * @return int
55 |      */
56 |     public function getE()
57 |     {
58 |         return $this->e;
59 |     }
60 | 
61 |     /**
62 |      * @return int
63 |      */
64 |     public function getN()
65 |     {
66 |         return $this->n;
67 |     }
68 | }
69 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Wire/AMQPIOReader.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | 
  3 | namespace PhpAmqpLib\Wire;
  4 | 
  5 | use PhpAmqpLib\Exception\AMQPDataReadException;
  6 | use PhpAmqpLib\Exception\AMQPIOException;
  7 | use PhpAmqpLib\Exception\AMQPNoDataException;
  8 | use PhpAmqpLib\Exception\AMQPTimeoutException;
  9 | use PhpAmqpLib\Helper\MiscHelper;
 10 | use PhpAmqpLib\Wire\IO\AbstractIO;
 11 | use RuntimeException;
 12 | 
 13 | class AMQPIOReader extends AMQPReader
 14 | {
 15 |     /** @var AbstractIO */
 16 |     private $io;
 17 | 
 18 |     /** @var int|float|null */
 19 |     protected $timeout;
 20 | 
 21 |     public function __construct(AbstractIO $io, $timeout = 0)
 22 |     {
 23 |         $this->io = $io;
 24 |         $this->timeout = $timeout;
 25 |     }
 26 | 
 27 |     public function close(): void
 28 |     {
 29 |         $this->io->close();
 30 |     }
 31 | 
 32 |     /**
 33 |      * @return float|int|mixed|null
 34 |      */
 35 |     public function getTimeout()
 36 |     {
 37 |         return $this->timeout;
 38 |     }
 39 | 
 40 |     /**
 41 |      * Sets the timeout (second)
 42 |      *
 43 |      * @param int|float|null $timeout
 44 |      */
 45 |     public function setTimeout($timeout)
 46 |     {
 47 |         $this->timeout = $timeout;
 48 |     }
 49 | 
 50 |     /**
 51 |      * @param int $n
 52 |      * @return string
 53 |      * @throws RuntimeException
 54 |      * @throws AMQPDataReadException|AMQPNoDataException|AMQPIOException
 55 |      */
 56 |     protected function rawread(int $n): string
 57 |     {
 58 |         $res = '';
 59 |         while (true) {
 60 |             $this->wait();
 61 |             try {
 62 |                 $res = $this->io->read($n);
 63 |                 break;
 64 |             } catch (AMQPTimeoutException $e) {
 65 |                 if ($this->getTimeout() > 0) {
 66 |                     throw $e;
 67 |                 }
 68 |             }
 69 |         }
 70 |         $this->offset += $n;
 71 | 
 72 |         return $res;
 73 |     }
 74 | 
 75 |     /**
 76 |      * Waits until some data is retrieved from the socket.
 77 |      *
 78 |      * AMQPTimeoutException can be raised if the timeout is set
 79 |      *
 80 |      * @throws AMQPTimeoutException when timeout is set and no data received
 81 |      * @throws AMQPNoDataException when no data is ready to read from IO
 82 |      */
 83 |     protected function wait(): void
 84 |     {
 85 |         $timeout = $this->timeout;
 86 |         if (null === $timeout) {
 87 |             // timeout=null just poll state and return instantly
 88 |             $result = $this->io->select(0);
 89 |             if ($result === 0) {
 90 |                 throw new AMQPNoDataException('No data is ready to read');
 91 |             }
 92 |             return;
 93 |         }
 94 | 
 95 |         if (!($timeout > 0)) {
 96 |             // wait indefinitely for data if timeout=0
 97 |             $result = $this->io->select(null);
 98 |             if ($result === 0) {
 99 |                 throw new AMQPNoDataException('No data is ready to read');
100 |             }
101 |             return;
102 |         }
103 | 
104 |         $leftTime = $timeout;
105 |         $started = microtime(true);
106 |         do {
107 |             [$sec, $usec] = MiscHelper::splitSecondsMicroseconds($leftTime);
108 |             $result = $this->io->select($sec, $usec);
109 |             if ($result > 0) {
110 |                 return;
111 |             }
112 |             // select might be interrupted by signal, calculate left time and repeat
113 |             $leftTime = $timeout - (microtime(true) - $started);
114 |         } while ($leftTime > 0);
115 | 
116 |         throw new AMQPTimeoutException(sprintf(
117 |                                            'The connection timed out after %s sec while awaiting incoming data',
118 |                                            $timeout
119 |                                        ));
120 | 
121 |     }
122 | }
123 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Wire/AMQPReader.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | 
  3 | namespace PhpAmqpLib\Wire;
  4 | 
  5 | use PhpAmqpLib\Channel\Frame;
  6 | use PhpAmqpLib\Exception\AMQPInvalidArgumentException;
  7 | use PhpAmqpLib\Exception\AMQPOutOfBoundsException;
  8 | use PhpAmqpLib\Helper\BigInteger;
  9 | 
 10 | abstract class AMQPReader extends AMQPByteStream
 11 | {
 12 |     /** @var int */
 13 |     protected $offset = 0;
 14 | 
 15 |     /** @var int */
 16 |     protected $bitcount = 0;
 17 | 
 18 |     /** @var int */
 19 |     protected $bits = 0;
 20 | 
 21 |     /**
 22 |      * Close the byte stream.
 23 |      */
 24 |     abstract public function close(): void;
 25 | 
 26 |     abstract protected function rawread(int $n): string;
 27 | 
 28 |     /**
 29 |      * @param int $n
 30 |      * @return string
 31 |      */
 32 |     public function read($n)
 33 |     {
 34 |         $this->resetCounters();
 35 | 
 36 |         return $this->rawread($n);
 37 |     }
 38 | 
 39 |     public function read_bit(): bool
 40 |     {
 41 |         if (empty($this->bitcount)) {
 42 |             $this->bits = ord($this->rawread(1));
 43 |             $this->bitcount = 8;
 44 |         }
 45 | 
 46 |         $result = ($this->bits & 1) === 1;
 47 |         $this->bits >>= 1;
 48 |         $this->bitcount--;
 49 | 
 50 |         return $result;
 51 |     }
 52 | 
 53 |     /**
 54 |      * @return int
 55 |      */
 56 |     public function read_octet()
 57 |     {
 58 |         $this->resetCounters();
 59 |         list(, $res) = unpack('C', $this->rawread(1));
 60 | 
 61 |         return $res;
 62 |     }
 63 | 
 64 |     /**
 65 |      * @return int
 66 |      */
 67 |     public function read_signed_octet()
 68 |     {
 69 |         $this->resetCounters();
 70 |         list(, $res) = unpack('c', $this->rawread(1));
 71 | 
 72 |         return $res;
 73 |     }
 74 | 
 75 |     /**
 76 |      * @return int
 77 |      */
 78 |     public function read_short()
 79 |     {
 80 |         $this->resetCounters();
 81 |         list(, $res) = unpack('n', $this->rawread(2));
 82 | 
 83 |         return $res;
 84 |     }
 85 | 
 86 |     /**
 87 |      * @return int
 88 |      */
 89 |     public function read_signed_short()
 90 |     {
 91 |         $this->resetCounters();
 92 |         list(, $res) = unpack('s', $this->correctEndianness($this->rawread(2)));
 93 | 
 94 |         return $res;
 95 |     }
 96 | 
 97 |     /**
 98 |      * Reads 32 bit integer in big-endian byte order.
 99 |      *
100 |      * On 64 bit systems it will return always unsigned int
101 |      * value in 0..2^32 range.
102 |      *
103 |      * On 32 bit systems it will return signed int value in
104 |      * -2^31...+2^31 range.
105 |      *
106 |      * Use with caution!
107 |      * @return int|string
108 |      */
109 |     public function read_php_int()
110 |     {
111 |         list(, $res) = unpack('N', $this->rawread(4));
112 | 
113 |         if (self::PLATFORM_64BIT) {
114 |             return (int) sprintf('%u', $res);
115 |         }
116 | 
117 |         return $res;
118 |     }
119 | 
120 |     /**
121 |      * PHP does not have unsigned 32 bit int,
122 |      * so we return it as a string
123 |      *
124 |      * @return int|string
125 |      */
126 |     public function read_long()
127 |     {
128 |         $this->resetCounters();
129 |         list(, $res) = unpack('N', $this->rawread(4));
130 |         if (!self::PLATFORM_64BIT && $this->getLongMSB($res)) {
131 |             return sprintf('%u', $res);
132 |         }
133 | 
134 |         return $res;
135 |     }
136 | 
137 |     /**
138 |      * @return int
139 |      */
140 |     private function readSignedLong()
141 |     {
142 |         $this->resetCounters();
143 |         list(, $res) = unpack('l', $this->correctEndianness($this->rawread(4)));
144 | 
145 |         return $res;
146 |     }
147 | 
148 |     /**
149 |      * Even on 64 bit systems PHP integers are signed.
150 |      * Since we need an unsigned value here we return it as a string.
151 |      *
152 |      * @return int|string
153 |      */
154 |     public function read_longlong()
155 |     {
156 |         $this->resetCounters();
157 |         $bytes = $this->rawread(8);
158 | 
159 |         if (self::PLATFORM_64BIT) {
160 |             // we can "unpack" if MSB bit is 0 (at most 63 bit integer), fallback to BigInteger otherwise
161 |             if (!$this->getMSB($bytes)) {
162 |                 $res = unpack('J', $bytes);
163 |                 return $res[1];
164 |             }
165 |         } else {
166 |             // on 32-bit systems we can "unpack" up to 31 bits integer
167 |             list(, $hi, $lo) = unpack('N2', $bytes);
168 |             if ($hi === 0 && $lo > 0) {
169 |                 return $lo;
170 |             }
171 |         }
172 | 
173 |         $var = new BigInteger($bytes, 256);
174 | 
175 |         return $var->toString();
176 |     }
177 | 
178 |     /**
179 |      * @return int|string
180 |      */
181 |     public function read_signed_longlong()
182 |     {
183 |         $this->resetCounters();
184 |         $bytes = $this->rawread(8);
185 | 
186 |         if (self::PLATFORM_64BIT) {
187 |             $res = unpack('q', $this->correctEndianness($bytes));
188 |             return $res[1];
189 |         } else {
190 |             // on 32-bit systems we can "unpack" up to 31 bits integer
191 |             list(, $hi, $lo) = unpack('N2', $bytes);
192 |             if ($hi === 0 && $lo > 0) {
193 |                 // positive and less than 2^31-1
194 |                 return $lo;
195 |             }
196 |             // negative and more than -2^31
197 |             if ($hi === -1 && $this->getLongMSB($lo)) {
198 |                 return $lo;
199 |             }
200 |         }
201 | 
202 |         $var = new BigInteger($bytes, -256);
203 | 
204 |         return $var->toString();
205 |     }
206 | 
207 |     /**
208 |      * @return float
209 |      */
210 |     public function read_float()
211 |     {
212 |         $this->resetCounters();
213 |         list(, $res) = unpack('G', $this->rawread(4));
214 | 
215 |         return (float)$res;
216 |     }
217 | 
218 |     /**
219 |      * @return float
220 |      */
221 |     public function read_double()
222 |     {
223 |         $this->resetCounters();
224 |         list(, $res) = unpack('E', $this->rawread(8));
225 | 
226 |         return (float)$res;
227 |     }
228 | 
229 |     /**
230 |      * Read a utf-8 encoded string that's stored in up to
231 |      * 255 bytes.  Return it decoded as a PHP unicode object.
232 |      * @return string
233 |      */
234 |     public function read_shortstr()
235 |     {
236 |         $this->resetCounters();
237 |         list(, $slen) = unpack('C', $this->rawread(1));
238 | 
239 |         return $this->rawread($slen);
240 |     }
241 | 
242 |     /**
243 |      * Read a string that's up to 2**32 bytes, the encoding
244 |      * isn't specified in the AMQP spec, so just return it as
245 |      * a plain PHP string.
246 |      * @return string
247 |      */
248 |     public function read_longstr()
249 |     {
250 |         $this->resetCounters();
251 |         $slen = $this->read_php_int();
252 | 
253 |         if ($slen < 0) {
254 |             throw new AMQPOutOfBoundsException('Strings longer than supported on this platform');
255 |         }
256 | 
257 |         return $this->rawread($slen);
258 |     }
259 | 
260 |     /**
261 |      * Read and AMQP timestamp, which is a 64-bit integer representing
262 |      * seconds since the Unix epoch in 1-second resolution.
263 |      * @return int|string
264 |      */
265 |     public function read_timestamp()
266 |     {
267 |         return $this->read_longlong();
268 |     }
269 | 
270 |     /**
271 |      * Read an AMQP table, and return as a PHP array. keys are strings,
272 |      * values are (type,value) tuples.
273 |      *
274 |      * @param bool $returnObject Whether to return AMQPArray instance instead of plain array
275 |      * @return array|AMQPTable
276 |      */
277 |     public function read_table(bool $returnObject = false)
278 |     {
279 |         $this->resetCounters();
280 |         $tlen = $this->read_php_int();
281 | 
282 |         if ($tlen < 0) {
283 |             throw new AMQPOutOfBoundsException('Table is longer than supported');
284 |         }
285 | 
286 |         $table_data = new AMQPBufferReader($this->rawread($tlen));
287 |         $result = $returnObject ? new AMQPTable() : array();
288 | 
289 |         while ($table_data->tell() < $tlen) {
290 |             $name = $table_data->read_shortstr();
291 |             $ftype = AMQPAbstractCollection::getDataTypeForSymbol($ftypeSym = $table_data->rawread(1));
292 |             $val = $table_data->read_value($ftype, $returnObject);
293 |             $returnObject ? $result->set($name, $val, $ftype) : $result[$name] = array($ftypeSym, $val);
294 |         }
295 | 
296 |         return $result;
297 |     }
298 | 
299 |     /**
300 |      * @return array|AMQPTable
301 |      */
302 |     public function read_table_object()
303 |     {
304 |         return $this->read_table(true);
305 |     }
306 | 
307 |     /**
308 |      * Reads the array in the next value.
309 |      *
310 |      * @param bool $returnObject Whether to return AMQPArray instance instead of plain array
311 |      * @return array|AMQPArray
312 |      */
313 |     public function read_array($returnObject = false)
314 |     {
315 |         $this->resetCounters();
316 | 
317 |         // Determine array length and its end position
318 |         $arrayLength = $this->read_php_int();
319 |         $endOffset = $this->offset + $arrayLength;
320 | 
321 |         $result = $returnObject ? new AMQPArray() : array();
322 | 
323 |         // Read values until we reach the end of the array
324 |         while ($this->offset < $endOffset) {
325 |             $fieldType = AMQPAbstractCollection::getDataTypeForSymbol($this->rawread(1));
326 |             $fieldValue = $this->read_value($fieldType, $returnObject);
327 |             $returnObject ? $result->push($fieldValue, $fieldType) : $result[] = $fieldValue;
328 |         }
329 | 
330 |         return $result;
331 |     }
332 | 
333 |     /**
334 |      * @return array|AMQPArray
335 |      */
336 |     public function read_array_object()
337 |     {
338 |         return $this->read_array(true);
339 |     }
340 | 
341 |     /**
342 |      * @return array{type:int, channel:int, size:int}
343 |      */
344 |     public function readFrameHeader(): array
345 |     {
346 |         return unpack('Ctype/nchannel/Nsize', $this->rawread(Frame::FRAME_HEADER_SIZE));
347 |     }
348 | 
349 |     /**
350 |      * Reads the next value as the provided field type.
351 |      *
352 |      * @param int $fieldType One of AMQPAbstractCollection::T_* constants
353 |      * @param bool $collectionsAsObjects Description
354 |      * @return mixed
355 |      * @throws \PhpAmqpLib\Exception\AMQPDataReadException
356 |      */
357 |     public function read_value(int $fieldType, bool $collectionsAsObjects = false)
358 |     {
359 |         $this->resetCounters();
360 | 
361 |         switch ($fieldType) {
362 |             case AMQPAbstractCollection::T_INT_SHORTSHORT:
363 |                 //according to AMQP091 spec, 'b' is not bit, it is short-short-int, also valid for rabbit/qpid
364 |                 //$val=$this->read_bit();
365 |                 $val = $this->read_signed_octet();
366 |                 break;
367 |             case AMQPAbstractCollection::T_INT_SHORTSHORT_U:
368 |             case AMQPAbstractCollection::T_BOOL:
369 |                 $val = $this->read_octet();
370 |                 break;
371 |             case AMQPAbstractCollection::T_INT_SHORT:
372 |                 $val = $this->read_signed_short();
373 |                 break;
374 |             case AMQPAbstractCollection::T_INT_SHORT_U:
375 |                 $val = $this->read_short();
376 |                 break;
377 |             case AMQPAbstractCollection::T_INT_LONG:
378 |                 $val = $this->readSignedLong();
379 |                 break;
380 |             case AMQPAbstractCollection::T_INT_LONG_U:
381 |                 $val = $this->read_long();
382 |                 break;
383 |             case AMQPAbstractCollection::T_INT_LONGLONG:
384 |                 $val = $this->read_signed_longlong();
385 |                 break;
386 |             case AMQPAbstractCollection::T_INT_LONGLONG_U:
387 |                 $val = $this->read_longlong();
388 |                 break;
389 |             case AMQPAbstractCollection::T_DECIMAL:
390 |                 $e = $this->read_octet();
391 |                 $n = $this->readSignedLong();
392 |                 $val = new AMQPDecimal($n, $e);
393 |                 break;
394 |             case AMQPAbstractCollection::T_TIMESTAMP:
395 |                 $val = $this->read_timestamp();
396 |                 break;
397 |             case AMQPAbstractCollection::T_STRING_SHORT:
398 |                 $val = $this->read_shortstr();
399 |                 break;
400 |             case AMQPAbstractCollection::T_STRING_LONG:
401 |             case AMQPAbstractCollection::T_BYTES:
402 |                 $val = $this->read_longstr();
403 |                 break;
404 |             case AMQPAbstractCollection::T_ARRAY:
405 |                 $val = $this->read_array($collectionsAsObjects);
406 |                 break;
407 |             case AMQPAbstractCollection::T_TABLE:
408 |                 $val = $this->read_table($collectionsAsObjects);
409 |                 break;
410 |             case AMQPAbstractCollection::T_VOID:
411 |                 $val = null;
412 |                 break;
413 |             case AMQPAbstractCollection::T_FLOAT:
414 |                 $val = $this->read_float();
415 |                 break;
416 |             case AMQPAbstractCollection::T_DOUBLE:
417 |                 $val = $this->read_double();
418 |                 break;
419 |             default:
420 |                 throw new AMQPInvalidArgumentException(sprintf(
421 |                     'Unsupported type "%s"',
422 |                     $fieldType
423 |                 ));
424 |         }
425 | 
426 |         return $val;
427 |     }
428 | 
429 |     protected function tell(): int
430 |     {
431 |         return $this->offset;
432 |     }
433 | 
434 |     protected function resetCounters(): void
435 |     {
436 |         $this->bitcount = $this->bits = 0;
437 |     }
438 | }
439 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Wire/AMQPTable.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | namespace PhpAmqpLib\Wire;
 4 | 
 5 | use PhpAmqpLib\Exception;
 6 | 
 7 | class AMQPTable extends AMQPAbstractCollection
 8 | {
 9 | 
10 |     /**
11 |      * @return int
12 |      */
13 |     final public function getType()
14 |     {
15 |         return self::T_TABLE;
16 |     }
17 | 
18 |     /**
19 |      * @param string $key
20 |      * @param mixed $val
21 |      * @param int|null $type
22 |      */
23 |     public function set($key, $val, $type = null)
24 |     {
25 |         //https://www.rabbitmq.com/resources/specs/amqp0-9-1.pdf, https://www.rabbitmq.com/resources/specs/amqp0-8.pdf
26 |         //Field names MUST start with a letter, '
#39; or '#' and may continue with letters, '
#39; or '#', digits,
27 |         // or underlines, to a maximum length of 128 characters
28 |         //The server SHOULD validate field names and upon receiving an invalid field name, it SHOULD signal a connection
29 |         // exception with reply code 503 (syntax error)
30 | 
31 |         //validating length only and delegating other stuff to server, as rabbit seems to currently support numeric keys
32 |         if (!($len = strlen($key)) || ($len > 128)) {
33 |             throw new Exception\AMQPInvalidArgumentException(
34 |                 'Table key must be non-empty string up to 128 chars in length'
35 |             );
36 |         }
37 |         $this->setValue($val, $type, $key);
38 |     }
39 | }
40 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Wire/AMQPWriter.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | 
  3 | namespace PhpAmqpLib\Wire;
  4 | 
  5 | use PhpAmqpLib\Exception\AMQPInvalidArgumentException;
  6 | use PhpAmqpLib\Exception\AMQPOutOfRangeException;
  7 | use PhpAmqpLib\Helper\BigInteger;
  8 | 
  9 | class AMQPWriter extends AMQPByteStream
 10 | {
 11 |     /** @var string */
 12 |     protected $out = '';
 13 | 
 14 |     /** @var array */
 15 |     protected $bits = array();
 16 | 
 17 |     /** @var int */
 18 |     protected $bitcount = 0;
 19 | 
 20 |     private function flushbits()
 21 |     {
 22 |         if (!empty($this->bits)) {
 23 |             $this->out .= implode('', array_map('chr', $this->bits));
 24 |             $this->bits = array();
 25 |             $this->bitcount = 0;
 26 |         }
 27 |     }
 28 | 
 29 |     /**
 30 |      * Get what's been encoded so far.
 31 |      *
 32 |      * @return string
 33 |      */
 34 |     public function getvalue()
 35 |     {
 36 |         /* temporarily needed for compatibility with write_bit unit tests */
 37 |         if ($this->bitcount) {
 38 |             $this->flushbits();
 39 |         }
 40 | 
 41 |         return $this->out;
 42 |     }
 43 | 
 44 |     /**
 45 |      * Write a plain PHP string, with no special encoding.
 46 |      *
 47 |      * @param string $s
 48 |      *
 49 |      * @return $this
 50 |      */
 51 |     public function write($s)
 52 |     {
 53 |         $this->out .= $s;
 54 | 
 55 |         return $this;
 56 |     }
 57 | 
 58 |     /**
 59 |      * Write a boolean value.
 60 |      * (deprecated, use write_bits instead)
 61 |      *
 62 |      * @deprecated
 63 |      * @param bool $b
 64 |      * @return $this
 65 |      */
 66 |     public function write_bit($b)
 67 |     {
 68 |         $b = $b ? 1 : 0;
 69 |         $shift = $this->bitcount % 8;
 70 |         $last = $shift === 0 ? 0 : array_pop($this->bits);
 71 |         $last |= ($b << $shift);
 72 |         $this->bits[] = $last;
 73 |         $this->bitcount++;
 74 | 
 75 |         return $this;
 76 |     }
 77 | 
 78 |     /**
 79 |      * Write multiple bits as an octet
 80 |      *
 81 |      * @param bool[] $bits
 82 |      * @return $this
 83 |      */
 84 |     public function write_bits($bits)
 85 |     {
 86 |         $value = 0;
 87 | 
 88 |         foreach ($bits as $n => $bit) {
 89 |             $bit = $bit ? 1 : 0;
 90 |             $value |= ($bit << $n);
 91 |         }
 92 | 
 93 |         $this->out .= chr($value);
 94 | 
 95 |         return $this;
 96 |     }
 97 | 
 98 |     /**
 99 |      * Write an integer as an unsigned 8-bit value
100 |      *
101 |      * @param int $n
102 |      * @return $this
103 |      * @throws \PhpAmqpLib\Exception\AMQPInvalidArgumentException
104 |      */
105 |     public function write_octet($n)
106 |     {
107 |         if ($n < 0 || $n > 255) {
108 |             throw new AMQPInvalidArgumentException('Octet out of range: ' . $n);
109 |         }
110 | 
111 |         $this->out .= chr($n);
112 | 
113 |         return $this;
114 |     }
115 | 
116 |     /**
117 |      * @param int $n
118 |      * @return $this
119 |      */
120 |     public function write_signed_octet($n)
121 |     {
122 |         if (($n < -128) || ($n > 127)) {
123 |             throw new AMQPInvalidArgumentException('Signed octet out of range: ' . $n);
124 |         }
125 | 
126 |         $this->out .= pack('c', $n);
127 | 
128 |         return $this;
129 |     }
130 | 
131 |     /**
132 |      * Write an integer as an unsigned 16-bit value
133 |      *
134 |      * @param int $n
135 |      * @return $this
136 |      * @throws \PhpAmqpLib\Exception\AMQPInvalidArgumentException
137 |      */
138 |     public function write_short($n)
139 |     {
140 |         if ($n < 0 || $n > 65535) {
141 |             throw new AMQPInvalidArgumentException('Short out of range: ' . $n);
142 |         }
143 | 
144 |         $this->out .= pack('n', $n);
145 | 
146 |         return $this;
147 |     }
148 | 
149 |     /**
150 |      * @param int $n
151 |      * @return $this
152 |      */
153 |     public function write_signed_short($n)
154 |     {
155 |         if (($n < -32768) || ($n > 32767)) {
156 |             throw new AMQPInvalidArgumentException('Signed short out of range: ' . $n);
157 |         }
158 | 
159 |         $this->out .= $this->correctEndianness(pack('s', $n));
160 | 
161 |         return $this;
162 |     }
163 | 
164 |     /**
165 |      * Write an integer as an unsigned 32-bit value
166 |      *
167 |      * @param int|string $n
168 |      * @return $this
169 |      */
170 |     public function write_long($n)
171 |     {
172 |         if (($n < 0) || ($n > 4294967295)) {
173 |             throw new AMQPInvalidArgumentException('Long out of range: ' . $n);
174 |         }
175 | 
176 |         //Numeric strings >PHP_INT_MAX on 32bit are casted to PHP_INT_MAX, damn PHP
177 |         if (!self::PLATFORM_64BIT && is_string($n)) {
178 |             $n = (float) $n;
179 |         }
180 |         $this->out .= pack('N', $n);
181 | 
182 |         return $this;
183 |     }
184 | 
185 |     /**
186 |      * @param int $n
187 |      * @return $this
188 |      */
189 |     private function writeSignedLong($n)
190 |     {
191 |         if (($n < -2147483648) || ($n > 2147483647)) {
192 |             throw new AMQPInvalidArgumentException('Signed long out of range: ' . $n);
193 |         }
194 | 
195 |         //on my 64bit debian this approach is slightly faster than splitIntoQuads()
196 |         $this->out .= $this->correctEndianness(pack('l', $n));
197 | 
198 |         return $this;
199 |     }
200 | 
201 |     /**
202 |      * Write a numeric value as an unsigned 64-bit value
203 |      *
204 |      * @param int|string $n
205 |      * @return $this
206 |      * @throws AMQPOutOfRangeException
207 |      */
208 |     public function write_longlong($n)
209 |     {
210 |         if (is_int($n)) {
211 |             if ($n < 0) {
212 |                 throw new AMQPOutOfRangeException('Longlong out of range: ' . $n);
213 |             }
214 | 
215 |             if (self::PLATFORM_64BIT) {
216 |                 $res = pack('J', $n);
217 |                 $this->out .= $res;
218 |             } else {
219 |                 $this->out .= pack('NN', 0, $n);
220 |             }
221 | 
222 |             return $this;
223 |         }
224 | 
225 |         $value = new BigInteger($n);
226 |         if (
227 |             $value->compare(self::getBigInteger('0')) < 0
228 |             || $value->compare(self::getBigInteger('FFFFFFFFFFFFFFFF', 16)) > 0
229 |         ) {
230 |             throw new AMQPInvalidArgumentException('Longlong out of range: ' . $n);
231 |         }
232 | 
233 |         $value->setPrecision(64);
234 |         $this->out .= $value->toBytes();
235 | 
236 |         return $this;
237 |     }
238 | 
239 |     /**
240 |      * @param int|string $n
241 |      * @return $this
242 |      */
243 |     public function write_signed_longlong($n)
244 |     {
245 |         if (is_int($n)) {
246 |             if (self::PLATFORM_64BIT) {
247 |                 // q is for 64-bit signed machine byte order
248 |                 $packed = pack('q', $n);
249 |                 if (self::isLittleEndian()) {
250 |                     $packed = $this->convertByteOrder($packed);
251 |                 }
252 |                 $this->out .= $packed;
253 |             } else {
254 |                 $hi = $n < 0 ? -1 : 0;
255 |                 $lo = $n;
256 |                 $this->out .= pack('NN', $hi, $lo);
257 |             }
258 | 
259 |             return $this;
260 |         }
261 | 
262 |         $value = new BigInteger($n);
263 |         if (
264 |             $value->compare(self::getBigInteger('-8000000000000000', 16)) < 0
265 |             || $value->compare(self::getBigInteger('7FFFFFFFFFFFFFFF', 16)) > 0
266 |         ) {
267 |             throw new AMQPInvalidArgumentException('Signed longlong out of range: ' . $n);
268 |         }
269 | 
270 |         $value->setPrecision(64);
271 |         $this->out .= substr($value->toBytes(true), -8);
272 | 
273 |         return $this;
274 |     }
275 | 
276 |     /**
277 |      * Write a string up to 255 bytes long after encoding.
278 |      * Assume UTF-8 encoding
279 |      *
280 |      * @param string $s
281 |      * @return $this
282 |      * @throws \PhpAmqpLib\Exception\AMQPInvalidArgumentException
283 |      */
284 |     public function write_shortstr($s)
285 |     {
286 |         if ($s === null) {
287 |             $this->write_octet(0);
288 | 
289 |             return $this;
290 |         }
291 | 
292 |         $len = mb_strlen($s, 'ASCII');
293 |         if ($len > 255) {
294 |             throw new AMQPInvalidArgumentException('String too long');
295 |         }
296 | 
297 |         $this->write_octet($len);
298 |         $this->out .= $s;
299 | 
300 |         return $this;
301 |     }
302 | 
303 |     /**
304 |      * Write a string up to 2**32 bytes long.  Assume UTF-8 encoding
305 |      *
306 |      * @param string $s
307 |      * @return $this
308 |      */
309 |     public function write_longstr($s)
310 |     {
311 |         if ($s === null) {
312 |             $this->write_long(0);
313 | 
314 |             return $this;
315 |         }
316 | 
317 |         $this->write_long(mb_strlen($s, 'ASCII'));
318 |         $this->out .= $s;
319 | 
320 |         return $this;
321 |     }
322 | 
323 |     /**
324 |      * Supports the writing of Array types, so that you can implement
325 |      * array methods, like Rabbitmq's HA parameters
326 |      *
327 |      * @param AMQPArray|array $a Instance of AMQPArray or PHP array WITHOUT format hints (unlike write_table())
328 |      * @return self
329 |      */
330 |     public function write_array($a)
331 |     {
332 |         if (!($a instanceof AMQPArray)) {
333 |             $a = new AMQPArray($a);
334 |         }
335 |         $data = new self();
336 | 
337 |         foreach ($a as $v) {
338 |             $data->writeValue($v[0], $v[1]);
339 |         }
340 | 
341 |         $data = $data->getvalue();
342 |         $this->write_long(mb_strlen($data, 'ASCII'));
343 |         $this->write($data);
344 | 
345 |         return $this;
346 |     }
347 | 
348 |     /**
349 |      * Write unix time_t value as 64 bit timestamp
350 |      *
351 |      * @param int $v
352 |      * @return $this
353 |      */
354 |     public function write_timestamp($v)
355 |     {
356 |         $this->write_longlong($v);
357 | 
358 |         return $this;
359 |     }
360 | 
361 |     /**
362 |      * Write PHP array, as table. Input array format: keys are strings,
363 |      * values are (type,value) tuples.
364 |      *
365 |      * @param AMQPTable|array $d Instance of AMQPTable or PHP array WITH format hints (unlike write_array())
366 |      * @return $this
367 |      * @throws \PhpAmqpLib\Exception\AMQPInvalidArgumentException
368 |      */
369 |     public function write_table($d)
370 |     {
371 |         $typeIsSym = !($d instanceof AMQPTable); //purely for back-compat purposes
372 | 
373 |         $table_data = new self();
374 |         foreach ($d as $k => $va) {
375 |             list($ftype, $v) = $va;
376 |             $table_data->write_shortstr($k);
377 |             $table_data->writeValue($typeIsSym ? AMQPAbstractCollection::getDataTypeForSymbol($ftype) : $ftype, $v);
378 |         }
379 | 
380 |         $table_data = $table_data->getvalue();
381 |         $this->write_long(mb_strlen($table_data, 'ASCII'));
382 |         $this->write($table_data);
383 | 
384 |         return $this;
385 |     }
386 | 
387 |     /**
388 |      * for compat with method mapping used by AMQPMessage
389 |      *
390 |      * @param AMQPTable|array $d
391 |      * @return $this
392 |      */
393 |     public function write_table_object($d)
394 |     {
395 |         return $this->write_table($d);
396 |     }
397 | 
398 |     /**
399 |      * @param int $type One of AMQPAbstractCollection::T_* constants
400 |      * @param mixed $val
401 |      */
402 |     private function writeValue($type, $val)
403 |     {
404 |         //This will find appropriate symbol for given data type for currently selected protocol
405 |         //Also will raise an exception on unknown type
406 |         $this->write(AMQPAbstractCollection::getSymbolForDataType($type));
407 | 
408 |         switch ($type) {
409 |             case AMQPAbstractCollection::T_INT_SHORTSHORT:
410 |                 $this->write_signed_octet($val);
411 |                 break;
412 |             case AMQPAbstractCollection::T_INT_SHORTSHORT_U:
413 |                 $this->write_octet($val);
414 |                 break;
415 |             case AMQPAbstractCollection::T_INT_SHORT:
416 |                 $this->write_signed_short($val);
417 |                 break;
418 |             case AMQPAbstractCollection::T_INT_SHORT_U:
419 |                 $this->write_short($val);
420 |                 break;
421 |             case AMQPAbstractCollection::T_INT_LONG:
422 |                 $this->writeSignedLong($val);
423 |                 break;
424 |             case AMQPAbstractCollection::T_INT_LONG_U:
425 |                 $this->write_long($val);
426 |                 break;
427 |             case AMQPAbstractCollection::T_INT_LONGLONG:
428 |                 $this->write_signed_longlong($val);
429 |                 break;
430 |             case AMQPAbstractCollection::T_INT_LONGLONG_U:
431 |                 $this->write_longlong($val);
432 |                 break;
433 |             case AMQPAbstractCollection::T_DECIMAL:
434 |                 $this->write_octet($val->getE());
435 |                 $this->writeSignedLong($val->getN());
436 |                 break;
437 |             case AMQPAbstractCollection::T_TIMESTAMP:
438 |                 $this->write_timestamp($val);
439 |                 break;
440 |             case AMQPAbstractCollection::T_BOOL:
441 |                 $this->write_octet($val ? 1 : 0);
442 |                 break;
443 |             case AMQPAbstractCollection::T_STRING_SHORT:
444 |                 $this->write_shortstr($val);
445 |                 break;
446 |             case AMQPAbstractCollection::T_STRING_LONG:
447 |                 $this->write_longstr($val);
448 |                 break;
449 |             case AMQPAbstractCollection::T_ARRAY:
450 |                 $this->write_array($val);
451 |                 break;
452 |             case AMQPAbstractCollection::T_TABLE:
453 |                 $this->write_table($val);
454 |                 break;
455 |             case AMQPAbstractCollection::T_VOID:
456 |                 break;
457 |             case AMQPAbstractCollection::T_BYTES:
458 |                 $this->write_longstr($val);
459 |                 break;
460 |             default:
461 |                 throw new AMQPInvalidArgumentException(sprintf(
462 |                     'Unsupported type "%s"',
463 |                     $type
464 |                 ));
465 |         }
466 |     }
467 | }
468 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Wire/Constants.php:
--------------------------------------------------------------------------------
 1 | <?php
 2 | 
 3 | namespace PhpAmqpLib\Wire;
 4 | 
 5 | abstract class Constants
 6 | {
 7 |     const VERSION = '';
 8 |     const AMQP_HEADER = '';
 9 | 
10 |     /**
11 |      * @var array<int, string>
12 |      */
13 |     protected static $FRAME_TYPES = array();
14 | 
15 |     /**
16 |      * @var array<int, string>
17 |      */
18 |     protected static $CONTENT_METHODS = array();
19 | 
20 |     /**
21 |      * @var array<int, string>
22 |      */
23 |     protected static $CLOSE_METHODS = array();
24 | 
25 |     /**
26 |      * @var array<string, string>
27 |      */
28 |     public static $GLOBAL_METHOD_NAMES = array();
29 | 
30 |     /**
31 |      * @return string
32 |      */
33 |     public function getHeader()
34 |     {
35 |         return static::AMQP_HEADER;
36 |     }
37 | 
38 |     /**
39 |      * @param int $type
40 |      * @return bool
41 |      */
42 |     public function isFrameType($type)
43 |     {
44 |         return array_key_exists($type, static::$FRAME_TYPES);
45 |     }
46 | 
47 |     /**
48 |      * @param int $type
49 |      * @return string
50 |      */
51 |     public function getFrameType($type)
52 |     {
53 |         return static::$FRAME_TYPES[$type];
54 |     }
55 | 
56 |     /**
57 |      * @param string $method
58 |      * @return bool
59 |      */
60 |     public function isContentMethod($method)
61 |     {
62 |         return in_array($method, static::$CONTENT_METHODS, false);
63 |     }
64 | 
65 |     /**
66 |      * @param string $method
67 |      * @return bool
68 |      */
69 |     public function isCloseMethod($method)
70 |     {
71 |         return in_array($method, static::$CLOSE_METHODS, false);
72 |     }
73 | }
74 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Wire/Constants080.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | 
  3 | /* This file was autogenerated by spec/parser.php - Do not modify */
  4 | 
  5 | namespace PhpAmqpLib\Wire;
  6 | 
  7 | final class Constants080 extends Constants
  8 | {
  9 |     const VERSION = '8.0';
 10 |     const AMQP_HEADER = "AMQP\x01\x01\x08\x00";
 11 | 
 12 |     /**
 13 |      * @var array
 14 |      */
 15 |     public static $FRAME_TYPES = array(
 16 |         1 => 'FRAME-METHOD',
 17 |         2 => 'FRAME-HEADER',
 18 |         3 => 'FRAME-BODY',
 19 |         4 => 'FRAME-OOB-METHOD',
 20 |         5 => 'FRAME-OOB-HEADER',
 21 |         6 => 'FRAME-OOB-BODY',
 22 |         7 => 'FRAME-TRACE',
 23 |         8 => 'FRAME-HEARTBEAT',
 24 |         4096 => 'FRAME-MIN-SIZE',
 25 |         206 => 'FRAME-END',
 26 |         501 => 'FRAME-ERROR',
 27 |     );
 28 | 
 29 |     /**
 30 |      * @var array
 31 |      */
 32 |     public static $CONTENT_METHODS = array(
 33 |         0 => '60,40',
 34 |         1 => '60,50',
 35 |         2 => '60,60',
 36 |         3 => '60,71',
 37 |         4 => '70,50',
 38 |         5 => '70,70',
 39 |         6 => '80,40',
 40 |         7 => '80,50',
 41 |         8 => '80,60',
 42 |         9 => '110,10',
 43 |         10 => '120,40',
 44 |         11 => '120,41',
 45 |     );
 46 | 
 47 |     /**
 48 |      * @var array
 49 |      */
 50 |     public static $CLOSE_METHODS = array(
 51 |         0 => '10,60',
 52 |         1 => '20,40',
 53 |     );
 54 | 
 55 |     /**
 56 |      * @var array
 57 |      */
 58 |     public static $GLOBAL_METHOD_NAMES = array(
 59 |         '10,10' => 'Connection.start',
 60 |         '10,11' => 'Connection.start_ok',
 61 |         '10,20' => 'Connection.secure',
 62 |         '10,21' => 'Connection.secure_ok',
 63 |         '10,30' => 'Connection.tune',
 64 |         '10,31' => 'Connection.tune_ok',
 65 |         '10,40' => 'Connection.open',
 66 |         '10,41' => 'Connection.open_ok',
 67 |         '10,50' => 'Connection.redirect',
 68 |         '10,60' => 'Connection.close',
 69 |         '10,61' => 'Connection.close_ok',
 70 |         '20,10' => 'Channel.open',
 71 |         '20,11' => 'Channel.open_ok',
 72 |         '20,20' => 'Channel.flow',
 73 |         '20,21' => 'Channel.flow_ok',
 74 |         '20,30' => 'Channel.alert',
 75 |         '20,40' => 'Channel.close',
 76 |         '20,41' => 'Channel.close_ok',
 77 |         '30,10' => 'Access.request',
 78 |         '30,11' => 'Access.request_ok',
 79 |         '40,10' => 'Exchange.declare',
 80 |         '40,11' => 'Exchange.declare_ok',
 81 |         '40,20' => 'Exchange.delete',
 82 |         '40,21' => 'Exchange.delete_ok',
 83 |         '50,10' => 'Queue.declare',
 84 |         '50,11' => 'Queue.declare_ok',
 85 |         '50,20' => 'Queue.bind',
 86 |         '50,21' => 'Queue.bind_ok',
 87 |         '50,30' => 'Queue.purge',
 88 |         '50,31' => 'Queue.purge_ok',
 89 |         '50,40' => 'Queue.delete',
 90 |         '50,41' => 'Queue.delete_ok',
 91 |         '50,50' => 'Queue.unbind',
 92 |         '50,51' => 'Queue.unbind_ok',
 93 |         '60,10' => 'Basic.qos',
 94 |         '60,11' => 'Basic.qos_ok',
 95 |         '60,20' => 'Basic.consume',
 96 |         '60,21' => 'Basic.consume_ok',
 97 |         '60,30' => 'Basic.cancel',
 98 |         '60,31' => 'Basic.cancel_ok',
 99 |         '60,40' => 'Basic.publish',
100 |         '60,50' => 'Basic.return',
101 |         '60,60' => 'Basic.deliver',
102 |         '60,70' => 'Basic.get',
103 |         '60,71' => 'Basic.get_ok',
104 |         '60,72' => 'Basic.get_empty',
105 |         '60,80' => 'Basic.ack',
106 |         '60,90' => 'Basic.reject',
107 |         '60,100' => 'Basic.recover_async',
108 |         '60,110' => 'Basic.recover',
109 |         '60,111' => 'Basic.recover_ok',
110 |         '70,10' => 'File.qos',
111 |         '70,11' => 'File.qos_ok',
112 |         '70,20' => 'File.consume',
113 |         '70,21' => 'File.consume_ok',
114 |         '70,30' => 'File.cancel',
115 |         '70,31' => 'File.cancel_ok',
116 |         '70,40' => 'File.open',
117 |         '70,41' => 'File.open_ok',
118 |         '70,50' => 'File.stage',
119 |         '70,60' => 'File.publish',
120 |         '70,70' => 'File.return',
121 |         '70,80' => 'File.deliver',
122 |         '70,90' => 'File.ack',
123 |         '70,100' => 'File.reject',
124 |         '80,10' => 'Stream.qos',
125 |         '80,11' => 'Stream.qos_ok',
126 |         '80,20' => 'Stream.consume',
127 |         '80,21' => 'Stream.consume_ok',
128 |         '80,30' => 'Stream.cancel',
129 |         '80,31' => 'Stream.cancel_ok',
130 |         '80,40' => 'Stream.publish',
131 |         '80,50' => 'Stream.return',
132 |         '80,60' => 'Stream.deliver',
133 |         '90,10' => 'Tx.select',
134 |         '90,11' => 'Tx.select_ok',
135 |         '90,20' => 'Tx.commit',
136 |         '90,21' => 'Tx.commit_ok',
137 |         '90,30' => 'Tx.rollback',
138 |         '90,31' => 'Tx.rollback_ok',
139 |         '100,10' => 'Dtx.select',
140 |         '100,11' => 'Dtx.select_ok',
141 |         '100,20' => 'Dtx.start',
142 |         '100,21' => 'Dtx.start_ok',
143 |         '110,10' => 'Tunnel.request',
144 |         '120,10' => 'Test.integer',
145 |         '120,11' => 'Test.integer_ok',
146 |         '120,20' => 'Test.string',
147 |         '120,21' => 'Test.string_ok',
148 |         '120,30' => 'Test.table',
149 |         '120,31' => 'Test.table_ok',
150 |         '120,40' => 'Test.content',
151 |         '120,41' => 'Test.content_ok',
152 |     );
153 | }
154 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Wire/Constants091.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | 
  3 | /* This file was autogenerated by spec/parser.php - Do not modify */
  4 | 
  5 | namespace PhpAmqpLib\Wire;
  6 | 
  7 | final class Constants091 extends Constants
  8 | {
  9 |     const VERSION = '0.9.1';
 10 |     const AMQP_HEADER = "AMQP\x00\x00\x09\x01";
 11 | 
 12 |     /**
 13 |      * @var array
 14 |      */
 15 |     public static $FRAME_TYPES = array(
 16 |         1 => 'FRAME-METHOD',
 17 |         2 => 'FRAME-HEADER',
 18 |         3 => 'FRAME-BODY',
 19 |         8 => 'FRAME-HEARTBEAT',
 20 |         4096 => 'FRAME-MIN-SIZE',
 21 |         206 => 'FRAME-END',
 22 |         501 => 'FRAME-ERROR',
 23 |     );
 24 | 
 25 |     /**
 26 |      * @var array
 27 |      */
 28 |     public static $CONTENT_METHODS = array(
 29 |         0 => '60,40',
 30 |         1 => '60,50',
 31 |         2 => '60,60',
 32 |         3 => '60,71',
 33 |     );
 34 | 
 35 |     /**
 36 |      * @var array
 37 |      */
 38 |     public static $CLOSE_METHODS = array(
 39 |         0 => '10,50',
 40 |         1 => '20,40',
 41 |     );
 42 | 
 43 |     /**
 44 |      * @var array
 45 |      */
 46 |     public static $GLOBAL_METHOD_NAMES = array(
 47 |         '10,10' => 'Connection.start',
 48 |         '10,11' => 'Connection.start_ok',
 49 |         '10,20' => 'Connection.secure',
 50 |         '10,21' => 'Connection.secure_ok',
 51 |         '10,30' => 'Connection.tune',
 52 |         '10,31' => 'Connection.tune_ok',
 53 |         '10,40' => 'Connection.open',
 54 |         '10,41' => 'Connection.open_ok',
 55 |         '10,50' => 'Connection.close',
 56 |         '10,51' => 'Connection.close_ok',
 57 |         '10,60' => 'Connection.blocked',
 58 |         '10,61' => 'Connection.unblocked',
 59 |         '20,10' => 'Channel.open',
 60 |         '20,11' => 'Channel.open_ok',
 61 |         '20,20' => 'Channel.flow',
 62 |         '20,21' => 'Channel.flow_ok',
 63 |         '20,40' => 'Channel.close',
 64 |         '20,41' => 'Channel.close_ok',
 65 |         '30,10' => 'Access.request',
 66 |         '30,11' => 'Access.request_ok',
 67 |         '40,10' => 'Exchange.declare',
 68 |         '40,11' => 'Exchange.declare_ok',
 69 |         '40,20' => 'Exchange.delete',
 70 |         '40,21' => 'Exchange.delete_ok',
 71 |         '40,30' => 'Exchange.bind',
 72 |         '40,31' => 'Exchange.bind_ok',
 73 |         '40,40' => 'Exchange.unbind',
 74 |         '40,51' => 'Exchange.unbind_ok',
 75 |         '50,10' => 'Queue.declare',
 76 |         '50,11' => 'Queue.declare_ok',
 77 |         '50,20' => 'Queue.bind',
 78 |         '50,21' => 'Queue.bind_ok',
 79 |         '50,30' => 'Queue.purge',
 80 |         '50,31' => 'Queue.purge_ok',
 81 |         '50,40' => 'Queue.delete',
 82 |         '50,41' => 'Queue.delete_ok',
 83 |         '50,50' => 'Queue.unbind',
 84 |         '50,51' => 'Queue.unbind_ok',
 85 |         '60,10' => 'Basic.qos',
 86 |         '60,11' => 'Basic.qos_ok',
 87 |         '60,20' => 'Basic.consume',
 88 |         '60,21' => 'Basic.consume_ok',
 89 |         '60,30' => 'Basic.cancel',
 90 |         '60,31' => 'Basic.cancel_ok',
 91 |         '60,40' => 'Basic.publish',
 92 |         '60,50' => 'Basic.return',
 93 |         '60,60' => 'Basic.deliver',
 94 |         '60,70' => 'Basic.get',
 95 |         '60,71' => 'Basic.get_ok',
 96 |         '60,72' => 'Basic.get_empty',
 97 |         '60,80' => 'Basic.ack',
 98 |         '60,90' => 'Basic.reject',
 99 |         '60,100' => 'Basic.recover_async',
100 |         '60,110' => 'Basic.recover',
101 |         '60,111' => 'Basic.recover_ok',
102 |         '60,120' => 'Basic.nack',
103 |         '90,10' => 'Tx.select',
104 |         '90,11' => 'Tx.select_ok',
105 |         '90,20' => 'Tx.commit',
106 |         '90,21' => 'Tx.commit_ok',
107 |         '90,30' => 'Tx.rollback',
108 |         '90,31' => 'Tx.rollback_ok',
109 |         '85,10' => 'Confirm.select',
110 |         '85,11' => 'Confirm.select_ok',
111 |     );
112 | }
113 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Wire/IO/AbstractIO.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | 
  3 | namespace PhpAmqpLib\Wire\IO;
  4 | 
  5 | use PhpAmqpLib\Connection\AMQPConnectionConfig;
  6 | use PhpAmqpLib\Exception\AMQPConnectionClosedException;
  7 | use PhpAmqpLib\Exception\AMQPHeartbeatMissedException;
  8 | use PhpAmqpLib\Exception\AMQPIOWaitException;
  9 | use PhpAmqpLib\Exception\AMQPRuntimeException;
 10 | use PhpAmqpLib\Wire\AMQPWriter;
 11 | 
 12 | abstract class AbstractIO
 13 | {
 14 |     const BUFFER_SIZE = 8192;
 15 | 
 16 |     /** @var null|AMQPConnectionConfig */
 17 |     protected $config;
 18 | 
 19 |     /** @var string */
 20 |     protected $host;
 21 | 
 22 |     /** @var int */
 23 |     protected $port;
 24 | 
 25 |     /** @var int|float */
 26 |     protected $connection_timeout;
 27 | 
 28 |     /** @var float */
 29 |     protected $read_timeout;
 30 | 
 31 |     /** @var float */
 32 |     protected $write_timeout;
 33 | 
 34 |     /** @var int */
 35 |     protected $heartbeat;
 36 | 
 37 |     /** @var int */
 38 |     protected $initial_heartbeat;
 39 | 
 40 |     /** @var bool */
 41 |     protected $keepalive;
 42 | 
 43 |     /** @var int|float */
 44 |     protected $last_read;
 45 | 
 46 |     /** @var int|float */
 47 |     protected $last_write;
 48 | 
 49 |     /** @var \ErrorException|null */
 50 |     protected $last_error;
 51 | 
 52 |     /** @var bool */
 53 |     protected $canDispatchPcntlSignal = false;
 54 | 
 55 |     /**
 56 |      * @param int $len
 57 |      * @return string
 58 |      * @throws \PhpAmqpLib\Exception\AMQPIOException
 59 |      * @throws AMQPRuntimeException
 60 |      * @throws \PhpAmqpLib\Exception\AMQPSocketException
 61 |      * @throws \PhpAmqpLib\Exception\AMQPTimeoutException
 62 |      * @throws \PhpAmqpLib\Exception\AMQPConnectionClosedException
 63 |      */
 64 |     abstract public function read($len);
 65 | 
 66 |     /**
 67 |      * @param string $data
 68 |      * @throws \PhpAmqpLib\Exception\AMQPIOException
 69 |      * @throws \PhpAmqpLib\Exception\AMQPSocketException
 70 |      * @throws \PhpAmqpLib\Exception\AMQPConnectionClosedException
 71 |      * @throws \PhpAmqpLib\Exception\AMQPTimeoutException
 72 |      */
 73 |     abstract public function write($data);
 74 | 
 75 |     /**
 76 |      * @return void
 77 |      */
 78 |     abstract public function close();
 79 | 
 80 |     /**
 81 |      * @param int|null $sec
 82 |      * @param int $usec
 83 |      * @return int
 84 |      * @throws AMQPIOWaitException
 85 |      * @throws AMQPRuntimeException
 86 |      * @throws AMQPConnectionClosedException
 87 |      */
 88 |     public function select(?int $sec, int $usec = 0)
 89 |     {
 90 |         $this->check_heartbeat();
 91 |         $this->setErrorHandler();
 92 |         try {
 93 |             $result = $this->do_select($sec, $usec);
 94 |             $this->throwOnError();
 95 |         } catch (\ErrorException $e) {
 96 |             throw new AMQPIOWaitException($e->getMessage(), $e->getCode(), $e->getPrevious());
 97 |         } finally {
 98 |             $this->restoreErrorHandler();
 99 |         }
100 | 
101 |         if ($this->canDispatchPcntlSignal) {
102 |             pcntl_signal_dispatch();
103 |         }
104 | 
105 |         // no exception and false result - either timeout or signal was sent
106 |         if ($result === false) {
107 |             $result = 0;
108 |         }
109 | 
110 |         return $result;
111 |     }
112 | 
113 |     /**
114 |      * @param int|null $sec
115 |      * @param int $usec
116 |      * @return int|bool
117 |      * @throws AMQPConnectionClosedException
118 |      */
119 |     abstract protected function do_select(?int $sec, int $usec);
120 | 
121 |     /**
122 |      * Set ups the connection.
123 |      * @return void
124 |      * @throws \PhpAmqpLib\Exception\AMQPIOException
125 |      * @throws AMQPRuntimeException
126 |      */
127 |     abstract public function connect();
128 | 
129 |     /**
130 |      * Set connection params connection tune(negotiation).
131 |      * @param int $heartbeat
132 |      */
133 |     public function afterTune(int $heartbeat): void
134 |     {
135 |         $this->heartbeat = $heartbeat;
136 |         $this->initial_heartbeat = $heartbeat;
137 |     }
138 | 
139 |     /**
140 |      * Heartbeat logic: check connection health here
141 |      * @return void
142 |      * @throws AMQPRuntimeException
143 |      */
144 |     public function check_heartbeat()
145 |     {
146 |         // ignore unless heartbeat interval is set
147 |         if ($this->heartbeat !== 0 && $this->last_read > 0 && $this->last_write > 0) {
148 |             // server has gone away
149 |             $this->checkBrokerHeartbeat();
150 | 
151 |             // time for client to send a heartbeat
152 |             $now = microtime(true);
153 |             if (($this->heartbeat / 2) < $now - $this->last_write) {
154 |                 $this->write_heartbeat();
155 |             }
156 |         }
157 |     }
158 | 
159 |     /**
160 |      * @throws \PhpAmqpLib\Exception\AMQPHeartbeatMissedException
161 |      */
162 |     protected function checkBrokerHeartbeat(): void
163 |     {
164 |         if ($this->heartbeat > 0 && ($this->last_read > 0 || $this->last_write > 0)) {
165 |             $lastActivity = $this->getLastActivity();
166 |             $now = microtime(true);
167 |             if (($now - $lastActivity) > $this->heartbeat * 2 + 1) {
168 |                 $this->close();
169 |                 throw new AMQPHeartbeatMissedException('Missed server heartbeat');
170 |             }
171 |         }
172 |     }
173 | 
174 |     /**
175 |      * @return float|int
176 |      */
177 |     public function getLastActivity()
178 |     {
179 |         return max($this->last_read, $this->last_write);
180 |     }
181 | 
182 |     public function getReadTimeout(): float
183 |     {
184 |         return $this->read_timeout;
185 |     }
186 | 
187 |     /**
188 |      * @return $this
189 |      */
190 |     public function disableHeartbeat()
191 |     {
192 |         $this->initial_heartbeat = $this->heartbeat;
193 |         $this->heartbeat = 0;
194 | 
195 |         return $this;
196 |     }
197 | 
198 |     /**
199 |      * @return $this
200 |      */
201 |     public function reenableHeartbeat()
202 |     {
203 |         $this->heartbeat = $this->initial_heartbeat;
204 | 
205 |         return $this;
206 |     }
207 | 
208 |     /**
209 |      * Sends a heartbeat message
210 |      */
211 |     protected function write_heartbeat()
212 |     {
213 |         $pkt = new AMQPWriter();
214 |         $pkt->write_octet(8);
215 |         $pkt->write_short(0);
216 |         $pkt->write_long(0);
217 |         $pkt->write_octet(0xCE);
218 |         $this->write($pkt->getvalue());
219 |     }
220 | 
221 |     /**
222 |      * Begin tracking errors and set the error handler
223 |      */
224 |     protected function setErrorHandler(): void
225 |     {
226 |         $this->last_error = null;
227 |         set_error_handler(array($this, 'error_handler'));
228 |     }
229 | 
230 |     protected function throwOnError(): void
231 |     {
232 |         if ($this->last_error instanceof \ErrorException) {
233 |             $error = $this->last_error;
234 |             $this->last_error = null;
235 |             throw $error;
236 |         }
237 |     }
238 | 
239 |     protected function restoreErrorHandler(): void
240 |     {
241 |         restore_error_handler();
242 |     }
243 | 
244 |     /**
245 |      * Internal error handler to deal with stream and socket errors.
246 |      *
247 |      * @param  int $errno
248 |      * @param  string $errstr
249 |      * @param  string $errfile
250 |      * @param  int $errline
251 |      * @return void
252 |      */
253 |     public function error_handler($errno, $errstr, $errfile, $errline): void
254 |     {
255 |         // throwing an exception in an error handler will halt execution
256 |         // collect error continue
257 |         $this->last_error = new \ErrorException($errstr, $errno, 1, $errfile, $errline, $this->last_error);
258 |     }
259 | 
260 |     protected function isPcntlSignalEnabled(): bool
261 |     {
262 |         return extension_loaded('pcntl')
263 |             && function_exists('pcntl_signal_dispatch')
264 |             && (defined('AMQP_WITHOUT_SIGNALS') ? !AMQP_WITHOUT_SIGNALS : true);
265 |     }
266 | }
267 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Wire/IO/SocketIO.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | 
  3 | namespace PhpAmqpLib\Wire\IO;
  4 | 
  5 | use PhpAmqpLib\Connection\AMQPConnectionConfig;
  6 | use PhpAmqpLib\Exception\AMQPConnectionClosedException;
  7 | use PhpAmqpLib\Exception\AMQPIOException;
  8 | use PhpAmqpLib\Exception\AMQPSocketException;
  9 | use PhpAmqpLib\Exception\AMQPTimeoutException;
 10 | use PhpAmqpLib\Helper\MiscHelper;
 11 | use PhpAmqpLib\Helper\SocketConstants;
 12 | 
 13 | class SocketIO extends AbstractIO
 14 | {
 15 |     /** @var null|resource|\Socket */
 16 |     private $sock;
 17 | 
 18 |     /**
 19 |      * @param string $host
 20 |      * @param int $port
 21 |      * @param int|float $read_timeout
 22 |      * @param bool $keepalive
 23 |      * @param int|float|null $write_timeout if null defaults to read timeout
 24 |      * @param int $heartbeat how often to send heartbeat. 0 means off
 25 |      * @param null|AMQPConnectionConfig $config
 26 |      */
 27 |     public function __construct(
 28 |         $host,
 29 |         $port,
 30 |         $read_timeout = 3,
 31 |         $keepalive = false,
 32 |         $write_timeout = null,
 33 |         $heartbeat = 0,
 34 |         ?AMQPConnectionConfig $config = null
 35 |     ) {
 36 |         $this->config = $config;
 37 |         $this->host = str_replace(['[', ']'], '', $host);
 38 |         $this->port = $port;
 39 |         $this->read_timeout = (float)$read_timeout;
 40 |         $this->write_timeout = (float)($write_timeout ?: $read_timeout);
 41 |         $this->heartbeat = $heartbeat;
 42 |         $this->initial_heartbeat = $heartbeat;
 43 |         $this->keepalive = $keepalive;
 44 |         $this->canDispatchPcntlSignal = $this->isPcntlSignalEnabled();
 45 | 
 46 |         /*
 47 |             TODO FUTURE enable this check
 48 |             php-amqplib/php-amqplib#648, php-amqplib/php-amqplib#666
 49 |         if ($this->heartbeat !== 0 && ($this->read_timeout <= ($this->heartbeat * 2))) {
 50 |             throw new \InvalidArgumentException('read_timeout must be greater than 2x the heartbeat');
 51 |         }
 52 |         if ($this->heartbeat !== 0 && ($this->write_timeout <= ($this->heartbeat * 2))) {
 53 |             throw new \InvalidArgumentException('send_timeout must be greater than 2x the heartbeat');
 54 |         }
 55 |          */
 56 |     }
 57 | 
 58 |     /**
 59 |      * @inheritdoc
 60 |      */
 61 |     public function connect()
 62 |     {
 63 |         $this->sock = socket_create(!$this->isIpv6() ? AF_INET : AF_INET6, SOCK_STREAM, SOL_TCP);
 64 | 
 65 |         list($sec, $uSec) = MiscHelper::splitSecondsMicroseconds($this->write_timeout);
 66 |         socket_set_option($this->sock, SOL_SOCKET, SO_SNDTIMEO, array('sec' => $sec, 'usec' => $uSec));
 67 |         list($sec, $uSec) = MiscHelper::splitSecondsMicroseconds($this->read_timeout);
 68 |         socket_set_option($this->sock, SOL_SOCKET, SO_RCVTIMEO, array('sec' => $sec, 'usec' => $uSec));
 69 | 
 70 |         $this->setErrorHandler();
 71 |         try {
 72 |             $connected = socket_connect($this->sock, $this->host, $this->port);
 73 |             $this->throwOnError();
 74 |         } catch (\ErrorException $e) {
 75 |             $connected = false;
 76 |         } finally {
 77 |             $this->restoreErrorHandler();
 78 |         }
 79 |         if (!$connected) {
 80 |             $errno = socket_last_error($this->sock);
 81 |             $errstr = socket_strerror($errno);
 82 |             throw new AMQPIOException(sprintf(
 83 |                 'Error Connecting to server (%s): %s',
 84 |                 $errno,
 85 |                 $errstr
 86 |             ), $errno);
 87 |         }
 88 | 
 89 |         socket_set_block($this->sock);
 90 |         socket_set_option($this->sock, SOL_TCP, TCP_NODELAY, 1);
 91 |         if ($this->config && $this->config->getSendBufferSize() > 0) {
 92 |             socket_set_option($this->sock, SOL_SOCKET, SO_SNDBUF, $this->config->getSendBufferSize());
 93 |         }
 94 | 
 95 |         if ($this->keepalive) {
 96 |             $this->enable_keepalive();
 97 |         }
 98 | 
 99 |         $this->heartbeat = $this->initial_heartbeat;
100 |     }
101 | 
102 |     /**
103 |      * @deprecated
104 |      * @return null|resource|\Socket
105 |      */
106 |     public function getSocket()
107 |     {
108 |         return $this->sock;
109 |     }
110 | 
111 |     /**
112 |      * @inheritdoc
113 |      */
114 |     public function read($len)
115 |     {
116 |         if (is_null($this->sock)) {
117 |             throw new AMQPSocketException(sprintf(
118 |                 'Socket was null! Last SocketError was: %s',
119 |                 socket_strerror(socket_last_error())
120 |             ));
121 |         }
122 | 
123 |         $this->check_heartbeat();
124 | 
125 |         list($timeout_sec, $timeout_uSec) = MiscHelper::splitSecondsMicroseconds($this->read_timeout);
126 |         $read_start = microtime(true);
127 |         $read = 0;
128 |         $data = '';
129 |         while ($read < $len) {
130 |             $buffer = null;
131 |             $result = socket_recv($this->sock, $buffer, $len - $read, 0);
132 |             if ($result === 0) {
133 |                 // From linux recv() manual:
134 |                 // When a stream socket peer has performed an orderly shutdown,
135 |                 // the return value will be 0 (the traditional "end-of-file" return).
136 |                 // http://php.net/manual/en/function.socket-recv.php#47182
137 |                 $this->close();
138 |                 throw new AMQPConnectionClosedException('Broken pipe or closed connection');
139 |             }
140 | 
141 |             if (empty($buffer)) {
142 |                 $read_now = microtime(true);
143 |                 $t_read = $read_now - $read_start;
144 |                 if ($t_read > $this->read_timeout) {
145 |                     throw new AMQPTimeoutException('Too many read attempts detected in SocketIO');
146 |                 }
147 |                 $this->select($timeout_sec, $timeout_uSec);
148 |                 continue;
149 |             }
150 | 
151 |             $read += mb_strlen($buffer, 'ASCII');
152 |             $data .= $buffer;
153 |         }
154 | 
155 |         if (mb_strlen($data, 'ASCII') !== $len) {
156 |             throw new AMQPIOException(sprintf(
157 |                 'Error reading data. Received %s instead of expected %s bytes',
158 |                 mb_strlen($data, 'ASCII'),
159 |                 $len
160 |             ));
161 |         }
162 | 
163 |         $this->last_read = microtime(true);
164 | 
165 |         return $data;
166 |     }
167 | 
168 |     /**
169 |      * @inheritdoc
170 |      */
171 |     public function write($data)
172 |     {
173 |         // Null sockets are invalid, throw exception
174 |         if (is_null($this->sock)) {
175 |             throw new AMQPSocketException(sprintf(
176 |                 'Socket was null! Last SocketError was: %s',
177 |                 socket_strerror(socket_last_error())
178 |             ));
179 |         }
180 | 
181 |         $this->checkBrokerHeartbeat();
182 | 
183 |         $written = 0;
184 |         $len = mb_strlen($data, 'ASCII');
185 |         $write_start = microtime(true);
186 | 
187 |         while ($written < $len) {
188 |             $this->setErrorHandler();
189 |             try {
190 |                 $result = 0;
191 |                 if ($this->select_write()) {
192 |                     // if data is smaller than buffer - no need to cut part of it
193 |                     if ($len <= self::BUFFER_SIZE) {
194 |                         $buffer = $data;
195 |                     } else {
196 |                         $buffer = mb_substr($data, $written, self::BUFFER_SIZE, 'ASCII');
197 |                     }
198 |                     $result = socket_write($this->sock, $buffer);
199 |                 }
200 |                 $this->throwOnError();
201 |             } catch (\ErrorException $e) {
202 |                 $code = socket_last_error($this->sock);
203 |                 $constants = SocketConstants::getInstance();
204 |                 switch ($code) {
205 |                     case $constants->SOCKET_EPIPE:
206 |                     case $constants->SOCKET_ENETDOWN:
207 |                     case $constants->SOCKET_ENETUNREACH:
208 |                     case $constants->SOCKET_ENETRESET:
209 |                     case $constants->SOCKET_ECONNABORTED:
210 |                     case $constants->SOCKET_ECONNRESET:
211 |                     case $constants->SOCKET_ECONNREFUSED:
212 |                     case $constants->SOCKET_ETIMEDOUT:
213 |                         $this->close();
214 |                         throw new AMQPConnectionClosedException(socket_strerror($code), $code, $e);
215 |                     default:
216 |                         throw new AMQPIOException(sprintf(
217 |                             'Error sending data. Last SocketError: %s',
218 |                             socket_strerror($code)
219 |                         ), $code, $e);
220 |                 }
221 |             } finally {
222 |                 $this->restoreErrorHandler();
223 |             }
224 | 
225 |             if ($result === false) {
226 |                 throw new AMQPIOException(sprintf(
227 |                     'Error sending data. Last SocketError: %s',
228 |                     socket_strerror(socket_last_error($this->sock))
229 |                 ));
230 |             }
231 | 
232 |             $now = microtime(true);
233 |             if ($result > 0) {
234 |                 $this->last_write = $write_start = $now;
235 |                 $written += $result;
236 |             } else {
237 |                 if (($now - $write_start) > $this->write_timeout) {
238 |                     throw AMQPTimeoutException::writeTimeout($this->write_timeout);
239 |                 }
240 |             }
241 |         }
242 |     }
243 | 
244 |     /**
245 |      * @inheritdoc
246 |      */
247 |     public function close()
248 |     {
249 |         $this->disableHeartbeat();
250 |         if (is_resource($this->sock) || is_a($this->sock, \Socket::class)) {
251 |             socket_close($this->sock);
252 |         }
253 |         $this->sock = null;
254 |         $this->last_read = 0;
255 |         $this->last_write = 0;
256 |     }
257 | 
258 |     /**
259 |      * @inheritdoc
260 |      */
261 |     protected function do_select(?int $sec, int $usec)
262 |     {
263 |         if (!is_resource($this->sock) && !is_a($this->sock, \Socket::class)) {
264 |             $this->sock = null;
265 |             throw new AMQPConnectionClosedException('Broken pipe or closed connection', 0);
266 |         }
267 | 
268 |         $read = array($this->sock);
269 |         $write = null;
270 |         $except = null;
271 | 
272 |         return socket_select($read, $write, $except, $sec, $usec);
273 |     }
274 | 
275 |     /**
276 |      * @return int|bool
277 |      */
278 |     protected function select_write()
279 |     {
280 |         $read = $except = null;
281 |         $write = array($this->sock);
282 | 
283 |         return socket_select($read, $write, $except, 0, 100000);
284 |     }
285 | 
286 |     /**
287 |      * @throws \PhpAmqpLib\Exception\AMQPIOException
288 |      */
289 |     protected function enable_keepalive(): void
290 |     {
291 |         if (!defined('SOL_SOCKET') || !defined('SO_KEEPALIVE')) {
292 |             throw new AMQPIOException('Can not enable keepalive: SOL_SOCKET or SO_KEEPALIVE is not defined');
293 |         }
294 | 
295 |         socket_set_option($this->sock, SOL_SOCKET, SO_KEEPALIVE, 1);
296 |     }
297 | 
298 |     /**
299 |      * @inheritdoc
300 |      */
301 |     public function error_handler($errno, $errstr, $errfile, $errline): void
302 |     {
303 |         $constants = SocketConstants::getInstance();
304 |         // socket_select warning that it has been interrupted by a signal - EINTR
305 |         if (isset($constants->SOCKET_EINTR) && false !== strrpos($errstr, socket_strerror($constants->SOCKET_EINTR))) {
306 |             // it's allowed while processing signals
307 |             return;
308 |         }
309 | 
310 |         parent::error_handler($errno, $errstr, $errfile, $errline);
311 |     }
312 | 
313 |     /**
314 |      * @inheritdoc
315 |      */
316 |     protected function setErrorHandler(): void
317 |     {
318 |         parent::setErrorHandler();
319 |         socket_clear_error($this->sock);
320 |     }
321 | 
322 |     private function isIpv6(): bool
323 |     {
324 |         $ipv6 = filter_var($this->host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);
325 | 
326 |         if ($ipv6 !== false || checkdnsrr($this->host, 'AAAA')) {
327 |             return true;
328 |         }
329 | 
330 |         return false;
331 |     }
332 | }
333 | 


--------------------------------------------------------------------------------
/PhpAmqpLib/Wire/IO/StreamIO.php:
--------------------------------------------------------------------------------
  1 | <?php
  2 | 
  3 | namespace PhpAmqpLib\Wire\IO;
  4 | 
  5 | use PhpAmqpLib\Exception\AMQPConnectionClosedException;
  6 | use PhpAmqpLib\Exception\AMQPDataReadException;
  7 | use PhpAmqpLib\Exception\AMQPIOException;
  8 | use PhpAmqpLib\Exception\AMQPRuntimeException;
  9 | use PhpAmqpLib\Exception\AMQPTimeoutException;
 10 | use PhpAmqpLib\Helper\MiscHelper;
 11 | use PhpAmqpLib\Helper\SocketConstants;
 12 | 
 13 | class StreamIO extends AbstractIO
 14 | {
 15 |     /** @var null|resource */
 16 |     protected $context;
 17 | 
 18 |     /** @var null|resource */
 19 |     private $sock;
 20 | 
 21 |     /**
 22 |      * @param string $host
 23 |      * @param int $port
 24 |      * @param float $connection_timeout
 25 |      * @param float $read_write_timeout
 26 |      * @param resource|null $context
 27 |      * @param bool $keepalive
 28 |      * @param int $heartbeat
 29 |      * @param string|null $ssl_protocol @deprecated
 30 |      */
 31 |     public function __construct(
 32 |         $host,
 33 |         $port,
 34 |         $connection_timeout,
 35 |         $read_write_timeout,
 36 |         $context = null,
 37 |         $keepalive = false,
 38 |         $heartbeat = 0,
 39 |         $ssl_protocol = null
 40 |     ) {
 41 |         if (func_num_args() === 8) {
 42 |             trigger_error(
 43 |                 '$ssl_protocol parameter is deprecated, use stream_context_set_option($context, \'ssl\', \'crypto_method\', $ssl_protocol) instead (see https://www.php.net/manual/en/function.stream-socket-enable-crypto.php for possible values)',
 44 |                 E_USER_DEPRECATED
 45 |             );
 46 |         }
 47 |         // TODO FUTURE change comparison to <=
 48 |         // php-amqplib/php-amqplib#648, php-amqplib/php-amqplib#666
 49 |         /*
 50 |             TODO FUTURE enable this check
 51 |         if ($heartbeat !== 0 && ($read_write_timeout < ($heartbeat * 2))) {
 52 |             throw new \InvalidArgumentException('read_write_timeout must be at least 2x the heartbeat');
 53 |         }
 54 |          */
 55 | 
 56 |         $this->host = $host;
 57 |         $this->port = $port;
 58 |         $this->connection_timeout = $connection_timeout;
 59 |         $this->read_timeout = (float)$read_write_timeout;
 60 |         $this->write_timeout = (float)$read_write_timeout;
 61 |         $this->context = $context;
 62 |         $this->keepalive = $keepalive;
 63 |         $this->heartbeat = $heartbeat;
 64 |         $this->initial_heartbeat = $heartbeat;
 65 |         $this->canDispatchPcntlSignal = $this->isPcntlSignalEnabled();
 66 |     }
 67 | 
 68 |     /**
 69 |      * @inheritdoc
 70 |      */
 71 |     public function connect()
 72 |     {
 73 |         $errstr = $errno = null;
 74 | 
 75 |         $remote = sprintf(
 76 |             'tcp://%s:%s',
 77 |             $this->host,
 78 |             $this->port
 79 |         );
 80 | 
 81 |         $context = $this->setupContext();
 82 |         $this->setErrorHandler();
 83 | 
 84 |         try {
 85 |             $this->sock = stream_socket_client(
 86 |                 $remote,
 87 |                 $errno,
 88 |                 $errstr,
 89 |                 $this->connection_timeout,
 90 |                 STREAM_CLIENT_CONNECT,
 91 |                 $context
 92 |             );
 93 |             $this->throwOnError();
 94 |         } catch (\ErrorException $e) {
 95 |             throw new AMQPIOException($e->getMessage(), $e->getCode(), $e->getPrevious());
 96 |         } finally {
 97 |             $this->restoreErrorHandler();
 98 |         }
 99 | 
100 |         if (false === $this->sock) {
101 |             throw new AMQPIOException(
102 |                 sprintf(
103 |                     'Error Connecting to server(%s): %s ',
104 |                     $errno,
105 |                     $errstr
106 |                 ),
107 |                 $errno
108 |             );
109 |         }
110 | 
111 |         if (!stream_socket_get_name($this->sock, true)) {
112 |             throw new AMQPIOException(
113 |                 sprintf(
114 |                     'Connection refused: %s ',
115 |                     $remote
116 |                 )
117 |             );
118 |         }
119 | 
120 |         list($sec, $uSec) = MiscHelper::splitSecondsMicroseconds(max($this->read_timeout, $this->write_timeout));
121 |         if (!stream_set_timeout($this->sock, $sec, $uSec)) {
122 |             throw new AMQPIOException('Timeout could not be set');
123 |         }
124 | 
125 |         // php cannot capture signals while streams are blocking
126 |         if ($this->canDispatchPcntlSignal) {
127 |             stream_set_blocking($this->sock, false);
128 |             stream_set_write_buffer($this->sock, 0);
129 |             if (function_exists('stream_set_read_buffer')) {
130 |                 stream_set_read_buffer($this->sock, 0);
131 |             }
132 |         } else {
133 |             stream_set_blocking($this->sock, true);
134 |         }
135 | 
136 |         if ($this->keepalive) {
137 |             $this->enable_keepalive();
138 |         }
139 | 
140 |         $options = stream_context_get_options($context);
141 |         if (isset($options['ssl']['crypto_method'])) {
142 |             $this->enableCrypto();
143 |         }
144 | 
145 |         $this->heartbeat = $this->initial_heartbeat;
146 |     }
147 | 
148 |     /**
149 |      * @return resource
150 |      * @throws AMQPIOException
151 |      */
152 |     private function setupContext()
153 |     {
154 |         $context = $this->context;
155 |         if (!is_resource($context) || get_resource_type($context) !== 'stream-context') {
156 |             $context = stream_context_create();
157 |         }
158 | 
159 |         stream_context_set_option($context, 'socket', 'tcp_nodelay', true);
160 | 
161 |         $options = stream_context_get_options($context);
162 |         if (!empty($options['ssl']) && !isset($options['ssl']['crypto_method'])) {
163 |             if (!stream_context_set_option($context, 'ssl', 'crypto_method', STREAM_CRYPTO_METHOD_ANY_CLIENT)) {
164 |                 throw new AMQPIOException("Can not set ssl.crypto_method stream context option");
165 |             }
166 |         }
167 | 
168 |         return $context;
169 |     }
170 | 
171 |     /**
172 |      * @inheritdoc
173 |      */
174 |     public function read($len)
175 |     {
176 |         $this->check_heartbeat();
177 | 
178 |         list($timeout_sec, $timeout_uSec) = MiscHelper::splitSecondsMicroseconds($this->read_timeout);
179 | 
180 |         $read_start = microtime(true);
181 |         $read = 0;
182 |         $data = '';
183 | 
184 |         while ($read < $len) {
185 |             if (!is_resource($this->sock) || feof($this->sock)) {
186 |                 $this->close();
187 |                 throw new AMQPConnectionClosedException('Broken pipe or closed connection');
188 |             }
189 | 
190 |             $this->setErrorHandler();
191 |             try {
192 |                 $buffer = fread($this->sock, ($len - $read));
193 |                 $this->throwOnError();
194 |             } catch (\ErrorException $e) {
195 |                 throw new AMQPDataReadException($e->getMessage(), $e->getCode(), $e->getPrevious());
196 |             } finally {
197 |                 $this->restoreErrorHandler();
198 |             }
199 | 
200 |             if ($buffer === false) {
201 |                 throw new AMQPDataReadException('Error receiving data');
202 |             }
203 | 
204 |             if ($buffer === '') {
205 |                 $read_now = microtime(true);
206 |                 $t_read = $read_now - $read_start;
207 |                 if ($t_read > $this->read_timeout) {
208 |                     throw new AMQPTimeoutException('Too many read attempts detected in StreamIO');
209 |                 }
210 |                 $this->select($timeout_sec, $timeout_uSec);
211 | 
212 |                 continue;
213 |             }
214 | 
215 |             $this->last_read = microtime(true);
216 |             $read_start = $this->last_read;
217 |             $read += mb_strlen($buffer, 'ASCII');
218 |             $data .= $buffer;
219 |         }
220 | 
221 |         if (mb_strlen($data, 'ASCII') !== $len) {
222 |             throw new AMQPDataReadException(
223 |                 sprintf(
224 |                     'Error reading data. Received %s instead of expected %s bytes',
225 |                     mb_strlen($data, 'ASCII'),
226 |                     $len
227 |                 )
228 |             );
229 |         }
230 | 
231 |         $this->last_read = microtime(true);
232 | 
233 |         return $data;
234 |     }
235 | 
236 |     /**
237 |      * @inheritdoc
238 |      */
239 |     public function write($data)
240 |     {
241 |         $this->checkBrokerHeartbeat();
242 | 
243 |         $written = 0;
244 |         $len = mb_strlen($data, 'ASCII');
245 |         $write_start = microtime(true);
246 | 
247 |         while ($written < $len) {
248 |             // on Windows, feof() fails when connecting to some (but not all) servers
249 |             if (!is_resource($this->sock) || (PHP_OS_FAMILY != 'Windows' && feof($this->sock))) {
250 |                 $this->close();
251 |                 $constants = SocketConstants::getInstance();
252 |                 throw new AMQPConnectionClosedException('Broken pipe or closed connection', $constants->SOCKET_EPIPE);
253 |             }
254 | 
255 |             $result = false;
256 |             $this->setErrorHandler();
257 |             // OpenSSL's C library function SSL_write() can balk on buffers > 8192
258 |             // bytes in length, so we're limiting the write size here. On both TLS
259 |             // and plaintext connections, the write loop will continue until the
260 |             // buffer has been fully written.
261 |             // This behavior has been observed in OpenSSL dating back to at least
262 |             // September 2002:
263 |             // http://comments.gmane.org/gmane.comp.encryption.openssl.user/4361
264 |             try {
265 |                 // check stream and prevent from high CPU usage
266 |                 $result = 0;
267 |                 if ($this->select_write()) {
268 |                     // if data is smaller than buffer - no need to cut part of it
269 |                     if ($len <= self::BUFFER_SIZE) {
270 |                         $buffer = $data;
271 |                     } else {
272 |                         $buffer = mb_substr($data, $written, self::BUFFER_SIZE, 'ASCII');
273 |                     }
274 |                     $result = fwrite($this->sock, $buffer);
275 |                 }
276 |                 $this->throwOnError();
277 |             } catch (\ErrorException $e) {
278 |                 $code = $e->getCode();
279 |                 $constants = SocketConstants::getInstance();
280 |                 switch ($code) {
281 |                     case $constants->SOCKET_EPIPE:
282 |                     case $constants->SOCKET_ENETDOWN:
283 |                     case $constants->SOCKET_ENETUNREACH:
284 |                     case $constants->SOCKET_ENETRESET:
285 |                     case $constants->SOCKET_ECONNABORTED:
286 |                     case $constants->SOCKET_ECONNRESET:
287 |                     case $constants->SOCKET_ECONNREFUSED:
288 |                     case $constants->SOCKET_ETIMEDOUT:
289 |                         $this->close();
290 |                         throw new AMQPConnectionClosedException(socket_strerror($code), $code, $e);
291 |                     default:
292 |                         throw new AMQPRuntimeException($e->getMessage(), $code, $e);
293 |                 }
294 |             } finally {
295 |                 $this->restoreErrorHandler();
296 |             }
297 | 
298 |             if ($result === false) {
299 |                 throw new AMQPRuntimeException('Error sending data');
300 |             }
301 | 
302 |             if ($this->timed_out()) {
303 |                 throw AMQPTimeoutException::writeTimeout($this->write_timeout);
304 |             }
305 | 
306 |             $now = microtime(true);
307 |             if ($result > 0) {
308 |                 $this->last_write = $write_start = $now;
309 |                 $written += $result;
310 |             } else {
311 |                 if (feof($this->sock)) {
312 |                     $this->close();
313 |                     throw new AMQPConnectionClosedException('Broken pipe or closed connection');
314 |                 }
315 |                 if (($now - $write_start) > $this->write_timeout) {
316 |                     throw AMQPTimeoutException::writeTimeout($this->write_timeout);
317 |                 }
318 |             }
319 |         }
320 |     }
321 | 
322 |     /**
323 |      * @inheritdoc
324 |      */
325 |     public function error_handler($errno, $errstr, $errfile, $errline): void
326 |     {
327 |         $code = $this->extract_error_code($errstr);
328 |         $constants = SocketConstants::getInstance();
329 |         switch ($code) {
330 |             // fwrite notice that the stream isn't ready - EAGAIN or EWOULDBLOCK
331 |             case $constants->SOCKET_EAGAIN:
332 |             case $constants->SOCKET_EWOULDBLOCK:
333 |             // stream_select warning that it has been interrupted by a signal - EINTR
334 |             case $constants->SOCKET_EINTR:
335 |                 return;
336 |         }
337 | 
338 |         parent::error_handler($code > 0 ? $code : $errno, $errstr, $errfile, $errline);
339 |     }
340 | 
341 |     public function close()
342 |     {
343 |         $this->disableHeartbeat();
344 |         if (is_resource($this->sock)) {
345 |             fclose($this->sock);
346 |         }
347 |         $this->sock = null;
348 |         $this->last_read = 0;
349 |         $this->last_write = 0;
350 |     }
351 | 
352 |     /**
353 |      * @deprecated
354 |      * @return null|resource|\Socket
355 |      */
356 |     public function getSocket()
357 |     {
358 |         return $this->sock;
359 |     }
360 | 
361 |     /**
362 |      * @inheritdoc
363 |      */
364 |     protected function do_select(?int $sec, int $usec)
365 |     {
366 |         if ($this->sock === null || !is_resource($this->sock)) {
367 |             $this->sock = null;
368 |             throw new AMQPConnectionClosedException('Broken pipe or closed connection', 0);
369 |         }
370 | 
371 |         $read = array($this->sock);
372 |         $write = null;
373 |         $except = null;
374 | 
375 |         if ($sec === null && PHP_VERSION_ID >= 80100) {
376 |             $usec = 0;
377 |         }
378 | 
379 |         return stream_select($read, $write, $except, $sec, $usec);
380 |     }
381 | 
382 |     /**
383 |      * @return int|bool
384 |      */
385 |     protected function select_write()
386 |     {
387 |         $read = $except = null;
388 |         $write = array($this->sock);
389 | 
390 |         return stream_select($read, $write, $except, 0, 100000);
391 |     }
392 | 
393 |     /**
394 |      * @return mixed
395 |      */
396 |     protected function timed_out()
397 |     {
398 |         // get status of socket to determine whether or not it has timed out
399 |         $info = stream_get_meta_data($this->sock);
400 | 
401 |         return $info['timed_out'];
402 |     }
403 | 
404 |     /**
405 |      * @throws \PhpAmqpLib\Exception\AMQPIOException
406 |      */
407 |     protected function enable_keepalive(): void
408 |     {
409 |         if (!function_exists('socket_import_stream')) {
410 |             throw new AMQPIOException('Can not enable keepalive: function socket_import_stream does not exist');
411 |         }
412 | 
413 |         if (!defined('SOL_SOCKET') || !defined('SO_KEEPALIVE')) {
414 |             throw new AMQPIOException('Can not enable keepalive: SOL_SOCKET or SO_KEEPALIVE is not defined');
415 |         }
416 | 
417 |         $socket = socket_import_stream($this->sock);
418 |         socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1);
419 |     }
420 | 
421 |     /**
422 |      * @param string $message
423 |      * @return int
424 |      */
425 |     protected function extract_error_code($message)
426 |     {
427 |         if (0 === strpos($message, 'stream_select():')) {
428 |             $pattern = '/\s+\[(\d+)\]:\s+/';
429 |         } else {
430 |             $pattern = '/\s+errno=(\d+)\s+/';
431 |         }
432 |         $matches = array();
433 |         $result = preg_match($pattern, $message, $matches);
434 |         if ($result > 0) {
435 |             return (int)$matches[1];
436 |         }
437 | 
438 |         return 0;
439 |     }
440 | 
441 |     /**
442 |      * @throws AMQPIOException
443 |      */
444 |     private function enableCrypto(): void
445 |     {
446 |         $timeout_at = time() + ($this->read_timeout + $this->write_timeout) * 2; // 2 round-trips during handshake
447 | 
448 |         try {
449 |             $this->setErrorHandler();
450 |             do {
451 |                 $enabled = stream_socket_enable_crypto($this->sock, true);
452 |                 if ($enabled === true) {
453 |                     return;
454 |                 }
455 |                 $this->throwOnError();
456 |                 usleep(1e3);
457 |             } while ($enabled === 0 && time() < $timeout_at);
458 |         } catch (\ErrorException $exception) {
459 |             throw new AMQPIOException($exception->getMessage(), $exception->getCode(), $exception->getPrevious());
460 |         } finally {
461 |             $this->restoreErrorHandler();
462 |         }
463 | 
464 |         if ($enabled !== true) {
465 |             throw new AMQPIOException('Could not enable socket crypto');
466 |         }
467 |     }
468 | }
469 | 


--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
  1 | # php-amqplib #
  2 | 
  3 | ![PHPUnit tests](https://github.com/php-amqplib/php-amqplib/workflows/PHPUnit%20tests/badge.svg)
  4 | [![Latest Version on Packagist][ico-version]][link-packagist]
  5 | [![Total Downloads][ico-downloads]][link-downloads]
  6 | [![Software License][ico-license]](LICENSE)
  7 | 
  8 | [![codecov](https://codecov.io/gh/php-amqplib/php-amqplib/branch/master/graph/badge.svg?token=tgeYkUsaDM)](https://codecov.io/gh/php-amqplib/php-amqplib)
  9 | [![Coverage Status][ico-scrutinizer]][link-scrutinizer]
 10 | [![Quality Score][ico-code-quality]][link-code-quality]
 11 | 
 12 | This library is a _pure PHP_ implementation of the [AMQP 0-9-1 protocol](http://www.rabbitmq.com/tutorials/amqp-concepts.html).
 13 | It's been tested against [RabbitMQ](http://www.rabbitmq.com/).
 14 | 
 15 | The library was used for the PHP examples of [RabbitMQ in Action](http://manning.com/videla/) and the [official RabbitMQ tutorials](http://www.rabbitmq.com/tutorials/tutorial-one-php.html).
 16 | 
 17 | Please note that this project is released with a [Contributor Code of Conduct](.github/CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms.
 18 | 
 19 | ## Project Maintainers
 20 | 
 21 | Thanks to [videlalvaro](https://github.com/videlalvaro) and [postalservice14](https://github.com/postalservice14) for creating `php-amqplib`.
 22 | 
 23 | The package is now maintained by [Ramūnas Dronga](https://github.com/ramunasd), [Luke Bakken](https://github.com/lukebakken) and several VMware engineers working on RabbitMQ.
 24 | 
 25 | ## Supported RabbitMQ Versions ##
 26 | 
 27 | Starting with version 2.0 this library uses `AMQP 0.9.1` by default and thus requires [RabbitMQ 2.0 or later version](http://www.rabbitmq.com/download.html).
 28 | Usually server upgrades do not require any application code changes since
 29 | the protocol changes very infrequently but please conduct your own testing before upgrading.
 30 | 
 31 | ## Supported RabbitMQ Extensions ##
 32 | 
 33 | Since the library uses `AMQP 0.9.1` we added support for the following RabbitMQ extensions:
 34 | 
 35 | * Exchange to Exchange Bindings
 36 | * Basic Nack
 37 | * Publisher Confirms
 38 | * Consumer Cancel Notify
 39 | 
 40 | Extensions that modify existing methods like `alternate exchanges` are also supported.
 41 | 
 42 | ### Related libraries
 43 | 
 44 | * [enqueue/amqp-lib](https://github.com/php-enqueue/amqp-lib) is a [amqp interop](https://github.com/queue-interop/queue-interop#amqp-interop) compatible wrapper.
 45 | 
 46 | * [AMQProxy](https://github.com/cloudamqp/amqproxy) is a proxy library with connection and channel pooling/reusing. This allows for lower connection and channel churn when using php-amqplib, leading to less CPU usage of RabbitMQ.
 47 | 
 48 | ## Setup ##
 49 | 
 50 | Ensure you have [composer](http://getcomposer.org) installed, then run the following command:
 51 | 
 52 | ```bash
 53 | composer require php-amqplib/php-amqplib
 54 | ```
 55 | 
 56 | That will fetch the library and its dependencies inside your vendor folder. Then you can add the following to your
 57 | .php files in order to use the library
 58 | 
 59 | ```php
 60 | require_once __DIR__.'/vendor/autoload.php';
 61 | ```
 62 | 
 63 | Then you need to `use` the relevant classes, for example:
 64 | 
 65 | ```php
 66 | use PhpAmqpLib\Connection\AMQPStreamConnection;
 67 | use PhpAmqpLib\Message\AMQPMessage;
 68 | ```
 69 | 
 70 | ## Usage ##
 71 | 
 72 | With RabbitMQ running open two Terminals and on the first one execute the following commands to start the consumer:
 73 | 
 74 | ```bash
 75 | cd php-amqplib/demo
 76 | php amqp_consumer.php
 77 | ```
 78 | 
 79 | Then on the other Terminal do:
 80 | 
 81 | ```bash
 82 | cd php-amqplib/demo
 83 | php amqp_publisher.php some text to publish
 84 | ```
 85 | 
 86 | You should see the message arriving to the process on the other Terminal
 87 | 
 88 | Then to stop the consumer, send to it the `quit` message:
 89 | 
 90 | ```bash
 91 | php amqp_publisher.php quit
 92 | ```
 93 | 
 94 | If you need to listen to the sockets used to connect to RabbitMQ then see the example in the non blocking consumer.
 95 | 
 96 | ```bash
 97 | php amqp_consumer_non_blocking.php
 98 | ```
 99 | 
100 | ## Change log
101 | 
102 | Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently.
103 | 
104 | ## API Documentation ##
105 | 
106 | http://php-amqplib.github.io/php-amqplib/
107 | 
108 | ## Tutorials ##
109 | 
110 | To not repeat ourselves, if you want to learn more about this library,
111 | please refer to the [official RabbitMQ tutorials](http://www.rabbitmq.com/tutorials/tutorial-one-php.html).
112 | 
113 | ## More Examples ##
114 | 
115 | - `amqp_ha_consumer.php`: demos the use of mirrored queues.
116 | - `amqp_consumer_exclusive.php` and `amqp_publisher_exclusive.php`: demos fanout exchanges using exclusive queues.
117 | - `amqp_consumer_fanout_{1,2}.php` and `amqp_publisher_fanout.php`: demos fanout exchanges with named queues.
118 | - `amqp_consumer_pcntl_heartbeat.php`: demos signal-based heartbeat sender usage.
119 | - `basic_get.php`: demos obtaining messages from the queues by using the _basic get_ AMQP call.
120 | 
121 | ## Multiple hosts connections ##
122 | 
123 | If you have a cluster of multiple nodes to which your application can connect,
124 | you can start a connection with an array of hosts. To do that you should use
125 | the `create_connection` static method.
126 | 
127 | For example:
128 | ```php
129 | $connection = AMQPStreamConnection::create_connection([
130 |     ['host' => HOST1, 'port' => PORT, 'user' => USER, 'password' => PASS, 'vhost' => VHOST],
131 |     ['host' => HOST2, 'port' => PORT, 'user' => USER, 'password' => PASS, 'vhost' => VHOST]
132 | ],
133 | $options);
134 | ```
135 | 
136 | This code will try to connect to `HOST1` first, and connect to `HOST2` if the
137 | first connection fails. The method returns a connection object for the first
138 | successful connection. Should all connections fail it will throw the exception
139 | from the last connection attempt.
140 | 
141 | See `demo/amqp_connect_multiple_hosts.php` for more examples.
142 | 
143 | ## Batch Publishing ##
144 | 
145 | Let's say you have a process that generates a bunch of messages that are going to be published to the same `exchange` using the same `routing_key` and options like `mandatory`.
146 | Then you could make use of the `batch_basic_publish` library feature. You can batch messages like this:
147 | 
148 | ```php
149 | $msg = new AMQPMessage($msg_body);
150 | $ch->batch_basic_publish($msg, $exchange);
151 | 
152 | $msg2 = new AMQPMessage($msg_body);
153 | $ch->batch_basic_publish($msg2, $exchange);
154 | ```
155 | 
156 | and then send the batch like this:
157 | 
158 | ```php
159 | $ch->publish_batch();
160 | ```
161 | 
162 | ### When do we publish the message batch? ###
163 | 
164 | Let's say our program needs to read from a file and then publish one message per line. Depending on the message size, you will have to decide when it's better to send the batch.
165 | You could send it every 50 messages, or every hundred. That's up to you.
166 | 
167 | ## Optimized Message Publishing ##
168 | 
169 | Another way to speed up your message publishing is by reusing the `AMQPMessage` message instances. You can create your new message like this:
170 | 
171 | ```php
172 | $properties = array('content_type' => 'text/plain', 'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT);
173 | $msg = new AMQPMessage($body, $properties);
174 | $ch->basic_publish($msg, $exchange);
175 | ```
176 | 
177 | Now let's say that while you want to change the message body for future messages, you will keep the same properties, that is, your messages will still be `text/plain` and the `delivery_mode` will still be `AMQPMessage::DELIVERY_MODE_PERSISTENT`. If you create a new `AMQPMessage` instance for every published message, then those properties would have to be re-encoded in the AMQP binary format. You could avoid all that by just reusing the `AMQPMessage` and then resetting the message body like this:
178 | 
179 | ```php
180 | $msg->setBody($body2);
181 | $ch->basic_publish($msg, $exchange);
182 | ```
183 | 
184 | ## Truncating Large Messages ##
185 | 
186 | AMQP imposes no limit on the size of messages; if a very large message is received by a consumer, PHP's memory limit may be reached
187 | within the library before the callback passed to `basic_consume` is called.
188 | 
189 | To avoid this, you can call the method `AMQPChannel::setBodySizeLimit(int $bytes)` on your Channel instance. Body sizes exceeding this limit will be truncated,
190 | and delivered to your callback with a `AMQPMessage::$is_truncated` flag set to `true`. The property `AMQPMessage::$body_size` will reflect the true body size of
191 | a received message, which will be higher than `strlen(AMQPMessage::getBody())` if the message has been truncated.
192 | 
193 | Note that all data above the limit is read from the AMQP Channel and immediately discarded, so there is no way to retrieve it within your
194 | callback. If you have another consumer which can handle messages with larger payloads, you can use `basic_reject` or `basic_nack` to tell
195 | the server (which still has a complete copy) to forward it to a Dead Letter Exchange.
196 | 
197 | By default, no truncation will occur. To disable truncation on a Channel that has had it enabled, pass `0` (or `null`) to `AMQPChannel::setBodySizeLimit()`.
198 | 
199 | ## Connection recovery ##
200 | 
201 | Some RabbitMQ clients using automated connection recovery mechanisms to reconnect
202 | and recover channels and consumers in case of network errors.
203 | 
204 | Since this client is using a single-thread, you can set up connection recovery
205 | using exception handling mechanism.
206 | 
207 | Exceptions which might be thrown in case of connection errors:
208 | 
209 | ```php
210 | PhpAmqpLib\Exception\AMQPConnectionClosedException
211 | PhpAmqpLib\Exception\AMQPIOException
212 | \RuntimeException
213 | \ErrorException
214 | ```
215 | 
216 | Some other exceptions might be thrown, but connection can still be there. It's
217 | always a good idea to clean up an old connection when handling an exception
218 | before reconnecting.
219 | 
220 | For example, if you want to set up a recovering connection:
221 | 
222 | ```php
223 | $connection = null;
224 | $channel = null;
225 | while(true){
226 |     try {
227 |         $connection = new AMQPStreamConnection(HOST, PORT, USER, PASS, VHOST);
228 |         // Your application code goes here.
229 |         do_something_with_connection($connection);
230 |     } catch(AMQPRuntimeException $e) {
231 |         echo $e->getMessage();
232 |         cleanup_connection($connection);
233 |         usleep(WAIT_BEFORE_RECONNECT_uS);
234 |     } catch(\RuntimeException $e) {
235 |         cleanup_connection($connection);
236 |         usleep(WAIT_BEFORE_RECONNECT_uS);
237 |     } catch(\ErrorException $e) {
238 |         cleanup_connection($connection);
239 |         usleep(WAIT_BEFORE_RECONNECT_uS);
240 |     }
241 | }
242 | 
243 | ```
244 | 
245 | A full example is in `demo/connection_recovery_consume.php`.
246 | 
247 | This code will reconnect and retry the application code every time the
248 | exception occurs. Some exceptions can still be thrown and should not be handled
249 | as a part of reconnection process, because they might be application errors.
250 | 
251 | This approach makes sense mostly for consumer applications, producers will
252 | require some additional application code to avoid publishing the same message
253 | multiple times.
254 | 
255 | This was a simplest example, in a real-life application you might want to
256 | control retr count and maybe gracefully degrade wait time to reconnection.
257 | 
258 | You can find a more excessive example in [#444](https://github.com/php-amqplib/php-amqplib/issues/444)
259 | 
260 | 
261 | ## UNIX Signals ##
262 | 
263 | If you have installed [PCNTL extension](http://www.php.net/manual/en/book.pcntl.php) dispatching of signal will be handled when consumer is not processing message.
264 | 
265 | ```php
266 | $pcntlHandler = function ($signal) {
267 |     switch ($signal) {
268 |         case \SIGTERM:
269 |         case \SIGUSR1:
270 |         case \SIGINT:
271 |             // some stuff before stop consumer e.g. delete lock etc
272 |             pcntl_signal($signal, SIG_DFL); // restore handler
273 |             posix_kill(posix_getpid(), $signal); // kill self with signal, see https://www.cons.org/cracauer/sigint.html
274 |         case \SIGHUP:
275 |             // some stuff to restart consumer
276 |             break;
277 |         default:
278 |             // do nothing
279 |     }
280 | };
281 | 
282 | pcntl_signal(\SIGTERM, $pcntlHandler);
283 | pcntl_signal(\SIGINT,  $pcntlHandler);
284 | pcntl_signal(\SIGUSR1, $pcntlHandler);
285 | pcntl_signal(\SIGHUP,  $pcntlHandler);
286 | ```
287 | 
288 | To disable this feature just define constant `AMQP_WITHOUT_SIGNALS` as `true`
289 | 
290 | ```php
291 | <?php
292 | define('AMQP_WITHOUT_SIGNALS', true);
293 | 
294 | ... more code
295 | 
296 | ```
297 | 
298 | 
299 | ## Signal-based Heartbeat ##
300 | 
301 | If you have installed [PCNTL extension](http://www.php.net/manual/en/book.pcntl.php) and are using PHP 7.1 or greater,
302 | you can register a signal-based heartbeat sender.
303 | 
304 | ```php
305 | <?php
306 | 
307 | $sender = new PCNTLHeartbeatSender($connection);
308 | $sender->register();
309 | ... code
310 | $sender->unregister();
311 | 
312 | ```
313 | 
314 | ## Debugging ##
315 | 
316 | If you want to know what's going on at a protocol level then add the following constant to your code:
317 | 
318 | ```php
319 | <?php
320 | define('AMQP_DEBUG', true);
321 | 
322 | ... more code
323 | 
324 | ?>
325 | ```
326 | 
327 | ## Benchmarks ##
328 | 
329 | To run the publishing/consume benchmark type:
330 | 
331 | ```bash
332 | make benchmark
333 | ```
334 | 
335 | ## Tests and Contributing
336 | 
337 | Please see [CONTRIBUTING](CONTRIBUTING.md) for details.
338 | 
339 | ## Using AMQP 0.8 ##
340 | 
341 | If you still want to use the old version of the protocol then you can do it by setting the following constant in your configuration code:
342 | 
343 | ```php
344 | define('AMQP_PROTOCOL', '0.8');
345 | ```
346 | 
347 | The default value is `'0.9.1'`.
348 | 
349 | ## Providing your own autoloader ##
350 | 
351 | If for some reason you don't want to use composer, then you need to have an autoloader in place fo the library classes. People have [reported](https://github.com/videlalvaro/php-amqplib/issues/61#issuecomment-37855050) to use this [autoloader](https://gist.github.com/jwage/221634) with success.
352 | 
353 | ## Original README: ##
354 | 
355 | Below is the original README file content. Credits goes to the original authors.
356 | 
357 | PHP library implementing Advanced Message Queuing Protocol (AMQP).
358 | 
359 | The library is port of python code of py-amqplib
360 | http://barryp.org/software/py-amqplib/
361 | 
362 | It have been tested with RabbitMQ server.
363 | 
364 | Project home page: http://code.google.com/p/php-amqplib/
365 | 
366 | For discussion, please join the group:
367 | 
368 | http://groups.google.com/group/php-amqplib-devel
369 | 
370 | For bug reports, please use bug tracking system at the project page.
371 | 
372 | Patches are very welcome!
373 | 
374 | Author: Vadim Zaliva <lord@crocodile.org>
375 | 
376 | [ico-version]: https://img.shields.io/packagist/v/php-amqplib/php-amqplib.svg?style=flat-square
377 | [ico-license]: https://img.shields.io/badge/license-LGPL_2.1-brightgreen.svg?style=flat-square
378 | [ico-scrutinizer]: https://img.shields.io/scrutinizer/coverage/g/php-amqplib/php-amqplib.svg?style=flat-square
379 | [ico-code-quality]: https://img.shields.io/scrutinizer/g/php-amqplib/php-amqplib.svg?style=flat-square
380 | [ico-downloads]: https://img.shields.io/packagist/dt/php-amqplib/php-amqplib.svg?style=flat-square
381 | 
382 | [link-packagist]: https://packagist.org/packages/php-amqplib/php-amqplib
383 | [link-scrutinizer]: https://scrutinizer-ci.com/g/php-amqplib/php-amqplib/code-structure
384 | [link-code-quality]: https://scrutinizer-ci.com/g/php-amqplib/php-amqplib
385 | [link-downloads]: https://packagist.org/packages/php-amqplib/php-amqplib
386 | [link-author]: https://github.com/php-amqplib
387 | [link-contributors]: ../../contributors
388 | 


--------------------------------------------------------------------------------
/codecov.yml:
--------------------------------------------------------------------------------
1 | coverage:
2 |   status:
3 |     project:
4 |       default:
5 |         target: auto
6 |         threshold: 0.5
7 | 


--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "name": "php-amqplib/php-amqplib",
 3 |     "replace": {
 4 |         "videlalvaro/php-amqplib": "self.version"
 5 |     },
 6 |     "type": "library",
 7 |     "description": "Formerly videlalvaro/php-amqplib.  This library is a pure PHP implementation of the AMQP protocol. It's been tested against RabbitMQ.",
 8 |     "keywords": ["rabbitmq", "message", "queue"],
 9 |     "homepage": "https://github.com/php-amqplib/php-amqplib/",
10 |     "authors": [
11 |         {
12 |             "name": "Alvaro Videla",
13 |             "role": "Original Maintainer"
14 |         },
15 |         {
16 |             "name": "Raúl Araya",
17 |             "email": "nubeiro@gmail.com",
18 |             "role": "Maintainer"
19 |         },
20 |         {
21 |             "name": "Luke Bakken",
22 |             "email": "luke@bakken.io",
23 |             "role": "Maintainer"
24 |         },
25 |         {
26 |             "name": "Ramūnas Dronga",
27 |             "email": "github@ramuno.lt",
28 |             "role": "Maintainer"
29 |         }
30 |     ],
31 |     "require": {
32 |         "php": "^7.2||^8.0",
33 |         "ext-sockets": "*",
34 |         "ext-mbstring": "*",
35 |         "phpseclib/phpseclib": "^2.0|^3.0"
36 |     },
37 |     "require-dev": {
38 |         "ext-curl": "*",
39 |         "phpunit/phpunit": "^7.5|^9.5",
40 |         "squizlabs/php_codesniffer": "^3.6",
41 |         "nategood/httpful": "^0.2.20"
42 |     },
43 |     "conflict": {
44 |         "php": "7.4.0 - 7.4.1"
45 |     },
46 |     "autoload": {
47 |         "psr-4": {
48 |             "PhpAmqpLib\\": "PhpAmqpLib/"
49 |         }
50 |     },
51 |     "autoload-dev": {
52 |         "psr-4": {
53 |             "PhpAmqpLib\\Tests\\Functional\\": "tests/Functional",
54 |             "PhpAmqpLib\\Tests\\Unit\\": "tests/Unit"
55 |         }
56 |     },
57 |     "license": "LGPL-2.1-or-later",
58 |     "extra": {
59 |         "branch-alias": {
60 |             "dev-master": "3.0-dev"
61 |         }
62 |     }
63 | }
64 | 


--------------------------------------------------------------------------------
/phpcs.xml.dist:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <ruleset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3 |          xsi:noNamespaceSchemaLocation="vendor/squizlabs/php_codesniffer/phpcs.xsd">
 4 | 
 5 |     <arg name="basepath" value="."/>
 6 |     <arg name="cache" value=".phpcs-cache"/>
 7 |     <arg name="colors"/>
 8 |     <arg value="p"/>
 9 |     <arg name="extensions" value="php"/>
10 |     <arg name="tab-width" value="4"/>
11 |     <arg name="report-width" value="120"/>
12 | 
13 |     <rule ref="PEAR.Functions.ValidDefaultValue">
14 |         <!-- We should preserve BC with possible child classes until next major version -->
15 |         <exclude-pattern>PhpAmqpLib/Helper/Protocol/Protocol091.php</exclude-pattern>
16 |         <exclude-pattern>PhpAmqpLib/Helper/Protocol/Protocol080.php</exclude-pattern>
17 |         <exclude-pattern>PhpAmqpLib/Connection/AbstractConnection.php</exclude-pattern>
18 |     </rule>
19 | 
20 |     <rule ref="PSR1.Methods.CamelCapsMethodName.NotCamelCaps">
21 |         <!-- We should preserve BC with possible child classes
22 |             and public method usage until next major version -->
23 |         <exclude-pattern>PhpAmqpLib/Wire/AMQPReader.php</exclude-pattern>
24 |         <exclude-pattern>PhpAmqpLib/Wire/IO/SocketIO.php</exclude-pattern>
25 |         <exclude-pattern>PhpAmqpLib/Wire/IO/StreamIO.php</exclude-pattern>
26 |         <exclude-pattern>PhpAmqpLib/Wire/IO/AbstractIO.php</exclude-pattern>
27 |         <exclude-pattern>PhpAmqpLib/Wire/AMQPWriter.php</exclude-pattern>
28 |         <exclude-pattern>PhpAmqpLib/Connection/AMQPSocketConnection.php</exclude-pattern>
29 |         <exclude-pattern>PhpAmqpLib/Connection/AMQPSSLConnection.php</exclude-pattern>
30 |         <exclude-pattern>PhpAmqpLib/Connection/AMQPStreamConnection.php</exclude-pattern>
31 |         <exclude-pattern>PhpAmqpLib/Connection/AMQPLazyConnection.php</exclude-pattern>
32 |         <exclude-pattern>PhpAmqpLib/Connection/AMQPLazySocketConnection.php</exclude-pattern>
33 |         <exclude-pattern>PhpAmqpLib/Connection/AMQPLazySSLConnection.php</exclude-pattern>
34 |         <exclude-pattern>PhpAmqpLib/Connection/AbstractConnection.php</exclude-pattern>
35 |         <exclude-pattern>PhpAmqpLib/Message/AMQPMessage.php</exclude-pattern>
36 |         <exclude-pattern>PhpAmqpLib/Helper/Protocol/Wait091.php</exclude-pattern>
37 |         <exclude-pattern>PhpAmqpLib/Helper/Protocol/MethodMap091.php</exclude-pattern>
38 |         <exclude-pattern>PhpAmqpLib/Helper/Protocol/Wait080.php</exclude-pattern>
39 |         <exclude-pattern>PhpAmqpLib/Helper/Protocol/MethodMap080.php</exclude-pattern>
40 |         <exclude-pattern>PhpAmqpLib/Helper/DebugHelper.php</exclude-pattern>
41 |         <exclude-pattern>PhpAmqpLib/Helper/MiscHelper.php</exclude-pattern>
42 |         <exclude-pattern>PhpAmqpLib/Channel/AMQPChannel.php</exclude-pattern>
43 |         <exclude-pattern>PhpAmqpLib/Channel/AbstractChannel.php</exclude-pattern>
44 |     </rule>
45 | 
46 |     <file>PhpAmqpLib/</file>
47 | </ruleset>
48 | 


--------------------------------------------------------------------------------
/test.env:
--------------------------------------------------------------------------------
1 | TEST_RABBITMQ_HOST=php-amqplib-rabbitmq
2 | TOXIPROXY_HOST=php-amqplib-toxiproxy
3 | TOXIPROXY_AMQP_PORT=5673
4 | 


--------------------------------------------------------------------------------