216 | Tokudu Android Push Demo
217 | |
218 |
221 |
222 | Server status:
223 |
224 |
226 | |
229 | | 258 | 257 |
├── .gitignore
├── README.md
├── composer.json
├── config
└── mqtt.php
├── index.php
├── src
├── Sam.php
├── SamConnection.php
├── SamMessage.php
└── lib
│ └── Mqtt.php
└── tests
├── 16x16_loading.gif
├── README
├── index.php
├── jquery.js
├── jquery.label_over.js
└── send_mqtt.php
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | /vendor
3 | composer.lock
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Laravel Mqtt Publisher
2 | Mqtt is used to publish messages from backend to andriod.
3 |
4 | ### Getting start
5 | `
6 | composer require luzhuqun/laravel-mqtt-publish
7 | `
8 | ### How to use
9 |
10 | use Lzq\Mqtt\SamMessage;
11 | use Lzq\Mqtt\SamConnection;
12 |
13 | $conn = new SAMConnection();//create a new connection object
14 |
15 | $conn->connect('mqtt', array('SAM_HOST' => '192.168.10.147', 'SAM_PORT' => '1883'));//start initialise the connection
16 |
17 | $msgCpu = new SAMMessage('hehe');//create a new MQTT message with the output of the shell command as the body
18 |
19 | $conn->send('topic://'.'tokudu/ab7867d9fd60db65', $msgCpu);//send the message on the topic cpu
20 |
21 | $conn->disconnect();
22 |
23 | ### Learn more
24 | A complet mqtt service incluede publisher, service and subscriber.
25 | ##### service
26 | [mosquitto](https://github.com/eclipse/mosquitto)
27 | ##### subscriber
28 | [AndroidPushNotificationsDemo](https://github.com/tokudu/AndroidPushNotificationsDemo)
29 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "luzhuqun/laravel-mqtt-publish",
3 | "description": "A simple Laravel 5 mqtt publisher",
4 | "keywords": ["mqtt","laravel","publish"],
5 | "license": "MIT",
6 | "authors": [
7 | {
8 | "name": "luzhuqun",
9 | "email": "595500783@qq.com"
10 | }
11 | ],
12 | "require": {
13 | "php": ">=5.4.0"
14 | },
15 | "autoload": {
16 | "psr-4": {
17 | "Lzq\\Mqtt\\": "src"
18 | }
19 | },
20 | "autoload-dev": {
21 | "psr-4": {
22 | "Lzq\\Mqtt\\Tests\\": "tests/"
23 | }
24 | },
25 | "minimum-stability": "dev"
26 | }
27 |
28 |
--------------------------------------------------------------------------------
/config/mqtt.php:
--------------------------------------------------------------------------------
1 | env('MQTT_SERVER_HOST', '192.168.10.147'),
5 | 'MQTT_SERVER_POST' => env('MQTT_SERVER_POST', '1883'),
6 | 'SAM_MQTT_CLEANSTART' => env('SAM_MQTT_CLEANSTART', 'SAM_MQTT_CLEANSTART'),
7 | 'SAM_MQTT_QOS' => env('SAM_MQTT_QOS', 2),
8 | 'SAM_MQTT_SUB_SEPARATOR' => env('SAM_MQTT_SUB_SEPARATOR', '#-#'),
9 | ];
10 |
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 | connect('mqtt', array('SAM_HOST' => '192.168.10.147', 'SAM_PORT' => '1883'));
12 |
13 | //create a new MQTT message with the output of the shell command as the body
14 | $msgCpu = new SAMMessage('hehe');
15 |
16 | //send the message on the topic cpu
17 | $conn->send('topic://'.'tokudu/ab7867d9fd60db65', $msgCpu);
18 |
19 | $conn->disconnect();
--------------------------------------------------------------------------------
/src/Sam.php:
--------------------------------------------------------------------------------
1 | eol = "\n";
18 | if (isset($_SERVER['REQUEST_URI'])) {
19 | $this->eol = '
';
20 | }
21 | }
22 |
23 | protected function e($s)
24 | {
25 | echo '-->'.$s."$this->eol";
26 | }
27 |
28 | protected function t($s)
29 | {
30 | echo ' '.$s."$this->eol";
31 | }
32 |
33 | protected function x($s)
34 | {
35 | echo '<--'.$s."$this->eol";
36 | }
37 | }
--------------------------------------------------------------------------------
/src/SamConnection.php:
--------------------------------------------------------------------------------
1 | debug) {
17 | $this->e('SAMConnection()');
18 | }
19 |
20 | if ($this->debug) {
21 | $this->x('SAMConnection()');
22 | }
23 | }
24 |
25 | public function create($proto)
26 | {
27 | if ($this->debug) {
28 | $this->e("SAMConnection.Create(proto=$proto)");
29 | }
30 | $rc = false;
31 | /* search the PHP config for a factory to use... */
32 | $x = get_cfg_var('sam.factory.'.$proto);
33 | if ($this->debug) {
34 | $this->t('SAMConnection.Create() get_cfg_var() "'.$x.'"');
35 | }
36 |
37 | /* If there is no configuration (php.ini) entry for this protocol, default it. */
38 | if (strlen($x) == 0) {
39 | /* for every protocol other than MQTT assume we will use XMS */
40 | if ($proto != 'mqtt') {
41 | $x = 'xms';
42 | if (!class_exists('SAMXMSConnection')) {
43 | global $eol;
44 | $l = (strstr(PHP_OS, 'WIN') ? 'php_' : '').'sam_xms.'.(strstr(PHP_OS, 'WIN') ? 'dll' : 'so');
45 | echo $eol.'Unable to access SAM XMS capabilities. Ensure the '.$l.' library is defined as an extension.'.$eol;
46 | $rc = false;
47 | } else {
48 | $rc = new SAMXMSConnection();
49 | }
50 | } else {
51 | $x = 'mqtt';
52 | $rc = new Mqtt();
53 | }
54 | }
55 |
56 | if ($this->debug && $rc) {
57 | $this->t('SAMConnection.Create() rc = '.get_class($rc));
58 | }
59 | if ($this->debug) {
60 | $this->x('SAMConnection.Create()');
61 | }
62 | return $rc;
63 | }
64 |
65 | public function commit()
66 | {
67 | if ($this->debug) {
68 | $this->e('SAMConnection.Commit()');
69 | }
70 | $rc = true;
71 |
72 | if (!$this->connection) {
73 | $errNo = 106;
74 | $error = 'No active connection!';
75 | $rc = false;
76 | } else {
77 | /* Call the method on the underlying connection object... */
78 | $rc = $this->connection->commit($target, $options);
79 | $this->errNo = $this->connection->errNo;
80 | $this->error = $this->connection->error;
81 | if (!$rc) {
82 | if ($this->debug) {
83 | $this->t("SAMConnection.Commit() commit failed ($this->errNo) $this->error");
84 | }
85 | $rc = false;
86 | }
87 | }
88 |
89 | if ($this->debug) {
90 | $this->x("SAMConnection.Commit() rc=$rc");
91 | }
92 | return $rc;
93 | }
94 |
95 | /* ---------------------------------
96 | Connect
97 | --------------------------------- */
98 | public function connect($proto = '', $options = array())
99 | {
100 | if ($this->debug) {
101 | $this->e('SAMConnection.connect()');
102 | }
103 | $rc = false;
104 |
105 | if ($options['SAM_PORT'] == '') {
106 | $this->port = 1883;
107 | } else {
108 | $this->port = $options['SAM_PORT'];
109 | }
110 | if ($options['SAM_HOST'] == '') {
111 | $this->host = 'localhost';
112 | } else {
113 | $this->host = $options['SAM_HOST'];
114 | }
115 |
116 | if ($proto == '') {
117 | $errNo = 101;
118 | $error = 'Incorrect number of parameters on connect call!';
119 | $rc = false;
120 | } else {
121 | $this->connection = $this->create($proto);
122 | if (!$this->connection) {
123 | $errNo = 102;
124 | $error = 'Unsupported protocol!';
125 | $rc = false;
126 | } else {
127 | if ($this->debug) {
128 | $this->t("SAMConnection.Connect() connection created for protocol $proto");
129 | }
130 |
131 | $this->connection->setdebug($this->debug);
132 |
133 | /* Call the connect method on the newly created connection object... */
134 | $rc = $this->connection->connect($proto, $options);
135 | $this->errNo = $this->connection->errNo;
136 | $this->error = $this->connection->error;
137 | if (!$rc) {
138 | if ($this->debug) {
139 | $this->t("SAMConnection.Connect() connect failed ($this->errNo) $this->error");
140 | }
141 | } else {
142 | $rc = true;
143 | }
144 | }
145 | }
146 |
147 | if ($this->debug) {
148 | $this->x("SAMConnection.Connect() rc=$rc");
149 | }
150 | return $rc;
151 | }
152 |
153 | /* ---------------------------------
154 | Disconnect
155 | --------------------------------- */
156 | public function disconnect()
157 | {
158 | if ($this->debug) {
159 | $this->e('SAMConnection.Disconnect()');
160 | }
161 | $rc = true;
162 |
163 | if (!$this->connection) {
164 | $errNo = 106;
165 | $error = 'No active connection!';
166 | $rc = false;
167 | } else {
168 | /* Call the method on the underlying connection object... */
169 | $rc = $this->connection->Disconnect();
170 | $this->errNo = $this->connection->errNo;
171 | $this->error = $this->connection->error;
172 | if (!$rc) {
173 | if ($this->debug) {
174 | $this->t("SAMConnection.Disconnect() Disconnect failed ($this->errNo) $this->error");
175 | }
176 | } else {
177 | $rc = true;
178 | $this->connection = false;
179 | }
180 | }
181 |
182 | if ($this->debug) {
183 | $this->x("SAMConnection.Disconnect() rc=$rc");
184 | }
185 | return $rc;
186 | }
187 |
188 | /* ---------------------------------
189 | IsConnected
190 | --------------------------------- */
191 | public function isConnected()
192 | {
193 | if ($this->debug) {
194 | $this->e('SAMConnection.IsConnected()');
195 | }
196 | $rc = true;
197 |
198 | if (!$this->connection) {
199 | $errNo = 106;
200 | $error = 'No active connection!';
201 | $rc = false;
202 | } else {
203 | /* Call the method on the underlying connection object... */
204 | $rc = $this->connection->isconnected();
205 | $this->errNo = $this->connection->errNo;
206 | $this->error = $this->connection->error;
207 | if (!$rc) {
208 | if ($this->debug) {
209 | $this->t("SAMConnection.IsConnected() isconnected failed ($this->errNo) $this->error");
210 | }
211 | $rc = false;
212 | }
213 | }
214 |
215 | if ($this->debug) {
216 | $this->x("SAMConnection.IsConnected() rc=$rc");
217 | }
218 | return $rc;
219 | }
220 |
221 | /* ---------------------------------
222 | Peek
223 | --------------------------------- */
224 | public function peek($target, $options = array())
225 | {
226 | if ($this->debug) {
227 | $this->e('SAMConnection.Peek()');
228 | }
229 | $rc = true;
230 |
231 | if (!$this->connection) {
232 | $errNo = 106;
233 | $error = 'No active connection!';
234 | $rc = false;
235 | } else {
236 | /* Call the method on the underlying connection object... */
237 | $rc = $this->connection->peek($target, $options);
238 | $this->errNo = $this->connection->errNo;
239 | $this->error = $this->connection->error;
240 | if (!$rc) {
241 | if ($this->debug) {
242 | $this->t("SAMConnection.Peek() peek failed ($this->errNo) $this->error");
243 | }
244 | $rc = false;
245 | }
246 | }
247 |
248 | if ($this->debug) {
249 | $this->x("SAMConnection.Peek() rc=$rc");
250 | }
251 | return $rc;
252 | }
253 |
254 | /* ---------------------------------
255 | PeekAll
256 | --------------------------------- */
257 | public function peekAll($target, $options = array())
258 | {
259 | if ($this->debug) {
260 | $this->e('SAMConnection.PeekAll()');
261 | }
262 | $rc = true;
263 |
264 | if (!$this->connection) {
265 | $errNo = 106;
266 | $error = 'No active connection!';
267 | $rc = false;
268 | } else {
269 | /* Call the method on the underlying connection object... */
270 | $rc = $this->connection->peekall($target, $options);
271 | $this->errNo = $this->connection->errNo;
272 | $this->error = $this->connection->error;
273 | if (!$rc) {
274 | if ($this->debug) {
275 | $this->t("SAMConnection.PeekAll() peekall failed ($this->errNo) $this->error");
276 | }
277 | $rc = false;
278 | }
279 | }
280 |
281 | if ($this->debug) {
282 | $this->x("SAMConnection.PeekAll() rc=$rc");
283 | }
284 | return $rc;
285 | }
286 |
287 | /* ---------------------------------
288 | Receive
289 | --------------------------------- */
290 | public function receive($target, $options = array())
291 | {
292 | if ($this->debug) {
293 | $this->e('SAMConnection.Receive()');
294 | }
295 | $rc = true;
296 |
297 | if (!$this->connection) {
298 | $errNo = 106;
299 | $error = 'No active connection!';
300 | $rc = false;
301 | } else {
302 | /* Call the receive method on the underlying connection object... */
303 | $rc = $this->connection->receive($target, $options);
304 | $this->errNo = $this->connection->errNo;
305 | $this->error = $this->connection->error;
306 | if (!$rc) {
307 | if ($this->debug) {
308 | $this->t("SAMConnection.Receive() receive failed ($this->errNo) $this->error");
309 | }
310 | }
311 | }
312 |
313 | if ($this->debug) {
314 | $this->x("SAMConnection.Receive() rc=$rc");
315 | }
316 | return $rc;
317 | }
318 |
319 | /* ---------------------------------
320 | Remove
321 | --------------------------------- */
322 | public function remove($target, $options = array())
323 | {
324 | if ($this->debug) {
325 | $this->e('SAMConnection.Remove()');
326 | }
327 | $rc = true;
328 |
329 | if (!$this->connection) {
330 | $errNo = 106;
331 | $error = 'No active connection!';
332 | $rc = false;
333 | } else {
334 | /* Call the method on the underlying connection object... */
335 | $rc = $this->connection->remove($target, $options);
336 | $this->errNo = $this->connection->errNo;
337 | $this->error = $this->connection->error;
338 | if (!$rc) {
339 | if ($this->debug) {
340 | $this->t("SAMConnection.Remove() remove failed ($this->errNo) $this->error");
341 | }
342 | $rc = false;
343 | }
344 | }
345 |
346 | if ($this->debug) {
347 | $this->x("SAMConnection.Remove() rc=$rc");
348 | }
349 | return $rc;
350 | }
351 |
352 | /* ---------------------------------
353 | Rollback
354 | --------------------------------- */
355 | public function rollback()
356 | {
357 | if ($this->debug) {
358 | $this->e('SAMConnection.Rollback()');
359 | }
360 | $rc = true;
361 |
362 | if (!$this->connection) {
363 | $errNo = 106;
364 | $error = 'No active connection!';
365 | $rc = false;
366 | } else {
367 | /* Call the method on the underlying connection object... */
368 | $rc = $this->connection->rollback($target, $options);
369 | $this->errNo = $this->connection->errNo;
370 | $this->error = $this->connection->error;
371 | if (!$rc) {
372 | if ($this->debug) {
373 | $this->t("SAMConnection.Rollback() rollback failed ($this->errNo) $this->error");
374 | }
375 | $rc = false;
376 | }
377 | }
378 |
379 | if ($this->debug) {
380 | $this->x("SAMConnection.Rollback() rc=$rc");
381 | }
382 | return $rc;
383 | }
384 |
385 | /* ---------------------------------
386 | Send
387 | --------------------------------- */
388 | public function send($target, $msg, $options = array())
389 | {
390 | if ($this->debug) {
391 | $this->e('SAMConnection.Send()');
392 | }
393 | $rc = true;
394 |
395 | if (!$this->connection) {
396 | $errNo = 106;
397 | $error = 'No active connection!';
398 | $rc = false;
399 | } else {
400 | /* Call the send method on the underlying connection object... */
401 | $rc = $this->connection->send($target, $msg, $options);
402 | $this->errNo = $this->connection->errNo;
403 | $this->error = $this->connection->error;
404 | if (!$rc) {
405 | if ($this->debug) {
406 | $this->t("SAMConnection.Send() send failed ($this->errNo) $this->error");
407 | }
408 | $rc = false;
409 | }
410 | }
411 |
412 | if ($this->debug) {
413 | $this->x("SAMConnection.Send() rc=$rc");
414 | }
415 | return $rc;
416 | }
417 |
418 | /* ---------------------------------
419 | SetDebug
420 | --------------------------------- */
421 | public function setDebug($option = false)
422 | {
423 | if ($this->debug) {
424 | $this->e("SAMConnection.setDebug($option)");
425 | }
426 |
427 | $this->debug = $option;
428 |
429 | if ($this->connection) {
430 | $this->connection->setdebug($option);
431 | }
432 |
433 | if ($this->debug) {
434 | $this->x('SAMConnection.SetDebug()');
435 | }
436 | return;
437 | }
438 |
439 | /* ---------------------------------
440 | Subscribe
441 | --------------------------------- */
442 | public function subscribe($topic, $options = array())
443 | {
444 | if ($this->debug) {
445 | $this->e("SAMConnection.Subscribe($topic)");
446 | }
447 | $rc = true;
448 |
449 | if (!$this->connection) {
450 | $errNo = 106;
451 | $error = 'No active connection!';
452 | $rc = false;
453 | } else {
454 | /* Call the subscribe method on the underlying connection object... */
455 | $rc = $this->connection->subscribe($topic, $options);
456 | $this->errNo = $this->connection->errNo;
457 | $this->error = $this->connection->error;
458 | if (!$rc) {
459 | if ($this->debug) {
460 | $this->t("SAMConnection.Subscribe() subscribe failed ($this->errNo) $this->error");
461 | }
462 | $rc = false;
463 | }
464 | }
465 |
466 | if ($this->debug) {
467 | $this->x("SAMConnection.Subscribe() rc=$rc");
468 | }
469 | return $rc;
470 | }
471 |
472 | /* ---------------------------------
473 | Unsubscribe
474 | --------------------------------- */
475 | public function unsubscribe($sub_id)
476 | {
477 | if ($this->debug) {
478 | $this->e("SAMConnection.unsubscribe($sub_id)");
479 | }
480 | $rc = true;
481 |
482 | if (!$this->connection) {
483 | $errNo = 106;
484 | $error = 'No active connection!';
485 | $rc = false;
486 | } else {
487 | /* Call the subscribe method on the underlying connection object... */
488 | $rc = $this->connection->unsubscribe($sub_id);
489 | $this->errNo = $this->connection->errNo;
490 | $this->error = $this->connection->error;
491 | if (!$rc) {
492 | if ($this->debug) {
493 | $this->t("SAMConnection.unsubscribe() unsubscribe failed ($this->errNo) $this->error");
494 | }
495 | $rc = false;
496 | }
497 | }
498 |
499 | if ($this->debug) {
500 | $this->x("SAMConnection.unsubscribe() rc=$rc");
501 | }
502 | return $rc;
503 | }
504 | }
--------------------------------------------------------------------------------
/src/SamMessage.php:
--------------------------------------------------------------------------------
1 | body = $body;
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/src/lib/Mqtt.php:
--------------------------------------------------------------------------------
1 | 1,
42 | "MQTT_CONNACK" => 2,
43 | "MQTT_PUBLISH" => 3,
44 | "MQTT_PUBACK" => 4,
45 | "MQTT_PUBREC" => 5,
46 | "MQTT_PUBREL" => 6,
47 | "MQTT_PUBCOMP" => 7,
48 | "MQTT_SUBSCRIBE" => 8,
49 | "MQTT_SUBACK" => 9,
50 | "MQTT_UNSUBSCRIBE" => 10,
51 | "MQTT_UNSUBACK" => 11,
52 | "MQTT_PINGREC" => 12,
53 | "MQTT_PINGRESP" => 13,
54 | "MQTT_DISCONNECT" => 14);
55 |
56 | /* ---------------------------------
57 | Constructor
58 | --------------------------------- */
59 | function SAMConnection_MQTT() {
60 | if ($this->debug) $this->$this->e('SAMConnection_MQTT()');
61 |
62 | if ($this->debug) $this->x('SAMConnection_MQTT()');
63 | }
64 |
65 | /* ---------------------------------
66 | Commit
67 | --------------------------------- */
68 | function Commit() {
69 | if ($this->debug) $this->$this->e('SAMConnection_MQTT.Commit()');
70 |
71 | $errNo = 100;
72 | $error = 'Unsupported operation for MQTT protocol!';
73 | $rc = false;
74 |
75 | if ($this->debug) $this->x("SAMConnection_MQTT.Commit() rc=$rc");
76 | return $rc;
77 | }
78 |
79 | /* ---------------------------------
80 | Connect
81 | --------------------------------- */
82 | function Connect($proto, $options=array()) {
83 | if ($this->debug) $this->e('SAMConnection_MQTT.Connect()');
84 |
85 | /* Check our optional parameter array for the necessary bits... */
86 | if ($options['SAM_PORT'] == '') {
87 | $this->port = 1883;
88 | } else {
89 | $this->port = $options['SAM_PORT'];
90 | }
91 | if ($options['SAM_HOST'] == '') {
92 | $this->host = 'localhost';
93 | } else {
94 | $this->host = $options['SAM_HOST'];
95 | }
96 |
97 | $this->cleanstart = in_array(SAM_MQTT_CLEANSTART, $options);
98 |
99 | if ($this->debug) $this->t("SAMConnection_MQTT.Connect() host=$this->host, port=$this->port, cleanstart=$this->cleanstart");
100 |
101 | if ($this->checkHost($this->host, $this->port)) {
102 | $this->virtualConnected = true;
103 | } else {
104 | $this->virtualConnected = false;
105 | }
106 |
107 | if ($this->debug) $this->x("SAMConnection_MQTT.Connect() rc=$this->virtualConnected");
108 | return $this->virtualConnected;
109 | }
110 |
111 | /* ---------------------------------
112 | Disconnect
113 | --------------------------------- */
114 | function Disconnect() {
115 | if ($this->debug) $this->e('SAMConnection_MQTT.Disconnect()');
116 | $rc = false;
117 |
118 | if ($this->virtualConnected) {
119 | if ($this->connected) {
120 | $msg = $this->fixed_header("MQTT_DISCONNECT").pack('C', 0);
121 | fwrite($this->sock, $msg);
122 | $response = fgets($this->sock, 128);
123 | if ($this->debug) t('SAMConnection_MQTT.Disconnect() response is '.strlen($response).' bytes');
124 | if (strlen($response) == 0) {
125 | fclose($this->sock);
126 | $this->sock = NULL;
127 | }
128 | }
129 | $this->virtualConnected = false;
130 | $this->connected = false;
131 | $rc = true;
132 | }
133 |
134 | if ($this->debug) $this->x("SAMConnection_MQTT.Disconnect() rc=$rc");
135 | return $rc;
136 | }
137 |
138 | /* ---------------------------------
139 | IsConnected
140 | --------------------------------- */
141 | function IsConnected() {
142 | if ($this->debug) $this->e('SAMConnection_MQTT.IsConnected()');
143 | $rc = false;
144 |
145 | if ($this->connected) {
146 | $rc = true;
147 | }
148 |
149 | if ($this->debug) $this->x("SAMConnection_MQTT.IsConnected() rc=$rc");
150 | return $rc;
151 | }
152 |
153 | /* ---------------------------------
154 | Peek
155 | --------------------------------- */
156 | function Peek() {
157 | if ($this->debug) $this->e('SAMConnection_MQTT.Peek()');
158 |
159 | $errNo = 100;
160 | $error = 'Unsupported operation for MQTT protocol!';
161 | $rc = false;
162 |
163 | if ($this->debug) $this->x("SAMConnection_MQTT.Peek() rc=$rc");
164 | return $rc;
165 | }
166 |
167 | /* ---------------------------------
168 | PeekAll
169 | --------------------------------- */
170 | function PeekAll() {
171 | if ($this->debug) $this->e('SAMConnection_MQTT.PeekAll()');
172 |
173 | $errNo = 100;
174 | $error = 'Unsupported operation for MQTT protocol!';
175 | $rc = false;
176 |
177 | if ($this->debug) $this->x("SAMConnection_MQTT.PeekAll() rc=$rc");
178 | return $rc;
179 | }
180 |
181 | /* ---------------------------------
182 | Receive
183 | --------------------------------- */
184 | function Receive($sub_id, $options=array()) {
185 | if ($this->debug) $this->e('SAMConnection_MQTT.Receive()');
186 | $rc = false;
187 |
188 | /* strip the topic from the rear of the subscription id... */
189 | $x = strpos($sub_id, SAM_MQTT_SUB_SEPARATOR);
190 | if (!$x) {
191 | $this->errNo = 279;
192 | $this->error = 'Specified subscription id ('.$sub_id.') is not valid!';
193 | return false;
194 | }
195 | $topic = substr($sub_id, $x + strlen(SAM_MQTT_SUB_SEPARATOR));
196 | $si = substr($sub_id, 0, $x);
197 |
198 | /* Are we already connected? */
199 | if (!$this->connected) {
200 | if ($this->debug) t('SAMConnection_MQTT.Receive() Not connected.');
201 | /* No, so open up the connection... */
202 | $this->sub_id = $si;
203 | $rc = $this->do_connect_now();
204 | } else {
205 | /* We are already connected. Are we using the right subscriber id? */
206 | if ($this->sub_id != $si) {
207 | if ($this->debug) t('SAMConnection_MQTT.Receive() Connected with wrong sub_id.');
208 | /* No, We better reconnect then... */
209 | $this->disconnect();
210 | $this->sub_id = $si;
211 | $rc = $this->do_connect_now();
212 | } else {
213 | if ($this->debug) t('SAMConnection_MQTT.Receive() Connected OK.');
214 | $rc = true;
215 | }
216 | }
217 |
218 | if ($rc) {
219 |
220 | /* have we got a timeout specified? */
221 | if ($options[SAM_WAIT] > 1) {
222 | $m = $options[SAM_WAIT] % 1000;
223 | $s = ($options[SAM_WAIT] - $m) /1000;
224 | if ($this->debug) t('SAMConnection_MQTT.Receive() timeout='.$options[SAM_WAIT]." ($s secs $m millisecs)");
225 | stream_set_timeout($this->sock, $s, $m);
226 | if ($this->debug) t('SAMConnection_MQTT.Receive() timeout set.');
227 | } else {
228 | if ($this->debug) t('SAMConnection_MQTT.Receive() no timeout value found!');
229 | }
230 |
231 | $hdr = $this->read_fixed_header($this->sock);
232 | if (!$hdr) {
233 | $this->errNo = 500;
234 | $this->error = 'Receive request failed, timed out with no data!';
235 | $rc = false;
236 | } else {
237 | if ($hdr['mtype'] == $this->operations['MQTT_PUBLISH']) {
238 | $len = $this->read_remaining_length($this->sock);
239 | if ($len > 1) {
240 | /* read the topic length... */
241 | $topic = $this->read_topic($this->sock);
242 | if (!$topic) {
243 | $this->errNo = 303;
244 | $this->error = 'Receive request failed, message format invalid!';
245 | $rc = false;
246 | } else {
247 | if ($this->debug) t('SAMConnection_MQTT.Receive() topic='.$topic);
248 | $len -= (strlen($topic) + 2);
249 | /* If QoS 1 or 2 then read the message id... */
250 | if ($hdr['qos'] > 0) {
251 | $idb = fread($this->sock, 2);
252 | $len -= 2;
253 | $fields = unpack('na', $idb);
254 | $mid = $fields['a'];
255 | if ($this->debug) t('SAMConnection_MQTT.Receive() mid='.$mid);
256 | }
257 | $payload = fread($this->sock, $len);
258 | if ($this->debug) t('SAMConnection_MQTT.Receive() payload='.$payload);
259 | $rc = new SAMMessage();
260 | $rc->body = $payload;
261 | $rc->header->SAM_MQTT_TOPIC = 'topic://'.$topic;
262 | $rc->header->SAM_MQTT_QOS = $hdr['qos'];
263 | $rc->header->SAM_TYPE = 'SAM_BYTES';
264 | }
265 | } else {
266 | $this->errNo = 303;
267 | $this->error = 'Receive request failed, received message too short! No topic data';
268 | $rc = false;
269 | }
270 | } else {
271 | if ($this->debug) t('SAMConnection_MQTT.Receive() Receive failed response mtype = '.$mtype);
272 | $rc = false;
273 | }
274 | }
275 | }
276 |
277 | if ($this->debug) $this->x("SAMConnection_MQTT.Receive() rc=$rc");
278 | return $rc;
279 | }
280 |
281 | /* ---------------------------------
282 | Remove
283 | --------------------------------- */
284 | function Remove() {
285 | if ($this->debug) $this->e('SAMConnection_MQTT.Remove()');
286 |
287 | $errNo = 100;
288 | $error = 'Unsupported operation for MQTT protocol!';
289 | $rc = false;
290 |
291 | if ($this->debug) $this->x("SAMConnection_MQTT.Remove() rc=$rc");
292 | return $rc;
293 | }
294 |
295 | /* ---------------------------------
296 | Rollback
297 | --------------------------------- */
298 | function Rollback() {
299 | if ($this->debug) $this->e('SAMConnection_MQTT.Rollback()');
300 |
301 | $errNo = 100;
302 | $error = 'Unsupported operation for MQTT protocol!';
303 | $rc = false;
304 |
305 | if ($this->debug) $this->x("SAMConnection_MQTT.Rollback() rc=$rc");
306 | return $rc;
307 | }
308 |
309 | /* ---------------------------------
310 | Send
311 | --------------------------------- */
312 | function Send($topic, $message, $options=array()) {
313 | if ($this->debug) $this->e('SAMConnection_MQTT.Send()');
314 | $rc = true;
315 |
316 | /* check the format of the topic... */
317 | if (strncmp($topic, 'topic://', 8) == 0) {
318 | $t = substr($topic, 8);
319 | } else {
320 | $this->errNo = 279;
321 | $this->error = 'Specified target ('.$topic.') is not a valid topic!';
322 | return false;
323 | }
324 |
325 | if (in_array(SAM_MQTT_QOS, $options)) {
326 | $qos = $options[SAM_MQTT_QOS];
327 | } else {
328 | $qos = 0;
329 | }
330 |
331 | /* Are we already connected? */
332 | if (!$this->connected) {
333 | /* No, so open up the connection... */
334 | $this->do_connect_now();
335 | }
336 |
337 | $mid = rand();
338 | $variable = $this->utf($t);
339 | if ($qos > 0) {
340 | $variable .= pack('n', $mid);
341 | }
342 |
343 | $payload = $message->body;
344 |
345 | // add in the remaining length field and fix it together
346 | $msg = $this->fixed_header("MQTT_PUBLISH", 0, $qos) . $this->remaining_length(strlen($variable)+strlen($payload)) . $variable . $payload;
347 |
348 | fwrite($this->sock, $msg);
349 | if ($qos > 0) {
350 | $hdr = $this->read_fixed_header($this->sock);
351 | if ($hdr) {
352 | /* is this a QoS level 1 message being sent? */
353 | if ($qos == 1) {
354 | /* Yup, so we should get a PUBACK response message... */
355 | if ($hdr['mtype'] == $this->operations['MQTT_PUBACK']) {
356 | $len = $this->read_remaining_length($this->sock);
357 | if ($len > 0) {
358 | $response = fread($this->sock, $len);
359 | }
360 | if ($len < 2) {
361 | if ($this->debug) $this->t("SAMConnection_MQTT.Send() send failed, incorrect length response ($len) received!");
362 | $this->errNo = 302;
363 | $this->error = 'Send request failed!';
364 | $rc = false;
365 | } else {
366 | $rc = true;
367 | }
368 | } else {
369 | if ($this->debug) t('SAMConnection_MQTT.Send() Send failed response mtype = '.$mtype.' Expected PUBREC!');
370 | $rc = false;
371 | }
372 | } else {
373 | /* lets assume it's QoS level 2... */
374 | /* We should get a PUBREC response message... */
375 | if ($hdr['mtype'] == $this->operations['MQTT_PUBREC']) {
376 | $len = $this->read_remaining_length($this->sock);
377 | if ($len > 0) {
378 | $response = fread($this->sock, $len);
379 | }
380 | if ($len < 2) {
381 | if ($this->debug) $this->t("SAMConnection_MQTT.Send() send failed, incorrect length response ($len) received!");
382 | $this->errNo = 302;
383 | $this->error = 'Send request failed!';
384 | $rc = false;
385 | } else {
386 | $rc = true;
387 | /* Now we can send a PUBREL message... */
388 | $variable = pack('n', $mid);
389 | $msg = $this->fixed_header("MQTT_PUBREL").$this->remaining_length(strlen($variable)).$variable;
390 | fwrite($this->sock, $msg);
391 |
392 | /* get a response... */
393 | $hdr = $this->read_fixed_header($this->sock);
394 | if ($hdr['mtype'] == $this->operations['MQTT_PUBCOMP']) {
395 | $len = $this->read_remaining_length($this->sock);
396 | if ($len > 0) {
397 | $response = fread($this->sock, $len);
398 | }
399 | if ($len < 2) {
400 | if ($this->debug) $this->t("SAMConnection_MQTT.Send() send failed, incorrect length response ($len) received!");
401 | $this->errNo = 302;
402 | $this->error = 'Send request failed!';
403 | $rc = false;
404 | } else {
405 | $rc = true;
406 | }
407 | } else {
408 | if ($this->debug) t('SAMConnection_MQTT.Send() Send failed response mtype = '.$mtype.' Expected PUBCOMP!');
409 | $rc = false;
410 | }
411 | }
412 | } else {
413 | if ($this->debug) t('SAMConnection_MQTT.Send() Send failed response mtype = '.$mtype);
414 | $rc = false;
415 | }
416 | }
417 | }
418 | }
419 |
420 | if ($this->debug) $this->x("SAMConnection_MQTT.Send() rc=$rc");
421 | return $rc;
422 | }
423 |
424 | /* ---------------------------------
425 | SetDebug
426 | --------------------------------- */
427 | function SetDebug($option=false) {
428 | $this->debug = $option;
429 | return;
430 | }
431 |
432 | /* ---------------------------------
433 | Subscribe
434 | --------------------------------- */
435 | function Subscribe($topic, $options=array()) {
436 | if ($this->debug) e("SAMConnection_MQTT.Subscribe($topic)");
437 | $rc = true;
438 |
439 | /* check the format of the topic... */
440 | if (strncmp($topic, 'topic://', 8) == 0) {
441 | $t = substr($topic, 8);
442 | } else {
443 | $this->errNo = 279;
444 | $this->error = 'Specified target ('.$topic.') is not a valid topic!';
445 | return false;
446 | }
447 |
448 | if (in_array(SAM_MQTT_QOS, $options)) {
449 | $qos = $options[SAM_MQTT_QOS];
450 | } else {
451 | $qos = 0;
452 | }
453 |
454 | /* Are we already connected? */
455 | if (!$this->connected) {
456 | /* No, so open up the connection... */
457 | if (!$this->do_connect_now()) {
458 | return false;
459 | }
460 | }
461 |
462 | // variable header: message id (16 bits)
463 | $x = rand(1, 16000);
464 | $variable = pack('n', $x);
465 |
466 | // payload: client ID
467 | $payload = $this->utf($t).pack('C', $qos);
468 |
469 | // add in the remaining length field and fix it together
470 | $msg = $this->fixed_header("MQTT_SUBSCRIBE", 0, 1) . $this->remaining_length(strlen($variable)+strlen($payload)) . $variable . $payload;
471 |
472 | fwrite($this->sock, $msg);
473 | $hdr = $this->read_fixed_header($this->sock);
474 | if (!$hdr) {
475 | if ($this->debug) $this->t("SAMConnection_MQTT.Subscribe() subscribe failed, no response from broker!");
476 | $this->errNo = 301;
477 | $this->error = 'Subscribe request failed, no response from broker!';
478 | $rc = false;
479 | } else {
480 | if ($hdr['mtype'] == $this->operations['MQTT_SUBACK']) {
481 | $len = $this->read_remaining_length($this->sock);
482 | if ($len > 0) {
483 | $response = fread($this->sock, $len);
484 | /* Return the subscription id with the topic appended to it so we can unsubscribe easily... */
485 | $rc = $this->sub_id.SAM_MQTT_SUB_SEPARATOR.$t;
486 | }
487 | if ($len < 3) {
488 | if ($this->debug) $this->t("SAMConnection_MQTT.Subscribe() subscribe failed, incorrect length response ($len) received!");
489 | $this->errNo = 301;
490 | $this->error = 'Subscribe request failed, incorrect length response ($len) received!';
491 | $rc = false;
492 | }
493 | } else {
494 | if ($this->debug) t('SAMConnection_MQTT.Subscribe() subscribe failed response mtype = '.$mtype);
495 | $rc = false;
496 | }
497 | }
498 |
499 | if ($this->debug) $this->x("SAMConnection_MQTT.Subscribe() rc=$rc");
500 | return $rc;
501 | }
502 |
503 | /* ---------------------------------
504 | Unsubscribe
505 | --------------------------------- */
506 | function Unsubscribe($sub_id) {
507 | if ($this->debug) e("SAMConnection_MQTT.Unsubscribe($sub_id)");
508 |
509 | /* Detach the topic from the rear of the subscription id... */
510 | $x = strpos($sub_id, SAM_MQTT_SUB_SEPARATOR);
511 | if (!$x) {
512 | $this->errNo = 279;
513 | $this->error = 'Specified subscription id ('.$sub_id.') is not valid!';
514 | return false;
515 | }
516 |
517 | $topic = substr($sub_id, $x + strlen(SAM_MQTT_SUB_SEPARATOR));
518 | $si = substr($sub_id, 0, $x);
519 |
520 |
521 | /* Are we already connected? */
522 | if (!$this->connected) {
523 | if ($this->debug) t('SAMConnection_MQTT.Unsubscribe() Not connected.');
524 | /* No, so open up the connection... */
525 | $this->sub_id = $si;
526 | $rc = $this->do_connect_now();
527 | } else {
528 | /* We are already connected. Are we using the right subscriber id? */
529 | if ($this->sub_id != $si) {
530 | if ($this->debug) t('SAMConnection_MQTT.Unsubscribe() Connected with wrong sub_id.');
531 | /* No, We better reconnect then... */
532 | $this->disconnect();
533 | $this->sub_id = $si;
534 | $rc = $this->do_connect_now();
535 | } else {
536 | if ($this->debug) t('SAMConnection_MQTT.Unsubscribe() Connected OK.');
537 | $rc = true;
538 | }
539 | }
540 |
541 | /* variable header: message id (16 bits) */
542 | $x = rand(1, 16000);
543 | $variable = pack('n', $x);
544 |
545 | /* payload: client ID */
546 | $payload = $this->utf($topic);
547 |
548 | /* add in the remaining length field and fix it together */
549 | $msg = $this->fixed_header("MQTT_UNSUBSCRIBE", 0, 1) . $this->remaining_length(strlen($variable)+strlen($payload)) . $variable . $payload;
550 |
551 | fwrite($this->sock, $msg);
552 | $hdr = $this->read_fixed_header($this->sock);
553 | if (!$hdr) {
554 | if ($this->debug) $this->t("SAMConnection_MQTT.Unsubscribe() unsubscribe failed, no response from broker!");
555 | $this->errNo = 302;
556 | $this->error = 'Unsubscribe request failed, no response from broker!';
557 | $rc = false;
558 | } else {
559 | if ($hdr['mtype'] == $this->operations['MQTT_UNSUBACK']) {
560 | $len = $this->read_remaining_length($this->sock);
561 | if ($len > 0) {
562 | $response = fread($this->sock, $len);
563 | $rc = $this->sub_id;
564 | }
565 | if ($len != 2) {
566 | if ($this->debug) $this->t("SAMConnection_MQTT.Unsubscribe() unsubscribe failed, incorrect length response ($len) received!");
567 | $this->errNo = 301;
568 | $this->error = "Unsubscribe request failed, incorrect length response ($len) received!";
569 | $rc = false;
570 | }
571 | } else {
572 | if ($this->debug) t('SAMConnection_MQTT.Unsubscribe() unsubscribe failed response mtype = '.$hdr['mtype']);
573 | $rc = false;
574 | }
575 | }
576 |
577 | if ($this->debug) $this->x("SAMConnection_MQTT.Unsubscribe() rc=$rc");
578 | return $rc;
579 | }
580 |
581 |
582 |
583 | function remaining_length($l) {
584 | /* return the remaining length field bytes for an integer input parameter */
585 | if ($this->debug) $this->t("SAMConnection_MQTT.remaining_length() l=$l");
586 |
587 | $rlf = '';
588 | do {
589 | $digit = $l % 128;
590 | $l = ($l - $digit)/128;
591 | if ($this->debug) $this->t("SAMConnection_MQTT.remaining_length() digit=$digit l=$l");
592 |
593 | # if there are more digits to encode, set the top bit of this digit
594 | if ( $l > 0 ) {
595 | $digit += 128;
596 | }
597 | $digit = pack('C', $digit);
598 |
599 | $rlf .= $digit;
600 | if ($this->debug) $this->t("SAMConnection_MQTT.remaining_length() rlf=$rlf");
601 | } while ($l > 0);
602 |
603 | return $rlf;
604 | }
605 |
606 | function utf($s) {
607 | /* return the UTF-8 encoded version of the parameter */
608 | $l = strlen($s);
609 | $b1 = pack('C', $l/256);
610 | $b2 = pack('C', $l%256);
611 | $rc = $b1.$b2.$s;
612 | return $rc;
613 | }
614 |
615 | function fixed_header($operation, $dup=0, $qos=0, $retain=0) {
616 | /* fixed header: msg type (4) dup (1) qos (2) retain (1) */
617 | return pack('C', ($this->operations[$operation] * 16) + ($dup * 4) + ($qos * 2) + $retain);
618 | }
619 |
620 | function checkHost($hostname, $port) {
621 | if ($this->debug) e("SAMConnection_MQTT.checkHost($hostname)");
622 | $rc = false;
623 |
624 | $fp = fsockopen($hostname, $port);
625 | if (!$fp) {
626 | $rc = false;
627 | } else {
628 | $this->sock = $fp;
629 | $rc = true;
630 | }
631 | if ($this->debug) $this->x("SAMConnection_MQTT.checkHost(rc=$rc)");
632 | return $rc;
633 | }
634 |
635 | function do_connect_now() {
636 | $rc = true;
637 |
638 | /* Do we have a client/subscriber id yet? */
639 | if ($this->sub_id == '') {
640 | /* No, so create a unique one... */
641 | $this->sub_id = uniqid('', true);
642 | if ($this->debug) $this->t("SAMConnection_MQTT.do_connect_now() sub_id=$this->sub_id");
643 | } else {
644 | if ($this->debug) $this->t("SAMConnection_MQTT.do_connect_now() using existing sub_id=$this->sub_id");
645 | }
646 |
647 | if ($this->cleanstart) {
648 | $x = "\x03";
649 | } else {
650 | $x = "\x00";
651 | }
652 | $variable = $this->utf('MQIsdp')."\x03$x\x00\x00";
653 |
654 | /* payload is subscriber id */
655 | $payload = $this->utf($this->sub_id);
656 |
657 | /* add in the remaining length field and fix it together */
658 | $msg = $this->fixed_header("MQTT_CONNECT") . $this->remaining_length(strlen($variable)+strlen($payload)) . $variable . $payload;
659 |
660 | $errNo = 0;
661 | $errstr = '';
662 |
663 | if (!$this->virtualConnected) {
664 | $fp = fsockopen($this->host, $this->port, $errNo, $errstr);
665 | if (!$fp) {
666 | if ($this->debug) $this->t("SAMConnection_MQTT.do_connect_now() fsockopen failed! ($errNo) $errstr");
667 | $this->errNo = 208;
668 | $this->error = 'Unable to open socket to broker!';
669 | $this->sock = NULL;
670 | return false;
671 | } else {
672 | $this->virtualConnected = true;
673 | $this->sock = $fp;
674 | }
675 | }
676 |
677 | stream_set_timeout($this->sock, 10);
678 | fwrite($this->sock, $msg);
679 |
680 | $hdr = $this->read_fixed_header($this->sock);
681 | if ($hdr) {
682 | if ($hdr['mtype'] == $this->operations['MQTT_CONNACK']) {
683 | $len = $this->read_remaining_length($this->sock);
684 | if ($len < 2) {
685 | if ($this->debug) $this->t("SAMConnection_MQTT.do_connect_now() connect failed, incorrect length response ($len) received!");
686 | $this->errNo = 218;
687 | $this->error = 'Unable to open connection to broker!';
688 | $rc = false;
689 | } else {
690 | $response = fread($this->sock, $len);
691 | $fields = unpack('Ccomp/Cretcode', $response);
692 | if ($fields['retcode'] == 0) {
693 | $rc = $this->sock;
694 | $this->connected = true;
695 | $rc = true;
696 | if ($this->debug) t('SAMConnection_MQTT.do_connect_now() connected OK');
697 | } else {
698 | if ($this->debug) t('SAMConnection_MQTT.do_connect_now() connect failed retcode = '.$fields['retcode']);
699 | $rc = false;
700 | if ($fields['retcode'] == 2) {
701 | $this->sub_id = '';
702 | $this->errNo = 279;
703 | $this->error = 'Invalid subscription id!';
704 | }
705 | }
706 | }
707 | } else {
708 | if ($this->debug) t('SAMConnection_MQTT.do_connect_now() connect failed response mtype = '.$mtype);
709 | $rc = false;
710 | }
711 | }
712 |
713 | if (!$rc) {
714 | fclose($this->sock);
715 | $this->sock = NULL;
716 | $this->virtualConnected = false;
717 | }
718 |
719 | return $rc;
720 | }
721 |
722 | function read_fixed_header($conn) {
723 | $rc = false;
724 | $response = fread($conn, 1);
725 | if (strlen($response) > 0) {
726 | $fields = unpack('Cbyte1', $response);
727 | $x = $fields['byte1'];
728 | $ret = $x % 2;
729 | $x -= $ret;
730 | $qos = ($x % 8) / 2;
731 | $x -= ($qos * 2);
732 | $dup = ($x % 16) / 8;
733 | $x -= ($dup * 8);
734 | $mtype = $x / 16;
735 | if ($this->debug) $this->t("SAMConnection_MQTT.read_fixed_header() mtype=$mtype, dup=$dup, qos=$qos, retain=$ret");
736 | $rc = array('mtype' => $mtype, 'dup' => $dup, 'qos' => $qos, 'retain' => $ret);
737 | }
738 | return $rc;
739 | }
740 |
741 | function read_remaining_length($conn) {
742 | $rc = 0;
743 | $m = 1;
744 | while (!feof($conn)) {
745 | $byte = fgetc($conn);
746 | $fields = unpack('Ca', $byte);
747 | $x = $fields['a'];
748 | if ($this->debug) t('SAMConnection_MQTT.read_remaining_length() byte ('.strlen($byte).') = '.$x);
749 | if ($x < 128) {
750 | $rc += $x * $m;
751 | break;
752 | } else {
753 | $rc += (($x - 128) * $m);
754 | }
755 | $m *= 128;
756 | }
757 | if ($this->debug) t('SAMConnection_MQTT.read_remaining_length() remaining length = '.$rc);
758 | return $rc;
759 | }
760 |
761 | function read_topic($conn) {
762 | if ($this->debug) $this->e('SAMConnection_MQTT.read_topic()');
763 | $rc = false;
764 | while (!feof($conn)) {
765 | $tlen = fread($conn, 2);
766 | $fields = unpack('na', $tlen);
767 | if ($this->debug) t('SAMConnection_MQTT.read_topic() topic length='.$fields['a']);
768 | $rc = fread($conn, $fields['a']);
769 | break;
770 | }
771 | if ($this->debug) $this->x("SAMConnection_MQTT.read_topic(rc=$rc)");
772 | return $rc;
773 | }
774 |
775 | }
--------------------------------------------------------------------------------
/tests/16x16_loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AIRootUser/laravel-mqtt-publish/05597071d0c64cc7fc8f25f0b6b704bd17b37866/tests/16x16_loading.gif
--------------------------------------------------------------------------------
/tests/README:
--------------------------------------------------------------------------------
1 | Everything here is licenced under Apache 2.0
2 | http://www.apache.org/licenses/LICENSE-2.0
--------------------------------------------------------------------------------
/tests/index.php:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
216 | Tokudu Android Push Demo
217 | |
218 |
221 |
222 | Server status:
223 |
224 |
226 | |
229 | | 258 | 257 |