Passed
Push — master ( af3a0b...87be02 )
by
unknown
03:36
created

BotApi::getUserProfilePhotos()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 0
cts 6
cp 0
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 5
nc 1
nop 3
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);
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
     *
254
     * @throws \TelegramBot\Api\HttpException
255
     */
256
    public static function curlValidate($curl)
257
    {
258
        if (($httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE))
259
            && !in_array($httpCode, [self::DEFAULT_STATUS_CODE, self::NOT_MODIFIED_STATUS_CODE])
260
        ) {
261
            throw new HttpException(self::$codes[$httpCode], $httpCode);
262
        }
263
    }
264
265
    /**
266
     * JSON validation
267
     *
268
     * @param string $jsonString
269
     * @param boolean $asArray
270
     *
271
     * @return object|array
272
     * @throws \TelegramBot\Api\InvalidJsonException
273
     */
274
    public static function jsonValidate($jsonString, $asArray)
275
    {
276
        $json = json_decode($jsonString, $asArray);
277
278
        if (json_last_error() != JSON_ERROR_NONE) {
279
            throw new InvalidJsonException(json_last_error_msg(), json_last_error());
280
        }
281
282
        return $json;
283
    }
284
285
    /**
286
     * Use this method to send text messages. On success, the sent \TelegramBot\Api\Types\Message is returned.
287
     *
288
     * @param int|string $chatId
289
     * @param string $text
290
     * @param string|null $parseMode
291
     * @param bool $disablePreview
292
     * @param int|null $replyToMessageId
293
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
294
     * @param bool $disableNotification
295
     *
296
     * @return \TelegramBot\Api\Types\Message
297
     * @throws \TelegramBot\Api\InvalidArgumentException
298
     * @throws \TelegramBot\Api\Exception
299
     */
300
    public function sendMessage(
301
        $chatId,
302
        $text,
303
        $parseMode = null,
304
        $disablePreview = false,
305
        $replyToMessageId = null,
306
        $replyMarkup = null,
307
        $disableNotification = false
308
    ) {
309
        return Message::fromResponse($this->call('sendMessage', [
310
            'chat_id' => $chatId,
311
            'text' => $text,
312
            'parse_mode' => $parseMode,
313
            'disable_web_page_preview' => $disablePreview,
314
            'reply_to_message_id' => (int)$replyToMessageId,
315
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
316
            'disable_notification' => (bool)$disableNotification,
317
        ]));
318
    }
319
320
    /**
321
     * Use this method to send phone contacts
322
     *
323
     * @param int|string $chatId chat_id or @channel_name
324
     * @param string $phoneNumber
325
     * @param string $firstName
326
     * @param string $lastName
327
     * @param int|null $replyToMessageId
328
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
329
     * @param bool $disableNotification
330
     *
331
     * @return \TelegramBot\Api\Types\Message
332
     * @throws \TelegramBot\Api\Exception
333
     */
334 View Code Duplication
    public function sendContact(
335
        $chatId,
336
        $phoneNumber,
337
        $firstName,
338
        $lastName = null,
339
        $replyToMessageId = null,
340
        $replyMarkup = null,
341
        $disableNotification = false
342
    ) {
343
        return Message::fromResponse($this->call('sendContact', [
344
            'chat_id' => $chatId,
345
            'phone_number' => $phoneNumber,
346
            'first_name' => $firstName,
347
            'last_name' => $lastName,
348
            'reply_to_message_id' => $replyToMessageId,
349
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
350
            'disable_notification' => (bool)$disableNotification,
351
        ]));
352
    }
353
354
    /**
355
     * Use this method when you need to tell the user that something is happening on the bot's side.
356
     * The status is set for 5 seconds or less (when a message arrives from your bot,
357
     * Telegram clients clear its typing status).
358
     *
359
     * We only recommend using this method when a response from the bot will take a noticeable amount of time to arrive.
360
     *
361
     * Type of action to broadcast. Choose one, depending on what the user is about to receive:
362
     * `typing` for text messages, `upload_photo` for photos, `record_video` or `upload_video` for videos,
363
     * `record_audio` or upload_audio for audio files, `upload_document` for general files,
364
     * `find_location` for location data.
365
     *
366
     * @param int $chatId
367
     * @param string $action
368
     *
369
     * @return bool
370
     * @throws \TelegramBot\Api\Exception
371
     */
