Completed
Push — master ( 84868c...645e8e )
by Gusev
02:51
created

BotApi::curlValidate()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 8
ccs 0
cts 6
cp 0
rs 9.4285
cc 3
eloc 4
nc 2
nop 1
crap 12
1
<?php
2
3
namespace TelegramBot\Api;
4
5
use TelegramBot\Api\Types\ArrayOfUpdates;
6
use TelegramBot\Api\Types\File;
7
use TelegramBot\Api\Types\Message;
8
use TelegramBot\Api\Types\Update;
9
use TelegramBot\Api\Types\User;
10
use TelegramBot\Api\Types\UserProfilePhotos;
11
12
/**
13
 * Class BotApi
14
 *
15
 * @package TelegramBot\Api
16
 */
17
class BotApi
18
{
19
    /**
20
     * HTTP codes
21
     *
22
     * @var array
23
     */
24
    public static $codes = [
25
        // Informational 1xx
26
        100 => 'Continue',
27
        101 => 'Switching Protocols',
28
        102 => 'Processing',            // RFC2518
29
        // Success 2xx
30
        200 => 'OK',
31
        201 => 'Created',
32
        202 => 'Accepted',
33
        203 => 'Non-Authoritative Information',
34
        204 => 'No Content',
35
        205 => 'Reset Content',
36
        206 => 'Partial Content',
37
        207 => 'Multi-Status',          // RFC4918
38
        208 => 'Already Reported',      // RFC5842
39
        226 => 'IM Used',               // RFC3229
40
        // Redirection 3xx
41
        300 => 'Multiple Choices',
42
        301 => 'Moved Permanently',
43
        302 => 'Found', // 1.1
44
        303 => 'See Other',
45
        304 => 'Not Modified',
46
        305 => 'Use Proxy',
47
        // 306 is deprecated but reserved
48
        307 => 'Temporary Redirect',
49
        308 => 'Permanent Redirect',    // RFC7238
50
        // Client Error 4xx
51
        400 => 'Bad Request',
52
        401 => 'Unauthorized',
53
        402 => 'Payment Required',
54
        403 => 'Forbidden',
55
        404 => 'Not Found',
56
        405 => 'Method Not Allowed',
57
        406 => 'Not Acceptable',
58
        407 => 'Proxy Authentication Required',
59
        408 => 'Request Timeout',
60
        409 => 'Conflict',
61
        410 => 'Gone',
62
        411 => 'Length Required',
63
        412 => 'Precondition Failed',
64
        413 => 'Payload Too Large',
65
        414 => 'URI Too Long',
66
        415 => 'Unsupported Media Type',
67
        416 => 'Range Not Satisfiable',
68
        417 => 'Expectation Failed',
69
        422 => 'Unprocessable Entity',                                        // RFC4918
70
        423 => 'Locked',                                                      // RFC4918
71
        424 => 'Failed Dependency',                                           // RFC4918
72
        425 => 'Reserved for WebDAV advanced collections expired proposal',   // RFC2817
73
        426 => 'Upgrade Required',                                            // RFC2817
74
        428 => 'Precondition Required',                                       // RFC6585
75
        429 => 'Too Many Requests',                                           // RFC6585
76
        431 => 'Request Header Fields Too Large',                             // RFC6585
77
        // Server Error 5xx
78
        500 => 'Internal Server Error',
79
        501 => 'Not Implemented',
80
        502 => 'Bad Gateway',
81
        503 => 'Service Unavailable',
82
        504 => 'Gateway Timeout',
83
        505 => 'HTTP Version Not Supported',
84
        506 => 'Variant Also Negotiates (Experimental)',                      // RFC2295
85
        507 => 'Insufficient Storage',                                        // RFC4918
86
        508 => 'Loop Detected',                                               // RFC5842
87
        510 => 'Not Extended',                                                // RFC2774
88
        511 => 'Network Authentication Required',                             // RFC6585
89
    ];
90
91
92
    /**
93
     * Default http status code
94
     */
95
    const DEFAULT_STATUS_CODE = 200;
96
97
    /**
98
     * Not Modified http status code
99
     */
100
    const NOT_MODIFIED_STATUS_CODE = 304;
101
102
    /**
103
     * Limits for tracked ids
104
     */
105
    const MAX_TRACKED_EVENTS = 200;
106
107
    /**
108
     * Url prefixes
109
     */
110
    const URL_PREFIX = 'https://api.telegram.org/bot';
111
112
    /**
113
     * Url prefix for files
114
     */
115
    const FILE_URL_PREFIX = 'https://api.telegram.org/file/bot';
116
117
    /**
118
     * CURL object
119
     *
120
     * @var
121
     */
122
    protected $curl;
123
124
    /**
125
     * Bot token
126
     *
127
     * @var string
128
     */
129
    protected $token;
130
131
    /**
132
     * Botan tracker
133
     *
134
     * @var \TelegramBot\Api\Botan
135
     */
136
    protected $tracker;
137
138
    /**
139
     * list of event ids
140
     *
141
     * @var array
142
     */
143
    protected $trackedEvents = [];
144
145
    /**
146
     * Check whether return associative array
147
     *
148
     * @var bool
149
     */
150
    protected $returnArray = true;
151
152
153
    /**
154
     * Constructor
155
     *
156
     * @param string $token Telegram Bot API token
157
     * @param string|null $trackerToken Yandex AppMetrica application api_key
158
     */
159 9
    public function __construct($token, $trackerToken = null)
160
    {
161 9
        $this->curl = curl_init();
162 9
        $this->token = $token;
163
164 9
        if ($trackerToken) {
165
            $this->tracker = new Botan($trackerToken);
166
        }
167 9
    }
168
169
    /**
170
     * Set return array
171
     *
172
     * @param bool $mode
173
     *
174
     * @return $this
175
     */
176
    public function setModeObject($mode = true)
177
    {
178
        $this->returnArray = !$mode;
179
180
        return $this;
181
    }
182
183
184
    /**
185
     * Call method
186
     *
187
     * @param string $method
188
     * @param array|null $data
189
     *
190
     * @return mixed
191
     * @throws \TelegramBot\Api\Exception
192
     * @throws \TelegramBot\Api\HttpException
193
     * @throws \TelegramBot\Api\InvalidJsonException
194
     */
195
    public function call($method, array $data = null)
196
    {
197
        $options = [
198
            CURLOPT_URL => $this->getUrl() . '/' . $method,
199
            CURLOPT_RETURNTRANSFER => true,
200
            CURLOPT_POST => null,
201
            CURLOPT_POSTFIELDS => null
202
        ];
203
204
        if ($data) {
205
            $options[CURLOPT_POST] = true;
206
            $options[CURLOPT_POSTFIELDS] = $data;
207
        }
208
209
        $response = self::jsonValidate($this->executeCurl($options), $this->returnArray);
210
211
        if ($this->returnArray) {
212
            if (!isset($response['ok'])) {
213
                throw new Exception($response['description'], $response['error_code']);
214
            }
215
216
            return $response['result'];
217
        }
218
219
        if (!$response->ok) {
220
            throw new Exception($response->description, $response->error_code);
221
        }
222
223
        return $response->result;
224
    }
225
226
    /**
227
     * curl_exec wrapper for response validation
228
     *
229
     * @param array $options
230
     *
231
     * @return string
232
     *
233
     * @throws \TelegramBot\Api\HttpException
234
     */
235
    protected function executeCurl(array $options)
236
    {
237
        curl_setopt_array($this->curl, $options);
238
239
        $result = curl_exec($this->curl);
240
        self::curlValidate($this->curl);
241
242
        return $result;
243
    }
244
245
    /**
246
     * Response validation
247
     *
248
     * @param resource $curl
249
     *
250
     * @throws \TelegramBot\Api\HttpException
251
     */
252
    public static function curlValidate($curl)
253
    {
254
        if (($httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE))
255
            && !in_array($httpCode, [self::DEFAULT_STATUS_CODE, self::NOT_MODIFIED_STATUS_CODE])
256
        ) {
257
            throw new HttpException(self::$codes[$httpCode], $httpCode);
258
        }
259
    }
