├── .gitignore ├── Makefile ├── README.md ├── docker-compose.yml ├── docker ├── composer │ └── Dockerfile ├── config │ ├── nginx.conf │ └── php.ini ├── nginx │ └── Dockerfile ├── php │ └── Dockerfile ├── php_receiver │ ├── Dockerfile │ └── bcmath.ini └── rabbitmq │ └── Dockerfile └── src ├── composer.json ├── composer.lock ├── receive.php └── send.php /.gitignore: -------------------------------------------------------------------------------- 1 | src/vendor 2 | .idea -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL := /usr/bin/env bash 2 | up: 3 | export UID && docker-compose up -d 4 | 5 | down: 6 | docker-compose down -v 7 | 8 | build: 9 | export UID && docker-compose build --pull 10 | 11 | bash: 12 | export UID && docker-compose run --rm php_sender bash 13 | 14 | composer_bash: 15 | export UID && docker-compose run --rm composer bash 16 | 17 | push_jobs: 18 | docker-compose exec php_sender sh -c 'while true; do php send.php; done;' 19 | 20 | docker_clean: 21 | docker rm $(docker ps -a -q) || true 22 | docker rmi < echo $(docker images -q | tr "\n" " ") 23 | 24 | tail: 25 | docker-compose logs -f 26 | 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Demo RabbitMQ implementation in PHP 2 | 3 | Using `php-amqplib/php-amqplib` with a full dockerised setup to minimise setup and provide a fully working environment. 4 | Based on https://www.rabbitmq.com/tutorials/tutorial-two-php.html 5 | 6 | This setup works on Macs and Linux, not tested on Windows 7 | 8 | ## Start stack 9 | 10 | `make up` 11 | 12 | Once rabbitMQ is started you can see the queue in the management console at http://localhost:15672/#/queues 13 | 14 | ## Send several messages 15 | 16 | This steps calls the sender infinitely to start queueing messages. Notice that the queue will grow considerably so to 17 | stop it do it in your console with CTRL + C (or similar depending on your Operating system) 18 | 19 | `make push_jobs` 20 | 21 | ## See the logs 22 | 23 | `make tail` 24 | 25 | ## Stop the stack 26 | 27 | `make down` -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2.2' 2 | 3 | services: 4 | nginx: 5 | build: 6 | context: . 7 | dockerfile: docker/nginx/Dockerfile 8 | ports: 9 | - "8888:80" 10 | volumes: 11 | - ./docker/config/nginx.conf:/etc/nginx/nginx.conf:ro 12 | - ./src:/var/www/html/:z 13 | depends_on: 14 | - php_sender 15 | 16 | php_sender: 17 | build: 18 | context: . 19 | dockerfile: docker/php/Dockerfile 20 | user: $UID 21 | ports: 22 | - "9000" 23 | volumes: 24 | - ./docker/config/php.ini:/usr/local/etc/php/php.ini 25 | - ./src:/var/www/html/:z 26 | depends_on: 27 | - php_receiver 28 | - composer 29 | 30 | php_receiver: 31 | #image: phpdockerio/php71-cli 32 | build: 33 | context: . 34 | dockerfile: docker/php_receiver/Dockerfile 35 | command: "php /app/receive.php" 36 | volumes: 37 | - ./src:/app 38 | depends_on: 39 | composer: 40 | condition: service_started 41 | rabbitmq: 42 | condition: service_healthy 43 | links: 44 | - rabbitmq 45 | scale: 5 46 | 47 | #https://stackoverflow.com/questions/31746182/docker-compose-wait-for-container-x-before-starting-y 48 | rabbitmq: 49 | # image: rabbitmq 50 | build: 51 | context: . 52 | dockerfile: docker/rabbitmq/Dockerfile 53 | ports: 54 | - "15672:15672" 55 | - "5672:5672" 56 | healthcheck: 57 | test: ["CMD", "curl", "-f", "http://localhost:15672"] 58 | interval: 30s 59 | timeout: 10s 60 | retries: 5 61 | volumes: 62 | - rabbitmq-data:/var/lib/rabbitmq 63 | 64 | composer: 65 | build: docker/composer 66 | user: $UID 67 | volumes: 68 | - ./src:/app 69 | command: composer install 70 | environment: 71 | - HOME=/home/composer 72 | working_dir: /app 73 | 74 | volumes: 75 | rabbitmq-data: -------------------------------------------------------------------------------- /docker/composer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.1-cli 2 | MAINTAINER Diego Gullo 3 | 4 | RUN apt-get update && apt-get install -y libcurl4-gnutls-dev git zip \ 5 | && docker-php-ext-install curl bcmath sockets \ 6 | && apt-get clean \ 7 | && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/* 8 | 9 | #COPY ./docker/php_receiver/bcmath.ini /etc/php/7.1/cli/conf.d/20-bcmath.ini 10 | RUN curl --silent --show-error https://getcomposer.org/installer | php \ 11 | && mkdir -p /usr/local/bin \ 12 | && mv composer.phar /usr/local/bin/composer \ 13 | && chmod +x /usr/local/bin/composer 14 | 15 | RUN mkdir -p /home/composer && chmod 777 /home/composer 16 | -------------------------------------------------------------------------------- /docker/config/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes 4; 2 | 3 | http { 4 | tcp_nopush on; 5 | tcp_nodelay on; 6 | keepalive_timeout 65; 7 | types_hash_max_size 2048; 8 | client_max_body_size 20m; 9 | 10 | include /etc/nginx/mime.types; 11 | default_type application/octet-stream; 12 | 13 | access_log /tmp/nginx-access.log; 14 | error_log /tmp/nginx-error.log; 15 | 16 | gzip on; 17 | gzip_disable "msie6"; 18 | 19 | server { 20 | # listen 8091; 21 | listen 80 default_server; 22 | root /var/www/html; 23 | index index.php index.html index.htm; 24 | try_files $uri /$uri /index.php?$query_string; 25 | 26 | location / { 27 | try_files $uri $uri/ /index.php?$query_string; 28 | root /var/www/html; 29 | } 30 | 31 | location ~ ^/.+\.php(/|$) { 32 | fastcgi_pass php_sender:9000; 33 | fastcgi_split_path_info ^(.+\.php)(/.*)$; 34 | include fastcgi_params; 35 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 36 | fastcgi_param HTTPS off; 37 | fastcgi_read_timeout 3000; 38 | } 39 | } 40 | } 41 | 42 | events { 43 | worker_connections 768; 44 | } 45 | -------------------------------------------------------------------------------- /docker/config/php.ini: -------------------------------------------------------------------------------- 1 | catch_workers_output = yes 2 | error_log = /tmp/php-error.log; 3 | log_errors = On 4 | date.timezone = Europe/London 5 | memory_limit = 2048M 6 | ;xdebug.remote_enable = 1 7 | ;xdebug.remote_connect_back = 1 8 | ;xdebug.remote_host = 10.0.2.2 9 | auto_detect_line_endings = 1 10 | max_execution_time = 3000 11 | ;xdebug.profiler_enable_trigger = 1 12 | ;xdebug.profiler_enable = 1 13 | ;xdebug.profiler_output_dir = /tmp/webgrind 14 | post_max_size = 21M 15 | upload_max_filesize = 20M -------------------------------------------------------------------------------- /docker/nginx/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx 2 | MAINTAINER Diego Gullo 3 | 4 | COPY ./docker/config/nginx.conf /etc/nginx/nginx.conf 5 | 6 | COPY ./src /var/www/html -------------------------------------------------------------------------------- /docker/php/Dockerfile: -------------------------------------------------------------------------------- 1 | #FROM php:5-fpm 2 | FROM php:fpm-alpine 3 | MAINTAINER Diego Gullo 4 | 5 | COPY ./docker/config/php.ini /usr/local/etc/php/php.ini 6 | 7 | #RUN apt-get update && apt-get install -y libcurl \ 8 | # && docker-php-ext-install curl \ 9 | # && apt-get clean \ 10 | # && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/* 11 | 12 | #RUN apk update && apk add -f libcurl \ 13 | # && docker-php-ext-install curl bcmath 14 | 15 | RUN docker-php-ext-install bcmath 16 | 17 | COPY ./src /var/www/html -------------------------------------------------------------------------------- /docker/php_receiver/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.1-cli 2 | MAINTAINER Diego Gullo 3 | 4 | RUN apt-get update && apt-get install -y libcurl4-gnutls-dev \ 5 | && docker-php-ext-install curl bcmath \ 6 | && apt-get clean \ 7 | && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/* 8 | -------------------------------------------------------------------------------- /docker/php_receiver/bcmath.ini: -------------------------------------------------------------------------------- 1 | ; configuration for php bcmath module 2 | ; priority=20 3 | extension=bcmath.so -------------------------------------------------------------------------------- /docker/rabbitmq/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rabbitmq:3-management 2 | RUN apt-get update 3 | RUN apt-get install -y curl 4 | EXPOSE 25672 15672 -------------------------------------------------------------------------------- /src/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "php-amqplib/php-amqplib": ">=2.6.1" 4 | } 5 | } -------------------------------------------------------------------------------- /src/composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "f0b42ac9169509834501cb7aa271b580", 8 | "packages": [ 9 | { 10 | "name": "paragonie/constant_time_encoding", 11 | "version": "v2.4.0", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/paragonie/constant_time_encoding.git", 15 | "reference": "f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c", 20 | "reference": "f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "php": "^7|^8" 25 | }, 26 | "require-dev": { 27 | "phpunit/phpunit": "^6|^7|^8|^9", 28 | "vimeo/psalm": "^1|^2|^3|^4" 29 | }, 30 | "type": "library", 31 | "autoload": { 32 | "psr-4": { 33 | "ParagonIE\\ConstantTime\\": "src/" 34 | } 35 | }, 36 | "notification-url": "https://packagist.org/downloads/", 37 | "license": [ 38 | "MIT" 39 | ], 40 | "authors": [ 41 | { 42 | "name": "Paragon Initiative Enterprises", 43 | "email": "security@paragonie.com", 44 | "homepage": "https://paragonie.com", 45 | "role": "Maintainer" 46 | }, 47 | { 48 | "name": "Steve 'Sc00bz' Thomas", 49 | "email": "steve@tobtu.com", 50 | "homepage": "https://www.tobtu.com", 51 | "role": "Original Developer" 52 | } 53 | ], 54 | "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", 55 | "keywords": [ 56 | "base16", 57 | "base32", 58 | "base32_decode", 59 | "base32_encode", 60 | "base64", 61 | "base64_decode", 62 | "base64_encode", 63 | "bin2hex", 64 | "encoding", 65 | "hex", 66 | "hex2bin", 67 | "rfc4648" 68 | ], 69 | "support": { 70 | "email": "info@paragonie.com", 71 | "issues": "https://github.com/paragonie/constant_time_encoding/issues", 72 | "source": "https://github.com/paragonie/constant_time_encoding" 73 | }, 74 | "time": "2020-12-06T15:14:20+00:00" 75 | }, 76 | { 77 | "name": "paragonie/random_compat", 78 | "version": "v9.99.100", 79 | "source": { 80 | "type": "git", 81 | "url": "https://github.com/paragonie/random_compat.git", 82 | "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" 83 | }, 84 | "dist": { 85 | "type": "zip", 86 | "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", 87 | "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", 88 | "shasum": "" 89 | }, 90 | "require": { 91 | "php": ">= 7" 92 | }, 93 | "require-dev": { 94 | "phpunit/phpunit": "4.*|5.*", 95 | "vimeo/psalm": "^1" 96 | }, 97 | "suggest": { 98 | "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." 99 | }, 100 | "type": "library", 101 | "notification-url": "https://packagist.org/downloads/", 102 | "license": [ 103 | "MIT" 104 | ], 105 | "authors": [ 106 | { 107 | "name": "Paragon Initiative Enterprises", 108 | "email": "security@paragonie.com", 109 | "homepage": "https://paragonie.com" 110 | } 111 | ], 112 | "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", 113 | "keywords": [ 114 | "csprng", 115 | "polyfill", 116 | "pseudorandom", 117 | "random" 118 | ], 119 | "support": { 120 | "email": "info@paragonie.com", 121 | "issues": "https://github.com/paragonie/random_compat/issues", 122 | "source": "https://github.com/paragonie/random_compat" 123 | }, 124 | "time": "2020-10-15T08:29:30+00:00" 125 | }, 126 | { 127 | "name": "php-amqplib/php-amqplib", 128 | "version": "v3.0.0", 129 | "source": { 130 | "type": "git", 131 | "url": "https://github.com/php-amqplib/php-amqplib.git", 132 | "reference": "c0a8eade209b7e43d6a405303d8de716dfd02749" 133 | }, 134 | "dist": { 135 | "type": "zip", 136 | "url": "https://api.github.com/repos/php-amqplib/php-amqplib/zipball/c0a8eade209b7e43d6a405303d8de716dfd02749", 137 | "reference": "c0a8eade209b7e43d6a405303d8de716dfd02749", 138 | "shasum": "" 139 | }, 140 | "require": { 141 | "ext-mbstring": "*", 142 | "ext-sockets": "*", 143 | "php": "^7.0|~8.0.0", 144 | "phpseclib/phpseclib": "^2.0|^3.0" 145 | }, 146 | "conflict": { 147 | "php": "7.4.0 - 7.4.1" 148 | }, 149 | "replace": { 150 | "videlalvaro/php-amqplib": "self.version" 151 | }, 152 | "require-dev": { 153 | "ext-curl": "*", 154 | "nategood/httpful": "^0.2.20", 155 | "phpunit/phpunit": "^6.5|^7.0|^9.5", 156 | "squizlabs/php_codesniffer": "^3.5" 157 | }, 158 | "type": "library", 159 | "extra": { 160 | "branch-alias": { 161 | "dev-master": "3.0-dev" 162 | } 163 | }, 164 | "autoload": { 165 | "psr-4": { 166 | "PhpAmqpLib\\": "PhpAmqpLib/" 167 | } 168 | }, 169 | "notification-url": "https://packagist.org/downloads/", 170 | "license": [ 171 | "LGPL-2.1-or-later" 172 | ], 173 | "authors": [ 174 | { 175 | "name": "Alvaro Videla", 176 | "role": "Original Maintainer" 177 | }, 178 | { 179 | "name": "Raúl Araya", 180 | "email": "nubeiro@gmail.com", 181 | "role": "Maintainer" 182 | }, 183 | { 184 | "name": "Luke Bakken", 185 | "email": "luke@bakken.io", 186 | "role": "Maintainer" 187 | }, 188 | { 189 | "name": "Ramūnas Dronga", 190 | "email": "github@ramuno.lt", 191 | "role": "Maintainer" 192 | } 193 | ], 194 | "description": "Formerly videlalvaro/php-amqplib. This library is a pure PHP implementation of the AMQP protocol. It's been tested against RabbitMQ.", 195 | "homepage": "https://github.com/php-amqplib/php-amqplib/", 196 | "keywords": [ 197 | "message", 198 | "queue", 199 | "rabbitmq" 200 | ], 201 | "support": { 202 | "issues": "https://github.com/php-amqplib/php-amqplib/issues", 203 | "source": "https://github.com/php-amqplib/php-amqplib/tree/v3.0.0" 204 | }, 205 | "time": "2021-03-16T15:00:23+00:00" 206 | }, 207 | { 208 | "name": "phpseclib/phpseclib", 209 | "version": "3.0.9", 210 | "source": { 211 | "type": "git", 212 | "url": "https://github.com/phpseclib/phpseclib.git", 213 | "reference": "a127a5133804ff2f47ae629dd529b129da616ad7" 214 | }, 215 | "dist": { 216 | "type": "zip", 217 | "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/a127a5133804ff2f47ae629dd529b129da616ad7", 218 | "reference": "a127a5133804ff2f47ae629dd529b129da616ad7", 219 | "shasum": "" 220 | }, 221 | "require": { 222 | "paragonie/constant_time_encoding": "^1|^2", 223 | "paragonie/random_compat": "^1.4|^2.0|^9.99.99", 224 | "php": ">=5.6.1" 225 | }, 226 | "require-dev": { 227 | "phing/phing": "~2.7", 228 | "phpunit/phpunit": "^5.7|^6.0|^9.4", 229 | "squizlabs/php_codesniffer": "~2.0" 230 | }, 231 | "suggest": { 232 | "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", 233 | "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", 234 | "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", 235 | "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." 236 | }, 237 | "type": "library", 238 | "autoload": { 239 | "files": [ 240 | "phpseclib/bootstrap.php" 241 | ], 242 | "psr-4": { 243 | "phpseclib3\\": "phpseclib/" 244 | } 245 | }, 246 | "notification-url": "https://packagist.org/downloads/", 247 | "license": [ 248 | "MIT" 249 | ], 250 | "authors": [ 251 | { 252 | "name": "Jim Wigginton", 253 | "email": "terrafrost@php.net", 254 | "role": "Lead Developer" 255 | }, 256 | { 257 | "name": "Patrick Monnerat", 258 | "email": "pm@datasphere.ch", 259 | "role": "Developer" 260 | }, 261 | { 262 | "name": "Andreas Fischer", 263 | "email": "bantu@phpbb.com", 264 | "role": "Developer" 265 | }, 266 | { 267 | "name": "Hans-Jürgen Petrich", 268 | "email": "petrich@tronic-media.com", 269 | "role": "Developer" 270 | }, 271 | { 272 | "name": "Graham Campbell", 273 | "email": "graham@alt-three.com", 274 | "role": "Developer" 275 | } 276 | ], 277 | "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", 278 | "homepage": "http://phpseclib.sourceforge.net", 279 | "keywords": [ 280 | "BigInteger", 281 | "aes", 282 | "asn.1", 283 | "asn1", 284 | "blowfish", 285 | "crypto", 286 | "cryptography", 287 | "encryption", 288 | "rsa", 289 | "security", 290 | "sftp", 291 | "signature", 292 | "signing", 293 | "ssh", 294 | "twofish", 295 | "x.509", 296 | "x509" 297 | ], 298 | "support": { 299 | "issues": "https://github.com/phpseclib/phpseclib/issues", 300 | "source": "https://github.com/phpseclib/phpseclib/tree/3.0.9" 301 | }, 302 | "funding": [ 303 | { 304 | "url": "https://github.com/terrafrost", 305 | "type": "github" 306 | }, 307 | { 308 | "url": "https://www.patreon.com/phpseclib", 309 | "type": "patreon" 310 | }, 311 | { 312 | "url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib", 313 | "type": "tidelift" 314 | } 315 | ], 316 | "time": "2021-06-14T06:54:45+00:00" 317 | } 318 | ], 319 | "packages-dev": [], 320 | "aliases": [], 321 | "minimum-stability": "stable", 322 | "stability-flags": [], 323 | "prefer-stable": false, 324 | "prefer-lowest": false, 325 | "platform": [], 326 | "platform-dev": [], 327 | "plugin-api-version": "2.1.0" 328 | } 329 | -------------------------------------------------------------------------------- /src/receive.php: -------------------------------------------------------------------------------- 1 | channel(); 14 | 15 | $channel->queue_declare('hello', false, true, false, false); 16 | 17 | echo ' [*] Waiting for messages. To exit press CTRL+C', "\n"; 18 | 19 | $callback = function($msg) { 20 | $waitSeconds = rand(15,30); 21 | echo " [x] Host: " . getenv('HOSTNAME') ." Waiting: " . $waitSeconds . " seconds. Received msg: ", $msg->body, "\n"; 22 | //sleep(substr_count($msg->body, '.')); 23 | sleep($waitSeconds); 24 | echo " [x] Done", "\n"; 25 | $msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']); 26 | }; 27 | 28 | $channel->basic_qos(null, 1, null); 29 | $channel->basic_consume('hello', '', false, false, false, false, $callback); 30 | 31 | while(count($channel->callbacks)) { 32 | $channel->wait(); 33 | } -------------------------------------------------------------------------------- /src/send.php: -------------------------------------------------------------------------------- 1 | channel(); 17 | 18 | $channel->queue_declare('hello', false, true, false, false); 19 | 20 | $msg = new AMQPMessage('Hello World!', 21 | array('delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT) 22 | ); 23 | $channel->basic_publish($msg, '', 'hello'); 24 | 25 | echo " [x] Sent 'Hello World!'\n"; 26 | 27 | $channel->close(); 28 | $connection->close(); --------------------------------------------------------------------------------