372
    public function sendChatAction($chatId, $action)
373
    {
374
        return $this->call('sendChatAction', [
375
            'chat_id' => $chatId,
376
            'action' => $action,
377
        ]);
378
    }
379
380
    /**
381
     * Use this method to get a list of profile pictures for a user.
382
     *
383
     * @param int $userId
384
     * @param int $offset
385
     * @param int $limit
386
     *
387
     * @return \TelegramBot\Api\Types\UserProfilePhotos
388
     * @throws \TelegramBot\Api\Exception
389
     */
390
    public function getUserProfilePhotos($userId, $offset = 0, $limit = 100)
391
    {
392
        return UserProfilePhotos::fromResponse($this->call('getUserProfilePhotos', [
393
            'user_id' => (int)$userId,
394
            'offset' => (int)$offset,
395
            'limit' => (int)$limit,
396
        ]));
397
    }
398
399
    /**
400
     * Use this method to specify a url and receive incoming updates via an outgoing webhook.
401
     * Whenever there is an update for the bot, we will send an HTTPS POST request to the specified url,
402
     * containing a JSON-serialized Update.
403
     * In case of an unsuccessful request, we will give up after a reasonable amount of attempts.
404
     *
405
     * @param string $url HTTPS url to send updates to. Use an empty string to remove webhook integration
406
     * @param \CURLFile|string $certificate Upload your public key certificate
407
     *                                      so that the root certificate in use can be checked
408
     *
409
     * @return string
410
     *
411
     * @throws \TelegramBot\Api\Exception
412
     */
413
    public function setWebhook($url = '', $certificate = null)
414
    {
415
        return $this->call('setWebhook', ['url' => $url, 'certificate' => $certificate]);
416
    }
417
418
    /**
419
     * A simple method for testing your bot's auth token.Requires no parameters.
420
     * Returns basic information about the bot in form of a User object.
421
     *
422
     * @return \TelegramBot\Api\Types\User
423
     * @throws \TelegramBot\Api\Exception
424
     * @throws \TelegramBot\Api\InvalidArgumentException
425
     */
426
    public function getMe()
427
    {
428
        return User::fromResponse($this->call('getMe'));
429
    }
430
431
    /**
432
     * Use this method to receive incoming updates using long polling.
433
     * An Array of Update objects is returned.
434
     *
435
     * Notes
436
     * 1. This method will not work if an outgoing webhook is set up.
437
     * 2. In order to avoid getting duplicate updates, recalculate offset after each server response.
438
     *
439
     * @param int $offset
440
     * @param int $limit
441
     * @param int $timeout
442
     *
443
     * @return Update[]
444
     * @throws \TelegramBot\Api\Exception
445
     * @throws \TelegramBot\Api\InvalidArgumentException
446
     */
447 2
    public function getUpdates($offset = 0, $limit = 100, $timeout = 0)
448
    {
449 2
        $updates = ArrayOfUpdates::fromResponse($this->call('getUpdates', [
450 2
            'offset' => $offset,
451 2
            'limit' => $limit,
452 2
            'timeout' => $timeout,
453 2
        ]));
454
455 2
        if ($this->tracker instanceof Botan) {
456
            foreach ($updates as $update) {
457
                $this->trackUpdate($update);
458
            }
459
        }
460
461 2
        return $updates;
462
    }
463
464
    /**
465
     * Use this method to send point on the map. On success, the sent Message is returned.
466
     *
467
     * @param int $chatId
468
     * @param float $latitude
469
     * @param float $longitude
470
     * @param int|null $replyToMessageId
471
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
472
     * @param bool $disableNotification
473
     *
474
     * @return \TelegramBot\Api\Types\Message
475
     * @throws \TelegramBot\Api\Exception
476
     */
