Test Failed
Pull Request — master (#247)
by
unknown
09:53
created

BotApi::sendAnimation()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 21

Duplication

Lines 21
Ratio 100 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 21
loc 21
ccs 0
cts 9
cp 0
rs 9.584
c 0
b 0
f 0
cc 1
nc 1
nop 8
crap 2

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace TelegramBot\Api;
4
5
use CURLFile;
6
use TelegramBot\Api\Types\ArrayOfChatMemberEntity;
7
use TelegramBot\Api\Types\ArrayOfMessages;
8
use TelegramBot\Api\Types\ArrayOfUpdates;
9
use TelegramBot\Api\Types\Chat;
10
use TelegramBot\Api\Types\ChatMember;
11
use TelegramBot\Api\Types\File;
12
use TelegramBot\Api\Types\Inline\QueryResult\AbstractInlineQueryResult;
13
use TelegramBot\Api\Types\InputMedia\ArrayOfInputMedia;
14
use TelegramBot\Api\Types\InputMedia\InputMedia;
15
use TelegramBot\Api\Types\Message;
16
use TelegramBot\Api\Types\Poll;
17
use TelegramBot\Api\Types\Update;
18
use TelegramBot\Api\Types\User;
19
use TelegramBot\Api\Types\UserProfilePhotos;
20
21
/**
22
 * Class BotApi
23
 *
24
 * @package TelegramBot\Api
25
 */
26
class BotApi
27
{
28
    /**
29
     * HTTP codes
30
     *
31
     * @var array
32
     */
33
    public static $codes = [
34
        // Informational 1xx
35
        100 => 'Continue',
36
        101 => 'Switching Protocols',
37
        102 => 'Processing',            // RFC2518
38
        // Success 2xx
39
        200 => 'OK',
40
        201 => 'Created',
41
        202 => 'Accepted',
42
        203 => 'Non-Authoritative Information',
43
        204 => 'No Content',
44
        205 => 'Reset Content',
45
        206 => 'Partial Content',
46
        207 => 'Multi-Status',          // RFC4918
47
        208 => 'Already Reported',      // RFC5842
48
        226 => 'IM Used',               // RFC3229
49
        // Redirection 3xx
50
        300 => 'Multiple Choices',
51
        301 => 'Moved Permanently',
52
        302 => 'Found', // 1.1
53
        303 => 'See Other',
54
        304 => 'Not Modified',
55
        305 => 'Use Proxy',
56
        // 306 is deprecated but reserved
57
        307 => 'Temporary Redirect',
58
        308 => 'Permanent Redirect',    // RFC7238
59
        // Client Error 4xx
60
        400 => 'Bad Request',
61
        401 => 'Unauthorized',
62
        402 => 'Payment Required',
63
        403 => 'Forbidden',
64
        404 => 'Not Found',
65
        405 => 'Method Not Allowed',
66
        406 => 'Not Acceptable',
67
        407 => 'Proxy Authentication Required',
68
        408 => 'Request Timeout',
69
        409 => 'Conflict',
70
        410 => 'Gone',
71
        411 => 'Length Required',
72
        412 => 'Precondition Failed',
73
        413 => 'Payload Too Large',
74
        414 => 'URI Too Long',
75
        415 => 'Unsupported Media Type',
76
        416 => 'Range Not Satisfiable',
77
        417 => 'Expectation Failed',
78
        422 => 'Unprocessable Entity',                                        // RFC4918
79
        423 => 'Locked',                                                      // RFC4918
80
        424 => 'Failed Dependency',                                           // RFC4918
81
        425 => 'Reserved for WebDAV advanced collections expired proposal',   // RFC2817
82
        426 => 'Upgrade Required',                                            // RFC2817
83
        428 => 'Precondition Required',                                       // RFC6585
84
        429 => 'Too Many Requests',                                           // RFC6585
85
        431 => 'Request Header Fields Too Large',                             // RFC6585
86
        // Server Error 5xx
87
        500 => 'Internal Server Error',
88
        501 => 'Not Implemented',
89
        502 => 'Bad Gateway',
90
        503 => 'Service Unavailable',
91
        504 => 'Gateway Timeout',
92
        505 => 'HTTP Version Not Supported',
93
        506 => 'Variant Also Negotiates (Experimental)',                      // RFC2295
94
        507 => 'Insufficient Storage',                                        // RFC4918
95
        508 => 'Loop Detected',                                               // RFC5842
96
        510 => 'Not Extended',                                                // RFC2774
97
        511 => 'Network Authentication Required',                             // RFC6585
98
    ];
99
100
    private $proxySettings = [];
101
102
    /**
103
     * Default http status code
104
     */
105
    const DEFAULT_STATUS_CODE = 200;
106
107
    /**
108
     * Not Modified http status code
109
     */
110
    const NOT_MODIFIED_STATUS_CODE = 304;
111
112
    /**
113
     * Limits for tracked ids
114
     */
115
    const MAX_TRACKED_EVENTS = 200;
116
117
    /**
118
     * Url prefixes
119
     */
120
    const URL_PREFIX = 'https://api.telegram.org/bot';
121
122
    /**
123
     * Url prefix for files
124
     */
125
    const FILE_URL_PREFIX = 'https://api.telegram.org/file/bot';
126
127
    /**
128
     * CURL object
129
     *
130
     * @var
131
     */
132
    protected $curl;
133
134
    /**
135
     * CURL custom options
136
     *
137
     * @var array
138
     */
139
    protected $customCurlOptions = [];
140
141
    /**
142
     * Bot token
143
     *
144
     * @var string
145
     */
146
    protected $token;
147
148
    /**
149
     * Botan tracker
150
     *
151
     * @var Botan
152
     */
153
    protected $tracker;
154
155
    /**
156
     * list of event ids
157
     *
158
     * @var array
159
     */
160
    protected $trackedEvents = [];
161
162
    /**
163
     * Check whether return associative array
164
     *
165
     * @var bool
166
     */
167
    protected $returnArray = true;
168
169
    /**
170
     * Constructor
171
     *
172
     * @param string $token Telegram Bot API token
173 9
     * @param string|null $trackerToken Yandex AppMetrica application api_key
174
     * @throws \Exception
175 9
     */
176 9
    public function __construct($token, $trackerToken = null)
177
    {
178 9
        $this->curl = curl_init();
179
        $this->token = $token;
180
181 9
        if ($trackerToken) {
182
            $this->tracker = new Botan($trackerToken);
183
        }
184
    }
185
186
    /**
187
     * Set return array
188
     *
189
     * @param bool $mode
190
     *
191
     * @return $this
192
     */
193
    public function setModeObject($mode = true)
194
    {
195
        $this->returnArray = !$mode;
196
197
        return $this;
198
    }
199
200
    /**
201
     * Call method
202
     *
203
     * @param string $method
204
     * @param array|null $data
205
     *
206
     * @return mixed
207
     * @throws Exception
208
     * @throws HttpException
209
     * @throws InvalidJsonException
210
     *
211
     */
212
    public function call($method, array $data = null)
213
    {
214
        $options = $this->proxySettings + [
215
            CURLOPT_URL => $this->getUrl().'/'.$method,
216
            CURLOPT_RETURNTRANSFER => true,
217
            CURLOPT_POST => null,
218
            CURLOPT_POSTFIELDS => null,
219
            CURLOPT_TIMEOUT => 5,
220
        ];
221
222
        if ($data) {
223
            $options[CURLOPT_POST] = true;
224
            $options[CURLOPT_POSTFIELDS] = http_build_query($data);
225
        }
226
227
        if (!empty($this->customCurlOptions) && is_array($this->customCurlOptions)) {
228
            $options = $this->customCurlOptions + $options;
229
        }
230
231
        $response = self::jsonValidate($this->executeCurl($options), $this->returnArray);
232
233
        if ($this->returnArray) {
234
            if (!isset($response['ok']) || !$response['ok']) {
235
                throw new Exception($response['description'], $response['error_code']);
236
            }
237
238
            return $response['result'];
239
        }
240
241
        if (!$response->ok) {
242
            throw new Exception($response->description, $response->error_code);
243
        }
244
245
        return $response->result;
246
    }
247
248
    /**
249
     * curl_exec wrapper for response validation
250
     *
251
     * @param array $options
252
     *
253
     * @return string
254
     *
255
     * @throws HttpException
256
     */
257
    protected function executeCurl(array $options)
258
    {
259
        curl_setopt_array($this->curl, $options);
260
261
        $result = curl_exec($this->curl);
262
        self::curlValidate($this->curl, $result);
263
        if ($result === false) {
264
            throw new HttpException(curl_error($this->curl), curl_errno($this->curl));
265
        }
266
267
        return $result;
268
    }
269
270
    /**
271
     * Response validation
272
     *
273
     * @param resource $curl
274
     * @param string $response
275
     * @throws HttpException
276
     */
277
    public static function curlValidate($curl, $response = null)
278
    {
279
        $json = json_decode($response, true)?: [];
280
        if (($httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE))
281
            && !in_array($httpCode, [self::DEFAULT_STATUS_CODE, self::NOT_MODIFIED_STATUS_CODE], true)
282
        ) {
283
            $errorDescription = array_key_exists('description', $json) ? $json['description'] : self::$codes[$httpCode];
284
            $errorParameters = array_key_exists('parameters', $json) ? $json['parameters'] : [];
285
            throw new HttpException($errorDescription, $httpCode, null, $errorParameters);
286
        }
287
    }
288
289
    /**
290
     * JSON validation
291
     *
292
     * @param string $jsonString
293
     * @param boolean $asArray
294
     *
295
     * @return object|array|null
296
     * @throws InvalidJsonException
297
     */
298
    public static function jsonValidate($jsonString, $asArray)
299
    {
300
        $json = json_decode($jsonString, $asArray);
301
302
        if (json_last_error() !== JSON_ERROR_NONE) {
303
            throw new InvalidJsonException(json_last_error_msg(), json_last_error());
304
        }
305
306
        return $json;
307
    }
308
309
    /**
310
     * Use this method to send text messages. On success, the sent \TelegramBot\Api\Types\Message is returned.
311
     *
312
     * @param int|string $chatId
313
     * @param string $text
314
     * @param string|null $parseMode
315
     * @param bool $disablePreview
316
     * @param int|null $replyToMessageId
317
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
318
     *        Types\ReplyKeyboardRemove|null $replyMarkup
319
     * @param bool $disableNotification
320
     *
321
     * @return Message
322
     * @throws Exception
323
     */
324
    public function sendMessage(
325
        $chatId,
326
        $text,
327
        $parseMode = null,
328
        $disablePreview = false,
329
        $replyToMessageId = null,
330
        $replyMarkup = null,
331
        $disableNotification = false
332
    ) {
333
        return Message::fromResponse($this->call('sendMessage', [
334
            'chat_id' => $chatId,
335
            'text' => $text,
336
            'parse_mode' => $parseMode,
337
            'disable_web_page_preview' => $disablePreview,
338
            'reply_to_message_id' => (int)$replyToMessageId,
339
            'reply_markup' => $replyMarkup,
340
            'disable_notification' => (bool)$disableNotification,
341
        ]));
342
    }
343
344
    /**
345
     * Use this method to send phone contacts
346
     *
347
     * @param int|string $chatId chat_id or @channel_name
348
     * @param string $phoneNumber
349
     * @param string $firstName
350
     * @param string $lastName
351
     * @param int|null $replyToMessageId
352
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
353
     *        Types\ReplyKeyboardRemove|null $replyMarkup
354
     * @param bool $disableNotification
355
     *
356
     * @return Message
357
     * @throws Exception
358
     */
359
    public function sendContact(
360
        $chatId,
361
        $phoneNumber,
362
        $firstName,
363
        $lastName = null,
364
        $replyToMessageId = null,
365
        $replyMarkup = null,
366
        $disableNotification = false
367
    ) {
368
        return Message::fromResponse($this->call('sendContact', [
369
            'chat_id' => $chatId,
370
            'phone_number' => $phoneNumber,
371
            'first_name' => $firstName,
372
            'last_name' => $lastName,
373
            'reply_to_message_id' => $replyToMessageId,
374
            'reply_markup' => $replyMarkup,
375
            'disable_notification' => (bool)$disableNotification,
376
        ]));
377
    }
378
379
    /**
380
     * Use this method when you need to tell the user that something is happening on the bot's side.
381
     * The status is set for 5 seconds or less (when a message arrives from your bot,
382
     * Telegram clients clear its typing status).
383
     *
384
     * We only recommend using this method when a response from the bot will take a noticeable amount of time to arrive.
385
     *
386
     * Type of action to broadcast. Choose one, depending on what the user is about to receive:
387
     * `typing` for text messages, `upload_photo` for photos, `record_video` or `upload_video` for videos,
388
     * `record_audio` or upload_audio for audio files, `upload_document` for general files,
389
     * `find_location` for location data.
390
     *
391
     * @param int $chatId
392
     * @param string $action
393
     *
394
     * @return bool
395
     * @throws Exception
396
     */
397
    public function sendChatAction($chatId, $action)
398
    {
399
        return $this->call('sendChatAction', [
400
            'chat_id' => $chatId,
401
            'action' => $action,
402
        ]);
403
    }
404
405
    /**
406
     * Use this method to get a list of profile pictures for a user.
407
     *
408
     * @param int $userId
409
     * @param int $offset
410
     * @param int $limit
411
     *
412
     * @return UserProfilePhotos
413
     * @throws Exception
414
     */
415
    public function getUserProfilePhotos($userId, $offset = 0, $limit = 100)
416
    {
417
        return UserProfilePhotos::fromResponse($this->call('getUserProfilePhotos', [
418
            'user_id' => (int)$userId,
419
            'offset' => (int)$offset,
420
            'limit' => (int)$limit,
421
        ]));
422
    }
423
424
    /**
425
     * Use this method to specify a url and receive incoming updates via an outgoing webhook.
426
     * Whenever there is an update for the bot, we will send an HTTPS POST request to the specified url,
427
     * containing a JSON-serialized Update.
428
     * In case of an unsuccessful request, we will give up after a reasonable amount of attempts.
429
     *
430
     * @param string $url HTTPS url to send updates to. Use an empty string to remove webhook integration
431
     * @param CURLFile|string $certificate Upload your public key certificate
432
     *                                      so that the root certificate in use can be checked
433
     *
434
     * @return string
435
     *
436
     * @throws Exception
437
     */
438
    public function setWebhook($url = '', $certificate = null)
439
    {
440
        return $this->call('setWebhook', ['url' => $url, 'certificate' => $certificate]);
441
    }
442
443
    /**
444
     * Use this method to clear webhook and use getUpdates again!
445
     *
446
     * @return mixed
447
     *
448
     * @throws Exception
449
     */
450
    public function deleteWebhook()
451
    {
452
        return $this->call('deleteWebhook');
453
    }
454
455
    /**
456
     * A simple method for testing your bot's auth token.Requires no parameters.
457
     * Returns basic information about the bot in form of a User object.
458
     *
459
     * @return User
460
     * @throws Exception
461
     * @throws InvalidArgumentException
462
     */
463
    public function getMe()
464
    {
465
        return User::fromResponse($this->call('getMe'));
466
    }
467
468
    /**
469
     * Use this method to receive incoming updates using long polling.
470
     * An Array of Update objects is returned.
471
     *
472
     * Notes
473
     * 1. This method will not work if an outgoing webhook is set up.
474
     * 2. In order to avoid getting duplicate updates, recalculate offset after each server response.
475
     *
476
     * @param int $offset
477
     * @param int $limit
478
     * @param int $timeout
479
     *
480
     * @return Update[]
481
     * @throws Exception
482
     * @throws InvalidArgumentException
483 2
     */
484
    public function getUpdates($offset = 0, $limit = 100, $timeout = 0)
485 2
    {
486 2
        $updates = ArrayOfUpdates::fromResponse($this->call('getUpdates', [
487 2
            'offset' => $offset,
488 2
            'limit' => $limit,
489 2
            'timeout' => $timeout,
490
        ]));
491 2
492
        if ($this->tracker instanceof Botan) {
493
            foreach ($updates as $update) {
494
                $this->trackUpdate($update);
495
            }
496
        }
497 2
498
        return $updates;
499
    }
500
501
    /**
502
     * Use this method to send point on the map. On success, the sent Message is returned.
503
     *
504
     * @param int|string $chatId
505
     * @param float $latitude
506
     * @param float $longitude
507
     * @param int|null $replyToMessageId
508
     * @param null $replyMarkup
509
     * @param bool $disableNotification
510
     *
511
     * @param null|int $livePeriod
512
     * @return Message
513
     * @throws Exception
514
     * @throws HttpException
515
     * @throws InvalidJsonException
516
     */
517
    public function sendLocation(
518
        $chatId,
519
        $latitude,
520
        $longitude,
521
        $replyToMessageId = null,
522
        $replyMarkup = null,
523
        $disableNotification = false,
524
        $livePeriod = null
525
    ) {
526
        return Message::fromResponse($this->call('sendLocation', [
527
            'chat_id'              => $chatId,
528
            'latitude'             => $latitude,
529
            'longitude'            => $longitude,
530
            'live_period'          => $livePeriod,
531
            'reply_to_message_id'  => $replyToMessageId,
532
            'reply_markup'         => $replyMarkup,
533
            'disable_notification' => (bool)$disableNotification,
534
        ]));
535
    }
536
537
    /**
538
     * Use this method to edit live location messages sent by the bot or via the bot (for inline bots).
539
     *
540
     * @param int|string $chatId
541
     * @param int $messageId
542
     * @param string $inlineMessageId
543
     * @param float $latitude
544
     * @param float $longitude
545
     * @param null $replyMarkup
546
     * @return Message
547
     * @throws Exception
548
     * @throws HttpException
549
     * @throws InvalidJsonException
550
     */
551
    public function editMessageLiveLocation(
552
        $chatId,
553
        $messageId,
554
        $inlineMessageId,
555
        $latitude,
556
        $longitude,
557
        $replyMarkup = null
558
    ) {
559
        return Message::fromResponse($this->call('sendLocation', [
560
            'chat_id'           => $chatId,
561
            'message_id'        => $messageId,
562
            'inline_message_id' => $inlineMessageId,
563
            'latitude'          => $latitude,
564
            'longitude'         => $longitude,
565
            'reply_markup'      => $replyMarkup,
566
        ]));
567
    }
568
569
    /**
570
     * Use this method to stop updating a live location message sent by the bot or via the bot (for inline bots) before
571
     * live_period expires.
572
     *
573
     * @param int|string $chatId
574
     * @param int $messageId
575
     * @param string $inlineMessageId
576
     * @param null $replyMarkup
577
     * @return Message
578
     * @throws Exception
579
     * @throws HttpException
580
     * @throws InvalidJsonException
581
     */
582 View Code Duplication
    public function stopMessageLiveLocation(
583
        $chatId,
584
        $messageId,
585
        $inlineMessageId,
586
        $replyMarkup = null
587
    ) {
588
        return Message::fromResponse($this->call('sendLocation', [
589
            'chat_id'           => $chatId,
590
            'message_id'        => $messageId,
591
            'inline_message_id' => $inlineMessageId,
592
            'reply_markup'      => $replyMarkup,
593
        ]));
594
    }
595
596
    /**
597
     * Use this method to send information about a venue. On success, the sent Message is returned.
598
     *
599
     * @param int|string $chatId chat_id or @channel_name
600
     * @param float $latitude
601
     * @param float $longitude
602
     * @param string $title
603
     * @param string $address
604
     * @param string|null $foursquareId
605
     * @param int|null $replyToMessageId
606
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
607
     *        Types\ReplyKeyboardRemove|null $replyMarkup
608
     * @param bool $disableNotification
609
     *
610
     * @return Message
611
     * @throws Exception
612
     */
613
    public function sendVenue(
614
        $chatId,
615
        $latitude,
616
        $longitude,
617
        $title,
618
        $address,
619
        $foursquareId = null,
620
        $replyToMessageId = null,
621
        $replyMarkup = null,
622
        $disableNotification = false
623
    ) {
624
        return Message::fromResponse($this->call('sendVenue', [
625
            'chat_id' => $chatId,
626
            'latitude' => $latitude,
627
            'longitude' => $longitude,
628
            'title' => $title,
629
            'address' => $address,
630
            'foursquare_id' => $foursquareId,
631
            'reply_to_message_id' => $replyToMessageId,
632
            'reply_markup' => $replyMarkup,
633
            'disable_notification' => (bool)$disableNotification,
634
        ]));
635
    }
636
637
    /**
638
     * Use this method to send .webp stickers. On success, the sent Message is returned.
639
     *
640
     * @param int|string $chatId chat_id or @channel_name
641
     * @param CURLFile|string $sticker
642
     * @param int|null $replyToMessageId
643
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
644
     *        Types\ReplyKeyboardRemove|null $replyMarkup
645
     * @param bool $disableNotification
646
     *
647
     * @return Message
648
     * @throws Exception
649
     */
650
    public function sendSticker(
651
        $chatId,
652
        $sticker,
653
        $replyToMessageId = null,
654
        $replyMarkup = null,
655
        $disableNotification = false
656
    ) {
657
        return Message::fromResponse($this->call('sendSticker', [
658
            'chat_id' => $chatId,
659
            'sticker' => $sticker,
660
            'reply_to_message_id' => $replyToMessageId,
661
            'reply_markup' => $replyMarkup,
662
            'disable_notification' => (bool)$disableNotification,
663
        ]));
664
    }
665
666
    /**
667
     * Use this method to send video files,
668
     * Telegram clients support mp4 videos (other formats may be sent as Document).
669
     * On success, the sent Message is returned.
670
     *
671
     * @param int|string $chatId chat_id or @channel_name
672
     * @param CURLFile|string $video
673
     * @param int|null $duration
674
     * @param string|null $caption
675
     * @param int|null $replyToMessageId
676
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
677
     *        Types\ReplyKeyboardRemove|null $replyMarkup
678
     * @param bool $disableNotification
679
     * @param bool $supportsStreaming Pass True, if the uploaded video is suitable for streaming
680
     * @param string|null $parseMode
681
     *
682
     * @return Message
683
     * @throws Exception
684
     */
685 View Code Duplication
    public function sendVideo(
686
        $chatId,
687
        $video,
688
        $duration = null,
689
        $caption = null,
690
        $replyToMessageId = null,
691
        $replyMarkup = null,
692
        $disableNotification = false,
693
        $supportsStreaming = false,
694
        $parseMode = null
695
    ) {
696
        return Message::fromResponse($this->call('sendVideo', [
697
            'chat_id' => $chatId,
698
            'video' => $video,
699
            'duration' => $duration,
700
            'caption' => $caption,
701
            'reply_to_message_id' => $replyToMessageId,
702
            'reply_markup' => $replyMarkup,
703
            'disable_notification' => (bool)$disableNotification,
704
            'supports_streaming' => (bool)$supportsStreaming,
705
            'parse_mode' => $parseMode
706
        ]));
707
    }
708
709
    /**
710
     * Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound),
711
     * On success, the sent Message is returned.
712
     * Bots can currently send animation files of up to 50 MB in size, this limit may be changed in the future.
713
     *
714
     * @param int|string $chatId chat_id or @channel_name
715
     * @param CURLFile|string $animation
716
     * @param int|null $duration
717
     * @param string|null $caption
718
     * @param int|null $replyToMessageId
719
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
720
     *        Types\ReplyKeyboardRemove|null $replyMarkup
721
     * @param bool $disableNotification
722
     * @param string|null $parseMode
723
     *
724
     * @return Message
725
     * @throws Exception
726
     */
727 View Code Duplication
    public function sendAnimation(
728
        $chatId,
729
        $animation,
730
        $duration = null,
731
        $caption = null,
732
        $replyToMessageId = null,
733
        $replyMarkup = null,
734
        $disableNotification = false,
735
        $parseMode = null
736
    ) {
737
        return Message::fromResponse($this->call('sendAnimation', [
738
            'chat_id' => $chatId,
739
            'animation' => $animation,
740
            'duration' => $duration,
741
            'caption' => $caption,
742
            'reply_to_message_id' => $replyToMessageId,
743
            'reply_markup' => $replyMarkup,
744
            'disable_notification' => (bool)$disableNotification,
745
            'parse_mode' => $parseMode
746
        ]));
747
    }
748
749
    /**
750
     * Use this method to send audio files,
751
     * if you want Telegram clients to display the file as a playable voice message.
752
     * For this to work, your audio must be in an .ogg file encoded with OPUS
753
     * (other formats may be sent as Audio or Document).
754
     * On success, the sent Message is returned.
755
     * Bots can currently send voice messages of up to 50 MB in size, this limit may be changed in the future.
756
     *
757
     * @param int|string $chatId chat_id or @channel_name
758
     * @param CURLFile|string $voice
759
     * @param int|null $duration
760
     * @param int|null $replyToMessageId
761
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
762
     *        Types\ReplyKeyboardRemove|null $replyMarkup
763
     * @param bool $disableNotification
764
     * @param string|null $parseMode
765
     *
766
     * @return Message
767
     * @throws Exception
768
     */
769
    public function sendVoice(
770
        $chatId,
771
        $voice,
772
        $duration = null,
773
        $replyToMessageId = null,
774
        $replyMarkup = null,
775
        $disableNotification = false,
776
        $parseMode = null
777
    ) {
778
        return Message::fromResponse($this->call('sendVoice', [
779
            'chat_id' => $chatId,
780
            'voice' => $voice,
781
            'duration' => $duration,
782
            'reply_to_message_id' => $replyToMessageId,
783
            'reply_markup' => $replyMarkup,
784
            'disable_notification' => (bool)$disableNotification,
785
            'parse_mode' => $parseMode
786
        ]));
787
    }
788
789
    /**
790
     * Use this method to forward messages of any kind. On success, the sent Message is returned.
791
     *
792
     * @param int|string $chatId chat_id or @channel_name
793
     * @param int $fromChatId
794
     * @param int $messageId
795
     * @param bool $disableNotification
796
     *
797
     * @return Message
798
     * @throws Exception
799
     */
800
    public function forwardMessage($chatId, $fromChatId, $messageId, $disableNotification = false)
801
    {
802
        return Message::fromResponse($this->call('forwardMessage', [
803
            'chat_id' => $chatId,
804
            'from_chat_id' => $fromChatId,
805
            'message_id' => (int)$messageId,
806
            'disable_notification' => (bool)$disableNotification,
807
        ]));
808
    }
809
810
    /**
811
     * Use this method to send audio files,
812
     * if you want Telegram clients to display them in the music player.
813
     * Your audio must be in the .mp3 format.
814
     * On success, the sent Message is returned.
815
     * Bots can currently send audio files of up to 50 MB in size, this limit may be changed in the future.
816
     *
817
     * For backward compatibility, when the fields title and performer are both empty
818
     * and the mime-type of the file to be sent is not audio/mpeg, the file will be sent as a playable voice message.
819
     * For this to work, the audio must be in an .ogg file encoded with OPUS.
820
     * This behavior will be phased out in the future. For sending voice messages, use the sendVoice method instead.
821
     *
822
     * @param int|string $chatId chat_id or @channel_name
823
     * @param CURLFile|string $audio
824
     * @param int|null $duration
825
     * @param string|null $performer
826
     * @param string|null $title
827
     * @param int|null $replyToMessageId
828
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
829
     *        Types\ReplyKeyboardRemove|null $replyMarkup
830
     * @param bool $disableNotification
831
     * @param string|null $parseMode
832
     *
833
     * @return Message
834
     * @throws Exception
835
     *@deprecated since 20th February. Removed backward compatibility from the method sendAudio.
836
     * Voice messages now must be sent using the method sendVoice.
837
     * There is no more need to specify a non-empty title or performer while sending the audio by file_id.
838
     *
839
     */
840 View Code Duplication
    public function sendAudio(
841
        $chatId,
842
        $audio,
843
        $duration = null,
844
        $performer = null,
845
        $title = null,
846
        $replyToMessageId = null,
847
        $replyMarkup = null,
848
        $disableNotification = false,
849
        $parseMode = null
850
    ) {
851
        return Message::fromResponse($this->call('sendAudio', [
852
            'chat_id' => $chatId,
853
            'audio' => $audio,
854
            'duration' => $duration,
855
            'performer' => $performer,
856
            'title' => $title,
857
            'reply_to_message_id' => $replyToMessageId,
858
            'reply_markup' => $replyMarkup,
859
            'disable_notification' => (bool)$disableNotification,
860
            'parse_mode' => $parseMode
861
        ]));
862
    }
863
864
    /**
865
     * Use this method to send photos. On success, the sent Message is returned.
866
     *
867
     * @param int|string $chatId chat_id or @channel_name
868
     * @param CURLFile|string $photo
869
     * @param string|null $caption
870
     * @param int|null $replyToMessageId
871
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
872
     *        Types\ReplyKeyboardRemove|null $replyMarkup
873
     * @param bool $disableNotification
874
     * @param string|null $parseMode
875
     *
876
     * @return Message
877
     * @throws Exception
878
     */
879
    public function sendPhoto(
880
        $chatId,
881
        $photo,
882
        $caption = null,
883
        $replyToMessageId = null,
884
        $replyMarkup = null,
885
        $disableNotification = false,
886
        $parseMode = null
887
    ) {
888
        return Message::fromResponse($this->call('sendPhoto', [
889
            'chat_id' => $chatId,
890
            'photo' => $photo,
891
            'caption' => $caption,
892
            'reply_to_message_id' => $replyToMessageId,
893
            'reply_markup' => $replyMarkup,
894
            'disable_notification' => (bool)$disableNotification,
895
            'parse_mode' => $parseMode
896
        ]));
897
    }
898
899
    /**
900
     * Use this method to send general files. On success, the sent Message is returned.
901
     * Bots can currently send files of any type of up to 50 MB in size, this limit may be changed in the future.
902
     *
903
     * @param int|string $chatId chat_id or @channel_name
904
     * @param CURLFile|string $document
905
     * @param string|null $caption
906
     * @param int|null $replyToMessageId
907
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
908
     *        Types\ReplyKeyboardRemove|null $replyMarkup
909
     * @param bool $disableNotification
910
     * @param string|null $parseMode
911
     *
912
     * @return Message
913
     * @throws Exception
914
     */
915
    public function sendDocument(
916
        $chatId,
917
        $document,
918
        $caption = null,
919
        $replyToMessageId = null,
920
        $replyMarkup = null,
921
        $disableNotification = false,
922
        $parseMode = null
923
    ) {
924
        return Message::fromResponse($this->call('sendDocument', [
925
            'chat_id' => $chatId,
926
            'document' => $document,
927
            'caption' => $caption,
928
            'reply_to_message_id' => $replyToMessageId,
929
            'reply_markup' => $replyMarkup,
930
            'disable_notification' => (bool)$disableNotification,
931
            'parse_mode' => $parseMode
932
        ]));
933
    }
934
935
    /**
936
     * Use this method to get basic info about a file and prepare it for downloading.
937
     * For the moment, bots can download files of up to 20MB in size.
938
     * On success, a File object is returned.
939
     * The file can then be downloaded via the link https://api.telegram.org/file/bot<token>/<file_path>,
940
     * where <file_path> is taken from the response.
941
     * It is guaranteed that the link will be valid for at least 1 hour.
942
     * When the link expires, a new one can be requested by calling getFile again.
943
     *
944
     * @param $fileId
945
     *
946
     * @return File
947
     * @throws Exception
948
     */
949
    public function getFile($fileId)
950
    {
951
        return File::fromResponse($this->call('getFile', ['file_id' => $fileId]));
952
    }
953
954
    /**
955
     * Get file contents via cURL
956
     *
957
     * @param $fileId
958
     *
959
     * @return string
960
     *
961
     * @throws HttpException
962
     * @throws Exception
963
     */
964
    public function downloadFile($fileId)
965
    {
966
        $file = $this->getFile($fileId);
967
        $options = [
968
            CURLOPT_HEADER => 0,
969
            CURLOPT_HTTPGET => 1,
970
            CURLOPT_RETURNTRANSFER => 1,
971
            CURLOPT_URL => $this->getFileUrl().'/'.$file->getFilePath(),
972
        ];
973
974
        return $this->executeCurl($options);
975
    }
976
977
    /**
978
     * Use this method to send answers to an inline query. On success, True is returned.
979
     * No more than 50 results per query are allowed.
980
     *
981
     * @param string $inlineQueryId
982
     * @param AbstractInlineQueryResult[] $results
983
     * @param int $cacheTime
984
     * @param bool $isPersonal
985
     * @param string $nextOffset
986
     * @param string $switchPmText
987
     * @param string $switchPmParameter
988
     *
989
     * @return mixed
990
     * @throws Exception
991
     */
992
    public function answerInlineQuery(
993
        $inlineQueryId,
994
        $results,
995
        $cacheTime = 300,
996
        $isPersonal = false,
997
        $nextOffset = '',
998
        $switchPmText = null,
999
        $switchPmParameter = null
1000
    ) {
1001
        $results = array_map(function ($item) {
1002
            /* @var AbstractInlineQueryResult $item */
1003
            return json_decode($item->toJson(), true);
1004
        }, $results);
1005
1006
        return $this->call('answerInlineQuery', [
1007
            'inline_query_id' => $inlineQueryId,
1008
            'results' => json_encode($results),
1009
            'cache_time' => $cacheTime,
1010
            'is_personal' => $isPersonal,
1011
            'next_offset' => $nextOffset,
1012
            'switch_pm_text' => $switchPmText,
1013
            'switch_pm_parameter' => $switchPmParameter,
1014
        ]);
1015
    }
1016
1017
    /**
1018
     * Use this method to kick a user from a group or a supergroup.
1019
     * In the case of supergroups, the user will not be able to return to the group
1020
     * on their own using invite links, etc., unless unbanned first.
1021
     * The bot must be an administrator in the group for this to work. Returns True on success.
1022
     *
1023
     * @param int|string $chatId Unique identifier for the target group
1024
     * or username of the target supergroup (in the format @supergroupusername)
1025
     * @param int $userId Unique identifier of the target user
1026
     * @param null|int $untilDate Date when the user will be unbanned, unix time.
1027
     *                            If user is banned for more than 366 days or less than 30 seconds from the current time
1028
     *                            they are considered to be banned forever
1029
     *
1030
     * @return bool
1031
     * @throws Exception
1032
     * @throws HttpException
1033
     * @throws InvalidJsonException
1034
     */
1035
    public function kickChatMember($chatId, $userId, $untilDate = null)
1036
    {
1037
        return $this->call('kickChatMember', [
1038
            'chat_id' => $chatId,
1039
            'user_id' => $userId,
1040
            'until_date' => $untilDate
1041
        ]);
1042
    }
1043
1044
    /**
1045
     * Use this method to unban a previously kicked user in a supergroup.
1046
     * The user will not return to the group automatically, but will be able to join via link, etc.
1047
     * The bot must be an administrator in the group for this to work. Returns True on success.
1048
     *
1049
     * @param int|string $chatId Unique identifier for the target group
1050
     * or username of the target supergroup (in the format @supergroupusername)
1051
     * @param int $userId Unique identifier of the target user
1052
     *
1053
     * @return bool
1054
     * @throws Exception
1055
     * @throws HttpException
1056
     * @throws InvalidJsonException
1057
     */
1058
    public function unbanChatMember($chatId, $userId)
1059
    {
1060
        return $this->call('unbanChatMember', [
1061
            'chat_id' => $chatId,
1062
            'user_id' => $userId,
1063
        ]);
1064
    }
1065
1066
    /**
1067
     * Use this method to send answers to callback queries sent from inline keyboards.
1068
     * The answer will be displayed to the user as a notification at the top of the chat screen or as an alert.
1069
     *
1070
     * @param $callbackQueryId
1071
     * @param null $text
1072
     * @param bool $showAlert
1073
     *
1074
     * @return bool
1075
     * @throws Exception
1076
     * @throws HttpException
1077
     * @throws InvalidJsonException
1078
     */
1079
    public function answerCallbackQuery($callbackQueryId, $text = null, $showAlert = false)
1080
    {
1081
        return $this->call('answerCallbackQuery', [
1082
            'callback_query_id' => $callbackQueryId,
1083
            'text' => $text,
1084
            'show_alert' => (bool)$showAlert,
1085
        ]);
1086
    }
1087
1088
    /**
1089
     * Use this method to edit text messages sent by the bot or via the bot
1090
     *
1091
     * @param int|string $chatId
1092
     * @param int $messageId
1093
     * @param string $text
1094
     * @param string|null $parseMode
1095
     * @param bool $disablePreview
1096
     * @param null $replyMarkup
1097
     * @param string $inlineMessageId
1098
     * @return Message
1099
     * @throws Exception
1100
     * @throws HttpException
1101
     * @throws InvalidJsonException
1102
     */
1103
    public function editMessageText(
1104
        $chatId,
1105
        $messageId,
1106
        $text,
1107
        $parseMode = null,
1108
        $disablePreview = false,
1109
        $replyMarkup = null,
1110
        $inlineMessageId = null
1111
    ) {
1112
        return Message::fromResponse($this->call('editMessageText', [
1113
            'chat_id' => $chatId,
1114
            'message_id' => $messageId,
1115
            'text' => $text,
1116
            'inline_message_id' => $inlineMessageId,
1117
            'parse_mode' => $parseMode,
1118
            'disable_web_page_preview' => $disablePreview,
1119
            'reply_markup' => $replyMarkup,
1120
        ]));
1121
    }
1122
1123
    /**
1124
     * Use this method to edit captions of messages.
1125
     * On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
1126
     *
1127
     * @param int|string $chatId
1128
     * @param int $messageId
1129
     * @param string|null $caption
1130
     * @param null $parseMode
1131
     * @param null $replyMarkup
1132
     * @param string $inlineMessageId
1133
     *
1134
     * @return Message
1135
     * @throws Exception
1136
     * @throws HttpException
1137
     * @throws InvalidJsonException
1138
     */
1139
    public function editMessageCaption(
1140
        $chatId,
1141
        $messageId,
1142
        $caption = null,
1143
        $parseMode = null,
1144
        $replyMarkup = null,
1145
        $inlineMessageId = null
1146
    ) {
1147
        return Message::fromResponse($this->call('editMessageCaption', [
1148
            'chat_id' => $chatId,
1149
            'message_id' => $messageId,
1150
            'inline_message_id' => $inlineMessageId,
1151
            'caption' => $caption,
1152
            'parse_mode' => $parseMode,
1153
            'reply_markup' => $replyMarkup,
1154
        ]));
1155
    }
1156
1157 View Code Duplication
    public function editMessageMedia(
1158
        $chatId,
1159
        $messageId,
1160
        InputMedia $media,
1161
        $inlineMessageId = null,
1162
        $replyMarkup = null
1163
    ) {
1164
        return Message::fromResponse($this->call('editMessageMedia', [
1165
            'chat_id' => $chatId,
1166
            'message_id' => $messageId,
1167
            'inline_message_id' => $inlineMessageId,
1168
            'media' => $media->toJson(),
1169
            'reply_markup' => $replyMarkup,
1170
        ]));
1171
    }
1172
1173
    /**
1174
     * Use this method to edit only the reply markup of messages sent by the bot or via the bot
1175
     *
1176
     * @param int|string $chatId
1177
     * @param int $messageId
1178
     * @param null $replyMarkup
1179
     * @param string $inlineMessageId
1180
     *
1181
     * @return Message
1182
     * @throws Exception
1183
     * @throws HttpException
1184
     * @throws InvalidJsonException
1185
     */
1186 View Code Duplication
    public function editMessageReplyMarkup(
1187
        $chatId,
1188
        $messageId,
1189
        $replyMarkup = null,
1190
        $inlineMessageId = null
1191
    ) {
1192
        return Message::fromResponse($this->call('editMessageReplyMarkup', [
1193 9
            'chat_id' => $chatId,
1194
            'message_id' => $messageId,
1195 9
            'inline_message_id' => $inlineMessageId,
1196 9
            'reply_markup' => $replyMarkup,
1197
        ]));
1198
    }
1199
1200
    /**
1201
     * Use this method to delete a message, including service messages, with the following limitations:
1202
     *  - A message can only be deleted if it was sent less than 48 hours ago.
1203
     *  - Bots can delete outgoing messages in groups and supergroups.
1204
     *  - Bots granted can_post_messages permissions can delete outgoing messages in channels.
1205
     *  - If the bot is an administrator of a group, it can delete any message there.
1206
     *  - If the bot has can_delete_messages permission in a supergroup or a channel, it can delete any message there.
1207
     *
1208
     * @param int|string $chatId
1209
     * @param int $messageId
1210
     *
1211
     * @return bool
1212
     * @throws Exception
1213
     * @throws HttpException
1214
     * @throws InvalidJsonException
1215
     */
1216
    public function deleteMessage($chatId, $messageId)
1217
    {
1218
        return $this->call('deleteMessage', [
1219
            'chat_id' => $chatId,
1220
            'message_id' => $messageId,
1221
        ]);
1222
    }
1223
1224
    /**
1225
     * Close curl
1226
     */
1227
    public function __destruct()
1228
    {
1229
        $this->curl && curl_close($this->curl);
1230
    }
1231
1232
    /**
1233
     * @return string
1234
     */
1235
    public function getUrl()
1236
    {
1237
        return self::URL_PREFIX.$this->token;
1238
    }
1239
1240
    /**
1241
     * @return string
1242
     */
1243
    public function getFileUrl()
1244
    {
1245
        return self::FILE_URL_PREFIX.$this->token;
1246
    }
1247
1248
    /**
1249
     * @param Update $update
1250
     * @param string $eventName
1251
     *
1252
     * @throws Exception
1253
     */
1254
    public function trackUpdate(Update $update, $eventName = 'Message')
1255
    {
1256
        if (!in_array($update->getUpdateId(), $this->trackedEvents, true)) {
1257
            $this->trackedEvents[] = $update->getUpdateId();
1258
1259
            $this->track($update->getMessage(), $eventName);
1260
1261
            if (count($this->trackedEvents) > self::MAX_TRACKED_EVENTS) {
1262
                $this->trackedEvents = array_slice($this->trackedEvents, round(self::MAX_TRACKED_EVENTS / 4));
1263
            }
1264
        }
1265
    }
1266
1267
    /**
1268
     * Wrapper for tracker
1269
     *
1270
     * @param Message $message
1271
     * @param string $eventName
1272
     *
1273
     * @throws Exception
1274
     */
1275
    public function track(Message $message, $eventName = 'Message')
1276
    {
1277
        if ($this->tracker instanceof Botan) {
1278
            $this->tracker->track($message, $eventName);
1279
        }
1280
    }
1281
1282
    /**
1283
     * Use this method to send invoices. On success, the sent Message is returned.
1284
     *
1285
     * @param int|string $chatId
1286
     * @param string $title
1287
     * @param string $description
1288
     * @param string $payload
1289
     * @param string $providerToken
1290
     * @param string $startParameter
1291
     * @param string $currency
1292
     * @param array $prices
1293
     * @param bool $isFlexible
1294
     * @param string|null $photoUrl
1295
     * @param int|null $photoSize
1296
     * @param int|null $photoWidth
1297
     * @param int|null $photoHeight
1298
     * @param bool $needName
1299
     * @param bool $needPhoneNumber
1300
     * @param bool $needEmail
1301
     * @param bool $needShippingAddress
1302
     * @param int|null $replyToMessageId
1303
     * @param null $replyMarkup
1304
     * @param bool $disableNotification
1305
     * @param string|null $providerData
1306
     * @param bool $sendPhoneNumberToProvider
1307
     * @param bool $sendEmailToProvider
1308
     *
1309
     * @return Message
1310
     * @throws Exception
1311
     * @throws HttpException
1312
     * @throws InvalidJsonException
1313
     */
1314
    public function sendInvoice(
1315
        $chatId,
1316
        $title,
1317
        $description,
1318
        $payload,
1319
        $providerToken,
1320
        $startParameter,
1321
        $currency,
1322
        $prices,
1323
        $isFlexible = false,
1324
        $photoUrl = null,
1325
        $photoSize = null,
1326
        $photoWidth = null,
1327
        $photoHeight = null,
1328
        $needName = false,
1329
        $needPhoneNumber = false,
1330
        $needEmail = false,
1331
        $needShippingAddress = false,
1332
        $replyToMessageId = null,
1333
        $replyMarkup = null,
1334
        $disableNotification = false,
1335
        $providerData = null,
1336
        $sendPhoneNumberToProvider = false,
1337
        $sendEmailToProvider = false
1338
    ) {
1339
        return Message::fromResponse($this->call('sendInvoice', [
1340
            'chat_id' => $chatId,
1341
            'title' => $title,
1342
            'description' => $description,
1343
            'payload' => $payload,
1344
            'provider_token' => $providerToken,
1345
            'start_parameter' => $startParameter,
1346
            'currency' => $currency,
1347
            'prices' => json_encode($prices),
1348
            'is_flexible' => $isFlexible,
1349
            'photo_url' => $photoUrl,
1350
            'photo_size' => $photoSize,
1351
            'photo_width' => $photoWidth,
1352
            'photo_height' => $photoHeight,
1353
            'need_name' => $needName,
1354
            'need_phone_number' => $needPhoneNumber,
1355
            'need_email' => $needEmail,
1356
            'need_shipping_address' => $needShippingAddress,
1357
            'reply_to_message_id' => $replyToMessageId,
1358
            'reply_markup' => $replyMarkup,
1359
            'disable_notification' => (bool)$disableNotification,
1360
            'provider_data' => $providerData,
1361
            'send_phone_number_to_provider' => (bool)$sendPhoneNumberToProvider,
1362
            'send_email_to_provider' => (bool)$sendEmailToProvider
1363
        ]));
1364
    }
1365
1366
    /**
1367
     * If you sent an invoice requesting a shipping address and the parameter is_flexible was specified, the Bot API
1368
     * will send an Update with a shipping_query field to the bot. Use this method to reply to shipping queries.
1369
     * On success, True is returned.
1370
     *
1371
     * @param string $shippingQueryId
1372
     * @param bool $ok
1373
     * @param array $shipping_options
1374
     * @param null|string $errorMessage
1375
     *
1376
     * @return bool
1377
     * @throws Exception
1378
     * @throws HttpException
1379
     * @throws InvalidJsonException
1380
     */
1381
    public function answerShippingQuery($shippingQueryId, $ok = true, $shipping_options = [], $errorMessage = null)
1382
    {
1383
        return $this->call('answerShippingQuery', [
1384
            'shipping_query_id' => $shippingQueryId,
1385
            'ok' => (bool)$ok,
1386
            'shipping_options' => json_encode($shipping_options),
1387
            'error_message' => $errorMessage
1388
        ]);
1389
    }
1390
1391
    /**
1392
     * Use this method to respond to such pre-checkout queries. On success, True is returned.
1393
     * Note: The Bot API must receive an answer within 10 seconds after the pre-checkout query was sent.
1394
     *
1395
     * @param string $preCheckoutQueryId
1396
     * @param bool $ok
1397
     * @param null|string $errorMessage
1398
     *
1399
     * @return mixed
1400
     * @throws Exception
1401
     * @throws HttpException
1402
     * @throws InvalidJsonException
1403
     */
1404
    public function answerPreCheckoutQuery($preCheckoutQueryId, $ok = true, $errorMessage = null)
1405
    {
1406
        return $this->call('answerPreCheckoutQuery', [
1407
            'pre_checkout_query_id' => $preCheckoutQueryId,
1408
            'ok' => (bool)$ok,
1409
            'error_message' => $errorMessage
1410
        ]);
1411
    }
1412
1413
    /**
1414
     * Use this method to restrict a user in a supergroup.
1415
     * The bot must be an administrator in the supergroup for this to work and must have the appropriate admin rights.
1416
     * Pass True for all boolean parameters to lift restrictions from a user.
1417
     *
1418
     * @param string|int $chatId Unique identifier for the target chat or username of the target supergroup
1419
     *                   (in the format @supergroupusername)
1420
     * @param int $userId Unique identifier of the target user
1421
     * @param null|integer $untilDate Date when restrictions will be lifted for the user, unix time.
1422
     *                     If user is restricted for more than 366 days or less than 30 seconds from the current time,
1423
     *                     they are considered to be restricted forever
1424
     * @param bool $canSendMessages Pass True, if the user can send text messages, contacts, locations and venues
1425
     * @param bool $canSendMediaMessages No Pass True, if the user can send audios, documents, photos, videos,
1426
     *                                   video notes and voice notes, implies can_send_messages
1427
     * @param bool $canSendOtherMessages Pass True, if the user can send animations, games, stickers and
1428
     *                                   use inline bots, implies can_send_media_messages
1429
     * @param bool $canAddWebPagePreviews Pass True, if the user may add web page previews to their messages,
1430
     *                                    implies can_send_media_messages
1431
     *
1432
     * @return bool
1433
     * @throws Exception
1434
     * @throws HttpException
1435
     * @throws InvalidJsonException
1436
     */
1437
    public function restrictChatMember(
1438
        $chatId,
1439
        $userId,
1440
        $untilDate = null,
1441
        $canSendMessages = false,
1442
        $canSendMediaMessages = false,
1443
        $canSendOtherMessages = false,
1444
        $canAddWebPagePreviews = false
1445
    ) {
1446
        return $this->call('restrictChatMember', [
1447
            'chat_id' => $chatId,
1448
            'user_id' => $userId,
1449
            'until_date' => $untilDate,
1450
            'can_send_messages' => $canSendMessages,
1451
            'can_send_media_messages' => $canSendMediaMessages,
1452
            'can_send_other_messages' => $canSendOtherMessages,
1453
            'can_add_web_page_previews' => $canAddWebPagePreviews
1454
        ]);
1455
    }
1456
1457
    /**
1458
     * Use this method to promote or demote a user in a supergroup or a channel.
1459
     * The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
1460
     * Pass False for all boolean parameters to demote a user.
1461
     *
1462
     * @param string|int $chatId Unique identifier for the target chat or username of the target supergroup
1463
     *                   (in the format @supergroupusername)
1464
     * @param int $userId Unique identifier of the target user
1465
     * @param bool $canChangeInfo Pass True, if the administrator can change chat title, photo and other settings
1466
     * @param bool $canPostMessages Pass True, if the administrator can create channel posts, channels only
1467
     * @param bool $canEditMessages Pass True, if the administrator can edit messages of other users, channels only
1468
     * @param bool $canDeleteMessages Pass True, if the administrator can delete messages of other users
1469
     * @param bool $canInviteUsers Pass True, if the administrator can invite new users to the chat
1470
     * @param bool $canRestrictMembers Pass True, if the administrator can restrict, ban or unban chat members
1471
     * @param bool $canPinMessages Pass True, if the administrator can pin messages, supergroups only
1472
     * @param bool $canPromoteMembers Pass True, if the administrator can add new administrators with a subset of his
1473
     *                                own privileges or demote administrators that he has promoted,directly or
1474
     *                                indirectly (promoted by administrators that were appointed by him)
1475
     *
1476
     * @return bool
1477
     * @throws Exception
1478
     * @throws HttpException
1479
     * @throws InvalidJsonException
1480
     */
1481
    public function promoteChatMember(
1482
        $chatId,
1483
        $userId,
1484
        $canChangeInfo = true,
1485
        $canPostMessages = true,
1486
        $canEditMessages = true,
1487
        $canDeleteMessages = true,
1488
        $canInviteUsers = true,
1489
        $canRestrictMembers = true,
1490
        $canPinMessages = true,
1491
        $canPromoteMembers = true
1492
    ) {
1493
        return $this->call('promoteChatMember', [
1494
            'chat_id' => $chatId,
1495
            'user_id' => $userId,
1496
            'can_change_info' => $canChangeInfo,
1497
            'can_post_messages' => $canPostMessages,
1498
            'can_edit_messages' => $canEditMessages,
1499
            'can_delete_messages' => $canDeleteMessages,
1500
            'can_invite_users' => $canInviteUsers,
1501
            'can_restrict_members' => $canRestrictMembers,
1502
            'can_pin_messages' => $canPinMessages,
1503
            'can_promote_members' => $canPromoteMembers
1504
        ]);
1505
    }
1506
1507
    /**
1508
     * Use this method to export an invite link to a supergroup or a channel.
1509
     * The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
1510
     *
1511
     * @param string|int $chatId Unique identifier for the target chat or username of the target channel
1512
     *                           (in the format @channelusername)
1513
     * @return string
1514
     * @throws Exception
1515
     * @throws HttpException
1516
     * @throws InvalidJsonException
1517
     */
1518
    public function exportChatInviteLink($chatId)
1519
    {
1520
        return $this->call('exportChatInviteLink', [
1521
            'chat_id' => $chatId
1522
        ]);
1523
    }
1524
1525
    /**
1526
     * Use this method to set a new profile photo for the chat. Photos can't be changed for private chats.
1527
     * The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
1528
     *
1529
     * @param string|int $chatId Unique identifier for the target chat or username of the target channel
1530
     *                           (in the format @channelusername)
1531
     * @param CURLFile|string $photo New chat photo, uploaded using multipart/form-data
1532
     *
1533
     * @return bool
1534
     * @throws Exception
1535
     * @throws HttpException
1536
     * @throws InvalidJsonException
1537
     */
1538
    public function setChatPhoto($chatId, $photo)
1539
    {
1540
        return $this->call('setChatPhoto', [
1541
            'chat_id' => $chatId,
1542
            'photo' => $photo
1543
        ]);
1544
    }
1545
1546
    /**
1547
     * Use this method to delete a chat photo. Photos can't be changed for private chats.
1548
     * The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
1549
     *
1550
     * @param string|int $chatId Unique identifier for the target chat or username of the target channel
1551
     *                           (in the format @channelusername)
1552
     *
1553
     * @return bool
1554
     * @throws Exception
1555
     * @throws HttpException
1556
     * @throws InvalidJsonException
1557
     */
1558
    public function deleteChatPhoto($chatId)
1559
    {
1560
        return $this->call('deleteChatPhoto', [
1561
            'chat_id' => $chatId
1562
        ]);
1563
    }
1564
1565
    /**
1566
     * Use this method to change the title of a chat. Titles can't be changed for private chats.
1567
     * The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
1568
     *
1569
     * @param string|int $chatId Unique identifier for the target chat or username of the target channel
1570
     *                           (in the format @channelusername)
1571
     * @param string $title New chat title, 1-255 characters
1572
     *
1573
     * @return bool
1574
     * @throws Exception
1575
     * @throws HttpException
1576
     * @throws InvalidJsonException
1577
     */
1578
    public function setChatTitle($chatId, $title)
1579
    {
1580
        return $this->call('setChatTitle', [
1581
            'chat_id' => $chatId,
1582
            'title' => $title
1583
        ]);
1584
    }
1585
1586
    /**
1587
     * Use this method to change the description of a supergroup or a channel.
1588
     * The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
1589
     *
1590
     * @param string|int $chatId Unique identifier for the target chat or username of the target channel
1591
     *                   (in the format @channelusername)
1592
     * @param string|null $description New chat description, 0-255 characters
1593
     *
1594
     * @return bool
1595
     * @throws Exception
1596
     * @throws HttpException
1597
     * @throws InvalidJsonException
1598
     */
1599
    public function setChatDescription($chatId, $description = null)
1600
    {
1601
        return $this->call('setChatDescription', [
1602
            'chat_id' => $chatId,
1603
            'title' => $description
1604
        ]);
1605
    }
1606
1607
    /**
1608
     * Use this method to pin a message in a supergroup.
1609
     * The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
1610
     *
1611
     * @param string|int $chatId Unique identifier for the target chat or username of the target channel
1612
     *                   (in the format @channelusername)
1613
     * @param int $messageId Identifier of a message to pin
1614
     * @param bool $disableNotification
1615
     *
1616
     * @return bool
1617
     * @throws Exception
1618
     * @throws HttpException
1619
     * @throws InvalidJsonException
1620
     */
1621
    public function pinChatMessage($chatId, $messageId, $disableNotification = false)
1622
    {
1623
        return $this->call('pinChatMessage', [
1624
            'chat_id' => $chatId,
1625
            'message_id' => $messageId,
1626
            'disable_notification' => $disableNotification
1627
        ]);
1628
    }
1629
1630
    /**
1631
     * Use this method to unpin a message in a supergroup chat.
1632
     * The bot must be an administrator in the chat for this to work and must have the appropriate admin rights.
1633
     *
1634
     * @param string|int $chatId Unique identifier for the target chat or username of the target channel
1635
     *                   (in the format @channelusername)
1636
     *
1637
     * @return bool
1638
     * @throws Exception
1639
     * @throws HttpException
1640
     * @throws InvalidJsonException
1641
     */
1642
    public function unpinChatMessage($chatId)
1643
    {
1644
        return $this->call('unpinChatMessage', [
1645
            'chat_id' => $chatId
1646
        ]);
1647
    }
1648
1649
    /**
1650
     * Use this method to get up to date information about the chat
1651
     * (current name of the user for one-on-one conversations, current username of a user, group or channel, etc.).
1652
     *
1653
     * @param string|int $chatId Unique identifier for the target chat or username of the target channel
1654
     *                   (in the format @channelusername)
1655
     *
1656
     * @return Chat
1657
     * @throws Exception
1658
     * @throws HttpException
1659
     * @throws InvalidJsonException
1660
     */
1661
    public function getChat($chatId)
1662
    {
1663
        return Chat::fromResponse($this->call('getChat', [
1664
            'chat_id' => $chatId
1665
        ]));
1666
    }
1667
1668
    /**
1669
     * Use this method to get information about a member of a chat.
1670
     *
1671
     * @param string|int $chatId Unique identifier for the target chat or username of the target channel
1672
     *                   (in the format @channelusername)
1673
     * @param int $userId
1674
     *
1675
     * @return ChatMember
1676
     * @throws Exception
1677
     * @throws HttpException
1678
     * @throws InvalidJsonException
1679
     */
1680
    public function getChatMember($chatId, $userId)
1681
    {
1682
        return ChatMember::fromResponse($this->call('getChatMember', [
1683
            'chat_id' => $chatId,
1684
            'user_id' => $userId
1685
        ]));
1686
    }
1687
1688
    /**
1689
     * Use this method for your bot to leave a group, supergroup or channel.
1690
     *
1691
     * @param string|int $chatId Unique identifier for the target chat or username of the target channel
1692
     *                   (in the format @channelusername)
1693
     *
1694
     * @return bool
1695
     * @throws Exception
1696
     * @throws HttpException
1697
     * @throws InvalidJsonException
1698
     */
1699
    public function leaveChat($chatId)
1700
    {
1701
        return $this->call('leaveChat', [
1702
            'chat_id' => $chatId
1703
        ]);
1704
    }
1705
1706
    /**
1707
     * Use this method to get the number of members in a chat.
1708
     *
1709
     * @param string|int $chatId Unique identifier for the target chat or username of the target channel
1710
     *                   (in the format @channelusername)
1711
     *
1712
     * @return int
1713
     * @throws Exception
1714
     * @throws HttpException
1715
     * @throws InvalidJsonException
1716
     */
1717
    public function getChatMembersCount($chatId)
1718
    {
1719
        return $this->call(
1720
            'getChatMembersCount',
1721
            [
1722
                'chat_id' => $chatId
1723
            ]
1724
        );
1725
    }
1726
1727
    /**
1728
     * Use this method to get a list of administrators in a chat.
1729
     *
1730
     * @param string|int $chatId Unique identifier for the target chat or username of the target channel
1731
     *                   (in the format @channelusername)
1732
     *
1733
     * @return array
1734
     * @throws Exception
1735
     * @throws HttpException
1736
     * @throws InvalidJsonException
1737
     */
1738
    public function getChatAdministrators($chatId)
1739
    {
1740
        return ArrayOfChatMemberEntity::fromResponse(
1741
            $this->call(
1742
                'getChatAdministrators',
1743
                [
1744
                    'chat_id' => $chatId
1745
                ]
1746
            )
1747
        );
1748
    }
1749
1750
    /**
1751
     * As of v.4.0, Telegram clients support rounded square mp4 videos of up to 1 minute long.
1752
     * Use this method to send video messages.
1753
     * On success, the sent Message is returned.
1754
     *
1755
     * @param int|string $chatId chat_id or @channel_name
1756
     * @param CURLFile|string $videoNote
1757
     * @param int|null $duration
1758
     * @param int|null $length
1759
     * @param int|null $replyToMessageId
1760
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
1761
     *        Types\ReplyKeyboardRemove|null $replyMarkup
1762
     * @param bool $disableNotification
1763
     *
1764
     * @return Message
1765
     * @throws InvalidArgumentException
1766
     * @throws Exception
1767
     */
1768
    public function sendVideoNote(
1769
        $chatId,
1770
        $videoNote,
1771
        $duration = null,
1772
        $length = null,
1773
        $replyToMessageId = null,
1774
        $replyMarkup = null,
1775
        $disableNotification = false
1776
    ) {
1777
        return Message::fromResponse($this->call('sendVideoNote', [
1778
            'chat_id' => $chatId,
1779
            'video_note' => $videoNote,
1780
            'duration' => $duration,
1781
            'length' => $length,
1782
            'reply_to_message_id' => $replyToMessageId,
1783
            'reply_markup' => $replyMarkup,
1784
            'disable_notification' => (bool)$disableNotification
1785
        ]));
1786
    }
1787
1788
    /**
1789
     * Use this method to send a group of photos or videos as an album.
1790
     * On success, the sent \TelegramBot\Api\Types\Message is returned.
1791
     *
1792
     * @param int|string $chatId
1793
     * @param ArrayOfInputMedia $media
1794
     * @param int|null $replyToMessageId
1795
     * @param bool $disableNotification
1796
     *
1797
     * @return array
1798
     * @throws Exception
1799
     */
1800
    public function sendMediaGroup(
1801
        $chatId,
1802
        $media,
1803
        $disableNotification = false,
1804
        $replyToMessageId = null
1805
    ) {
1806
        return ArrayOfMessages::fromResponse($this->call('sendMediaGroup', [
1807
            'chat_id' => $chatId,
1808
            'media' => $media->toJson(),
1809
            'reply_to_message_id' => (int)$replyToMessageId,
1810
            'disable_notification' => (bool)$disableNotification
1811
        ]));
1812
    }
1813
1814
    /**
1815
     * Enable proxy for curl requests. Empty string will disable proxy.
1816
     *
1817
     * @param string $proxyString
1818
     *
1819
     * @return BotApi
1820
     */
1821
    public function setProxy($proxyString = '', $socks5 = false)
1822
    {
1823
        if (empty($proxyString)) {
1824
            $this->proxySettings = [];
1825
            return $this;
1826
        }
1827
1828
        $this->proxySettings = [
1829
            CURLOPT_PROXY => $proxyString,
1830
            CURLOPT_HTTPPROXYTUNNEL => true,
1831
        ];
1832
1833
        if ($socks5) {
1834
            $this->proxySettings[CURLOPT_PROXYTYPE] = CURLPROXY_SOCKS5;
1835
        }
1836
        return $this;
1837
    }
1838
1839
    /**
1840
     * Use this method to edit animation, audio, document, photo, or video messages.
1841
     * If a message is a part of a message album, then it can be edited only to a photo or a video.
1842
     * Otherwise, message type can be changed arbitrarily.
1843
     * When inline message is edited, new file can't be uploaded. Use previously uploaded file via its file_id or specify a URL.
1844
     * On success, if the edited message was sent by the bot, the edited Message is returned, otherwise True is returned.
1845
     *
1846
     * @param int|string $chatId
1847
     * @param int $messageId
1848
     * @param InputMedia $media
1849
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
1850
     *        Types\ReplyKeyboardRemove|null $replyMarkup
1851
     * @param int|null $inlineMessageId
1852
     * @return Message
1853
     * @throws Exception
1854
     * @throws HttpException
1855
     * @throws InvalidJsonException
1856
     */
1857 View Code Duplication
    public function editMessageMedia(
1858
        $chatId,
1859
        $messageId,
1860
        InputMedia $media,
1861
        $replyMarkup = null,
1862
        $inlineMessageId = null
1863
    ) {
1864
        return Message::fromResponse($this->call('editMessageMedia', [
1865
            'chat_id' => $chatId,
1866
            'message_id' => $messageId,
1867
            'media' => $media->toJson(),
1868
            'inline_message_id' => $inlineMessageId,
1869
            'reply_markup' => $replyMarkup,
1870
        ]));
1871
    }
1872
1873
    /**
1874
     * Use this method to send a native poll. A native poll can't be sent to a private chat.
1875
     * On success, the sent \TelegramBot\Api\Types\Message is returned.
1876
     *
1877
     * @param int|string $chatId
1878
     * @param string $question
1879
     * @param array $options
1880
     * @param bool $disableNotification
1881
     * @param int|null $replyToMessageId
1882
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
1883
     *        Types\ReplyKeyboardRemove|null $replyMarkup
1884
     *
1885
     * @return Message
1886
     * @throws InvalidArgumentException
1887
     * @throws Exception
1888
     */
1889
    public function sendPoll(
1890
        $chatId,
1891
        $question,
1892
        $options,
1893
        $disableNotification = false,
1894
        $replyToMessageId = null,
1895
        $replyMarkup = null
1896
    ) {
1897
        return Message::fromResponse($this->call('sendPoll', [
1898
            'chat_id' => $chatId,
1899
            'question' => $question,
1900
            'options' => json_encode($options),
1901
            'disable_notification' => (bool)$disableNotification,
1902
            'reply_to_message_id' => (int)$replyToMessageId,
1903
            'reply_markup' => $replyMarkup,
1904
        ]));
1905
    }
1906
1907
    /**
1908
     * Use this method to stop a which was sent by the bot.
1909
     * On success, the stopped \TelegramBot\Api\Types\Poll with the final results is returned.
1910
     *
1911
     * @param int|string $chatId
1912
     * @param int $messageId
1913
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|
1914
     *        Types\ReplyKeyboardRemove|null $replyMarkup
1915
     * @return Poll
1916
     * @throws InvalidArgumentException
1917
     * @throws Exception
1918
     */
1919
    public function stopPoll(
1920
        $chatId,
1921
        $messageId,
1922
        $replyMarkup = null
1923
    ) {
1924
        return Poll::fromResponse($this->call('stopPoll', [
1925
            'chat_id' => $chatId,
1926
            'message_id' => $messageId,
1927
            'reply_markup' => $replyMarkup,
1928
        ]));
1929
    }
1930
1931
    /**
1932
     * Set an option for a cURL transfer
1933
     *
1934
     * @param int $option The CURLOPT_XXX option to set
1935
     * @param mixed $value The value to be set on option
1936
     */
1937
    public function setCurlOption($option, $value)
1938
    {
1939
        $this->customCurlOptions[$option] = $value;
1940
    }
1941
1942
    /**
1943
     * Unset an option for a cURL transfer
1944
     *
1945
     * @param int $option The CURLOPT_XXX option to unset
1946
     */
1947
    public function unsetCurlOption($option)
1948
    {
1949
        unset($this->customCurlOptions[$option]);
1950
    }
1951
1952
    /**
1953
     * Clean custom options
1954
     */
1955
    public function resetCurlOptions()
1956
    {
1957
        $this->customCurlOptions = [];
1958
    }
1959
}