Passed
Push — master ( 8b9dc8...67c9bb )
by
unknown
02:30
created

BotApi::getFileUrl()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 2
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\Inline\QueryResult\AbstractInlineQueryResult;
8
use TelegramBot\Api\Types\Message;
9
use TelegramBot\Api\Types\Update;
10
use TelegramBot\Api\Types\User;
11
use TelegramBot\Api\Types\UserProfilePhotos;
12
13
/**
14
 * Class BotApi
15
 *
16
 * @package TelegramBot\Api
17
 */
18
class BotApi
19
{
20
    /**
21
     * HTTP codes
22
     *
23
     * @var array
24
     */
25
    public static $codes = [
26
        // Informational 1xx
27
        100 => 'Continue',
28
        101 => 'Switching Protocols',
29
        102 => 'Processing',            // RFC2518
30
        // Success 2xx
31
        200 => 'OK',
32
        201 => 'Created',
33
        202 => 'Accepted',
34
        203 => 'Non-Authoritative Information',
35
        204 => 'No Content',
36
        205 => 'Reset Content',
37
        206 => 'Partial Content',
38
        207 => 'Multi-Status',          // RFC4918
39
        208 => 'Already Reported',      // RFC5842
40
        226 => 'IM Used',               // RFC3229
41
        // Redirection 3xx
42
        300 => 'Multiple Choices',
43
        301 => 'Moved Permanently',
44
        302 => 'Found', // 1.1
45
        303 => 'See Other',
46
        304 => 'Not Modified',
47
        305 => 'Use Proxy',
48
        // 306 is deprecated but reserved
49
        307 => 'Temporary Redirect',
50
        308 => 'Permanent Redirect',    // RFC7238
51
        // Client Error 4xx
52
        400 => 'Bad Request',
53
        401 => 'Unauthorized',
54
        402 => 'Payment Required',
55
        403 => 'Forbidden',
56
        404 => 'Not Found',
57
        405 => 'Method Not Allowed',
58
        406 => 'Not Acceptable',
59
        407 => 'Proxy Authentication Required',
60
        408 => 'Request Timeout',
61
        409 => 'Conflict',
62
        410 => 'Gone',
63
        411 => 'Length Required',
64
        412 => 'Precondition Failed',
65
        413 => 'Payload Too Large',
66
        414 => 'URI Too Long',
67
        415 => 'Unsupported Media Type',
68
        416 => 'Range Not Satisfiable',
69
        417 => 'Expectation Failed',
70
        422 => 'Unprocessable Entity',                                        // RFC4918
71
        423 => 'Locked',                                                      // RFC4918
72
        424 => 'Failed Dependency',                                           // RFC4918
73
        425 => 'Reserved for WebDAV advanced collections expired proposal',   // RFC2817
74
        426 => 'Upgrade Required',                                            // RFC2817
75
        428 => 'Precondition Required',                                       // RFC6585
76
        429 => 'Too Many Requests',                                           // RFC6585
77
        431 => 'Request Header Fields Too Large',                             // RFC6585
78
        // Server Error 5xx
79
        500 => 'Internal Server Error',
80
        501 => 'Not Implemented',
81
        502 => 'Bad Gateway',
82
        503 => 'Service Unavailable',
83
        504 => 'Gateway Timeout',
84
        505 => 'HTTP Version Not Supported',
85
        506 => 'Variant Also Negotiates (Experimental)',                      // RFC2295
86
        507 => 'Insufficient Storage',                                        // RFC4918
87
        508 => 'Loop Detected',                                               // RFC5842
88
        510 => 'Not Extended',                                                // RFC2774
89
        511 => 'Network Authentication Required',                             // RFC6585
90
    ];
91
92
93
    /**
94
     * Default http status code
95
     */
96
    const DEFAULT_STATUS_CODE = 200;
97
98
    /**
99
     * Not Modified http status code
100
     */
101
    const NOT_MODIFIED_STATUS_CODE = 304;
102
103
    /**
104
     * Limits for tracked ids
105
     */
106
    const MAX_TRACKED_EVENTS = 200;
107
108
    /**
109
     * Url prefixes
110
     */
111
    const URL_PREFIX = 'https://api.telegram.org/bot';
112
113
    /**
114
     * Url prefix for files
115
     */
116
    const FILE_URL_PREFIX = 'https://api.telegram.org/file/bot';
117
118
    /**
119
     * CURL object
120
     *
121
     * @var
122
     */
123
    protected $curl;
124
125
    /**
126
     * Bot token
127
     *
128
     * @var string
129
     */
130
    protected $token;
131
132
    /**
133
     * Botan tracker
134
     *
135
     * @var \TelegramBot\Api\Botan
136
     */
137
    protected $tracker;
138
139
    /**
140
     * list of event ids
141
     *
142
     * @var array
143
     */
144
    protected $trackedEvents = [];
145
146
    /**
147
     * Check whether return associative array
148
     *
149
     * @var bool
150
     */
151
    protected $returnArray = true;
152
153
154
    /**
155
     * Constructor
156
     *
157
     * @param string $token Telegram Bot API token
158
     * @param string|null $trackerToken Yandex AppMetrica application api_key
159
     */
160 9
    public function __construct($token, $trackerToken = null)
161
    {
162 9
        $this->curl = curl_init();
163 9
        $this->token = $token;
164
165 9
        if ($trackerToken) {
166
            $this->tracker = new Botan($trackerToken);
167
        }
168 9
    }
169
170
    /**
171
     * Set return array
172
     *
173
     * @param bool $mode
174
     *
175
     * @return $this
176
     */
177
    public function setModeObject($mode = true)
178
    {
179
        $this->returnArray = !$mode;
180
181
        return $this;
182
    }
183
184
185
    /**
186
     * Call method
187
     *
188
     * @param string $method
189
     * @param array|null $data
190
     *
191
     * @return mixed
192
     * @throws \TelegramBot\Api\Exception
193
     * @throws \TelegramBot\Api\HttpException
194
     * @throws \TelegramBot\Api\InvalidJsonException
195
     */
196
    public function call($method, array $data = null)
197
    {
198
        $options = [
199
            CURLOPT_URL => $this->getUrl().'/'.$method,
200
            CURLOPT_RETURNTRANSFER => true,
201
            CURLOPT_POST => null,
202
            CURLOPT_POSTFIELDS => null,
203
        ];
204
205
        if ($data) {
206
            $options[CURLOPT_POST] = true;
207
            $options[CURLOPT_POSTFIELDS] = $data;
208
        }
209
210
        $response = self::jsonValidate($this->executeCurl($options), $this->returnArray);
211
212
        if ($this->returnArray) {
213
            if (!isset($response['ok'])) {
214
                throw new Exception($response['description'], $response['error_code']);
215
            }
216
217
            return $response['result'];
218
        }
219
220
        if (!$response->ok) {
221
            throw new Exception($response->description, $response->error_code);
222
        }
223
224
        return $response->result;
225
    }
226
227
    /**
228
     * curl_exec wrapper for response validation
229
     *
230
     * @param array $options
231
     *
232
     * @return string
233
     *
234
     * @throws \TelegramBot\Api\HttpException
235
     */
236
    protected function executeCurl(array $options)
237
    {
238
        curl_setopt_array($this->curl, $options);
239
240
        $result = curl_exec($this->curl);
241
        self::curlValidate($this->curl, $result);
242
        if ($result === false) {
243
            throw new HttpException(curl_error($this->curl), curl_errno($this->curl));
244
        }
245
246
        return $result;
247
    }
248
249
    /**
250
     * Response validation
251
     *
252
     * @param resource $curl
253
     * @param string $response
254
     * @throws HttpException
255
     */
256
    public static function curlValidate($curl, $response = null)
257
    {
258
        $json = json_decode($response, true)?: [];
259
        if (($httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE))
260
            && !in_array($httpCode, [self::DEFAULT_STATUS_CODE, self::NOT_MODIFIED_STATUS_CODE])
261
        ) {
262
            $errorDescription = array_key_exists('description', $json) ? $json['description'] : self::$codes[$httpCode];
263
            throw new HttpException($errorDescription, $httpCode);
264
        }
265
    }