477 View Code Duplication
    public function sendLocation(
478
        $chatId,
479
        $latitude,
480
        $longitude,
481
        $replyToMessageId = null,
482
        $replyMarkup = null,
483
        $disableNotification = false
484
    ) {
485
        return Message::fromResponse($this->call('sendLocation', [
486
            'chat_id' => $chatId,
487
            'latitude' => $latitude,
488
            'longitude' => $longitude,
489
            'reply_to_message_id' => $replyToMessageId,
490
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
491
            'disable_notification' => (bool)$disableNotification,
492
        ]));
493
    }
494
495
    /**
496
     * Use this method to send information about a venue. On success, the sent Message is returned.
497
     *
498
     * @param int|string $chatId chat_id or @channel_name
499
     * @param float $latitude
500
     * @param float $longitude
501
     * @param string $title
502
     * @param string $address
503
     * @param string|null $foursquareId
504
     * @param int|null $replyToMessageId
505
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
506
     * @param bool $disableNotification
507
     *
508
     * @return \TelegramBot\Api\Types\Message
509
     * @throws \TelegramBot\Api\Exception
510
     */
511
    public function sendVenue(
512
        $chatId,
513
        $latitude,
514
        $longitude,
515
        $title,
516
        $address,
517
        $foursquareId = null,
518
        $replyToMessageId = null,
519
        $replyMarkup = null,
520
        $disableNotification = false
521
    ) {
522
        return Message::fromResponse($this->call('sendVenue', [
523
            'chat_id' => $chatId,
524
            'latitude' => $latitude,
525
            'longitude' => $longitude,
526
            'title' => $title,
527
            'address' => $address,
528
            'foursquare_id' => $foursquareId,
529
            'reply_to_message_id' => $replyToMessageId,
530
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
531
            'disable_notification' => (bool)$disableNotification,
532
        ]));
533
    }
534
535
    /**
536
     * Use this method to send .webp stickers. On success, the sent Message is returned.
537
     *
538
     * @param int|string $chatId chat_id or @channel_name
539
     * @param \CURLFile|string $sticker
540
     * @param int|null $replyToMessageId
541
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
542
     * @param bool $disableNotification
543
     *
544
     * @return \TelegramBot\Api\Types\Message
545
     * @throws \TelegramBot\Api\InvalidArgumentException
546
     * @throws \TelegramBot\Api\Exception
547
     */
548 View Code Duplication
    public function sendSticker(
549
        $chatId,
550
        $sticker,
551
        $replyToMessageId = null,
552
        $replyMarkup = null,
553
        $disableNotification = false
554
    ) {
555
        return Message::fromResponse($this->call('sendSticker', [
556
            'chat_id' => $chatId,
557
            'sticker' => $sticker,
558
            'reply_to_message_id' => $replyToMessageId,
559
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
560
            'disable_notification' => (bool)$disableNotification,
561
        ]));
562
    }
563
564
    /**
565
     * Use this method to send video files,
566
     * Telegram clients support mp4 videos (other formats may be sent as Document).
567
     * On success, the sent Message is returned.
568
     *
569
     * @param int|string $chatId chat_id or @channel_name
570
     * @param \CURLFile|string $video
571
     * @param int|null $duration
572
     * @param string|null $caption
573
     * @param int|null $replyToMessageId
574
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
575
     * @param bool $disableNotification
576
     *
577
     * @return \TelegramBot\Api\Types\Message
578
     * @throws \TelegramBot\Api\InvalidArgumentException
579
     * @throws \TelegramBot\Api\Exception
580
     */
581
    public function sendVideo(
582
        $chatId,
583
        $video,
584
        $duration = null,
585
        $caption = null,
586
        $replyToMessageId = null,
587
        $replyMarkup = null,
588
        $disableNotification = false
589
    ) {
590
        return Message::fromResponse($this->call('sendVideo', [
591
            'chat_id' => $chatId,
592
            'video' => $video,
593
            'duration' => $duration,
594
            'caption' => $caption,
595
            'reply_to_message_id' => $replyToMessageId,
596
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
597
            'disable_notification' => (bool)$disableNotification,
598
        ]));
599
    }
