Completed
Push — develop ( c2cb5c...b6e13b )
by Armando
14s
created

Request::setClient()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.032

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 4
cts 5
cp 0.8
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 1
crap 2.032
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
     * Request limiter
51
     *
52
     * @var boolean
53
     */
54
    private static $limiter_enabled;
55
56
    /**
57
     * Request limiter's interval between checks
58
     *
59
     * @var boolean
60
     */
61
    private static $limiter_interval;
62
63
    /**
64
     * Available actions to send
65
     *
66
     * @var array
67
     */
68
    private static $actions = [
69
        'getUpdates',
70
        'setWebhook',
71
        'deleteWebhook',
72
        'getMe',
73
        'sendMessage',
74
        'forwardMessage',
75
        'sendPhoto',
76
        'sendAudio',
77
        'sendDocument',
78
        'sendSticker',
79
        'sendVideo',
80
        'sendVoice',
81
        'sendLocation',
82
        'sendVenue',
83
        'sendContact',
84
        'sendChatAction',
85
        'getUserProfilePhotos',
86
        'getFile',
87
        'kickChatMember',
88
        'leaveChat',
89
        'unbanChatMember',
90
        'getChat',
91
        'getChatAdministrators',
92
        'getChatMember',
93
        'getChatMembersCount',
94
        'answerCallbackQuery',
95
        'answerInlineQuery',
96
        'editMessageText',
97
        'editMessageCaption',
98
        'editMessageReplyMarkup',
99
        'getWebhookInfo',
100
    ];
101
102
    /**
103
     * Initialize
104
     *
105
     * @param \Longman\TelegramBot\Telegram $telegram
106
     *
107
     * @throws TelegramException
108
     */
109 30
    public static function initialize(Telegram $telegram)
110
    {
111 30
        if (!($telegram instanceof Telegram)) {
112
            throw new TelegramException('Invalid Telegram pointer!');
113
        }
114
115 30
        self::$telegram = $telegram;
116 30
        self::setClient(new Client(['base_uri' => self::$api_base_uri]));
117 30
    }
118
119
    /**
120
     * Set a custom Guzzle HTTP Client object
121
     *
122
     * @param Client $client
123
     *
124
     * @throws TelegramException
125
     */
126 30
    public static function setClient(Client $client)
127
    {
128 30
        if (!($client instanceof Client)) {
129
            throw new TelegramException('Invalid GuzzleHttp\Client pointer!');
130
        }
131
132 30
        self::$client = $client;
133 30
    }
134
135
    /**
136
     * Set input from custom input or stdin and return it
137
     *
138
     * @return string
139
     * @throws \Longman\TelegramBot\Exception\TelegramException
140
     */
141
    public static function getInput()
142
    {
143
        // First check if a custom input has been set, else get the PHP input.
144
        if (!($input = self::$telegram->getCustomInput())) {
145
            $input = file_get_contents('php://input');
146
        }
147
148
        // Make sure we have a string to work with.
149
        if (is_string($input)) {
150
            self::$input = $input;
151
        } else {
152
            throw new TelegramException('Input must be a string!');
153
        }
154
155
        TelegramLog::update(self::$input);
156
157
        return self::$input;
158
    }
159
160
    /**
161
     * Generate general fake server response
162
     *
163
     * @param array $data Data to add to fake response
164
     *
165
     * @return array Fake response data
166
     */
167 1
    public static function generateGeneralFakeServerResponse(array $data = [])
168
    {
169
        //PARAM BINDED IN PHPUNIT TEST FOR TestServerResponse.php
170
        //Maybe this is not the best possible implementation
171
172
        //No value set in $data ie testing setWebhook
173
        //Provided $data['chat_id'] ie testing sendMessage
174
175 1
        $fake_response = ['ok' => true]; // :)
176
177 1
        if ($data === []) {
178 1
            $fake_response['result'] = true;
179
        }
180
181
        //some data to let iniatilize the class method SendMessage
182 1
        if (isset($data['chat_id'])) {
183 1
            $data['message_id'] = '1234';
184 1
            $data['date']       = '1441378360';
185 1
            $data['from']       = [
186
                'id'         => 123456789,
187
                'first_name' => 'botname',
188
                'username'   => 'namebot',
189
            ];
190 1
            $data['chat']       = ['id' => $data['chat_id']];
191
192 1
            $fake_response['result'] = $data;
193
        }
194
195 1
        return $fake_response;
196
    }