266
267
    /**
268
     * JSON validation
269
     *
270
     * @param string $jsonString
271
     * @param boolean $asArray
272
     *
273
     * @return object|array
274
     * @throws \TelegramBot\Api\InvalidJsonException
275
     */
276
    public static function jsonValidate($jsonString, $asArray)
277
    {
278
        $json = json_decode($jsonString, $asArray);
279
280
        if (json_last_error() != JSON_ERROR_NONE) {
281
            throw new InvalidJsonException(json_last_error_msg(), json_last_error());
282
        }
283
284
        return $json;
285
    }
286
287
    /**
288
     * Use this method to send text messages. On success, the sent \TelegramBot\Api\Types\Message is returned.
289
     *
290
     * @param int|string $chatId
291
     * @param string $text
292
     * @param string|null $parseMode
293
     * @param bool $disablePreview
294
     * @param int|null $replyToMessageId
295
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
296
     * @param bool $disableNotification
297
     *
298
     * @return \TelegramBot\Api\Types\Message
299
     * @throws \TelegramBot\Api\InvalidArgumentException
300
     * @throws \TelegramBot\Api\Exception
301
     */
302
    public function sendMessage(
303
        $chatId,
304
        $text,
305
        $parseMode = null,
306
        $disablePreview = false,
307
        $replyToMessageId = null,
308
        $replyMarkup = null,
309
        $disableNotification = false
310
    ) {
311
        return Message::fromResponse($this->call('sendMessage', [
312
            'chat_id' => $chatId,
313
            'text' => $text,
314
            'parse_mode' => $parseMode,
315
            'disable_web_page_preview' => $disablePreview,
316
            'reply_to_message_id' => (int)$replyToMessageId,
317
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
318
            'disable_notification' => (bool)$disableNotification,
319
        ]));
320
    }