600
601
    /**
602
     * Use this method to send audio files,
603
     * if you want Telegram clients to display the file as a playable voice message.
604
     * For this to work, your audio must be in an .ogg file encoded with OPUS
605
     * (other formats may be sent as Audio or Document).
606
     * On success, the sent Message is returned.
607
     * Bots can currently send voice messages of up to 50 MB in size, this limit may be changed in the future.
608
     *
609
     * @param int|string $chatId chat_id or @channel_name
610
     * @param \CURLFile|string $voice
611
     * @param int|null $duration
612
     * @param int|null $replyToMessageId
613
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
614
     * @param bool $disableNotification
615
     *
616
     * @return \TelegramBot\Api\Types\Message
617
     * @throws \TelegramBot\Api\InvalidArgumentException
618
     * @throws \TelegramBot\Api\Exception
619
     */
620 View Code Duplication
    public function sendVoice(
621
        $chatId,
622
        $voice,
623
        $duration = null,
624
        $replyToMessageId = null,
625
        $replyMarkup = null,
626
        $disableNotification = false
627
    ) {
628
        return Message::fromResponse($this->call('sendVoice', [
629
            'chat_id' => $chatId,
630
            'voice' => $voice,
631
            'duration' => $duration,
632
            'reply_to_message_id' => $replyToMessageId,
633
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
634
            'disable_notification' => (bool)$disableNotification,
635
        ]));
636
    }
637
638
    /**
639
     * Use this method to forward messages of any kind. On success, the sent Message is returned.
640
     *
641
     * @param int|string $chatId chat_id or @channel_name
642
     * @param int $fromChatId
643
     * @param int $messageId
644
     * @param bool $disableNotification
645
     *
646
     * @return \TelegramBot\Api\Types\Message
647
     * @throws \TelegramBot\Api\InvalidArgumentException
648
     * @throws \TelegramBot\Api\Exception
649
     */
650
    public function forwardMessage($chatId, $fromChatId, $messageId, $disableNotification = false)
651
    {
652
        return Message::fromResponse($this->call('forwardMessage', [
653
            'chat_id' => $chatId,
654
            'from_chat_id' => $fromChatId,
655
            'message_id' => (int)$messageId,
656
            'disable_notification' => (bool)$disableNotification,
657
        ]));
658
    }
659
660
    /**
661
     * Use this method to send audio files,
662
     * if you want Telegram clients to display them in the music player.
663
     * Your audio must be in the .mp3 format.
664
     * On success, the sent Message is returned.
665
     * Bots can currently send audio files of up to 50 MB in size, this limit may be changed in the future.
666
     *
667
     * For backward compatibility, when the fields title and performer are both empty
668
     * and the mime-type of the file to be sent is not audio/mpeg, the file will be sent as a playable voice message.
669
     * For this to work, the audio must be in an .ogg file encoded with OPUS.
670
     * This behavior will be phased out in the future. For sending voice messages, use the sendVoice method instead.
671
     *
672
     * @deprecated since 20th February. Removed backward compatibility from the method sendAudio.
673
     * Voice messages now must be sent using the method sendVoice.
674
     * There is no more need to specify a non-empty title or performer while sending the audio by file_id.
675
     *
676
     * @param int|string $chatId chat_id or @channel_name
677
     * @param \CURLFile|string $audio
678
     * @param int|null $duration
679
     * @param string|null $performer
680
     * @param string|null $title
681
     * @param int|null $replyToMessageId
682
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
683
     * @param bool $disableNotification
684
     *
685
     * @return \TelegramBot\Api\Types\Message
686
     * @throws \TelegramBot\Api\InvalidArgumentException
687
     * @throws \TelegramBot\Api\Exception
688
     */