197
198
    /**
199
     * Properly set up the request params
200
     *
201
     * If any item of the array is a resource, reformat it to a multipart request.
202
     * Else, just return the passed data as form params.
203
     *
204
     * @param array $data
205
     *
206
     * @return array
207
     */
208
    private static function setUpRequestParams(array $data)
209
    {
210
        $has_resource = false;
211
        $multipart = [];
212
213
        // Convert any nested arrays into JSON strings.
214
        array_walk($data, function (&$item) {
215
            is_array($item) && $item = json_encode($item);
216
        });
217
218
        //Reformat data array in multipart way if it contains a resource
219
        foreach ($data as $key => $item) {
220
            $has_resource |= (is_resource($item) || $item instanceof \GuzzleHttp\Psr7\Stream);
221
            $multipart[] = ['name' => $key, 'contents' => $item];
222
        }
223
        if ($has_resource) {
224
            return ['multipart' => $multipart];
225
        }
226
227
        return ['form_params' => $data];
228
    }
229
230
    /**
231
     * Execute HTTP Request
232
     *
233
     * @param string $action Action to execute
234
     * @param array  $data   Data to attach to the execution
235
     *
236
     * @return string Result of the HTTP Request
237
     * @throws \Longman\TelegramBot\Exception\TelegramException
238
     */
239
    public static function execute($action, array $data = [])
240
    {
241
        //Fix so that the keyboard markup is a string, not an object
242
        if (isset($data['reply_markup'])) {
243
            $data['reply_markup'] = json_encode($data['reply_markup']);
244
        }
245
246
        $result = null;
247
        $request_params = self::setUpRequestParams($data);
248
        $request_params['debug'] = TelegramLog::getDebugLogTempStream();
249
250
        try {
251
            $response = self::$client->post(
252
                '/bot' . self::$telegram->getApiKey() . '/' . $action,
253
                $request_params
254
            );
255
            $result = (string) $response->getBody();
256
257
            //Logging getUpdates Update
258
            if ($action === 'getUpdates') {
259
                TelegramLog::update($result);
260
            }
261
        } catch (RequestException $e) {
262
            $result = ($e->getResponse()) ? (string) $e->getResponse()->getBody() : '';
263
        } finally {
264
            //Logging verbose debug output
265
            TelegramLog::endDebugLogTempStream('Verbose HTTP Request output:' . PHP_EOL . '%s' . PHP_EOL);
266
        }
267
268
        return $result;
269
    }
270
271
    /**
272
     * Download file
273
     *
274
     * @param \Longman\TelegramBot\Entities\File $file
275
     *
276
     * @return boolean
277
     * @throws \Longman\TelegramBot\Exception\TelegramException
278
     */
279
    public static function downloadFile(File $file)
280
    {
281
        if (empty($download_path = self::$telegram->getDownloadPath())) {
282
            throw new TelegramException('Download path not set!');
283
        }
284
285
        $tg_file_path = $file->getFilePath();
286
        $file_path    = $download_path . '/' . $tg_file_path;
287
288
        $file_dir = dirname($file_path);
289
        //For safety reasons, first try to create the directory, then check that it exists.
290
        //This is in case some other process has created the folder in the meantime.
291
        if (!@mkdir($file_dir, 0755, true) && !is_dir($file_dir)) {
292
            throw new TelegramException('Directory ' . $file_dir . ' can\'t be created');
293
        }
294
295
        $debug_handle = TelegramLog::getDebugLogTempStream();
296
297
        try {
298
            self::$client->get(
299
                '/file/bot' . self::$telegram->getApiKey() . '/' . $tg_file_path,
300
                ['debug' => $debug_handle, 'sink' => $file_path]
301
            );
302
303
            return filesize($file_path) > 0;
304
        } catch (RequestException $e) {
305
            return ($e->getResponse()) ? (string) $e->getResponse()->getBody() : '';
306
        } finally {
307
            //Logging verbose debug output
308
            TelegramLog::endDebugLogTempStream('Verbose HTTP File Download Request output:' . PHP_EOL . '%s' . PHP_EOL);
309
        }
310
    }
311
312
    /**
313
     * Encode file
314
     *
315
     * @param string $file
316
     *
317
     * @return resource
318
     * @throws \Longman\TelegramBot\Exception\TelegramException
319
     */
320
    protected static function encodeFile($file)
321
    {
322
        $fp = fopen($file, 'r');
323
        if ($fp === false) {
324
            throw new TelegramException('Cannot open "' . $file . '" for reading');
325
        }
326
327
        return $fp;
328
    }