321
322
    /**
323
     * Use this method to send phone contacts
324
     *
325
     * @param int|string $chatId chat_id or @channel_name
326
     * @param string $phoneNumber
327
     * @param string $firstName
328
     * @param string $lastName
329
     * @param int|null $replyToMessageId
330
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
331
     * @param bool $disableNotification
332
     *
333
     * @return \TelegramBot\Api\Types\Message
334
     * @throws \TelegramBot\Api\Exception
335
     */
336 View Code Duplication
    public function sendContact(
337
        $chatId,
338
        $phoneNumber,
339
        $firstName,
340
        $lastName = null,
341
        $replyToMessageId = null,
342
        $replyMarkup = null,
343
        $disableNotification = false
344
    ) {
345
        return Message::fromResponse($this->call('sendContact', [
346
            'chat_id' => $chatId,
347
            'phone_number' => $phoneNumber,
348
            'first_name' => $firstName,
349
            'last_name' => $lastName,
350
            'reply_to_message_id' => $replyToMessageId,
351
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
352
            'disable_notification' => (bool)$disableNotification,
353
        ]));
354
    }
355
356
    /**
357
     * Use this method when you need to tell the user that something is happening on the bot's side.
358
     * The status is set for 5 seconds or less (when a message arrives from your bot,
359
     * Telegram clients clear its typing status).
360
     *
361
     * We only recommend using this method when a response from the bot will take a noticeable amount of time to arrive.
362
     *
363
     * Type of action to broadcast. Choose one, depending on what the user is about to receive:
364
     * `typing` for text messages, `upload_photo` for photos, `record_video` or `upload_video` for videos,
365
     * `record_audio` or upload_audio for audio files, `upload_document` for general files,
366
     * `find_location` for location data.
367
     *
368
     * @param int $chatId
369
     * @param string $action
370
     *
371
     * @return bool
372
     * @throws \TelegramBot\Api\Exception
373
     */
374
    public function sendChatAction($chatId, $action)
375
    {
376
        return $this->call('sendChatAction', [
377
            'chat_id' => $chatId,
378
            'action' => $action,
379
        ]);
380
    }
381
382
    /**
383
     * Use this method to get a list of profile pictures for a user.
384
     *
385
     * @param int $userId
386
     * @param int $offset
387
     * @param int $limit
388
     *
389
     * @return \TelegramBot\Api\Types\UserProfilePhotos
390
     * @throws \TelegramBot\Api\Exception
391
     */
392
    public function getUserProfilePhotos($userId, $offset = 0, $limit = 100)
393
    {
394
        return UserProfilePhotos::fromResponse($this->call('getUserProfilePhotos', [
395
            'user_id' => (int)$userId,
396
            'offset' => (int)$offset,
397
            'limit' => (int)$limit,
398
        ]));
399
    }
400
401
    /**
402
     * Use this method to specify a url and receive incoming updates via an outgoing webhook.
403
     * Whenever there is an update for the bot, we will send an HTTPS POST request to the specified url,
404
     * containing a JSON-serialized Update.
405
     * In case of an unsuccessful request, we will give up after a reasonable amount of attempts.
406
     *
407
     * @param string $url HTTPS url to send updates to. Use an empty string to remove webhook integration
408
     * @param \CURLFile|string $certificate Upload your public key certificate
409
     *                                      so that the root certificate in use can be checked
410
     *
411
     * @return string
412
     *
413
     * @throws \TelegramBot\Api\Exception
414
     */
415
    public function setWebhook($url = '', $certificate = null)
416
    {
417
        return $this->call('setWebhook', ['url' => $url, 'certificate' => $certificate]);
418
    }
419
420
    /**
421
     * A simple method for testing your bot's auth token.Requires no parameters.
422
     * Returns basic information about the bot in form of a User object.
423
     *
424
     * @return \TelegramBot\Api\Types\User
425
     * @throws \TelegramBot\Api\Exception
426
     * @throws \TelegramBot\Api\InvalidArgumentException
427
     */
428
    public function getMe()
429
    {
430
        return User::fromResponse($this->call('getMe'));
431
    }
432
433
    /**
434
     * Use this method to receive incoming updates using long polling.
435
     * An Array of Update objects is returned.
436
     *
437
     * Notes
438
     * 1. This method will not work if an outgoing webhook is set up.
439
     * 2. In order to avoid getting duplicate updates, recalculate offset after each server response.
440
     *
441
     * @param int $offset
442
     * @param int $limit
443
     * @param int $timeout
444
     *
445
     * @return Update[]
446
     * @throws \TelegramBot\Api\Exception
447
     * @throws \TelegramBot\Api\InvalidArgumentException
448
     */
449 2
    public function getUpdates($offset = 0, $limit = 100, $timeout = 0)