689
    public function sendAudio(
690
        $chatId,
691
        $audio,
692
        $duration = null,
693
        $performer = null,
694
        $title = null,
695
        $replyToMessageId = null,
696
        $replyMarkup = null,
697
        $disableNotification = false
698
    ) {
699
        return Message::fromResponse($this->call('sendAudio', [
700
            'chat_id' => $chatId,
701
            'audio' => $audio,
702
            'duration' => $duration,
703
            'performer' => $performer,
704
            'title' => $title,
705
            'reply_to_message_id' => $replyToMessageId,
706
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
707
            'disable_notification' => (bool)$disableNotification,
708
        ]));
709
    }
710
711
    /**
712
     * Use this method to send photos. On success, the sent Message is returned.
713
     *
714
     * @param int|string $chatId chat_id or @channel_name
715
     * @param \CURLFile|string $photo
716
     * @param string|null $caption
717
     * @param int|null $replyToMessageId
718
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
719
     * @param bool $disableNotification
720
     *
721
     * @return \TelegramBot\Api\Types\Message
722
     * @throws \TelegramBot\Api\InvalidArgumentException
723
     * @throws \TelegramBot\Api\Exception
724
     */
725 View Code Duplication
    public function sendPhoto(
726
        $chatId,
727
        $photo,
728
        $caption = null,
729
        $replyToMessageId = null,
730
        $replyMarkup = null,
731
        $disableNotification = false
732
    ) {
733
        return Message::fromResponse($this->call('sendPhoto', [
734
            'chat_id' => $chatId,
735
            'photo' => $photo,
736
            'caption' => $caption,
737
            'reply_to_message_id' => $replyToMessageId,
738
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
739
            'disable_notification' => (bool)$disableNotification,
740
        ]));
741
    }
742
743
    /**
744
     * Use this method to send general files. On success, the sent Message is returned.
745
     * Bots can currently send files of any type of up to 50 MB in size, this limit may be changed in the future.
746
     *
747
     * @param int|string $chatId chat_id or @channel_name
748
     * @param \CURLFile|string $document
749
     * @param string|null $caption
750
     * @param int|null $replyToMessageId
751
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
752
     * @param bool $disableNotification
753
     *
754
     * @return \TelegramBot\Api\Types\Message
755
     * @throws \TelegramBot\Api\InvalidArgumentException
756
     * @throws \TelegramBot\Api\Exception
757
     */
758 View Code Duplication
    public function sendDocument(
759
        $chatId,
760
        $document,
761
        $caption = null,
762
        $replyToMessageId = null,
763
        $replyMarkup = null,
764
        $disableNotification = false
765
    ) {
766
        return Message::fromResponse($this->call('sendDocument', [
767
            'chat_id' => $chatId,
768
            'document' => $document,
769
            'caption' => $caption,
770
            'reply_to_message_id' => $replyToMessageId,
771
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
772
            'disable_notification' => (bool)$disableNotification,
773
        ]));
774
    }
775
776
    /**
777
     * Use this method to get basic info about a file and prepare it for downloading.
778
     * For the moment, bots can download files of up to 20MB in size.
779
     * On success, a File object is returned.
780
     * The file can then be downloaded via the link https://api.telegram.org/file/bot<token>/<file_path>,
781
     * where <file_path> is taken from the response.
782
     * It is guaranteed that the link will be valid for at least 1 hour.
783
     * When the link expires, a new one can be requested by calling getFile again.
784
     *
785
     * @param $fileId
786
     *
787
     * @return \TelegramBot\Api\Types\File
788
     * @throws \TelegramBot\Api\InvalidArgumentException
789
     * @throws \TelegramBot\Api\Exception
790
     */
791
    public function getFile($fileId)
792
    {
793
        return File::fromResponse($this->call('getFile', ['file_id' => $fileId]));
794
    }
795
796
    /**
797
     * Get file contents via cURL
798
     *
799
     * @param $fileId
800
     *
801
     * @return string
802
     *
803
     * @throws \TelegramBot\Api\HttpException
804
     */
805
    public function downloadFile($fileId)
806
    {
807
        $file = $this->getFile($fileId);
808
        $options = [
809
            CURLOPT_HEADER => 0,
810
            CURLOPT_HTTPGET => 1,
811
            CURLOPT_RETURNTRANSFER => 1,
812
            CURLOPT_URL => $this->getFileUrl().'/'.$file->getFilePath(),
813
        ];
814
815
        return $this->executeCurl($options);
816
    }