329
330
    /**
331
     * Send command
332
     *
333
     * @todo Fake response doesn't need json encoding?
334
     *
335
     * @param string $action
336
     * @param array  $data
337
     *
338
     * @return \Longman\TelegramBot\Entities\ServerResponse
339
     * @throws \Longman\TelegramBot\Exception\TelegramException
340
     */
341
    public static function send($action, array $data = [])
342
    {
343
        self::ensureValidAction($action);
344
345
        $bot_username = self::$telegram->getBotUsername();
346
347
        if (defined('PHPUNIT_TESTSUITE')) {
348
            $fake_response = self::generateGeneralFakeServerResponse($data);
349
350
            return new ServerResponse($fake_response, $bot_username);
351
        }
352
353
        self::ensureNonEmptyData($data);
354
355
        self::limitTelegramRequests($action, $data);
356
357
        $response = json_decode(self::execute($action, $data), true);
358
359
        if (null === $response) {
360
            throw new TelegramException('Telegram returned an invalid response! Please review your bot name and API key.');
361
        }
362
363
        return new ServerResponse($response, $bot_username);
364
    }
365
366
    /**
367
     * Make sure the data isn't empty, else throw an exception
368
     *
369
     * @param array $data
370
     *
371
     * @throws \Longman\TelegramBot\Exception\TelegramException
372
     */
373
    private static function ensureNonEmptyData(array $data)
374
    {
375
        if (count($data) === 0) {
376
            throw new TelegramException('Data is empty!');
377
        }
378
    }
379
380
    /**
381
     * Make sure the action is valid, else throw an exception
382
     *
383
     * @param string $action
384
     *
385
     * @throws \Longman\TelegramBot\Exception\TelegramException
386
     */
387
    private static function ensureValidAction($action)
388
    {
389
        if (!in_array($action, self::$actions, true)) {
390
            throw new TelegramException('The action "' . $action . '" doesn\'t exist!');
391
        }
392
    }
393
394
    /**
395
     * Assign an encoded file to a data array
396
     *
397
     * @param array  $data
398
     * @param string $field
399
     * @param string $file
400
     *
401
     * @throws \Longman\TelegramBot\Exception\TelegramException
402
     */
403
    private static function assignEncodedFile(&$data, $field, $file)
404
    {
405
        if ($file !== null && $file !== '') {
406
            $data[$field] = self::encodeFile($file);
407
        }
408
    }
409
410
    /**
411
     * Returns basic information about the bot in form of a User object
412
     *
413
     * @link https://core.telegram.org/bots/api#getme
414
     *
415
     * @return \Longman\TelegramBot\Entities\ServerResponse
416
     * @throws \Longman\TelegramBot\Exception\TelegramException
417
     */
418
    public static function getMe()
419
    {
420
        // Added fake parameter, because of some cURL version failed POST request without parameters
421
        // see https://github.com/php-telegram-bot/core/pull/228
422
        return self::send('getMe', ['whoami']);
423
    }
424
425
    /**
426
     * Use this method to send text messages. On success, the sent Message is returned
427
     *
428
     * @link https://core.telegram.org/bots/api#sendmessage
429
     *
430
     * @param array $data
431
     *
432
     * @return \Longman\TelegramBot\Entities\ServerResponse
433
     * @throws \Longman\TelegramBot\Exception\TelegramException
434
     */
435
    public static function sendMessage(array $data)
436
    {
437
        $text = $data['text'];
438
439
        do {
440
            //Chop off and send the first message
441
            $data['text'] = mb_substr($text, 0, 4096);
442
            $response     = self::send('sendMessage', $data);
443
444
            //Prepare the next message
445
            $text = mb_substr($text, 4096);
446
        } while (mb_strlen($text, 'UTF-8') > 0);
447
448
        return $response;
449
    }
450
451
    /**
452
     * Use this method to forward messages of any kind. On success, the sent Message is returned
453
     *
454
     * @link https://core.telegram.org/bots/api#forwardmessage
455
     *
456
     * @param array $data
457
     *
458
     * @return \Longman\TelegramBot\Entities\ServerResponse
459
     * @throws \Longman\TelegramBot\Exception\TelegramException
460
     */
461
    public static function forwardMessage(array $data)
462
    {
463
        return self::send('forwardMessage', $data);
464
    }
465
466
    /**
467
     * Use this method to send photos. On success, the sent Message is returned
468
     *
469
     * @link https://core.telegram.org/bots/api#sendphoto
470
     *
471
     * @param array  $data
472
     * @param string $file
473
     *
474
     * @return \Longman\TelegramBot\Entities\ServerResponse
475
     * @throws \Longman\TelegramBot\Exception\TelegramException
476
     */