260
261
    /**
262
     * JSON validation
263
     *
264
     * @param string $jsonString
265
     * @param boolean $asArray
266
     *
267
     * @return object|array
268
     * @throws \TelegramBot\Api\InvalidJsonException
269
     */
270
    public static function jsonValidate($jsonString, $asArray)
271
    {
272
        $json = json_decode($jsonString, $asArray);
273
274
        if (json_last_error() != JSON_ERROR_NONE) {
275
            throw new InvalidJsonException(json_last_error_msg(), json_last_error());
276
        }
277
278
        return $json;
279
    }
280
281
    /**
282
     * Use this method to send text messages. On success, the sent \TelegramBot\Api\Types\Message is returned.
283
     *
284
     * @param int|string $chatId
285
     * @param string $text
286
     * @param string|null $parseMode
287
     * @param bool $disablePreview
288
     * @param int|null $replyToMessageId
289
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
290
     * @param bool $disableNotification
291
     *
292
     * @return \TelegramBot\Api\Types\Message
293
     * @throws \TelegramBot\Api\InvalidArgumentException
294
     * @throws \TelegramBot\Api\Exception
295
     */
296
    public function sendMessage(
297
        $chatId,
298
        $text,
299
        $parseMode = null,
300
        $disablePreview = false,
301
        $replyToMessageId = null,
302
        $replyMarkup = null,
303
        $disableNotification = false
304
    ) {
305
        return Message::fromResponse($this->call('sendMessage', [
306
            'chat_id' => $chatId,
307
            'text' => $text,
308
            'parse_mode' => $parseMode,
309
            'disable_web_page_preview' => $disablePreview,
310
            'reply_to_message_id' => (int) $replyToMessageId,
311
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
312
            'disable_notification' => (bool) $disableNotification,
313
        ]));
314
    }