817
818
    /**
819
     * Use this method to send answers to an inline query. On success, True is returned.
820
     * No more than 50 results per query are allowed.
821
     *
822
     * @param string $inlineQueryId
823
     * @param AbstractInlineQueryResult[] $results
824
     * @param int $cacheTime
825
     * @param bool $isPersonal
826
     * @param string $nextOffset
827
     *
828
     * @return mixed
829
     * @throws Exception
830
     */
831
    public function answerInlineQuery($inlineQueryId, $results, $cacheTime = 300, $isPersonal = false, $nextOffset = '')
832
    {
833
        $results = array_map(function ($item) {
834
            /* @var AbstractInlineQueryResult $item */
835
836
            return json_decode($item->toJson(), true);
837
        }, $results);
838
839
        return $this->call('answerInlineQuery', [
840
            'inline_query_id' => $inlineQueryId,
841
            'results' => json_encode($results),
842
            'cache_time' => $cacheTime,
843
            'is_personal' => $isPersonal,
844
            'next_offset' => $nextOffset,
845
        ]);
846
    }
847
848
    /**
849
     * Use this method to kick a user from a group or a supergroup.
850
     * In the case of supergroups, the user will not be able to return to the group
851
     * on their own using invite links, etc., unless unbanned first.
852
     * The bot must be an administrator in the group for this to work. Returns True on success.
853
     *
854
     * @param int|string $chatId Unique identifier for the target group
855
     * or username of the target supergroup (in the format @supergroupusername)
856
     * @param int $userId Unique identifier of the target user
857
     *
858
     * @return bool
859
     */
860
    public function kickChatMember($chatId, $userId)
861
    {
862
        return $this->call('kickChatMember', [
863
            'chat_id' => $chatId,
864
            'user_id' => $userId,
865
        ]);
866
    }
867
868
    /**
869
     * Use this method to unban a previously kicked user in a supergroup.
870
     * The user will not return to the group automatically, but will be able to join via link, etc.
871
     * The bot must be an administrator in the group for this to work. Returns True on success.
872
     *
873
     * @param int|string $chatId Unique identifier for the target group
874
     * or username of the target supergroup (in the format @supergroupusername)
875
     * @param int $userId Unique identifier of the target user
876
     *
877
     * @return bool
878
     */
879
    public function unbanChatMember($chatId, $userId)
880
    {
881
        return $this->call('unbanChatMember', [
882
            'chat_id' => $chatId,
883
            'user_id' => $userId,
884
        ]);
885
    }
886
887
    /**
888
     * Use this method to send answers to callback queries sent from inline keyboards.
889
     * The answer will be displayed to the user as a notification at the top of the chat screen or as an alert.
890
     *
891
     * @param $callbackQueryId
892
     * @param null $text
893
     * @param bool $showAlert
894
     *
895
     * @return bool
896
     */
897
    public function answerCallbackQuery($callbackQueryId, $text = null, $showAlert = false)
898
    {
899
        return $this->call('answerCallbackQuery', [
900
            'callback_query_id' => $callbackQueryId,
901
            'text' => $text,
902
            'show_alert' => (bool)$showAlert,
903
        ]);
904
    }
905
906
907
    /**
908
     * Use this method to edit text messages sent by the bot or via the bot
909
     *
910
     * @param int|string $chatId
911
     * @param int $messageId
912
     * @param string $text
913
     * @param string|null $parseMode
914
     * @param bool $disablePreview
915
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
916
     *
917
     * @return \TelegramBot\Api\Types\Message
918
     * @throws \TelegramBot\Api\InvalidArgumentException
919
     * @throws \TelegramBot\Api\Exception
920
     */
921 View Code Duplication
    public function editMessageText(
922
        $chatId,
923
        $messageId,
924
        $text,
925
        $parseMode = null,
926
        $disablePreview = false,
927
        $replyMarkup = null
928
    ) {
929
        return Message::fromResponse($this->call('editMessageText', [
930
            'chat_id' => $chatId,
931
            'message_id' => $messageId,
932
            'text' => $text,
933
            'parse_mode' => $parseMode,
934
            'disable_web_page_preview' => $disablePreview,
935
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
936
        ]));
937
    }