450
    {
451 2
        $updates = ArrayOfUpdates::fromResponse($this->call('getUpdates', [
452 2
            'offset' => $offset,
453 2
            'limit' => $limit,
454 2
            'timeout' => $timeout,
455 2
        ]));
456
457 2
        if ($this->tracker instanceof Botan) {
458
            foreach ($updates as $update) {
459
                $this->trackUpdate($update);
460
            }
461
        }
462
463 2
        return $updates;
464
    }
465
466
    /**
467
     * Use this method to send point on the map. On success, the sent Message is returned.
468
     *
469
     * @param int $chatId
470
     * @param float $latitude
471
     * @param float $longitude
472
     * @param int|null $replyToMessageId
473
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
474
     * @param bool $disableNotification
475
     *
476
     * @return \TelegramBot\Api\Types\Message
477
     * @throws \TelegramBot\Api\Exception
478
     */
479 View Code Duplication
    public function sendLocation(
480
        $chatId,
481
        $latitude,
482
        $longitude,
483
        $replyToMessageId = null,
484
        $replyMarkup = null,
485
        $disableNotification = false
486
    ) {
487
        return Message::fromResponse($this->call('sendLocation', [
488
            'chat_id' => $chatId,
489
            'latitude' => $latitude,
490
            'longitude' => $longitude,
491
            'reply_to_message_id' => $replyToMessageId,
492
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
493
            'disable_notification' => (bool)$disableNotification,
494
        ]));
495
    }
496
497
    /**
498
     * Use this method to send information about a venue. On success, the sent Message is returned.
499
     *
500
     * @param int|string $chatId chat_id or @channel_name
501
     * @param float $latitude
502
     * @param float $longitude
503
     * @param string $title
504
     * @param string $address
505
     * @param string|null $foursquareId
506
     * @param int|null $replyToMessageId
507
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
508
     * @param bool $disableNotification
509
     *
510
     * @return \TelegramBot\Api\Types\Message
511
     * @throws \TelegramBot\Api\Exception
512
     */
513
    public function sendVenue(
514
        $chatId,
515
        $latitude,
516
        $longitude,
517
        $title,
518
        $address,
519
        $foursquareId = null,
520
        $replyToMessageId = null,
521
        $replyMarkup = null,
522
        $disableNotification = false
523
    ) {
524
        return Message::fromResponse($this->call('sendVenue', [
525
            'chat_id' => $chatId,
526
            'latitude' => $latitude,
527
            'longitude' => $longitude,
528
            'title' => $title,
529
            'address' => $address,
530
            'foursquare_id' => $foursquareId,
531
            'reply_to_message_id' => $replyToMessageId,
532
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
533
            'disable_notification' => (bool)$disableNotification,
534
        ]));
535
    }
536
537
    /**
538
     * Use this method to send .webp stickers. On success, the sent Message is returned.
539
     *
540
     * @param int|string $chatId chat_id or @channel_name
541
     * @param \CURLFile|string $sticker
542
     * @param int|null $replyToMessageId
543
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
544
     * @param bool $disableNotification
545
     *
546
     * @return \TelegramBot\Api\Types\Message
547
     * @throws \TelegramBot\Api\InvalidArgumentException
548
     * @throws \TelegramBot\Api\Exception
549
     */
550 View Code Duplication
    public function sendSticker(
551
        $chatId,
552
        $sticker,
553
        $replyToMessageId = null,
554
        $replyMarkup = null,
555
        $disableNotification = false
556
    ) {
557
        return Message::fromResponse($this->call('sendSticker', [
558
            'chat_id' => $chatId,
559
            'sticker' => $sticker,
560
            'reply_to_message_id' => $replyToMessageId,
561
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
562
            'disable_notification' => (bool)$disableNotification,
563
        ]));
564
    }
565
566
    /**
567
     * Use this method to send video files,
568
     * Telegram clients support mp4 videos (other formats may be sent as Document).
569
     * On success, the sent Message is returned.
570
     *
571
     * @param int|string $chatId chat_id or @channel_name
572
     * @param \CURLFile|string $video
573
     * @param int|null $duration
574
     * @param string|null $caption
575
     * @param int|null $replyToMessageId
576
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
577
     * @param bool $disableNotification
578
     *
579
     * @return \TelegramBot\Api\Types\Message
580
     * @throws \TelegramBot\Api\InvalidArgumentException
581
     * @throws \TelegramBot\Api\Exception
582
     */
583
    public function sendVideo(
584
        $chatId,
585
        $video,
586
        $duration = null,
587
        $caption = null,
588
        $replyToMessageId = null,
589
        $replyMarkup = null,
590
        $disableNotification = false
591
    ) {
592
        return Message::fromResponse($this->call('sendVideo', [
593
            'chat_id' => $chatId,
594
            'video' => $video,
595
            'duration' => $duration,
596
            'caption' => $caption,
597
            'reply_to_message_id' => $replyToMessageId,
598
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
599
            'disable_notification' => (bool)$disableNotification,
600
        ]));
601
    }