477
    public static function sendPhoto(array $data, $file = null)
478
    {
479
        self::assignEncodedFile($data, 'photo', $file);
480
481
        return self::send('sendPhoto', $data);
482
    }
483
484
    /**
485
     * Use this method to send audio files
486
     *
487
     * Your audio must be in the .mp3 format. On success, the sent Message is returned.
488
     * Bots can currently send audio files of up to 50 MB in size, this limit may be changed in the future.
489
     * For sending voice messages, use the sendVoice method instead.
490
     *
491
     * @link https://core.telegram.org/bots/api#sendaudio
492
     *
493
     * @param array  $data
494
     * @param string $file
495
     *
496
     * @return \Longman\TelegramBot\Entities\ServerResponse
497
     * @throws \Longman\TelegramBot\Exception\TelegramException
498
     */
499
    public static function sendAudio(array $data, $file = null)
500
    {
501
        self::assignEncodedFile($data, 'audio', $file);
502
503
        return self::send('sendAudio', $data);
504
    }
505
506
    /**
507
     * Use this method to send general files. On success, the sent Message is returned.
508
     *
509
     * Bots can currently send files of any type of up to 50 MB in size, this limit may be changed in the future.
510
     *
511
     * @link https://core.telegram.org/bots/api#senddocument
512
     *
513
     * @param array  $data
514
     * @param string $file
515
     *
516
     * @return \Longman\TelegramBot\Entities\ServerResponse
517
     * @throws \Longman\TelegramBot\Exception\TelegramException
518
     */
519
    public static function sendDocument(array $data, $file = null)
520
    {
521
        self::assignEncodedFile($data, 'document', $file);
522
523
        return self::send('sendDocument', $data);
524
    }
525
526
    /**
527
     * Use this method to send .webp stickers. On success, the sent Message is returned.
528
     *
529
     * @link https://core.telegram.org/bots/api#sendsticker
530
     *
531
     * @param array  $data
532
     * @param string $file
533
     *
534
     * @return \Longman\TelegramBot\Entities\ServerResponse
535
     * @throws \Longman\TelegramBot\Exception\TelegramException
536
     */
537
    public static function sendSticker(array $data, $file = null)
538
    {
539
        self::assignEncodedFile($data, 'sticker', $file);
540
541
        return self::send('sendSticker', $data);
542
    }
543
544
    /**
545
     * Use this method to send video files. On success, the sent Message is returned.
546
     *
547
     * Telegram clients support mp4 videos (other formats may be sent as Document).
548
     * Bots can currently send video files of up to 50 MB in size, this limit may be changed in the future.
549
     *
550
     * @link https://core.telegram.org/bots/api#sendvideo
551
     *
552
     * @param array  $data
553
     * @param string $file
554
     *
555
     * @return \Longman\TelegramBot\Entities\ServerResponse
556
     * @throws \Longman\TelegramBot\Exception\TelegramException
557
     */
558
    public static function sendVideo(array $data, $file = null)
559
    {
560
        self::assignEncodedFile($data, 'video', $file);
561
562
        return self::send('sendVideo', $data);
563
    }
564
565
    /**
566
     * Use this method to send audio files. On success, the sent Message is returned.
567
     *
568
     * Telegram clients will display the file as a playable voice message.
569
     * For this to work, your audio must be in an .ogg file encoded with OPUS (other formats may be sent as Audio or Document).
570
     * Bots can currently send voice messages of up to 50 MB in size, this limit may be changed in the future.
571
     *
572
     * @link https://core.telegram.org/bots/api#sendvoice
573
     *
574
     * @param array  $data
575
     * @param string $file
576
     *
577
     * @return \Longman\TelegramBot\Entities\ServerResponse
578
     * @throws \Longman\TelegramBot\Exception\TelegramException
579
     */
580
    public static function sendVoice(array $data, $file = null)
581
    {
582
        self::assignEncodedFile($data, 'voice', $file);
583
584
        return self::send('sendVoice', $data);
585
    }
586
587
    /**
588
     * Use this method to send point on the map. On success, the sent Message is returned.
589
     *
590
     * @link https://core.telegram.org/bots/api#sendlocation
591
     *
592
     * @param array $data
593
     *
594
     * @return \Longman\TelegramBot\Entities\ServerResponse
595
     * @throws \Longman\TelegramBot\Exception\TelegramException
596
     */