315
316
    /**
317
     * Use this method to send phone contacts
318
     *
319
     * @param int $chatId
320
     * @param string $phoneNumber
321
     * @param string $firstName
322
     * @param string $lastName
323
     * @param int|null $replyToMessageId
324
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
325
     * @param bool $disableNotification
326
     *
327
     * @return \TelegramBot\Api\Types\Message
328
     * @throws \TelegramBot\Api\Exception
329
     */
330
    public function sendContact(
331
        $chatId,
332
        $phoneNumber,
333
        $firstName,
334
        $lastName = null,
335
        $replyToMessageId = null,
336
        $replyMarkup = null,
337
        $disableNotification = false
338
    ) {
339
        return Message::fromResponse($this->call('sendContact', [
340
            'chat_id' => $chatId,
341
            'phone_number' => $phoneNumber,
342
            'first_name' => $firstName,
343
            'last_name' => $lastName,
344
            'reply_to_message_id' => $replyToMessageId,
345
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
346
            'disable_notification' => (bool)$disableNotification,
347
        ]));
348
    }
349
350
    /**
351
     * Use this method when you need to tell the user that something is happening on the bot's side.
352
     * The status is set for 5 seconds or less (when a message arrives from your bot,
353
     * Telegram clients clear its typing status).
354
     *
355
     * We only recommend using this method when a response from the bot will take a noticeable amount of time to arrive.
356
     *
357
     * Type of action to broadcast. Choose one, depending on what the user is about to receive:
358
     * `typing` for text messages, `upload_photo` for photos, `record_video` or `upload_video` for videos,
359
     * `record_audio` or upload_audio for audio files, `upload_document` for general files,
360
     * `find_location` for location data.
361
     *
362
     * @param int $chatId
363
     * @param string $action
364
     *
365
     * @return bool
366
     * @throws \TelegramBot\Api\Exception
367
     */
368
    public function sendChatAction($chatId, $action)
369
    {
370
        return $this->call('sendChatAction', [
371
            'chat_id' => $chatId,
372
            'action' => $action
373
        ]);
374
    }
375
376
    /**
377
     * Use this method to get a list of profile pictures for a user.
378
     *
379
     * @param int $userId
380
     * @param int $offset
381
     * @param int $limit
382
     *
383
     * @return \TelegramBot\Api\Types\UserProfilePhotos
384
     * @throws \TelegramBot\Api\Exception
385
     */
386
    public function getUserProfilePhotos($userId, $offset = 0, $limit = 100)
387
    {
388
        return UserProfilePhotos::fromResponse($this->call('getUserProfilePhotos', [
389
            'user_id' => (int) $userId,
390
            'offset' => (int) $offset,
391
            'limit' => (int) $limit,
392
        ]));
393
    }
394
395
    /**
396
     * Use this method to specify a url and receive incoming updates via an outgoing webhook.
397
     * Whenever there is an update for the bot, we will send an HTTPS POST request to the specified url,
398
     * containing a JSON-serialized Update.
399
     * In case of an unsuccessful request, we will give up after a reasonable amount of attempts.
400
     *
401
     * @param string $url HTTPS url to send updates to. Use an empty string to remove webhook integration
402
     * @param \CURLFile|string $certificate Upload your public key certificate
403
     *                                      so that the root certificate in use can be checked
404
     *
405
     * @return string
406
     *
407
     * @throws \TelegramBot\Api\Exception
408
     */