602
603
    /**
604
     * Use this method to send audio files,
605
     * if you want Telegram clients to display the file as a playable voice message.
606
     * For this to work, your audio must be in an .ogg file encoded with OPUS
607
     * (other formats may be sent as Audio or Document).
608
     * On success, the sent Message is returned.
609
     * Bots can currently send voice messages of up to 50 MB in size, this limit may be changed in the future.
610
     *
611
     * @param int|string $chatId chat_id or @channel_name
612
     * @param \CURLFile|string $voice
613
     * @param int|null $duration
614
     * @param int|null $replyToMessageId
615
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
616
     * @param bool $disableNotification
617
     *
618
     * @return \TelegramBot\Api\Types\Message
619
     * @throws \TelegramBot\Api\InvalidArgumentException
620
     * @throws \TelegramBot\Api\Exception
621
     */
622 View Code Duplication
    public function sendVoice(
623
        $chatId,
624
        $voice,
625
        $duration = null,
626
        $replyToMessageId = null,
627
        $replyMarkup = null,
628
        $disableNotification = false
629
    ) {
630
        return Message::fromResponse($this->call('sendVoice', [
631
            'chat_id' => $chatId,
632
            'voice' => $voice,
633
            'duration' => $duration,
634
            'reply_to_message_id' => $replyToMessageId,
635
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
636
            'disable_notification' => (bool)$disableNotification,
637
        ]));
638
    }
639
640
    /**
641
     * Use this method to forward messages of any kind. On success, the sent Message is returned.
642
     *
643
     * @param int|string $chatId chat_id or @channel_name
644
     * @param int $fromChatId
645
     * @param int $messageId
646
     * @param bool $disableNotification
647
     *
648
     * @return \TelegramBot\Api\Types\Message
649
     * @throws \TelegramBot\Api\InvalidArgumentException
650
     * @throws \TelegramBot\Api\Exception
651
     */
652
    public function forwardMessage($chatId, $fromChatId, $messageId, $disableNotification = false)
653
    {
654
        return Message::fromResponse($this->call('forwardMessage', [
655
            'chat_id' => $chatId,
656
            'from_chat_id' => $fromChatId,
657
            'message_id' => (int)$messageId,
658
            'disable_notification' => (bool)$disableNotification,
659
        ]));
660
    }
661
662
    /**
663
     * Use this method to send audio files,
664
     * if you want Telegram clients to display them in the music player.
665
     * Your audio must be in the .mp3 format.
666
     * On success, the sent Message is returned.
667
     * Bots can currently send audio files of up to 50 MB in size, this limit may be changed in the future.
668
     *
669
     * For backward compatibility, when the fields title and performer are both empty
670
     * and the mime-type of the file to be sent is not audio/mpeg, the file will be sent as a playable voice message.
671
     * For this to work, the audio must be in an .ogg file encoded with OPUS.
672
     * This behavior will be phased out in the future. For sending voice messages, use the sendVoice method instead.
673
     *
674
     * @deprecated since 20th February. Removed backward compatibility from the method sendAudio.
675
     * Voice messages now must be sent using the method sendVoice.
676
     * There is no more need to specify a non-empty title or performer while sending the audio by file_id.
677
     *
678
     * @param int|string $chatId chat_id or @channel_name
679
     * @param \CURLFile|string $audio
680
     * @param int|null $duration
681
     * @param string|null $performer
682
     * @param string|null $title
683
     * @param int|null $replyToMessageId
684
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
685
     * @param bool $disableNotification
686
     *
687
     * @return \TelegramBot\Api\Types\Message
688
     * @throws \TelegramBot\Api\InvalidArgumentException
689
     * @throws \TelegramBot\Api\Exception
690
     */
691
    public function sendAudio(
692
        $chatId,
693
        $audio,
694
        $duration = null,
695
        $performer = null,
696
        $title = null,
697
        $replyToMessageId = null,
698
        $replyMarkup = null,
699
        $disableNotification = false
700
    ) {
701
        return Message::fromResponse($this->call('sendAudio', [
702
            'chat_id' => $chatId,
703
            'audio' => $audio,
704
            'duration' => $duration,
705
            'performer' => $performer,
706
            'title' => $title,
707
            'reply_to_message_id' => $replyToMessageId,
708
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
709
            'disable_notification' => (bool)$disableNotification,
710
        ]));
711
    }
712
713
    /**
714
     * Use this method to send photos. On success, the sent Message is returned.
715
     *
716
     * @param int|string $chatId chat_id or @channel_name
717
     * @param \CURLFile|string $photo
718
     * @param string|null $caption
719
     * @param int|null $replyToMessageId
720
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
721
     * @param bool $disableNotification
722
     *
723
     * @return \TelegramBot\Api\Types\Message
724
     * @throws \TelegramBot\Api\InvalidArgumentException
725
     * @throws \TelegramBot\Api\Exception
726
     */