597
    public static function sendLocation(array $data)
598
    {
599
        return self::send('sendLocation', $data);
600
    }
601
602
    /**
603
     * Use this method to send information about a venue. On success, the sent Message is returned.
604
     *
605
     * @link https://core.telegram.org/bots/api#sendvenue
606
     *
607
     * @param array $data
608
     *
609
     * @return \Longman\TelegramBot\Entities\ServerResponse
610
     * @throws \Longman\TelegramBot\Exception\TelegramException
611
     */
612
    public static function sendVenue(array $data)
613
    {
614
        return self::send('sendVenue', $data);
615
    }
616
617
    /**
618
     * Use this method to send phone contacts. On success, the sent Message is returned.
619
     *
620
     * @link https://core.telegram.org/bots/api#sendcontact
621
     *
622
     * @param array $data
623
     *
624
     * @return \Longman\TelegramBot\Entities\ServerResponse
625
     * @throws \Longman\TelegramBot\Exception\TelegramException
626
     */
627
    public static function sendContact(array $data)
628
    {
629
        return self::send('sendContact', $data);
630
    }
631
632
    /**
633
     * Use this method when you need to tell the user that something is happening on the bot's side.
634
     *
635
     * The status is set for 5 seconds or less.
636
     * (when a message arrives from your bot, Telegram clients clear its typing status)
637
     *
638
     * @link https://core.telegram.org/bots/api#sendchataction
639
     *
640
     * @param array $data
641
     *
642
     * @return \Longman\TelegramBot\Entities\ServerResponse
643
     * @throws \Longman\TelegramBot\Exception\TelegramException
644
     */
645
    public static function sendChatAction(array $data)
646
    {
647
        return self::send('sendChatAction', $data);
648
    }
649
650
    /**
651
     * Use this method to get a list of profile pictures for a user. Returns a UserProfilePhotos object.
652
     *
653
     * @param array $data
654
     *
655
     * @return \Longman\TelegramBot\Entities\ServerResponse
656
     * @throws \Longman\TelegramBot\Exception\TelegramException
657
     */
658
    public static function getUserProfilePhotos(array $data)
659
    {
660
        return self::send('getUserProfilePhotos', $data);
661
    }
662
663
    /**
664
     * Use this method to get basic info about a file and prepare it for downloading. On success, a File object is returned.
665
     *
666
     * For the moment, bots can download files of up to 20MB in size.
667
     * The file can then be downloaded via the link https://api.telegram.org/file/bot<token>/<file_path>,
668
     * where <file_path> is taken from the response.
669
     * It is guaranteed that the link will be valid for at least 1 hour.
670
     * When the link expires, a new one can be requested by calling getFile again.
671
     *
672
     * @link https://core.telegram.org/bots/api#getfile
673
     *
674
     * @param array $data
675
     *
676
     * @return \Longman\TelegramBot\Entities\ServerResponse
677
     * @throws \Longman\TelegramBot\Exception\TelegramException
678
     */
679
    public static function getFile(array $data)
680
    {
681
        return self::send('getFile', $data);
682
    }
683
684
    /**
685
     * Use this method to kick a user from a group or a supergroup. Returns True on success.
686
     *
687
     * In the case of supergroups, the user will not be able to return to the group on their own using invite links, etc., unless unbanned first.
688
     * The bot must be an administrator in the group for this to work.
689
     *
690
     * @link https://core.telegram.org/bots/api#kickchatmember
691
     *
692
     * @param array $data
693
     *
694
     * @return \Longman\TelegramBot\Entities\ServerResponse
695
     * @throws \Longman\TelegramBot\Exception\TelegramException
696
     */
697
    public static function kickChatMember(array $data)
698
    {
699
        return self::send('kickChatMember', $data);
700
    }
701
702
    /**
703
     * Use this method for your bot to leave a group, supergroup or channel. Returns True on success.
704
     *
705
     * @link https://core.telegram.org/bots/api#leavechat
706
     *
707
     * @param array $data
708
     *
709
     * @return \Longman\TelegramBot\Entities\ServerResponse
710
     * @throws \Longman\TelegramBot\Exception\TelegramException
711
     */
712
    public static function leaveChat(array $data)
713
    {
714
        return self::send('leaveChat', $data);
715
    }