409
    public function setWebhook($url = '', $certificate = null)
410
    {
411
        return $this->call('setWebhook', ['url' => $url, 'certificate' => $certificate]);
412
    }
413
414
    /**
415
     * A simple method for testing your bot's auth token.Requires no parameters.
416
     * Returns basic information about the bot in form of a User object.
417
     *
418
     * @return \TelegramBot\Api\Types\User
419
     * @throws \TelegramBot\Api\Exception
420
     * @throws \TelegramBot\Api\InvalidArgumentException
421
     */
422
    public function getMe()
423
    {
424
        return User::fromResponse($this->call('getMe'));
425
    }
426
427
    /**
428
     * Use this method to receive incoming updates using long polling.
429
     * An Array of Update objects is returned.
430
     *
431
     * Notes
432
     * 1. This method will not work if an outgoing webhook is set up.
433
     * 2. In order to avoid getting duplicate updates, recalculate offset after each server response.
434
     *
435
     * @param int $offset
436
     * @param int $limit
437
     * @param int $timeout
438
     *
439
     * @return Update[]
440
     * @throws \TelegramBot\Api\Exception
441
     * @throws \TelegramBot\Api\InvalidArgumentException
442
     */
443 2
    public function getUpdates($offset = 0, $limit = 100, $timeout = 0)
444
    {
445 2
        $updates = ArrayOfUpdates::fromResponse($this->call('getUpdates', [
446 2
            'offset' => $offset,
447 2
            'limit' => $limit,
448
            'timeout' => $timeout
449 2
        ]));
450
451 2
        if ($this->tracker instanceof Botan) {
452
            foreach ($updates as $update) {
453
                $this->trackUpdate($update);
454
            }
455
        }
456
457 2
        return $updates;
458
    }
459
460
    /**
461
     * Use this method to send point on the map. On success, the sent Message is returned.
462
     *
463
     * @param int $chatId
464
     * @param float $latitude
465
     * @param float $longitude
466
     * @param int|null $replyToMessageId
467
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
468
     * @param bool $disableNotification
469
     *
470
     * @return \TelegramBot\Api\Types\Message
471
     * @throws \TelegramBot\Api\Exception
472
     */