727 View Code Duplication
    public function sendPhoto(
728
        $chatId,
729
        $photo,
730
        $caption = null,
731
        $replyToMessageId = null,
732
        $replyMarkup = null,
733
        $disableNotification = false
734
    ) {
735
        return Message::fromResponse($this->call('sendPhoto', [
736
            'chat_id' => $chatId,
737
            'photo' => $photo,
738
            'caption' => $caption,
739
            'reply_to_message_id' => $replyToMessageId,
740
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
741
            'disable_notification' => (bool)$disableNotification,
742
        ]));
743
    }
744
745
    /**
746
     * Use this method to send general files. On success, the sent Message is returned.
747
     * Bots can currently send files of any type of up to 50 MB in size, this limit may be changed in the future.
748
     *
749
     * @param int|string $chatId chat_id or @channel_name
750
     * @param \CURLFile|string $document
751
     * @param string|null $caption
752
     * @param int|null $replyToMessageId
753
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
754
     * @param bool $disableNotification
755
     *
756
     * @return \TelegramBot\Api\Types\Message
757
     * @throws \TelegramBot\Api\InvalidArgumentException
758
     * @throws \TelegramBot\Api\Exception
759
     */
760 View Code Duplication
    public function sendDocument(
761
        $chatId,
762
        $document,
763
        $caption = null,
764
        $replyToMessageId = null,
765
        $replyMarkup = null,
766
        $disableNotification = false
767
    ) {
768
        return Message::fromResponse($this->call('sendDocument', [
769
            'chat_id' => $chatId,
770
            'document' => $document,
771
            'caption' => $caption,
772
            'reply_to_message_id' => $replyToMessageId,
773
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
774
            'disable_notification' => (bool)$disableNotification,
775
        ]));
776
    }
777
778
    /**
779
     * Use this method to get basic info about a file and prepare it for downloading.
780
     * For the moment, bots can download files of up to 20MB in size.
781
     * On success, a File object is returned.
782
     * The file can then be downloaded via the link https://api.telegram.org/file/bot<token>/<file_path>,
783
     * where <file_path> is taken from the response.
784
     * It is guaranteed that the link will be valid for at least 1 hour.
785
     * When the link expires, a new one can be requested by calling getFile again.
786
     *
787
     * @param $fileId
788
     *
789
     * @return \TelegramBot\Api\Types\File
790
     * @throws \TelegramBot\Api\InvalidArgumentException
791
     * @throws \TelegramBot\Api\Exception
792
     */
793
    public function getFile($fileId)
794
    {
795
        return File::fromResponse($this->call('getFile', ['file_id' => $fileId]));
796
    }
797
798
    /**
799
     * Get file contents via cURL
800
     *
801
     * @param $fileId
802
     *
803
     * @return string
804
     *
805
     * @throws \TelegramBot\Api\HttpException
806
     */
807
    public function downloadFile($fileId)
808
    {
809
        $file = $this->getFile($fileId);
810
        $options = [
811
            CURLOPT_HEADER => 0,
812
            CURLOPT_HTTPGET => 1,
813
            CURLOPT_RETURNTRANSFER => 1,
814
            CURLOPT_URL => $this->getFileUrl().'/'.$file->getFilePath(),
815
        ];
816
817
        return $this->executeCurl($options);
818
    }
819
820
    /**
821
     * Use this method to send answers to an inline query. On success, True is returned.
822
     * No more than 50 results per query are allowed.
823
     *
824
     * @param string $inlineQueryId
825
     * @param AbstractInlineQueryResult[] $results
826
     * @param int $cacheTime
827
     * @param bool $isPersonal
828
     * @param string $nextOffset
829
     *
830
     * @return mixed
831
     * @throws Exception
832
     */
833
    public function answerInlineQuery($inlineQueryId, $results, $cacheTime = 300, $isPersonal = false, $nextOffset = '')
834
    {
835
        $results = array_map(function ($item) {
836
            /* @var AbstractInlineQueryResult $item */
837
838
            return json_decode($item->toJson(), true);
839
        }, $results);
840
841
        return $this->call('answerInlineQuery', [
842
            'inline_query_id' => $inlineQueryId,
843
            'results' => json_encode($results),
844
            'cache_time' => $cacheTime,
845
            'is_personal' => $isPersonal,
846
            'next_offset' => $nextOffset,
847
        ]);
848
    }
849
850
    /**
851
     * Use this method to kick a user from a group or a supergroup.
852
     * In the case of supergroups, the user will not be able to return to the group
853
     * on their own using invite links, etc., unless unbanned first.
854
     * The bot must be an administrator in the group for this to work. Returns True on success.
855
     *
856
     * @param int|string $chatId Unique identifier for the target group
857
     * or username of the target supergroup (in the format @supergroupusername)
858
     * @param int $userId Unique identifier of the target user
859
     *
860
     * @return bool
861
     */
862
    public function kickChatMember($chatId, $userId)
863
    {
864
        return $this->call('kickChatMember', [
865
            'chat_id' => $chatId,
866
            'user_id' => $userId,
867
        ]);
868
    }