938
939
    /**
940
     * Use this method to edit text messages sent by the bot or via the bot
941
     *
942
     * @param int|string $chatId
943
     * @param int $messageId
944
     * @param string|null $caption
945
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
946
     *
947
     * @return \TelegramBot\Api\Types\Message
948
     * @throws \TelegramBot\Api\InvalidArgumentException
949
     * @throws \TelegramBot\Api\Exception
950
     */
951 View Code Duplication
    public function editMessageCaption(
952
        $chatId,
953
        $messageId,
954
        $caption = null,
955
        $replyMarkup = null
956
    ) {
957
        return Message::fromResponse($this->call('editMessageText', [
958
            'chat_id' => $chatId,
959
            'message_id' => $messageId,
960
            'caption' => $caption,
961
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
962
        ]));
963
    }
964
965
    /**
966
     * Use this method to edit only the reply markup of messages sent by the bot or via the bot
967
     *
968
     * @param int|string $chatId
969
     * @param int $messageId
970
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
971
     *
972
     * @return \TelegramBot\Api\Types\Message
973
     * @throws \TelegramBot\Api\InvalidArgumentException
974
     * @throws \TelegramBot\Api\Exception
975
     */
976 View Code Duplication
    public function editMessageReplyMarkup(
977
        $chatId,
978
        $messageId,
979
        $replyMarkup = null
980
    ) {
981
        return Message::fromResponse($this->call('editMessageText', [
982
            'chat_id' => $chatId,
983
            'message_id' => $messageId,
984
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
985
        ]));
986
    }
987
988
    /**
989
     * Close curl
990
     */
991 9
    public function __destruct()
992
    {
993 9
        $this->curl && curl_close($this->curl);
994 9
    }
995
996
    /**
997
     * @return string
998
     */
999
    public function getUrl()
1000
    {
1001
        return self::URL_PREFIX.$this->token;
1002
    }
1003
1004
    /**
1005
     * @return string
1006
     */
1007
    public function getFileUrl()
1008
    {
1009
        return self::FILE_URL_PREFIX.$this->token;
1010
    }
1011
1012
    /**
1013
     * @param \TelegramBot\Api\Types\Update $update
1014
     * @param string $eventName
1015
     *
1016
     * @throws \TelegramBot\Api\Exception
1017
     */
1018
    public function trackUpdate(Update $update, $eventName = 'Message')
1019
    {
1020
        if (!in_array($update->getUpdateId(), $this->trackedEvents)) {
1021
            $this->trackedEvents[] = $update->getUpdateId();
1022
1023
            $this->track($update->getMessage(), $eventName);
1024
1025
            if (count($this->trackedEvents) > self::MAX_TRACKED_EVENTS) {
1026
                $this->trackedEvents = array_slice($this->trackedEvents, round(self::MAX_TRACKED_EVENTS / 4));
1027
            }
1028
        }
1029
    }
1030
1031
    /**
1032
     * Wrapper for tracker
1033
     *
1034
     * @param \TelegramBot\Api\Types\Message $message
1035
     * @param string $eventName
1036
     *
1037
     * @throws \TelegramBot\Api\Exception
1038
     */
1039
    public function track(Message $message, $eventName = 'Message')
1040
    {
1041
        if ($this->tracker instanceof Botan) {
1042
            $this->tracker->track($message, $eventName);
1043
        }
1044
    }