473
    public function sendLocation(
474
        $chatId,
475
        $latitude,
476
        $longitude,
477
        $replyToMessageId = null,
478
        $replyMarkup = null,
479
        $disableNotification = false
480
    ) {
481
        return Message::fromResponse($this->call('sendLocation', [
482
            'chat_id' => $chatId,
483
            'latitude' => $latitude,
484
            'longitude' => $longitude,
485
            'reply_to_message_id' => $replyToMessageId,
486
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
487
            'disable_notification' => (bool) $disableNotification
488
    }
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected '}', expecting ']'
Loading history...
489
490
    /**
491
     * Use this method to send information about a venue. On success, the sent Message is returned.
492
     *
493
     * @param int|string $chatId
494
     * @param float $latitude
495
     * @param float $longitude
496
     * @param string $title
497
     * @param string $address
498
     * @param string|null $foursquareId
499
     * @param int|null $replyToMessageId
500
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
501
     * @param bool $disableNotification
502
     *
503
     * @return \TelegramBot\Api\Types\Message
504
     * @throws \TelegramBot\Api\Exception
505
     */
506
    public function sendVenue(
507
        $chatId,
508
        $latitude,
509
        $longitude,
510
        $title,
511
        $address,
512
        $foursquareId = null,
513
        $replyToMessageId = null,
514
        $replyMarkup = null,
515
        $disableNotification = false
516
    ) {
517
        return Message::fromResponse($this->call('sendVenue', [
518
            'chat_id' => $chatId,
519
            'latitude' => $latitude,
520
            'longitude' => $longitude,
521
            'title' => $title,
522
            'address' => $address,
523
            'foursquare_id' => $foursquareId,
524
            'reply_to_message_id' => $replyToMessageId,
525
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
526
            'disable_notification' => (bool)$disableNotification,
527
        ]));
528
    }
529
530
    /**
531
     * Use this method to send .webp stickers. On success, the sent Message is returned.
532
     *
533
     * @param int $chatId
534
     * @param \CURLFile|string $sticker
535
     * @param int|null $replyToMessageId
536
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
537
     * @param bool $disableNotification
538
     *
539
     * @return \TelegramBot\Api\Types\Message
540
     * @throws \TelegramBot\Api\InvalidArgumentException
541
     * @throws \TelegramBot\Api\Exception
542
     */
543
    public function sendSticker(
544
        $chatId,
545
        $sticker,
546
        $replyToMessageId = null,
547
        $replyMarkup = null,
548
        $disableNotification = false
549
    ) {
550
        return Message::fromResponse($this->call('sendSticker', [
551
            'chat_id' => $chatId,
552
            'sticker' => $sticker,
553
            'reply_to_message_id' => $replyToMessageId,
554
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
555
            'disable_notification' => (bool) $disableNotification
556
        ]));
557
    }
558
559
    /**
560
     * Use this method to send video files,
561
     * Telegram clients support mp4 videos (other formats may be sent as Document).
562
     * On success, the sent Message is returned.
563
     *
564
     * @param int $chatId
565
     * @param \CURLFile|string $video
566
     * @param int|null $duration
567
     * @param string|null $caption
568
     * @param int|null $replyToMessageId
569
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
570
     * @param bool $disableNotification
571
     *
572
     * @return \TelegramBot\Api\Types\Message
573
     * @throws \TelegramBot\Api\InvalidArgumentException
574
     * @throws \TelegramBot\Api\Exception
575
     */
576
    public function sendVideo(
577
        $chatId,
578
        $video,
579
        $duration = null,
580
        $caption = null,
581
        $replyToMessageId = null,
582
        $replyMarkup = null,
583
        $disableNotification = false
584
    ) {
585
        return Message::fromResponse($this->call('sendVideo', [
586
            'chat_id' => $chatId,
587
            'video' => $video,
588
            'duration' => $duration,
589
            'caption' => $caption,
590
            'reply_to_message_id' => $replyToMessageId,
591
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
592
            'disable_notification' => (bool) $disableNotification
593
        ]));
594
    }
595
596
    /**
597
     * Use this method to send audio files,
598
     * if you want Telegram clients to display the file as a playable voice message.
599
     * For this to work, your audio must be in an .ogg file encoded with OPUS
600
     * (other formats may be sent as Audio or Document).
601
     * On success, the sent Message is returned.
602
     * Bots can currently send voice messages of up to 50 MB in size, this limit may be changed in the future.
603
     *
604
     * @param int $chatId
605
     * @param \CURLFile|string $voice
606
     * @param int|null $duration
607
     * @param int|null $replyToMessageId
608
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
609
     * @param bool $disableNotification
610
     *
611
     * @return \TelegramBot\Api\Types\Message
612
     * @throws \TelegramBot\Api\InvalidArgumentException
613
     * @throws \TelegramBot\Api\Exception
614
     */
615
    public function sendVoice(
616
        $chatId,
617
        $voice,
618
        $duration = null,
619
        $replyToMessageId = null,
620
        $replyMarkup = null,
621
        $disableNotification = false
622
    ) {
623
        return Message::fromResponse($this->call('sendVoice', [
624
            'chat_id' => $chatId,
625
            'voice' => $voice,
626
            'duration' => $duration,
627
            'reply_to_message_id' => $replyToMessageId,
628
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
629
            'disable_notification' => (bool) $disableNotification
630
        ]));
631
    }
632
633
    /**
634
     * Use this method to forward messages of any kind. On success, the sent Message is returned.
635
     *
636
     * @param int $chatId
637
     * @param int $fromChatId
638
     * @param int $messageId
639
     * @param bool $disableNotification
640
     *
641
     * @return \TelegramBot\Api\Types\Message
642
     * @throws \TelegramBot\Api\InvalidArgumentException
643
     * @throws \TelegramBot\Api\Exception
644
     */
645
    public function forwardMessage($chatId, $fromChatId, $messageId, $disableNotification = false)
646
    {
647
        return Message::fromResponse($this->call('forwardMessage', [
648
            'chat_id' => $chatId,
649
            'from_chat_id' => $fromChatId,
650
            'message_id' => (int) $messageId,
651
            'disable_notification' => (bool) $disableNotification
652
        ]));
653
    }
654
655
    /**
656
     * Use this method to send audio files,
657
     * if you want Telegram clients to display them in the music player.
658
     * Your audio must be in the .mp3 format.
659
     * On success, the sent Message is returned.
660
     * Bots can currently send audio files of up to 50 MB in size, this limit may be changed in the future.
661
     *
662
     * For backward compatibility, when the fields title and performer are both empty
663
     * and the mime-type of the file to be sent is not audio/mpeg, the file will be sent as a playable voice message.
664
     * For this to work, the audio must be in an .ogg file encoded with OPUS.
665
     * This behavior will be phased out in the future. For sending voice messages, use the sendVoice method instead.
666
     *
667
     * @deprecated since 20th February. Removed backward compatibility from the method sendAudio.
668
     * Voice messages now must be sent using the method sendVoice.
669
     * There is no more need to specify a non-empty title or performer while sending the audio by file_id.
670
     *
671
     * @param int $chatId
672
     * @param \CURLFile|string $audio
673
     * @param int|null $duration
674
     * @param string|null $performer
675
     * @param string|null $title
676
     * @param int|null $replyToMessageId
677
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
678
     * @param bool $disableNotification
679
     *
680
     * @return \TelegramBot\Api\Types\Message
681
     * @throws \TelegramBot\Api\InvalidArgumentException
682
     * @throws \TelegramBot\Api\Exception
683
     */
684
    public function sendAudio(
685
        $chatId,
686
        $audio,
687
        $duration = null,
688
        $performer = null,
689
        $title = null,
690
        $replyToMessageId = null,
691
        $replyMarkup = null,
692
        $disableNotification = false
693
    ) {
694
        return Message::fromResponse($this->call('sendAudio', [
695
            'chat_id' => $chatId,
696
            'audio' => $audio,
697
            'duration' => $duration,
698
            'performer' => $performer,
699
            'title' => $title,
700
            'reply_to_message_id' => $replyToMessageId,
701
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
702
            'disable_notification' => (bool) $disableNotification
703
        ]));
704
    }
705
706
    /**
707
     * Use this method to send photos. On success, the sent Message is returned.
708
     *
709
     * @param int $chatId
710
     * @param \CURLFile|string $photo
711
     * @param string|null $caption
712
     * @param int|null $replyToMessageId
713
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
714
     * @param bool $disableNotification
715
     *
716
     * @return \TelegramBot\Api\Types\Message
717
     * @throws \TelegramBot\Api\InvalidArgumentException
718
     * @throws \TelegramBot\Api\Exception
719
     */
720
    public function sendPhoto(
721
        $chatId,
722
        $photo,
723
        $caption = null,
724
        $replyToMessageId = null,
725
        $replyMarkup = null,
726
        $disableNotification = false
727
    ) {
728
        return Message::fromResponse($this->call('sendPhoto', [
729
            'chat_id' => $chatId,
730
            'photo' => $photo,
731
            'caption' => $caption,
732
            'reply_to_message_id' => $replyToMessageId,
733
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
734
            'disable_notification' => (bool) $disableNotification
735
        ]));
736
    }
737
738
    /**
739
     * Use this method to send general files. On success, the sent Message is returned.
740
     * Bots can currently send files of any type of up to 50 MB in size, this limit may be changed in the future.
741
     *
742
     * @param int $chatId
743
     * @param \CURLFile|string $document
744
     * @param int|null $replyToMessageId
745
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
746
     * @param bool $disableNotification
747
     *
748
     * @return \TelegramBot\Api\Types\Message
749
     * @throws \TelegramBot\Api\InvalidArgumentException
750
     * @throws \TelegramBot\Api\Exception
751
     */
752
    public function sendDocument(
753
        $chatId,
754
        $document,
755
        $replyToMessageId = null,
756
        $replyMarkup = null,
757
        $disableNotification = false
758
    ) {
759
        return Message::fromResponse($this->call('sendDocument', [
760
            'chat_id' => $chatId,
761
            'document' => $document,
762
            'reply_to_message_id' => $replyToMessageId,
763
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
764
            'disable_notification' => (bool) $disableNotification
765
        ]));
766
    }
767
768
    /**
769
     * Use this method to get basic info about a file and prepare it for downloading.
770
     * For the moment, bots can download files of up to 20MB in size.
771
     * On success, a File object is returned.
772
     * The file can then be downloaded via the link https://api.telegram.org/file/bot<token>/<file_path>,
773
     * where <file_path> is taken from the response.
774
     * It is guaranteed that the link will be valid for at least 1 hour.
775
     * When the link expires, a new one can be requested by calling getFile again.
776
     *
777
     * @param $fileId
778
     *
779
     * @return \TelegramBot\Api\Types\File
780
     * @throws \TelegramBot\Api\InvalidArgumentException
781
     * @throws \TelegramBot\Api\Exception
782
     */
783
    public function getFile($fileId)
784
    {
785
        return File::fromResponse($this->call('getFile', ['file_id' => $fileId]));
786
    }
787
788
    /**
789
     * Get file contents via cURL
790
     *
791
     * @param $fileId
792
     *
793
     * @return string
794
     *
795
     * @throws \TelegramBot\Api\HttpException
796
     */
797
    public function downloadFile($fileId)
798
    {
799
        $file = $this->getFile($fileId);
800
        $options = [
801
            CURLOPT_HEADER => 0,
802
            CURLOPT_HTTPGET => 1,
803
            CURLOPT_RETURNTRANSFER => 1,
804
            CURLOPT_URL => $this->getFileUrl() . '/' . $file->getFilePath()
805
        ];
806
807
        return $this->executeCurl($options);
808
    }
809
810
    /**
811
     * Use this method to send answers to an inline query. On success, True is returned.
812
     * No more than 50 results per query are allowed.
813
     *
814
     * @param string $inlineQueryId
815
     * @param \TelegramBot\Api\Types\Inline\AbstractInlineQueryResult[] $results
816
     * @param int $cacheTime
817
     * @param bool $isPersonal
818
     * @param string $nextOffset
819
     *
820
     * @return mixed
821
     * @throws Exception
822
     */
823
    public function answerInlineQuery($inlineQueryId, $results, $cacheTime = 300, $isPersonal = false, $nextOffset = '')
824
    {
825
        $results = array_map(function ($item) {
826
            /* @var \TelegramBot\Api\Types\Inline\AbstractInlineQueryResult $item */
827
828
            return json_decode($item->toJson(), true);
829
        }, $results);
830
831
        return $this->call('answerInlineQuery', [
832
            'inline_query_id' => $inlineQueryId,
833
            'results' => json_encode($results),
834
            'cache_time' => $cacheTime,
835
            'is_personal' => $isPersonal,
836
            'next_offset' => $nextOffset,
837
        ]);
838
    }
839
840
    /**
841
     * Use this method to kick a user from a group or a supergroup.
842
     * In the case of supergroups, the user will not be able to return to the group
843
     * on their own using invite links, etc., unless unbanned first.
844
     * The bot must be an administrator in the group for this to work. Returns True on success.
845
     *
846
     * @param int|string $chatId Unique identifier for the target group
847
     * or username of the target supergroup (in the format @supergroupusername)
848
     * @param int $userId Unique identifier of the target user
849
     *
850
     * @return bool
851
     */
852
    public function kickChatMember($chatId, $userId)
853
    {
854
        return $this->call('kickChatMember', [
855
            'chat_id' => $chatId,
856
            'user_id' => $userId,
857
        ]);
858
    }
859
860
    /**
861
     * Use this method to unban a previously kicked user in a supergroup.
862
     * The user will not return to the group automatically, but will be able to join via link, etc.
863
     * The bot must be an administrator in the group for this to work. Returns True on success.
864
     *
865
     * @param int|string $chatId Unique identifier for the target group
866
     * or username of the target supergroup (in the format @supergroupusername)
867
     * @param int $userId Unique identifier of the target user
868
     *
869
     * @return bool
870
     */
871
    public function unbanChatMember($chatId, $userId)
872
    {
873
        return $this->call('unbanChatMember', [
874
            'chat_id' => $chatId,
875
            'user_id' => $userId,
876
        ]);
877
    }
878
879
    /**
880
     * Use this method to send answers to callback queries sent from inline keyboards.
881
     * The answer will be displayed to the user as a notification at the top of the chat screen or as an alert.
882
     *
883
     * @param $callbackQueryId
884
     * @param null $text
885
     * @param bool $showAlert
886
     *
887
     * @return bool
888
     */
889
    public function answerCallbackQuery($callbackQueryId, $text = null, $showAlert = false)
890
    {
891
        return $this->call('answerCallbackQuery', [
892
            'callback_query_id' => $callbackQueryId,
893
            'text' => $text,
894
            'show_alert' => (bool)$showAlert,
895
        ]);
896
    }
897
898
899
    /**
900
     * Use this method to edit text messages sent by the bot or via the bot
901
     *
902
     * @param int|string $chatId
903
     * @param int $messageId
904
     * @param string $text
905
     * @param string|null $parseMode
906
     * @param bool $disablePreview
907
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
908
     *
909
     * @return \TelegramBot\Api\Types\Message
910
     * @throws \TelegramBot\Api\InvalidArgumentException
911
     * @throws \TelegramBot\Api\Exception
912
     */
913
    public function editMessageText(
914
        $chatId,
915
        $messageId,
916
        $text,
917
        $parseMode = null,
918
        $disablePreview = false,
919
        $replyMarkup = null
920
    ) {
921
        return Message::fromResponse($this->call('editMessageText', [
922
            'chat_id' => $chatId,
923
            'message_id' => $messageId,
924
            'text' => $text,
925
            'parse_mode' => $parseMode,
926
            'disable_web_page_preview' => $disablePreview,
927
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
928
        ]));
929
    }
930
931
    /**
932
     * Use this method to edit text messages sent by the bot or via the bot
933
     *
934
     * @param int|string $chatId
935
     * @param int $messageId
936
     * @param string|null $caption
937
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
938
     *
939
     * @return \TelegramBot\Api\Types\Message
940
     * @throws \TelegramBot\Api\InvalidArgumentException
941
     * @throws \TelegramBot\Api\Exception
942
     */
943
    public function editMessageCaption(
944 9
        $chatId,
945
        $messageId,
946 9
        $caption = null,
947 9
        $replyMarkup = null
948
    ) {
949
        return Message::fromResponse($this->call('editMessageText', [
950
            'chat_id' => $chatId,
951
            'message_id' => $messageId,
952
            'caption' => $caption,
953
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
954
        ]));
955
    }
956
957
    /**
958
     * Use this method to edit only the reply markup of messages sent by the bot or via the bot
959
     *
960
     * @param int|string $chatId
961
     * @param int $messageId
962
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
963
     *
964
     * @return \TelegramBot\Api\Types\Message
965
     * @throws \TelegramBot\Api\InvalidArgumentException
966
     * @throws \TelegramBot\Api\Exception
967
     */
968
    public function editMessageReplyMarkup(
969
        $chatId,
970
        $messageId,
971
        $replyMarkup = null
972
    ) {
973
        return Message::fromResponse($this->call('editMessageText', [
974
            'chat_id' => $chatId,
975
            'message_id' => $messageId,
976
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
977
        ]));
978
    }
979
980
    /**
981
     * Close curl
982
     */
983
    public function __destruct()
984
    {
985
        $this->curl && curl_close($this->curl);
986
    }
987
988
    /**
989
     * @return string
990
     */
991
    public function getUrl()
992
    {
993
        return self::URL_PREFIX . $this->token;
994
    }
995
996
    /**
997
     * @return string
998
     */
999
    public function getFileUrl()
1000
    {
1001
        return self::FILE_URL_PREFIX . $this->token;
1002
    }
1003
1004
    /**
1005
     * @param \TelegramBot\Api\Types\Update $update
1006
     * @param string $eventName
1007
     *
1008
     * @throws \TelegramBot\Api\Exception
1009
     */
1010
    public function trackUpdate(Update $update, $eventName = 'Message')
1011
    {
1012
        if (!in_array($update->getUpdateId(), $this->trackedEvents)) {
1013
            $this->trackedEvents[] = $update->getUpdateId();
1014
1015
            $this->track($update->getMessage(), $eventName);
1016
1017
            if (count($this->trackedEvents) > self::MAX_TRACKED_EVENTS) {
1018
                $this->trackedEvents = array_slice($this->trackedEvents, round(self::MAX_TRACKED_EVENTS / 4));
1019
            }
1020
        }
1021
    }
1022
1023
    /**
1024
     * Wrapper for tracker
1025
     *
1026
     * @param \TelegramBot\Api\Types\Message $message
1027
     * @param string $eventName
1028
     *
1029
     * @throws \TelegramBot\Api\Exception
1030
     */
1031
    public function track(Message $message, $eventName = 'Message')
1032
    {
1033
        if ($this->tracker instanceof Botan) {
1034
            $this->tracker->track($message, $eventName);
1035
        }
1036
    }
1037
}
1038