869
870
    /**
871
     * Use this method to unban a previously kicked user in a supergroup.
872
     * The user will not return to the group automatically, but will be able to join via link, etc.
873
     * The bot must be an administrator in the group for this to work. Returns True on success.
874
     *
875
     * @param int|string $chatId Unique identifier for the target group
876
     * or username of the target supergroup (in the format @supergroupusername)
877
     * @param int $userId Unique identifier of the target user
878
     *
879
     * @return bool
880
     */
881
    public function unbanChatMember($chatId, $userId)
882
    {
883
        return $this->call('unbanChatMember', [
884
            'chat_id' => $chatId,
885
            'user_id' => $userId,
886
        ]);
887
    }
888
889
    /**
890
     * Use this method to send answers to callback queries sent from inline keyboards.
891
     * The answer will be displayed to the user as a notification at the top of the chat screen or as an alert.
892
     *
893
     * @param $callbackQueryId
894
     * @param null $text
895
     * @param bool $showAlert
896
     *
897
     * @return bool
898
     */
899
    public function answerCallbackQuery($callbackQueryId, $text = null, $showAlert = false)
900
    {
901
        return $this->call('answerCallbackQuery', [
902
            'callback_query_id' => $callbackQueryId,
903
            'text' => $text,
904
            'show_alert' => (bool)$showAlert,
905
        ]);
906
    }
907
908
909
    /**
910
     * Use this method to edit text messages sent by the bot or via the bot
911
     *
912
     * @param int|string $chatId
913
     * @param int $messageId
914
     * @param string $text
915
     * @param string $inlineMessageId
916
     * @param string|null $parseMode
917
     * @param bool $disablePreview
918
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
919
     * @return Message
920
     */
921 View Code Duplication
    public function editMessageText(
922
        $chatId,
923
        $messageId,
924
        $text,
925
        $parseMode = null,
926
        $disablePreview = false,
927
        $replyMarkup = null,
928
        $inlineMessageId = null
929
    ) {
930
        return Message::fromResponse($this->call('editMessageText', [
931
            'chat_id' => $chatId,
932
            'message_id' => $messageId,
933
            'text' => $text,
934
            'inline_message_id' => $inlineMessageId,
935
            'parse_mode' => $parseMode,
936
            'disable_web_page_preview' => $disablePreview,
937
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
938
        ]));
939
    }
940
941
    /**
942
     * Use this method to edit text messages sent by the bot or via the bot
943
     *
944
     * @param int|string $chatId
945
     * @param int $messageId
946
     * @param string|null $caption
947
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
948
     * @param string $inlineMessageId
949
     *
950
     * @return \TelegramBot\Api\Types\Message
951
     * @throws \TelegramBot\Api\InvalidArgumentException
952
     * @throws \TelegramBot\Api\Exception
953
     */
954
    public function editMessageCaption(
955
        $chatId,
956
        $messageId,
957
        $caption = null,
958
        $replyMarkup = null,
959
        $inlineMessageId = null
960
    ) {
961
        return Message::fromResponse($this->call('editMessageCaption', [
962
            'chat_id' => $chatId,
963
            'message_id' => $messageId,
964
            'inline_message_id' => $inlineMessageId,
965
            'caption' => $caption,
966
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
967
        ]));
968
    }
969
970
    /**
971
     * Use this method to edit only the reply markup of messages sent by the bot or via the bot
972
     *
973
     * @param int|string $chatId
974
     * @param int $messageId
975
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
976
     * @param string $inlineMessageId
977
     *
978
     * @return Message
979
     */
980 View Code Duplication
    public function editMessageReplyMarkup(
981
        $chatId,
982
        $messageId,
983
        $replyMarkup = null,
984
        $inlineMessageId = null
985
    ) {
986
        return Message::fromResponse($this->call('editMessageReplyMarkup', [
987
            'chat_id' => $chatId,
988
            'message_id' => $messageId,
989
            'inline_message_id' => $inlineMessageId,
990
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
991
        ]));
992
    }
993
994
    /**
995
     * Close curl
996
     */
997 9
    public function __destruct()
998
    {
999 9
        $this->curl && curl_close($this->curl);
1000 9
    }
1001
1002
    /**
1003
     * @return string
1004
     */
1005
    public function getUrl()
1006
    {
1007
        return self::URL_PREFIX.$this->token;
1008
    }
1009
1010
    /**
1011
     * @return string
1012
     */
1013
    public function getFileUrl()
1014
    {
1015
        return self::FILE_URL_PREFIX.$this->token;
1016
    }
1017
1018
    /**
1019
     * @param \TelegramBot\Api\Types\Update $update
1020
     * @param string $eventName
1021
     *
1022
     * @throws \TelegramBot\Api\Exception
1023
     */
1024
    public function trackUpdate(Update $update, $eventName = 'Message')
1025
    {
1026
        if (!in_array($update->getUpdateId(), $this->trackedEvents)) {
1027
            $this->trackedEvents[] = $update->getUpdateId();
1028
1029
            $this->track($update->getMessage(), $eventName);
1030
1031
            if (count($this->trackedEvents) > self::MAX_TRACKED_EVENTS) {
1032
                $this->trackedEvents = array_slice($this->trackedEvents, round(self::MAX_TRACKED_EVENTS / 4));
1033
            }
1034
        }
1035
    }