1045
1046
    /**
1047
     * Use this method to send invoices. On success, the sent Message is returned.
1048
     *
1049
     * @param int|string $chatId
1050
     * @param string $title
1051
     * @param string $description
1052
     * @param string $payload
1053
     * @param string $providerToken
1054
     * @param string $startParameter
1055
     * @param string $currency
1056
     * @param array $prices
1057
     * @param string|null $photoUrl
1058
     * @param int|null $photoSize
1059
     * @param int|null $photoWidth
1060
     * @param int|null $photoHeight
1061
     * @param bool $needName
1062
     * @param bool $needPhoneNumber
1063
     * @param bool $needEmail
1064
     * @param bool $needShippingAddress
1065
     * @param bool $isFlexible
1066
     * @param int|null $replyToMessageId
1067
     * @param Types\ReplyKeyboardMarkup|Types\ReplyKeyboardHide|Types\ForceReply|null $replyMarkup
1068
     * @param bool $disableNotification
1069
     *
1070
     * @return Message
1071
     */
1072
    public function sendInvoice(
1073
        $chatId,
1074
        $title,
1075
        $description,
1076
        $payload,
1077
        $providerToken,
1078
        $startParameter,
1079
        $currency,
1080
        $prices,
1081
        $isFlexible = false,
1082
        $photoUrl = null,
1083
        $photoSize = null,
1084
        $photoWidth = null,
1085
        $photoHeight = null,
1086
        $needName = false,
1087
        $needPhoneNumber = false,
1088
        $needEmail = false,
1089
        $needShippingAddress = false,
1090
        $replyToMessageId = null,
1091
        $replyMarkup = null,
1092
        $disableNotification = false
1093
    ) {
1094
        return Message::fromResponse($this->call('sendInvoice', [
1095
            'chat_id' => $chatId,
1096
            'title' => $title,
1097
            'description' => $description,
1098
            'payload' => $payload,
1099
            'provider_token' => $providerToken,
1100
            'start_parameter' => $startParameter,
1101
            'currency' => $currency,
1102
            'prices' => json_encode($prices),
1103
            'is_flexible' => $isFlexible,
1104
            'photo_url' => $photoUrl,
1105
            'photo_size' => $photoSize,
1106
            'photo_width' => $photoWidth,
1107
            'photo_height' => $photoHeight,
1108
            'need_name' => $needName,
1109
            'need_phone_number' => $needPhoneNumber,
1110
            'need_email' => $needEmail,
1111
            'need_shipping_address' => $needShippingAddress,
1112
            'reply_to_message_id' => $replyToMessageId,
1113
            'reply_markup' => is_null($replyMarkup) ? $replyMarkup : $replyMarkup->toJson(),
1114
            'disable_notification' => (bool)$disableNotification,
1115
        ]));
1116
    }
1117
1118
    /**
1119
     * If you sent an invoice requesting a shipping address and the parameter is_flexible was specified, the Bot API
1120
     * will send an Update with a shipping_query field to the bot. Use this method to reply to shipping queries.
1121
     * On success, True is returned.
1122
     *
1123
     * @param string $shippingQueryId
1124
     * @param bool $ok
1125
     * @param array $shipping_options
1126
     * @param null|string $errorMessage
1127
     *
1128
     * @return bool
1129
     *
1130
     */
1131
    public function answerShippingQuery($shippingQueryId, $ok = true, $shipping_options = [], $errorMessage = null)
1132
    {
1133
        return $this->call('answerShippingQuery', [
1134
            'shipping_query_id' => $shippingQueryId,
1135
            'ok' => (bool)$ok,
1136
            'shipping_options' => json_encode($shipping_options),
1137
            'error_message' => $errorMessage
1138
        ]);
1139
    }
1140
1141
    /**
1142
     * Use this method to respond to such pre-checkout queries. On success, True is returned.
1143
     * Note: The Bot API must receive an answer within 10 seconds after the pre-checkout query was sent.
1144
     *
1145
     * @param string $preCheckoutQueryId
1146
     * @param bool $ok
1147
     * @param null|string $errorMessage
1148
     *
1149
     * @return mixed
1150
     */
1151
    public function answerPreCheckoutQuery($preCheckoutQueryId, $ok = true, $errorMessage = null)
1152
    {
1153
        return $this->call('answerPreCheckoutQuery', [
1154
            'pre_checkout_query_id' => $preCheckoutQueryId,
1155
            'ok' => (bool)$ok,
1156
            'error_message' => $errorMessage
1157
        ]);
1158
    }
1159
}
1160