Completed
Pull Request — develop (#288)
by Armando
03:32
created

Request::initialize()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2.0185

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 9
rs 9.6666
ccs 5
cts 6
cp 0.8333
cc 2
eloc 6
nc 2
nop 1
crap 2.0185
1
<?php
2
/**
3
 * This file is part of the TelegramBot package.
4
 *
5
 * (c) Avtandil Kikabidze aka LONGMAN <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Longman\TelegramBot;
12
13
use GuzzleHttp\Client;
14
use GuzzleHttp\Exception\RequestException;
15
use Longman\TelegramBot\Entities\File;
16
use Longman\TelegramBot\Entities\ServerResponse;
17
use Longman\TelegramBot\Exception\TelegramException;
18
19
class Request
20
{
21
    /**
22
     * Telegram object
23
     *
24
     * @var \Longman\TelegramBot\Telegram
25
     */
26
    private static $telegram;
27
28
    /**
29
     * URI of the Telegram API
30
     *
31
     * @var string
32
     */
33
    private static $api_base_uri = 'https://api.telegram.org';
34
35
    /**
36
     * Guzzle Client object
37
     *
38
     * @var \GuzzleHttp\Client
39
     */
40
    private static $client;
41
42
    /**
43
     * Input value of the request
44
     *
45
     * @var string
46
     */
47
    private static $input;
48
49
    /**
50
     * Available actions to send
51
     *
52
     * @var array
53
     */
54
    private static $actions = [
55
        'getUpdates',
56
        'setWebhook',
57
        'getMe',
58
        'sendMessage',
59
        'forwardMessage',
60
        'sendPhoto',
61
        'sendAudio',
62
        'sendDocument',
63
        'sendSticker',
64
        'sendVideo',
65
        'sendVoice',
66
        'sendLocation',
67
        'sendVenue',
68
        'sendContact',
69
        'sendChatAction',
70
        'getUserProfilePhotos',
71
        'getFile',
72
        'kickChatMember',
73
        'leaveChat',
74
        'unbanChatMember',
75
        'getChat',
76
        'getChatAdministrators',
77
        'getChatMember',
78
        'getChatMembersCount',
79
        'answerCallbackQuery',
80
        'answerInlineQuery',
81
        'editMessageText',
82
        'editMessageCaption',
83
        'editMessageReplyMarkup',
84
    ];
85
86
    /**
87
     * Initialize
88
     *
89
     * @param \Longman\TelegramBot\Telegram $telegram
90
     *
91
     * @throws \Longman\TelegramBot\Exception\TelegramException
92
     */
93 39
    public static function initialize(Telegram $telegram)
94
    {
95 39
        if (is_object($telegram)) {
96 39
            self::$telegram = $telegram;
97 39
            self::$client   = new Client(['base_uri' => self::$api_base_uri]);
98
        } else {
99
            throw new TelegramException('Telegram pointer is empty!');
100
        }
101 39
    }
102
103
    /**
104
     * Set input from custom input or stdin and return it
105
     *
106
     * @return string
107
     * @throws \Longman\TelegramBot\Exception\TelegramException
108
     */
109
    public static function getInput()
110
    {
111
        // First check if a custom input has been set, else get the PHP input.
112
        if (!($input = self::$telegram->getCustomInput())) {
113
            $input = file_get_contents('php://input');
114
        }
115
116
        // Make sure we have a string to work with.
117
        if (is_string($input)) {
118
            self::$input = $input;
119
        } else {
120
            throw new TelegramException('Input must be a string!');
121
        }
122
123
        TelegramLog::update(self::$input);
124
125
        return self::$input;
126
    }
127
128
    /**
129
     * Generate general fake server response
130
     *
131
     * @param array $data Data to add to fake response
132
     *
133
     * @return array Fake response data
134
     */
135 6
    public static function generateGeneralFakeServerResponse(array $data = [])
136
    {
137
        //PARAM BINDED IN PHPUNIT TEST FOR TestServerResponse.php
138
        //Maybe this is not the best possible implementation
139
140
        //No value set in $data ie testing setWebhook
141
        //Provided $data['chat_id'] ie testing sendMessage
142
143 6
        $fake_response = ['ok' => true]; // :)
144
145 6
        if ($data === []) {
146 1
            $fake_response['result'] = true;
147
        }
148
149
        //some data to let iniatilize the class method SendMessage
150 6
        if (isset($data['chat_id'])) {
151 6
            $data['message_id'] = '1234';
152 6
            $data['date']       = '1441378360';
153 6
            $data['from']       = [
154
                'id'         => 123456789,
155
                'first_name' => 'botname',
156
                'username'   => 'namebot',
157
            ];
158 6
            $data['chat']       = ['id' => $data['chat_id']];
159
160 6
            $fake_response['result'] = $data;
161
        }
162
163 6
        return $fake_response;
164
    }
165
166
    /**
167
     * Properly set up the request params
168
     *
169
     * If any item of the array is a resource, reformat it to a multipart request.
170
     * Else, just return the passed data as form params.
171
     *
172
     * @param array $data
173
     *
174
     * @return array
175
     */
176
    private static function setUpRequestParams(array $data)
177
    {
178
        $has_resource = false;
179
        $multipart    = [];
180
181
        //Reformat data array in multipart way if it contains a resource
182
        foreach ($data as $key => $item) {
183
            $has_resource |= is_resource($item);
184
            $multipart[] = ['name' => $key, 'contents' => $item];
185
        }
186
        if ($has_resource) {
187
            return ['multipart' => $multipart];
188
        }
189
190
        return ['form_params' => $data];
191
    }
192
193
    /**
194
     * Execute HTTP Request
195
     *
196
     * @param string $action Action to execute
197
     * @param array  $data   Data to attach to the execution
198
     *
199
     * @return mixed Result of the HTTP Request
200
     * @throws \Longman\TelegramBot\Exception\TelegramException
201
     */
202
    public static function execute($action, array $data = [])
203
    {
204
        //Fix so that the keyboard markup is a string, not an object
205
        if (isset($data['reply_markup'])) {
206
            $data['reply_markup'] = (string)$data['reply_markup'];
207
        }
208
209
        $request_params = self::setUpRequestParams($data);
210
211
        $debug_handle            = TelegramLog::getDebugLogTempStream();
212
        $request_params['debug'] = $debug_handle;
213
214
        try {
215
            $response = self::$client->post(
216
                '/bot' . self::$telegram->getApiKey() . '/' . $action,
217
                $request_params
218
            );
219
            $result   = (string)$response->getBody();
220
221
            //Logging getUpdates Update
222
            if ($action === 'getUpdates') {
223
                TelegramLog::update($result);
224
            }
225
226
            return $result;
227
        } catch (RequestException $e) {
228
            throw new TelegramException($e->getMessage());
229
        } finally {
230
            //Logging verbose debug output
231
            TelegramLog::endDebugLogTempStream("Verbose HTTP Request output:\n%s\n");
232
        }
233
    }
234
235
    /**
236
     * Download file
237
     *
238
     * @param \Longman\TelegramBot\Entities\File $file
239
     *
240
     * @return boolean
241
     * @throws \Longman\TelegramBot\Exception\TelegramException
242
     */
243
    public static function downloadFile(File $file)
244
    {
245
        $tg_file_path = $file->getFilePath();
246
        $file_path    = self::$telegram->getDownloadPath() . '/' . $tg_file_path;
247
248
        $file_dir = dirname($file_path);
249
        //For safety reasons, first try to create the directory, then check that it exists.
250
        //This is in case some other process has created the folder in the meantime.
251
        if (!@mkdir($file_dir, 0755, true) && !is_dir($file_dir)) {
252
            throw new TelegramException('Directory ' . $file_dir . ' can\'t be created');
253
        }
254
255
        $debug_handle = TelegramLog::getDebugLogTempStream();
256
257
        try {
258
            self::$client->get(
259
                '/file/bot' . self::$telegram->getApiKey() . '/' . $tg_file_path,
260
                ['debug' => $debug_handle, 'sink' => $file_path]
261
            );
262
263
            return filesize($file_path) > 0;
264
        } catch (RequestException $e) {
265
            throw new TelegramException($e->getMessage());
266
        } finally {
267
            //Logging verbose debug output
268
            TelegramLog::endDebugLogTempStream("Verbose HTTP File Download Request output:\n%s\n");
269
        }
270
    }
271
272
    /**
273
     * Encode file
274
     *
275
     * @param string $file
276
     *
277
     * @return resource
278
     * @throws \Longman\TelegramBot\Exception\TelegramException
279
     */
280
    protected static function encodeFile($file)
281
    {
282
        $fp = fopen($file, 'r');
283
        if ($fp === false) {
284
            throw new TelegramException('Cannot open ' . $file . ' for reading');
285
        }
286
287
        return $fp;
288
    }
289
290
    /**
291
     * Send command
292
     *
293
     * @todo Fake response doesn't need json encoding?
294
     *
295
     * @param string $action
296
     * @param array  $data
297
     *
298
     * @return \Longman\TelegramBot\Entities\ServerResponse
299
     * @throws \Longman\TelegramBot\Exception\TelegramException
300
     */
301 5
    public static function send($action, array $data = [])
302
    {
303 5
        self::ensureValidAction($action);
304
305 5
        $bot_name = self::$telegram->getBotName();
306
307 5
        if (defined('PHPUNIT_TESTSUITE')) {
308 5
            $fake_response = self::generateGeneralFakeServerResponse($data);
309
310 5
            return new ServerResponse($fake_response, $bot_name);
311
        }
312
313
        self::ensureNonEmptyData($data);
314
315
        $response = json_decode(self::execute($action, $data), true);
316
317
        if (null === $response) {
318
            throw new TelegramException('Telegram returned an invalid response! Please review your bot name and API key.');
319
        }
320
321
        return new ServerResponse($response, $bot_name);
322
    }
323
324
    /**
325
     * Make sure the data isn't empty, else throw an exception
326
     *
327
     * @param array $data
328
     *
329
     * @throws \Longman\TelegramBot\Exception\TelegramException
330
     */
331
    private static function ensureNonEmptyData(array $data)
332
    {
333
        if (count($data) === 0) {
334
            throw new TelegramException('Data is empty!');
335
        }
336
    }
337
338
    /**
339
     * Make sure the action is valid, else throw an exception
340
     *
341
     * @param string $action
342
     *
343
     * @throws \Longman\TelegramBot\Exception\TelegramException
344
     */
345 5
    private static function ensureValidAction($action)
346
    {
347 5
        if (!in_array($action, self::$actions, true)) {
348
            throw new TelegramException('The action " . $action . " doesn\'t exist!');
349
        }
350 5
    }
351
352
    /**
353
     * Assign an encoded file to a data array
354
     *
355
     * @param array  $data
356
     * @param string $field
357
     * @param string $file
358
     *
359
     * @throws \Longman\TelegramBot\Exception\TelegramException
360
     */
361
    private static function assignEncodedFile(&$data, $field, $file)
362
    {
363
        if ($file !== null && $file !== '') {
364
            $data[$field] = self::encodeFile($file);
365
        }
366
    }
367
368
    /**
369
     * Get me
370
     *
371
     * @return mixed
372
     * @throws \Longman\TelegramBot\Exception\TelegramException
373
     */
374
    public static function getMe()
375
    {
376
        // Added fake parameter, because of some cURL version failed POST request without parameters
377
        // see https://github.com/akalongman/php-telegram-bot/pull/228
378
        return self::send('getMe', ['whoami']);
379
    }
380
381
    /**
382
     * Send message
383
     *
384
     * @param array $data
385
     *
386
     * @return mixed
387
     * @throws \Longman\TelegramBot\Exception\TelegramException
388
     */
389 5
    public static function sendMessage(array $data)
390
    {
391 5
        $text = $data['text'];
392
393
        do {
394
            //Chop off and send the first message
395 5
            $data['text'] = mb_substr($text, 0, 4096);
396 5
            $response = self::send('sendMessage', $data);
397
398
            //Prepare the next message
399 5
            $text = mb_substr($text, 4096);
400 5
        } while (mb_strlen($text, 'UTF-8') > 0);
401
402 5
        return $response;
403
    }
404
405
    /**
406
     * Forward message
407
     *
408
     * @param array $data
409
     *
410
     * @return mixed
411
     * @throws \Longman\TelegramBot\Exception\TelegramException
412
     */
413
    public static function forwardMessage(array $data)
414
    {
415
        return self::send('forwardMessage', $data);
416
    }
417
418
    /**
419
     * Send photo
420
     *
421
     * @param array  $data
422
     * @param string $file
423
     *
424
     * @return mixed
425
     * @throws \Longman\TelegramBot\Exception\TelegramException
426
     */
427
    public static function sendPhoto(array $data, $file = null)
428
    {
429
        self::assignEncodedFile($data, 'photo', $file);
430
431
        return self::send('sendPhoto', $data);
432
    }
433
434
    /**
435
     * Send audio
436
     *
437
     * @param array  $data
438
     * @param string $file
439
     *
440
     * @return mixed
441
     * @throws \Longman\TelegramBot\Exception\TelegramException
442
     */
443
    public static function sendAudio(array $data, $file = null)
444
    {
445
        self::assignEncodedFile($data, 'audio', $file);
446
447
        return self::send('sendAudio', $data);
448
    }
449
450
    /**
451
     * Send document
452
     *
453
     * @param array  $data
454
     * @param string $file
455
     *
456
     * @return mixed
457
     * @throws \Longman\TelegramBot\Exception\TelegramException
458
     */
459
    public static function sendDocument(array $data, $file = null)
460
    {
461
        self::assignEncodedFile($data, 'document', $file);
462
463
        return self::send('sendDocument', $data);
464
    }
465
466
    /**
467
     * Send sticker
468
     *
469
     * @param array  $data
470
     * @param string $file
471
     *
472
     * @return mixed
473
     * @throws \Longman\TelegramBot\Exception\TelegramException
474
     */
475
    public static function sendSticker(array $data, $file = null)
476
    {
477
        self::assignEncodedFile($data, 'sticker', $file);
478
479
        return self::send('sendSticker', $data);
480
    }
481
482
    /**
483
     * Send video
484
     *
485
     * @param array  $data
486
     * @param string $file
487
     *
488
     * @return mixed
489
     * @throws \Longman\TelegramBot\Exception\TelegramException
490
     */
491
    public static function sendVideo(array $data, $file = null)
492
    {
493
        self::assignEncodedFile($data, 'video', $file);
494
495
        return self::send('sendVideo', $data);
496
    }
497
498
    /**
499
     * Send voice
500
     *
501
     * @param array  $data
502
     * @param string $file
503
     *
504
     * @return mixed
505
     * @throws \Longman\TelegramBot\Exception\TelegramException
506
     */
507
    public static function sendVoice(array $data, $file = null)
508
    {
509
        self::assignEncodedFile($data, 'voice', $file);
510
511
        return self::send('sendVoice', $data);
512
    }
513
514
    /**
515
     * Send location
516
     *
517
     * @param array $data
518
     *
519
     * @return mixed
520
     * @throws \Longman\TelegramBot\Exception\TelegramException
521
     */
522
    public static function sendLocation(array $data)
523
    {
524
        return self::send('sendLocation', $data);
525
    }
526
527
    /**
528
     * Send venue
529
     *
530
     * @param array $data
531
     *
532
     * @return mixed
533
     * @throws \Longman\TelegramBot\Exception\TelegramException
534
     */
535
    public static function sendVenue(array $data)
536
    {
537
        return self::send('sendVenue', $data);
538
    }
539
540
    /**
541
     * Send contact
542
     *
543
     * @param array $data
544
     *
545
     * @return mixed
546
     * @throws \Longman\TelegramBot\Exception\TelegramException
547
     */
548
    public static function sendContact(array $data)
549
    {
550
        return self::send('sendContact', $data);
551
    }
552
553
    /**
554
     * Send chat action
555
     *
556
     * @param array $data
557
     *
558
     * @return mixed
559
     * @throws \Longman\TelegramBot\Exception\TelegramException
560
     */
561
    public static function sendChatAction(array $data)
562
    {
563
        return self::send('sendChatAction', $data);
564
    }
565
566
    /**
567
     * Get user profile photos
568
     *
569
     * @param array $data
570
     *
571
     * @return mixed
572
     * @throws \Longman\TelegramBot\Exception\TelegramException
573
     */
574
    public static function getUserProfilePhotos(array $data)
575
    {
576
        if (!isset($data['user_id'])) {
577
            throw new TelegramException('User id is empty!');
578
        }
579
580
        return self::send('getUserProfilePhotos', $data);
581
    }
582
583
    /**
584
     * Get updates
585
     *
586
     * @param array $data
587
     *
588
     * @return mixed
589
     * @throws \Longman\TelegramBot\Exception\TelegramException
590
     */
591
    public static function getUpdates(array $data)
592
    {
593
        return self::send('getUpdates', $data);
594
    }
595
596
    /**
597
     * Set webhook
598
     *
599
     * @param string $url
600
     * @param string $file
601
     *
602
     * @return mixed
603
     * @throws \Longman\TelegramBot\Exception\TelegramException
604
     */
605
    public static function setWebhook($url = '', $file = null)
606
    {
607
        $data = ['url' => $url];
608
609
        self::assignEncodedFile($data, 'certificate', $file);
610
611
        return self::send('setWebhook', $data);
612
    }
613
614
    /**
615
     * Get file
616
     *
617
     * @param array $data
618
     *
619
     * @return mixed
620
     * @throws \Longman\TelegramBot\Exception\TelegramException
621
     */
622
    public static function getFile(array $data)
623
    {
624
        return self::send('getFile', $data);
625
    }
626
627
    /**
628
     * Kick Chat Member
629
     *
630
     * @param array $data
631
     *
632
     * @return mixed
633
     * @throws \Longman\TelegramBot\Exception\TelegramException
634
     */
635
    public static function kickChatMember(array $data)
636
    {
637
        return self::send('kickChatMember', $data);
638
    }
639
640
    /**
641
     * Leave Chat
642
     *
643
     * @param array $data
644
     *
645
     * @return mixed
646
     * @throws \Longman\TelegramBot\Exception\TelegramException
647
     */
648
    public static function leaveChat(array $data)
649
    {
650
        return self::send('leaveChat', $data);
651
    }
652
653
    /**
654
     * Unban Chat Member
655
     *
656
     * @param array $data
657
     *
658
     * @return mixed
659
     * @throws \Longman\TelegramBot\Exception\TelegramException
660
     */
661
    public static function unbanChatMember(array $data)
662
    {
663
        return self::send('unbanChatMember', $data);
664
    }
665
666
    /**
667
     * Get Chat
668
     *
669
     * @todo add get response in ServerResponse.php?
670
     *
671
     * @param array $data
672
     *
673
     * @return mixed
674
     * @throws \Longman\TelegramBot\Exception\TelegramException
675
     */
676
    public static function getChat(array $data)
677
    {
678
        return self::send('getChat', $data);
679
    }
680
681
    /**
682
     * Get Chat Administrators
683
     *
684
     * @todo add get response in ServerResponse.php?
685
     *
686
     * @param array $data
687
     *
688
     * @return mixed
689
     * @throws \Longman\TelegramBot\Exception\TelegramException
690
     */
691
    public static function getChatAdministrators(array $data)
692
    {
693
        return self::send('getChatAdministrators', $data);
694
    }
695
696
    /**
697
     * Get Chat Members Count
698
     *
699
     * @todo add get response in ServerResponse.php?
700
     *
701
     * @param array $data
702
     *
703
     * @return mixed
704
     * @throws \Longman\TelegramBot\Exception\TelegramException
705
     */
706
    public static function getChatMembersCount(array $data)
707
    {
708
        return self::send('getChatMembersCount', $data);
709
    }
710
711
    /**
712
     * Get Chat Member
713
     *
714
     * @todo add get response in ServerResponse.php?
715
     *
716
     * @param array $data
717
     *
718
     * @return mixed
719
     * @throws \Longman\TelegramBot\Exception\TelegramException
720
     */
721
    public static function getChatMember(array $data)
722
    {
723
        return self::send('getChatMember', $data);
724
    }
725
726
    /**
727
     * Answer callback query
728
     *
729
     * @param array $data
730
     *
731
     * @return mixed
732
     * @throws \Longman\TelegramBot\Exception\TelegramException
733
     */
734
    public static function answerCallbackQuery(array $data)
735
    {
736
        return self::send('answerCallbackQuery', $data);
737
    }
738
739
    /**
740
     * Answer inline query
741
     *
742
     * @param array $data
743
     *
744
     * @return mixed
745
     * @throws \Longman\TelegramBot\Exception\TelegramException
746
     */
747
    public static function answerInlineQuery(array $data)
748
    {
749
        return self::send('answerInlineQuery', $data);
750
    }
751
752
    /**
753
     * Edit message text
754
     *
755
     * @param array $data
756
     *
757
     * @return mixed
758
     * @throws \Longman\TelegramBot\Exception\TelegramException
759
     */
760
    public static function editMessageText(array $data)
761
    {
762
        return self::send('editMessageText', $data);
763
    }
764
765
    /**
766
     * Edit message caption
767
     *
768
     * @param array $data
769
     *
770
     * @return mixed
771
     * @throws \Longman\TelegramBot\Exception\TelegramException
772
     */
773
    public static function editMessageCaption(array $data)
774
    {
775
        return self::send('editMessageCaption', $data);
776
    }
777
778
    /**
779
     * Edit message reply markup
780
     *
781
     * @param array $data
782
     *
783
     * @return mixed
784
     * @throws \Longman\TelegramBot\Exception\TelegramException
785
     */
786
    public static function editMessageReplyMarkup(array $data)
787
    {
788
        return self::send('editMessageReplyMarkup', $data);
789
    }
790
791
    /**
792
     * Return an empty Server Response
793
     *
794
     * No request to telegram are sent, this function is used in commands that
795
     * don't need to fire a message after execution
796
     *
797
     * @return \Longman\TelegramBot\Entities\ServerResponse
798
     * @throws \Longman\TelegramBot\Exception\TelegramException
799
     */
800
    public static function emptyResponse()
801
    {
802
        return new ServerResponse(['ok' => true, 'result' => true], null);
803
    }
804
805
    /**
806
     * Send message to all active chats
807
     *
808
     * @param string  $callback_function
809
     * @param array   $data
810
     * @param boolean $send_groups
811
     * @param boolean $send_super_groups
812
     * @param boolean $send_users
813
     * @param string  $date_from
814
     * @param string  $date_to
815
     *
816
     * @return array
817
     * @throws \Longman\TelegramBot\Exception\TelegramException
818
     */
819
    public static function sendToActiveChats(
820
        $callback_function,
821
        array $data,
822
        $send_groups = true,
823
        $send_super_groups = true,
824
        $send_users = true,
825
        $date_from = null,
826
        $date_to = null
827
    ) {
828
        $callback_path = __NAMESPACE__ . '\Request';
829
        if (!method_exists($callback_path, $callback_function)) {
830
            throw new TelegramException('Method "' . $callback_function . '" not found in class Request.');
831
        }
832
833
        $chats = DB::selectChats($send_groups, $send_super_groups, $send_users, $date_from, $date_to);
834
835
        $results = [];
836
        if (is_array($chats)) {
837
            foreach ($chats as $row) {
838
                $data['chat_id'] = $row['chat_id'];
839
                $results[]       = call_user_func_array($callback_path . '::' . $callback_function, [$data]);
840
            }
841
        }
842
843
        return $results;
844
    }
845
}
846