716
717
    /**
718
     * Use this method to unban a previously kicked user in a supergroup. Returns True on success.
719
     *
720
     * The user will not return to the group automatically, but will be able to join via link, etc.
721
     * The bot must be an administrator in the group for this to work.
722
     *
723
     * @link https://core.telegram.org/bots/api#unbanchatmember
724
     *
725
     * @param array $data
726
     *
727
     * @return \Longman\TelegramBot\Entities\ServerResponse
728
     * @throws \Longman\TelegramBot\Exception\TelegramException
729
     */
730
    public static function unbanChatMember(array $data)
731
    {
732
        return self::send('unbanChatMember', $data);
733
    }
734
735
    /**
736
     * Use this method to get up to date information about the chat (current name of the user for one-on-one conversations, current username of a user, group or channel, etc.). Returns a Chat object on success.
737
     *
738
     * @todo add get response in ServerResponse.php?
739
     *
740
     * @link https://core.telegram.org/bots/api#getchat
741
     *
742
     * @param array $data
743
     *
744
     * @return \Longman\TelegramBot\Entities\ServerResponse
745
     * @throws \Longman\TelegramBot\Exception\TelegramException
746
     */
747
    public static function getChat(array $data)
748
    {
749
        return self::send('getChat', $data);
750
    }
751
752
    /**
753
     * Use this method to get a list of administrators in a chat.
754
     *
755
     * On success, returns an Array of ChatMember objects that contains information about all chat administrators except other bots.
756
     * If the chat is a group or a supergroup and no administrators were appointed, only the creator will be returned.
757
     *
758
     * @todo add get response in ServerResponse.php?
759
     *
760
     * @link https://core.telegram.org/bots/api#getchatadministrators
761
     *
762
     * @param array $data
763
     *
764
     * @return \Longman\TelegramBot\Entities\ServerResponse
765
     * @throws \Longman\TelegramBot\Exception\TelegramException
766
     */
767
    public static function getChatAdministrators(array $data)
768
    {
769
        return self::send('getChatAdministrators', $data);
770
    }
771
772
    /**
773
     * Use this method to get the number of members in a chat. Returns Int on success.
774
     *
775
     * @todo add get response in ServerResponse.php?
776
     *
777
     * @link https://core.telegram.org/bots/api#getchatmemberscount
778
     *
779
     * @param array $data
780
     *
781
     * @return \Longman\TelegramBot\Entities\ServerResponse
782
     * @throws \Longman\TelegramBot\Exception\TelegramException
783
     */
784
    public static function getChatMembersCount(array $data)
785
    {
786
        return self::send('getChatMembersCount', $data);
787
    }
788
789
    /**
790
     * Use this method to get information about a member of a chat. Returns a ChatMember object on success.
791
     *
792
     * @todo add get response in ServerResponse.php?
793
     *
794
     * @link https://core.telegram.org/bots/api#getchatmember
795
     *
796
     * @param array $data
797
     *
798
     * @return \Longman\TelegramBot\Entities\ServerResponse
799
     * @throws \Longman\TelegramBot\Exception\TelegramException
800
     */
801
    public static function getChatMember(array $data)
802
    {
803
        return self::send('getChatMember', $data);
804
    }
805
806
    /**
807
     * Use this method to send answers to callback queries sent from inline keyboards. On success, True is returned.
808
     *
809
     * The answer will be displayed to the user as a notification at the top of the chat screen or as an alert.
810
     *
811
     * @link https://core.telegram.org/bots/api#answercallbackquery
812
     *
813
     * @param array $data
814
     *
815
     * @return \Longman\TelegramBot\Entities\ServerResponse
816
     * @throws \Longman\TelegramBot\Exception\TelegramException
817
     */
818
    public static function answerCallbackQuery(array $data)
819
    {
820
        return self::send('answerCallbackQuery', $data);
821
    }
822
823
    /**
824
     * Get updates
825
     *
826
     * @link https://core.telegram.org/bots/api#getupdates
827
     *
828
     * @param array $data
829
     *
830
     * @return \Longman\TelegramBot\Entities\ServerResponse
831
     * @throws \Longman\TelegramBot\Exception\TelegramException
832
     */
833
    public static function getUpdates(array $data)
834
    {
835
        return self::send('getUpdates', $data);
836
    }
837
838
    /**
839
     * Set webhook
840
     *
841
     * @link https://core.telegram.org/bots/api#setwebhook
842
     *
843
     * @param string $url
844
     * @param array  $data Optional parameters.
845
     *
846
     * @return \Longman\TelegramBot\Entities\ServerResponse
847
     * @throws \Longman\TelegramBot\Exception\TelegramException
848
     */
