Completed
Push — bot_api_3.0 ( 7bd4af )
by Armando
08:48
created

Request::setWebhook()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

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