1036
1037
    /**
1038
     * Wrapper for tracker
1039
     *
1040
     * @param \TelegramBot\Api\Types\Message $message
1041
     * @param string $eventName
1042
     *
1043
     * @throws \TelegramBot\Api\Exception
1044
     */
1045
    public function track(Message $message, $eventName = 'Message')
1046
    {
1047
        if ($this->tracker instanceof Botan) {
1048
            $this->tracker->track($message, $eventName);
1049
        }
1050
    }
1051
1052
    /**
1053
     * Use this method to send invoices. On success, the sent Message is returned.
1054
     *
1055
     * @param int|string $chatId
1056
     * @param string $title
1057
     * @param string $description
1058
     * @param string $payload
1059
     * @param string $providerToken
1060
     * @param string $startParameter
1061
     * @param string $currency
1062
     * @param array $prices
1063
     * @param string|null $photoUrl
1064
     * @param int|null $photoSize
1065
     * @param int|null $photoWidth
1066
     * @param int|null $photoHeight
1067
     * @param bool $needName
1068
     * @param bool $needPhoneNumber
1069
     * @param bool $needEmail
1070
     * @param bool $needShippingAddress
1071
     * @param bool $isFlexible
1072
     * @param int|null $replyToMessageId
1073
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
1074
     * @param bool $disableNotification
1075
     *
1076
     * @return Message
1077
     */
1078
    public function sendInvoice(
1079
        $chatId,
1080
        $title,
1081
        $description,
1082
        $payload,
1083
        $providerToken,
1084
        $startParameter,
1085
        $currency,
1086
        $prices,
1087
        $isFlexible = false,
1088
        $photoUrl = null,
1089
        $photoSize = null,
1090
        $photoWidth = null,
1091
        $photoHeight = null,
1092
        $needName = false,
1093
        $needPhoneNumber = false,
1094
        $needEmail = false,
1095
        $needShippingAddress = false,
1096
        $replyToMessageId = null,
1097
        $replyMarkup = null,
1098
        $disableNotification = false
1099
    ) {
1100
        return Message::fromResponse($this->call('sendInvoice', [
1101
            'chat_id' => $chatId,
1102
            'title' => $title,
1103
            'description' => $description,
1104
            'payload' => $payload,
1105
            'provider_token' => $providerToken,
1106
            'start_parameter' => $startParameter,
1107
            'currency' => $currency,
1108
            'prices' => json_encode($prices),
1109
            'is_flexible' => $isFlexible,
1110
            'photo_url' => $photoUrl,
1111
            'photo_size' => $photoSize,
1112
            'photo_width' => $photoWidth,
1113
            'photo_height' => $photoHeight,
1114
            'need_name' => $needName,
1115
            'need_phone_number' => $needPhoneNumber,
1116
            'need_email' => $needEmail,
1117
            'need_shipping_address' => $needShippingAddress,
1118
            'reply_to_message_id' => $replyToMessageId,
1119
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
1120
            'disable_notification' => (bool)$disableNotification,
1121
        ]));
1122
    }
1123
1124
    /**
1125
     * If you sent an invoice requesting a shipping address and the parameter is_flexible was specified, the Bot API
1126
     * will send an Update with a shipping_query field to the bot. Use this method to reply to shipping queries.
1127
     * On success, True is returned.
1128
     *
1129
     * @param string $shippingQueryId
1130
     * @param bool $ok
1131
     * @param array $shipping_options
1132
     * @param null|string $errorMessage
1133
     *
1134
     * @return bool
1135
     *
1136
     */
1137
    public function answerShippingQuery($shippingQueryId, $ok = true, $shipping_options = [], $errorMessage = null)
1138
    {
1139
        return $this->call('answerShippingQuery', [
1140
            'shipping_query_id' => $shippingQueryId,
1141
            'ok' => (bool)$ok,
1142
            'shipping_options' => json_encode($shipping_options),
1143
            'error_message' => $errorMessage
1144
        ]);
1145
    }
1146
1147
    /**
1148
     * Use this method to respond to such pre-checkout queries. On success, True is returned.
1149
     * Note: The Bot API must receive an answer within 10 seconds after the pre-checkout query was sent.
1150
     *
1151
     * @param string $preCheckoutQueryId
1152
     * @param bool $ok
1153
     * @param null|string $errorMessage
1154
     *
1155
     * @return mixed
1156
     */
1157
    public function answerPreCheckoutQuery($preCheckoutQueryId, $ok = true, $errorMessage = null)
1158
    {
1159
        return $this->call('answerPreCheckoutQuery', [
1160
            'pre_checkout_query_id' => $preCheckoutQueryId,
1161
            'ok' => (bool)$ok,
1162
            'error_message' => $errorMessage
1163
        ]);
1164
    }
1165
}
1166