849
    public static function setWebhook($url = '', array $data = [])
850
    {
851
        $data        = array_intersect_key($data, array_flip([
852
            'certificate',
853
            'max_connections',
854
            'allowed_updates',
855
        ]));
856
        $data['url'] = $url;
857
858
        if (isset($data['certificate'])) {
859
            self::assignEncodedFile($data, 'certificate', $data['certificate']);
860
        }
861
862
        return self::send('setWebhook', $data);
863
    }
864
865
    /**
866
     * Delete webhook
867
     *
868
     * @link https://core.telegram.org/bots/api#deletewebhook
869
     *
870
     * @return \Longman\TelegramBot\Entities\ServerResponse
871
     * @throws \Longman\TelegramBot\Exception\TelegramException
872
     */
873
    public static function deleteWebhook()
874
    {
875
        // Must send some arbitrary data for this to work for now...
876
        return self::send('deleteWebhook', ['delete']);
877
    }
878
879
    /**
880
     * Use this method to edit text and game messages sent by the bot or via the bot (for inline bots).
881
     *
882
     * On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
883
     *
884
     * @link https://core.telegram.org/bots/api#editmessagetext
885
     *
886
     * @param array $data
887
     *
888
     * @return \Longman\TelegramBot\Entities\ServerResponse
889
     * @throws \Longman\TelegramBot\Exception\TelegramException
890
     */
891
    public static function editMessageText(array $data)
892
    {
893
        return self::send('editMessageText', $data);
894
    }
895
896
    /**
897
     * Use this method to edit captions of messages sent by the bot or via the bot (for inline bots).
898
     *
899
     * On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
900
     *
901
     * @link https://core.telegram.org/bots/api#editmessagecaption
902
     *
903
     * @param array $data
904
     *
905
     * @return \Longman\TelegramBot\Entities\ServerResponse
906
     * @throws \Longman\TelegramBot\Exception\TelegramException
907
     */
908
    public static function editMessageCaption(array $data)
909
    {
910
        return self::send('editMessageCaption', $data);
911
    }
912
913
    /**
914
     * Use this method to edit only the reply markup of messages sent by the bot or via the bot (for inline bots).
915
     *
916
     * On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
917
     *
918
     * @link https://core.telegram.org/bots/api#editmessagereplymarkup
919
     *
920
     * @param array $data
921
     *
922
     * @return \Longman\TelegramBot\Entities\ServerResponse
923
     * @throws \Longman\TelegramBot\Exception\TelegramException
924
     */
925
    public static function editMessageReplyMarkup(array $data)
926
    {
927
        return self::send('editMessageReplyMarkup', $data);
928
    }
929
930
    /**
931
     * Use this method to send answers to an inline query. On success, True is returned.
932
     *
933
     * No more than 50 results per query are allowed.
934
     *
935
     * @link https://core.telegram.org/bots/api#answerinlinequery
936
     *
937
     * @param array $data
938
     *
939
     * @return \Longman\TelegramBot\Entities\ServerResponse
940
     * @throws \Longman\TelegramBot\Exception\TelegramException
941
     */
942
    public static function answerInlineQuery(array $data)
943
    {
944
        return self::send('answerInlineQuery', $data);
945
    }
946
947
    /**
948
     * Return an empty Server Response
949
     *
950
     * No request to telegram are sent, this function is used in commands that
951
     * don't need to fire a message after execution
952
     *
953
     * @return \Longman\TelegramBot\Entities\ServerResponse
954
     * @throws \Longman\TelegramBot\Exception\TelegramException
955
     */
956
    public static function emptyResponse()
957
    {
958
        return new ServerResponse(['ok' => true, 'result' => true], null);
959
    }
960
961
    /**
962
     * Send message to all active chats
963
     *
964
     * @param string  $callback_function
965
     * @param array   $data
966
     * @param boolean $send_groups
967
     * @param boolean $send_super_groups
968
     * @param boolean $send_users
969
     * @param string  $date_from
970
     * @param string  $date_to
971
     *
972
     * @return array
973
     * @throws \Longman\TelegramBot\Exception\TelegramException
974
     */
