1
|
|
|
<?php |
|
|
|
|
2
|
|
|
declare(strict_types = 1); |
3
|
|
|
namespace ZendFirebase; |
4
|
|
|
|
5
|
|
|
use Interfaces\FirebaseInterface; |
6
|
|
|
use GuzzleHttp\Client; |
7
|
|
|
use ZendFirebase\Stream\StreamClient; |
8
|
|
|
use Monolog\Logger; |
9
|
|
|
use Monolog\Handler\StreamHandler; |
10
|
|
|
use Monolog\Handler\FirePHPHandler; |
11
|
|
|
use Monolog\Formatter\LineFormatter; |
12
|
|
|
require 'Interfaces/FirebaseInterface.php'; |
13
|
|
|
require 'Stream/StreamClient.php'; |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* PHP7 FIREBASE LIBRARY (http://samuelventimiglia.it/) |
17
|
|
|
* |
18
|
|
|
* |
19
|
|
|
* @link https://github.com/Samuel18/zend_Firebase |
20
|
|
|
* @copyright Copyright (c) 2016-now Ventimiglia Samuel - Biasin Davide |
21
|
|
|
* @license BSD 3-Clause License |
22
|
|
|
* |
23
|
|
|
*/ |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* This class do rest operations to firebase server |
27
|
|
|
* |
28
|
|
|
* @author ghostbyte |
29
|
|
|
* @package ZendFirebase |
30
|
|
|
*/ |
31
|
|
|
class Firebase extends FirebaseResponce implements FirebaseInterface |
32
|
|
|
{ |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* Default Timeout |
36
|
|
|
* |
37
|
|
|
* @var integer $timeout |
38
|
|
|
*/ |
39
|
|
|
private $timeout = 30; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* Format of datetime of logs |
43
|
|
|
* |
44
|
|
|
* @var string $dateFormatLog |
45
|
|
|
*/ |
46
|
|
|
private $dateFormatLog = "Y n j, g:i a"; |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* DateTime of log filename |
50
|
|
|
* |
51
|
|
|
* @var string $dateFormatLogFilename |
52
|
|
|
*/ |
53
|
|
|
private static $dateFormatLogFilename; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* Authentication object |
57
|
|
|
* |
58
|
|
|
* @var $auth |
59
|
|
|
*/ |
60
|
|
|
private $auth; |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Create new Client |
64
|
|
|
* |
65
|
|
|
* @var $client |
66
|
|
|
*/ |
67
|
|
|
private $client; |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* Responce from firebase |
71
|
|
|
* |
72
|
|
|
* @var mixed $response |
73
|
|
|
*/ |
74
|
|
|
private $response; |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* Last Auto-Increment saved from post operation |
78
|
|
|
* |
79
|
|
|
* @var $lastIdStored |
80
|
|
|
*/ |
81
|
|
|
protected $lastIdStored = ''; |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Create new Firebase client object |
85
|
|
|
* Remember to install PHP CURL extention |
86
|
|
|
* |
87
|
|
|
* @param Config\FirebaseAuth $auth |
88
|
|
|
*/ |
89
|
|
|
public function __construct(\ZendFirebase\Config\FirebaseAuth $auth) |
90
|
|
|
{ |
91
|
|
|
$this->checkDipendenties($auth); |
92
|
|
|
|
93
|
|
|
// store object into variable |
94
|
|
|
$this->auth = $auth; |
95
|
|
|
|
96
|
|
|
$this->gulleClientInit(); |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* Create new guzzle client |
101
|
|
|
*/ |
102
|
|
|
private function gulleClientInit() |
103
|
|
|
{ |
104
|
|
|
|
105
|
|
|
/* create new client */ |
106
|
|
|
$this->client = new Client([ |
107
|
|
|
'base_uri' => $this->auth->getBaseURI(), |
108
|
|
|
'timeout' => $this->getTimeout(), |
109
|
|
|
'headers' => $this->getRequestHeaders() |
110
|
|
|
]); |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
/** |
114
|
|
|
* Controll of all dipendenties |
115
|
|
|
* |
116
|
|
|
* @param \ZendFirebase\Config\FirebaseAuth $auth |
117
|
|
|
*/ |
118
|
|
|
private function checkDipendenties($auth) |
119
|
|
|
{ |
120
|
|
|
$authMessage = 'Forget credential or is not an object.'; |
121
|
|
|
$curlMessage = 'Extension CURL is not loaded or not installed.'; |
122
|
|
|
|
123
|
|
|
// check if auth is null |
124
|
|
|
if (! is_object($auth) || null == $auth) { |
125
|
|
|
trigger_error($authMessage, E_USER_ERROR); |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
// check if extension is installed |
129
|
|
|
if (! extension_loaded('curl')) { |
130
|
|
|
trigger_error($curlMessage, E_USER_ERROR); |
131
|
|
|
} |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* Return Integer of Timeout |
136
|
|
|
* default 30 setted 10 |
137
|
|
|
* |
138
|
|
|
* @return integer $timeout |
139
|
|
|
*/ |
140
|
|
|
public function getTimeout(): int |
141
|
|
|
{ |
142
|
|
|
return $this->timeout; |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
/** |
146
|
|
|
* Default timeout is 10 seconds |
147
|
|
|
* is is not set switch to 30 |
148
|
|
|
* |
149
|
|
|
* @param integer $timeout |
150
|
|
|
*/ |
151
|
|
|
public function setTimeout($timeout) |
152
|
|
|
{ |
153
|
|
|
$this->timeout = $timeout; |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
/** |
157
|
|
|
* |
158
|
|
|
* @return the unknown_type |
159
|
|
|
*/ |
160
|
|
|
public function getLastIdStored() |
161
|
|
|
{ |
162
|
|
|
return $this->lastIdStored; |
163
|
|
|
} |
164
|
|
|
|
165
|
|
|
/** |
166
|
|
|
* |
167
|
|
|
* @param unknown_type $lastIdStored |
168
|
|
|
*/ |
169
|
|
|
public function setLastIdStored($lastIdStored) |
170
|
|
|
{ |
171
|
|
|
$this->lastIdStored = $lastIdStored; |
|
|
|
|
172
|
|
|
return $this; |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
/** |
176
|
|
|
* Method for get array headers for Guzzle client |
177
|
|
|
* |
178
|
|
|
* @throws \Exception |
179
|
|
|
* @return array |
180
|
|
|
*/ |
181
|
|
|
private function getRequestHeaders(): array |
182
|
|
|
{ |
183
|
|
|
$headers = []; |
184
|
|
|
$headers['stream'] = true; |
185
|
|
|
$headers['Accept'] = 'application/json'; |
186
|
|
|
$headers['Content-Type'] = 'application/json'; |
187
|
|
|
|
188
|
|
|
// check if header is an array |
189
|
|
|
if (! is_array($headers)) { |
190
|
|
|
$str = "The guzzle client headers must be an array."; |
191
|
|
|
throw new \Exception($str); |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
return $headers; |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
/** |
198
|
|
|
* Returns with the normalized JSON absolute path |
199
|
|
|
* |
200
|
|
|
* @param string $path |
201
|
|
|
* @param array $options |
202
|
|
|
* @return string $path |
203
|
|
|
*/ |
204
|
|
|
private function getJsonPath($path, $options = []): string |
205
|
|
|
{ |
206
|
|
|
/* autentication token */ |
207
|
|
|
$options['auth'] = $this->auth->getServertoken(); |
208
|
|
|
/* returns the data in a human-readable format */ |
209
|
|
|
$options['print'] = 'pretty'; |
210
|
|
|
|
211
|
|
|
foreach ($options as $opt => $optVal) { |
212
|
|
|
|
213
|
|
|
if ($opt == 'orderBy') { |
214
|
|
|
|
215
|
|
|
$options['orderBy']= '"' . $optVal . '"'; |
216
|
|
|
|
217
|
|
|
} |
218
|
|
|
} |
219
|
|
|
|
220
|
|
|
$path = ltrim($path, '/'); |
221
|
|
|
|
222
|
|
|
return $path . '.json?' . http_build_query($options); |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
/** |
226
|
|
|
* DELETE - Removing Data FROM FIREBASE |
227
|
|
|
* |
228
|
|
|
* @param string $path |
229
|
|
|
* @param array $options |
230
|
|
|
* |
231
|
|
|
* {@inheritdoc} |
232
|
|
|
* |
233
|
|
|
* @see \Interfaces\FirebaseInterface::delete() |
234
|
|
|
*/ |
235
|
|
|
public function delete($path, $options = []) |
236
|
|
|
{ |
237
|
|
|
$this->writeRequest('delete', $this->getJsonPath($path, $options), ''); |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
/** |
241
|
|
|
* GET - Reading Data FROM FIREBASE |
242
|
|
|
* |
243
|
|
|
* @param string $path |
244
|
|
|
* @param array $options |
245
|
|
|
* |
246
|
|
|
* {@inheritdoc} |
247
|
|
|
* |
248
|
|
|
* @see \Interfaces\FirebaseInterface::get() |
249
|
|
|
*/ |
250
|
|
|
public function get($path, $options = []) |
251
|
|
|
{ |
252
|
|
|
$this->writeRequest('get', $this->getJsonPath($path, $options), ''); |
253
|
|
|
} |
254
|
|
|
|
255
|
|
|
/** |
256
|
|
|
* PATCH - Updating Data TO FIREBASE |
257
|
|
|
* |
258
|
|
|
* @param string $path |
259
|
|
|
* @param array $data |
260
|
|
|
* @param array $options |
261
|
|
|
* |
262
|
|
|
* {@inheritdoc} |
263
|
|
|
* |
264
|
|
|
* @see \Interfaces\FirebaseInterface::patch() |
265
|
|
|
*/ |
266
|
|
|
public function patch($path, array $data, $options = []) |
267
|
|
|
{ |
268
|
|
|
$this->writeRequest('patch', $this->getJsonPath($path, $options), $data); |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
/** |
272
|
|
|
* POST - Pushing Data TO FIREBASE |
273
|
|
|
* |
274
|
|
|
* @param string $path |
275
|
|
|
* @param array $data |
276
|
|
|
* @param array $options |
277
|
|
|
* |
278
|
|
|
* {@inheritdoc} |
279
|
|
|
* |
280
|
|
|
* @see \Interfaces\FirebaseInterface::post() |
281
|
|
|
*/ |
282
|
|
|
public function post($path, array $data, $options = []) |
283
|
|
|
{ |
284
|
|
|
$this->writeRequest('post', $this->getJsonPath($path, $options), $data); |
285
|
|
|
} |
286
|
|
|
|
287
|
|
|
/** |
288
|
|
|
* PUT - Writing Data TO FIREBASE |
289
|
|
|
* |
290
|
|
|
* @param string $path |
291
|
|
|
* @param array $data |
292
|
|
|
* @param array $options |
293
|
|
|
* |
294
|
|
|
* {@inheritdoc} |
295
|
|
|
* |
296
|
|
|
* @see \Interfaces\FirebaseInterface::put() |
297
|
|
|
*/ |
298
|
|
|
public function put($path, array $data, $options = []) |
299
|
|
|
{ |
300
|
|
|
$this->writeRequest('put', $this->getJsonPath($path, $options), $data); |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
/** |
304
|
|
|
* Method to send request |
305
|
|
|
* |
306
|
|
|
* @param string $op |
307
|
|
|
* @param string $path |
308
|
|
|
* @param mixed $data |
309
|
|
|
*/ |
310
|
|
|
private function writeRequest($op, $path, $data) |
311
|
|
|
{ |
312
|
|
|
$operation = \strtolower($op); |
313
|
|
|
|
314
|
|
|
switch ($operation) { |
315
|
|
|
case 'get': |
316
|
|
|
$response = $this->client->{$operation}($path); |
317
|
|
|
$this->response = $response->getBody()->getContents(); |
318
|
|
|
|
319
|
|
|
$this->setDataFromOperation('get', $response->getStatusCode()); |
320
|
|
|
break; |
321
|
|
|
case 'delete': |
322
|
|
|
$response = $this->client->{$operation}($path); |
323
|
|
|
$this->response = $response->getReasonPhrase(); // OK |
324
|
|
|
$this->setDataFromOperation('get', $response->getStatusCode()); |
325
|
|
|
break; |
326
|
|
|
case 'post': |
327
|
|
|
$this->response = $this->client->{$operation}($path, [ |
328
|
|
|
'body' => \json_encode($data) |
329
|
|
|
]); |
330
|
|
|
|
331
|
|
|
// save auto-increment id created from Firebase after post operation |
332
|
|
|
$this->setLastIdStored(json_decode($this->response->getBody()->getContents(),true)['name']); |
333
|
|
|
|
334
|
|
|
$this->setDataFromOperation($op, $this->response->getStatusCode()); |
335
|
|
|
break; |
336
|
|
|
|
337
|
|
|
default: |
338
|
|
|
$this->response = $this->client->{$operation}($path, [ |
339
|
|
|
'body' => \json_encode($data) |
340
|
|
|
]); |
341
|
|
|
|
342
|
|
|
$this->setDataFromOperation($op, $this->response->getStatusCode()); |
343
|
|
|
break; |
344
|
|
|
} |
345
|
|
|
} |
346
|
|
|
|
347
|
|
|
/** |
348
|
|
|
* This function set variables after operation |
349
|
|
|
* |
350
|
|
|
* @param string $operation |
351
|
|
|
* @param mixed $status |
352
|
|
|
*/ |
353
|
|
|
private function setDataFromOperation($operation, $status) |
354
|
|
|
{ |
355
|
|
|
$oP = \strtoupper($operation); |
356
|
|
|
|
357
|
|
|
$this->status = $status; // 200 |
358
|
|
|
$this->operation = $oP; |
359
|
|
|
} |
360
|
|
|
|
361
|
|
|
/** |
362
|
|
|
* Start stream with server and write log in choised folder |
363
|
|
|
* |
364
|
|
|
* @param string $path |
365
|
|
|
* @param string $folderToStoreLog |
366
|
|
|
* @param integer $requestDelay |
367
|
|
|
* @example $requestDelay = 3000 -> 3 seconds between get request |
368
|
|
|
*/ |
369
|
|
|
public function startStream($path, $folderToStoreLog, $requestDelay = 5000) |
370
|
|
|
{ |
371
|
|
|
$url = $this->auth->getBaseURI() . $this->getJsonPath($path); |
372
|
|
|
|
373
|
|
|
$client = new StreamClient($url, $requestDelay); |
374
|
|
|
|
375
|
|
|
// returns generator |
376
|
|
|
$events = $client->getEvents(); |
377
|
|
|
|
378
|
|
|
// call method for create instance of logger |
379
|
|
|
$logger = $this->createLogger($this->formatFolderName($folderToStoreLog)); |
380
|
|
|
|
381
|
|
|
// blocks until new event arrive |
382
|
|
|
foreach ($events as $event) { |
383
|
|
|
// decode json data arrived to php array |
384
|
|
|
$eventData = \json_decode($event->getData(), true); |
385
|
|
|
|
386
|
|
|
$this->printEventData($eventData, $event); |
387
|
|
|
|
388
|
|
|
$this->writeEventLogs($logger, $eventData, $event, $path); |
389
|
|
|
} |
390
|
|
|
} |
391
|
|
|
|
392
|
|
|
/** |
393
|
|
|
* Print on output datas |
394
|
|
|
* |
395
|
|
|
* @param mixed $eventData |
396
|
|
|
* @param mixed $event |
397
|
|
|
*/ |
398
|
|
|
private function printEventData($eventData, $event) |
399
|
|
|
{ |
400
|
|
|
// pass event to callback function |
401
|
|
|
print_r($eventData); |
402
|
|
|
print_r("EVENT TYPE: " . $event->getEventType() . PHP_EOL . PHP_EOL); |
403
|
|
|
} |
404
|
|
|
|
405
|
|
|
/** |
406
|
|
|
* Write log of current event |
407
|
|
|
* |
408
|
|
|
* @param Logger $logger |
409
|
|
|
* @param array $eventData |
410
|
|
|
* @param mixed $event |
411
|
|
|
* @param string $path |
412
|
|
|
*/ |
413
|
|
|
private function writeEventLogs($logger, $eventData, $event, $path) |
414
|
|
|
{ |
415
|
|
|
if (! empty($eventData) || null != $eventData) { |
416
|
|
|
$logger->addDebug("path: {$path}", [ |
417
|
|
|
'DATA' => $eventData, |
418
|
|
|
'EVENT TYPE' => $event->getEventType() |
419
|
|
|
]); |
420
|
|
|
} else { |
421
|
|
|
$logger->addDebug("path: {$path}", [ |
422
|
|
|
'EVENT TYPE' => $event->getEventType() |
423
|
|
|
]); |
424
|
|
|
} |
425
|
|
|
} |
426
|
|
|
|
427
|
|
|
/** |
428
|
|
|
* Format folder name |
429
|
|
|
* |
430
|
|
|
* @param string $folderToStoreLog |
431
|
|
|
* @return string $folderName |
432
|
|
|
*/ |
433
|
|
|
private function formatFolderName($folderToStoreLog): string |
434
|
|
|
{ |
435
|
|
|
/* search / in string */ |
436
|
|
|
$folderName = substr(strrchr(trim($folderToStoreLog), "/"), 1); |
437
|
|
|
/* if not exsits add on path+/ */ |
438
|
|
|
$folderName = empty($folderName) ? $folderToStoreLog . '/' : $folderToStoreLog; |
439
|
|
|
|
440
|
|
|
return $folderName; |
441
|
|
|
} |
442
|
|
|
|
443
|
|
|
/** |
444
|
|
|
* |
445
|
|
|
* Create logger instance for save stream log |
446
|
|
|
* |
447
|
|
|
* @param string $folderToStoreLog |
448
|
|
|
* @return Logger $logger |
449
|
|
|
*/ |
450
|
|
|
private function createLogger($folderToStoreLog) |
451
|
|
|
{ |
452
|
|
|
// the default output format is "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n" |
453
|
|
|
$output = "%datetime% > %level_name% > %message% %context% %extra%\n"; |
454
|
|
|
// finally, create a formatter |
455
|
|
|
$formatter = new LineFormatter($output, $this->dateFormatLog); |
456
|
|
|
self::$dateFormatLogFilename = date("Y-m-d_H:i:s"); |
457
|
|
|
// Create the logger |
458
|
|
|
$logger = new Logger('stream_logger'); |
459
|
|
|
|
460
|
|
|
// Now add some handlers |
461
|
|
|
$stream = new StreamHandler(trim($folderToStoreLog) . self::$dateFormatLogFilename . ".log", Logger::DEBUG); |
462
|
|
|
|
463
|
|
|
$stream->setFormatter($formatter); |
464
|
|
|
$logger->pushHandler($stream); |
465
|
|
|
$logger->pushHandler(new FirePHPHandler()); |
466
|
|
|
|
467
|
|
|
// You can now use your logger |
468
|
|
|
$logger->addInfo('Stream logger is ready...'); |
469
|
|
|
return $logger; |
470
|
|
|
} |
471
|
|
|
|
472
|
|
|
/** |
473
|
|
|
* This method return the responce from firebase |
474
|
|
|
* |
475
|
|
|
* @example set and validate data passed |
476
|
|
|
*/ |
477
|
|
|
public function makeResponce() |
478
|
|
|
{ |
479
|
|
|
$jsonData = []; |
480
|
|
|
if ($this->operation === 'GET') { |
481
|
|
|
|
482
|
|
|
$jsonData = json_decode($this->response, true); |
483
|
|
|
if (empty($jsonData)){ |
484
|
|
|
$jsonData[] = '204 No Content'; |
485
|
|
|
}else { |
486
|
|
|
$jsonData = json_decode($this->response, true); |
487
|
|
|
} |
488
|
|
|
|
489
|
|
|
} else { |
490
|
|
|
$jsonData[] = 'Success'; |
491
|
|
|
} |
492
|
|
|
|
493
|
|
|
/* Set data after operations */ |
494
|
|
|
$this->setOperation($this->operation); |
495
|
|
|
$this->setStatus($this->status); |
496
|
|
|
|
497
|
|
|
$this->setFirebaseData($jsonData); |
498
|
|
|
$this->validateResponce(); |
499
|
|
|
} |
500
|
|
|
|
501
|
|
|
/** |
502
|
|
|
* Remove object from memory |
503
|
|
|
*/ |
504
|
|
|
public function __destruct() |
505
|
|
|
{} |
506
|
|
|
|
507
|
|
|
} |
508
|
|
|
|
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.