975
    public static function sendToActiveChats(
976
        $callback_function,
977
        array $data,
978
        $send_groups = true,
979
        $send_super_groups = true,
980
        $send_users = true,
981
        $date_from = null,
982
        $date_to = null
983
    ) {
984
        $callback_path = __NAMESPACE__ . '\Request';
985
        if (!method_exists($callback_path, $callback_function)) {
986
            throw new TelegramException('Method "' . $callback_function . '" not found in class Request.');
987
        }
988
989
        $chats = DB::selectChats($send_groups, $send_super_groups, $send_users, $date_from, $date_to);
990
991
        $results = [];
992
        if (is_array($chats)) {
993
            foreach ($chats as $row) {
994
                $data['chat_id'] = $row['chat_id'];
995
                $results[]       = call_user_func_array($callback_path . '::' . $callback_function, [$data]);
996
            }
997
        }
998
999
        return $results;
1000
    }
1001
1002
    /**
1003
     * Use this method to get current webhook status.
1004
     *
1005
     * @link https://core.telegram.org/bots/api#getwebhookinfo
1006
     *
1007
     * @return Entities\ServerResponse
1008
     * @throws \Longman\TelegramBot\Exception\TelegramException
1009
     */
1010
    public static function getWebhookInfo()
1011
    {
1012
        // Must send some arbitrary data for this to work for now...
1013
        return self::send('getWebhookInfo', ['info']);
1014
    }
1015
1016
    /**
1017
     * Enable request limiter
1018
     *
1019
     * @param boolean $value
1020
     * @param array   $options
1021
     *
1022
     * @throws \Longman\TelegramBot\Exception\TelegramException
1023
     */
1024
    public static function setLimiter($value = true, array $options = [])
1025
    {
1026
        if (DB::isDbConnected()) {
1027
            $options_default = [
1028
                'interval' => 1,
1029
            ];
1030
1031
            $options = array_merge($options_default, $options);
1032
1033
            if (!is_numeric($options['interval']) || $options['interval'] <= 0) {
1034
                throw new TelegramException('Interval must be a number and must be greater than zero!');
1035
            }
1036
1037
            self::$limiter_interval = $options['interval'];
0 ignored issues
show
Documentation Bug introduced by
It seems like $options['interval'] of type integer or double or string is incompatible with the declared type boolean of property $limiter_interval.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1038
            self::$limiter_enabled = $value;
1039
        }
1040
    }
1041
1042
    /**
1043
     * This functions delays API requests to prevent reaching Telegram API limits
1044
     *  Can be disabled while in execution by 'Request::setLimiter(false)'
1045
     *
1046
     * @link https://core.telegram.org/bots/faq#my-bot-is-hitting-limits-how-do-i-avoid-this
1047
     *
1048
     * @param string $action
1049
     * @param array  $data
1050
     *
1051
     * @throws \Longman\TelegramBot\Exception\TelegramException
1052
     */
1053
    private static function limitTelegramRequests($action, array $data = [])
1054
    {
1055
        if (self::$limiter_enabled) {
1056
            $limited_methods = [
1057
                'sendMessage',
1058
                'forwardMessage',
1059
                'sendPhoto',
1060
                'sendAudio',
1061
                'sendDocument',
1062
                'sendSticker',
1063
                'sendVideo',
1064
                'sendVoice',
1065
                'sendLocation',
1066
                'sendVenue',
1067
                'sendContact',
1068
                'editMessageText',
1069
                'editMessageCaption',
1070
                'editMessageReplyMarkup',
1071
            ];
1072
1073
            $chat_id = isset($data['chat_id']) ? $data['chat_id'] : null;
1074
            $inline_message_id = isset($data['inline_message_id']) ? $data['inline_message_id'] : null;
1075
1076
            if (($chat_id || $inline_message_id) && in_array($action, $limited_methods)) {
1077
                $timeout = 60;
1078
1079
                while (true) {
1080
                    if ($timeout <= 0) {
1081
                        throw new TelegramException('Timed out while waiting for a request spot!');
1082
                    }
1083
1084
                    $requests = DB::getTelegramRequestCount($chat_id, $inline_message_id);
1085
1086
                    if ($requests['LIMIT_PER_SEC'] == 0     // No more than one message per second inside a particular chat
1087
                        && ((($chat_id > 0 || $inline_message_id) && $requests['LIMIT_PER_SEC_ALL'] < 30)       // No more than 30 messages per second globally
1088
                        || ($chat_id < 0 && $requests['LIMIT_PER_MINUTE'] < 20))        // No more than 20 messages per minute in groups and channels
1089
                    ) {
1090
                        break;
1091
                    }
1092
1093
                    $timeout--;
1094
                    usleep(self::$limiter_interval * 1000000);
1095
                }
1096
1097
                DB::insertTelegramRequest($action, $data);
1098
            }
1099
        }
1100
    }
1101
}
1102