Completed
Pull Request — develop (#457)
by
unknown
03:06
created

Telegram::__construct()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 26
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 26
ccs 16
cts 16
cp 1
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 15
nc 4
nop 2
crap 4
1
<?php
2
/**
3
 * This file is part of the TelegramBot package.
4
 *
5
 * (c) Avtandil Kikabidze aka LONGMAN <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Longman\TelegramBot;
12
13 1
define('BASE_PATH', __DIR__);
14 1
define('BASE_COMMANDS_PATH', BASE_PATH . '/Commands');
15
16
use Exception;
17
use Longman\TelegramBot\Commands\Command;
18
use Longman\TelegramBot\Entities\ServerResponse;
19
use Longman\TelegramBot\Entities\Update;
20
use Longman\TelegramBot\Exception\TelegramException;
21
use PDO;
22
use RecursiveDirectoryIterator;
23
use RecursiveIteratorIterator;
24
use RegexIterator;
25
26
class Telegram
27
{
28
    /**
29
     * Version
30
     *
31
     * @var string
32
     */
33
    protected $version = '0.41.0';
34
35
    /**
36
     * Telegram API key
37
     *
38
     * @var string
39
     */
40
    protected $api_key = '';
41
42
    /**
43
     * Telegram Bot username
44
     *
45
     * @var string
46
     */
47
    protected $bot_username = '';
48
49
    /**
50
     * Telegram Bot id
51
     *
52
     * @var string
53
     */
54
    protected $bot_id = '';
55
56
    /**
57
     * Raw request data (json) for webhook methods
58
     *
59
     * @var string
60
     */
61
    protected $input;
62
63
    /**
64
     * Custom commands paths
65
     *
66
     * @var array
67
     */
68
    protected $commands_paths = [];
69
70
    /**
71
     * Current Update object
72
     *
73
     * @var \Longman\TelegramBot\Entities\Update
74
     */
75
    protected $update;
76
77
    /**
78
     * Upload path
79
     *
80
     * @var string
81
     */
82
    protected $upload_path;
83
84
    /**
85
     * Download path
86
     *
87
     * @var string
88
     */
89
    protected $download_path;
90
91
    /**
92
     * MySQL integration
93
     *
94
     * @var boolean
95
     */
96
    protected $mysql_enabled = false;
97
98
    /**
99
     * PDO object
100
     *
101
     * @var \PDO
102
     */
103
    protected $pdo;
104
105
    /**
106
     * Commands config
107
     *
108
     * @var array
109
     */
110
    protected $commands_config = [];
111
112
    /**
113
     * Admins list
114
     *
115
     * @var array
116
     */
117
    protected $admins_list = [];
118
119
    /**
120
     * ServerResponse of the last Command execution
121
     *
122
     * @var \Longman\TelegramBot\Entities\ServerResponse
123
     */
124
    protected $last_command_response;
125
126
    /**
127
     * Botan.io integration
128
     *
129
     * @var boolean
130
     */
131
    protected $botan_enabled = false;
132
133
    /**
134
     * Telegram constructor.
135
     *
136
     * @param string $api_key
137
     * @param string $bot_username
138
     *
139
     * @throws \Longman\TelegramBot\Exception\TelegramException
140
     */
141 42
    public function __construct($api_key, $bot_username)
142
    {
143 42
        if (empty($api_key)) {
144 1
            throw new TelegramException('API KEY not defined!');
145
        }
146 42
        preg_match('/(\d+)\:.+/', $api_key, $matches);
147 42
        if (!isset($matches[1])) {
148 1
            throw new TelegramException('Invalid API KEY defined!');
149
        }
150 42
        $this->bot_id  = $matches[1];
151 42
        $this->api_key = $api_key;
152
153 42
        if (empty($bot_username)) {
154 1
            throw new TelegramException('Bot Username not defined!');
155
        }
156 42
        $this->bot_username = $bot_username;
157
158
        //Set default download and upload path
159 42
        $this->setDownloadPath(BASE_PATH . '/../Download');
160 42
        $this->setUploadPath(BASE_PATH . '/../Upload');
161
162
        //Add default system commands path
163 42
        $this->addCommandsPath(BASE_COMMANDS_PATH . '/SystemCommands');
164
165 42
        Request::initialize($this);
166 42
    }
167
168
    /**
169
     * Initialize Database connection
170
     *
171
     * @param array  $credential
172
     * @param string $table_prefix
173
     * @param string $encoding
174
     *
175
     * @return \Longman\TelegramBot\Telegram
176
     * @throws \Longman\TelegramBot\Exception\TelegramException
177
     */
178 9 View Code Duplication
    public function enableMySql(array $credential, $table_prefix = null, $encoding = 'utf8mb4')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
179
    {
180 9
        $this->pdo = DB::initialize($credential, $this, $table_prefix, $encoding);
181 9
        ConversationDB::initializeConversation();
182 9
        $this->mysql_enabled = true;
183
184 9
        return $this;
185
    }
186
187
    /**
188
     * Initialize Database external connection
189
     *
190
     * @param PDO    $external_pdo_connection PDO database object
191
     * @param string $table_prefix
192
     *
193
     * @return \Longman\TelegramBot\Telegram
194
     * @throws \Longman\TelegramBot\Exception\TelegramException
195
     */
196 View Code Duplication
    public function enableExternalMySql($external_pdo_connection, $table_prefix = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
197
    {
198
        $this->pdo = DB::externalInitialize($external_pdo_connection, $this, $table_prefix);
199
        ConversationDB::initializeConversation();
200
        $this->mysql_enabled = true;
201
202
        return $this;
203
    }
204
205
    /**
206
     * Get commands list
207
     *
208
     * @return array $commands
209
     * @throws \Longman\TelegramBot\Exception\TelegramException
210
     */
211 11
    public function getCommandsList()
212
    {
213 11
        $commands = [];
214
215 11
        foreach ($this->commands_paths as $path) {
216
            try {
217
                //Get all "*Command.php" files
218 11
                $files = new RegexIterator(
219 11
                    new RecursiveIteratorIterator(
220 11
                        new RecursiveDirectoryIterator($path)
221
                    ),
222 11
                    '/^.+Command.php$/'
223
                );
224
225 11
                foreach ($files as $file) {
226
                    //Remove "Command.php" from filename
227 11
                    $command      = $this->sanitizeCommand(substr($file->getFilename(), 0, -11));
228 11
                    $command_name = strtolower($command);
229
230 11
                    if (array_key_exists($command_name, $commands)) {
231
                        continue;
232
                    }
233
234 11
                    require_once $file->getPathname();
235
236 11
                    $command_obj = $this->getCommandObject($command);
237 11
                    if ($command_obj instanceof Command) {
238 11
                        $commands[$command_name] = $command_obj;
239
                    }
240
                }
241
            } catch (Exception $e) {
242 11
                throw new TelegramException('Error getting commands from path: ' . $path);
243
            }
244
        }
245
246 11
        return $commands;
247
    }
248
249
    /**
250
     * Get an object instance of the passed command
251
     *
252
     * @param string $command
253
     *
254
     * @return \Longman\TelegramBot\Commands\Command|null
255
     */
256 12
    public function getCommandObject($command)
257
    {
258 12
        $which = ['System'];
259 12
        $this->isAdmin() && $which[] = 'Admin';
260 12
        $which[] = 'User';
261
262 12
        foreach ($which as $auth) {
263 12
            $command_namespace = __NAMESPACE__ . '\\Commands\\' . $auth . 'Commands\\' . $this->ucfirstUnicode($command) . 'Command';
264 12
            if (class_exists($command_namespace)) {
265 12
                return new $command_namespace($this, $this->update);
266
            }
267
        }
268
269
        return null;
270
    }
271
272
    /**
273
     * Set custom input string for debug purposes
274
     *
275
     * @param string $input (json format)
276
     *
277
     * @return \Longman\TelegramBot\Telegram
278
     */
279
    public function setCustomInput($input)
280
    {
281
        $this->input = $input;
282
283
        return $this;
284
    }
285
286
    /**
287
     * Get custom input string for debug purposes
288
     *
289
     * @return string
290
     */
291
    public function getCustomInput()
292
    {
293
        return $this->input;
294
    }
295
296
    /**
297
     * Get the ServerResponse of the last Command execution
298
     *
299
     * @return \Longman\TelegramBot\Entities\ServerResponse
300
     */
301
    public function getLastCommandResponse()
302
    {
303
        return $this->last_command_response;
304
    }
305
306
    /**
307
     * Handle getUpdates method
308
     *
309
     * @param int|null $limit
310
     * @param int|null $timeout
311
     *
312
     * @return \Longman\TelegramBot\Entities\ServerResponse
313
     * @throws \Longman\TelegramBot\Exception\TelegramException
314
     */
315
    public function handleGetUpdates($limit = null, $timeout = null)
316
    {
317
        if (!DB::isDbConnected()) {
318
            return new ServerResponse(
319
                [
320
                    'ok'          => false,
321
                    'description' => 'getUpdates needs MySQL connection!',
322
                ],
323
                $this->bot_username
324
            );
325
        }
326
327
        //DB Query
328
        $last_update = DB::selectTelegramUpdate(1);
329
        $last_update = reset($last_update);
330
331
        //As explained in the telegram bot api documentation
332
        $offset = isset($last_update['id']) ? $last_update['id'] + 1 : null;
333
334
        $response = Request::getUpdates(
335
            [
336
                'offset'  => $offset,
337
                'limit'   => $limit,
338
                'timeout' => $timeout,
339
            ]
340
        );
341
342
        if ($response->isOk()) {
343
            //Process all updates
344
            /** @var Update $result */
345
            foreach ((array) $response->getResult() as $result) {
346
                $this->processUpdate($result);
347
            }
348
        }
349
350
        return $response;
351
    }
352
353
    /**
354
     * Handle bot request from webhook
355
     *
356
     * @return bool
357
     *
358
     * @throws \Longman\TelegramBot\Exception\TelegramException
359
     */
360
    public function handle()
361
    {
362
        $this->input = Request::getInput();
363
364
        if (empty($this->input)) {
365
            throw new TelegramException('Input is empty!');
366
        }
367
368
        $post = json_decode($this->input, true);
369
        if (empty($post)) {
370
            throw new TelegramException('Invalid JSON!');
371
        }
372
373
        if ($response = $this->processUpdate(new Update($post, $this->bot_username))) {
374
            return $response->isOk();
375
        }
376
377
        return false;
378
    }
379
380
    /**
381
     * Get the command name from the command type
382
     *
383
     * @param string $type
384
     *
385
     * @return string
386
     */
387
    protected function getCommandFromType($type)
388
    {
389
        return $this->ucfirstUnicode(str_replace('_', '', $type));
390
    }
391
392
    /**
393
     * Process bot Update request
394
     *
395
     * @param \Longman\TelegramBot\Entities\Update $update
396
     *
397
     * @return \Longman\TelegramBot\Entities\ServerResponse
398
     * @throws \Longman\TelegramBot\Exception\TelegramException
399
     */
400
    public function processUpdate(Update $update)
401
    {
402
        $this->update = $update;
403
404
        //If all else fails, it's a generic message.
405
        $command = 'genericmessage';
406
407
        $update_type = $this->update->getUpdateType();
408
        if (in_array($update_type, ['edited_message', 'channel_post', 'edited_channel_post', 'inline_query', 'chosen_inline_result', 'callback_query'], true)) {
409
            $command = $this->getCommandFromType($update_type);
410
        } elseif ($update_type === 'message') {
411
            $message = $this->update->getMessage();
412
413
            //Load admin commands
414
            if ($this->isAdmin()) {
415
                $this->addCommandsPath(BASE_COMMANDS_PATH . '/AdminCommands', false);
416
            }
417
418
            $this->addCommandsPath(BASE_COMMANDS_PATH . '/UserCommands', false);
419
420
            $type = $message->getType();
421
            if ($type === 'command') {
422
                $command = $message->getCommand();
423
            } elseif (in_array($type, [
424
                'channel_chat_created',
425
                'delete_chat_photo',
426
                'group_chat_created',
427
                'left_chat_member',
428
                'migrate_from_chat_id',
429
                'migrate_to_chat_id',
430
                'new_chat_member',
431
                'new_chat_photo',
432
                'new_chat_title',
433
                'pinned_message',
434
                'supergroup_chat_created',
435
            ], true)
436
            ) {
437
                $command = $this->getCommandFromType($type);
438
            }
439
        }
440
441
        //Make sure we have an up-to-date command list
442
        //This is necessary to "require" all the necessary command files!
443
        $this->getCommandsList();
444
445
        DB::insertRequest($this->update);
446
447
        return $this->executeCommand($command);
0 ignored issues
show
Bug introduced by
It seems like $command defined by $message->getCommand() on line 422 can also be of type boolean; however, Longman\TelegramBot\Telegram::executeCommand() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
448
    }
449
450
    /**
451
     * Execute /command
452
     *
453
     * @param string $command
454
     *
455
     * @return mixed
456
     * @throws \Longman\TelegramBot\Exception\TelegramException
457
     */
458
    public function executeCommand($command)
459
    {
460
        $command_obj = $this->getCommandObject($command);
461
462
        if (!$command_obj || !$command_obj->isEnabled()) {
463
            //Failsafe in case the Generic command can't be found
464
            if ($command === 'Generic') {
465
                throw new TelegramException('Generic command missing!');
466
            }
467
468
            //Handle a generic command or non existing one
469
            $this->last_command_response = $this->executeCommand('Generic');
470
        } else {
471
            //Botan.io integration, make sure only the actual command user executed is reported
472
            if ($this->botan_enabled) {
473
                Botan::lock($command);
474
            }
475
476
            //execute() method is executed after preExecute()
477
            //This is to prevent executing a DB query without a valid connection
478
            $this->last_command_response = $command_obj->preExecute();
479
480
            //Botan.io integration, send report after executing the command
481
            if ($this->botan_enabled) {
482
                Botan::track($this->update, $command);
483
            }
484
        }
485
486
        return $this->last_command_response;
487
    }
488
489
    /**
490
     * Sanitize Command
491
     *
492
     * @param string $command
493
     *
494
     * @return string
495
     */
496 11
    protected function sanitizeCommand($command)
497
    {
498 11
        return str_replace(' ', '', $this->ucwordsUnicode(str_replace('_', ' ', $command)));
499
    }
500
501
    /**
502
     * Enable a single Admin account
503
     *
504
     * @param integer $admin_id Single admin id
505
     *
506
     * @return \Longman\TelegramBot\Telegram
507
     */
508 1
    public function enableAdmin($admin_id)
509
    {
510 1
        if (is_int($admin_id) && $admin_id > 0 && !in_array($admin_id, $this->admins_list, true)) {
511 1
            $this->admins_list[] = $admin_id;
512
        } else {
513 1
            TelegramLog::error('Invalid value "%s" for admin.', $admin_id);
514
        }
515
516 1
        return $this;
517
    }
518
519
    /**
520
     * Enable a list of Admin Accounts
521
     *
522
     * @param array $admin_ids List of admin ids
523
     *
524
     * @return \Longman\TelegramBot\Telegram
525
     */
526 1
    public function enableAdmins(array $admin_ids)
527
    {
528 1
        foreach ($admin_ids as $admin_id) {
529 1
            $this->enableAdmin($admin_id);
530
        }
531
532 1
        return $this;
533
    }
534
535
    /**
536
     * Get list of admins
537
     *
538
     * @return array
539
     */
540 1
    public function getAdminList()
541
    {
542 1
        return $this->admins_list;
543
    }
544
545
    /**
546
     * Check if the passed user is an admin
547
     *
548
     * If no user id is passed, the current update is checked for a valid message sender.
549
     *
550
     * @param int|null $user_id
551
     *
552
     * @return bool
553
     */
554 12
    public function isAdmin($user_id = null)
555
    {
556 12
        if ($user_id === null && $this->update !== null) {
557
            //Try to figure out if the user is an admin
558
            $update_methods = [
559
                'getMessage',
560
                'getEditedMessage',
561
                'getChannelPost',
562
                'getEditedChannelPost',
563
                'getInlineQuery',
564
                'getChosenInlineResult',
565
                'getCallbackQuery',
566
            ];
567
            foreach ($update_methods as $update_method) {
568
                $object = call_user_func([$this->update, $update_method]);
569
                if ($object !== null && $from = $object->getFrom()) {
570
                    $user_id = $from->getId();
571
                    break;
572
                }
573
            }
574
        }
575
576 12
        return ($user_id === null) ? false : in_array($user_id, $this->admins_list, true);
577
    }
578
579
    /**
580
     * Check if user required the db connection
581
     *
582
     * @return bool
583
     */
584
    public function isDbEnabled()
585
    {
586
        if ($this->mysql_enabled) {
587
            return true;
588
        } else {
589
            return false;
590
        }
591
    }
592
593
    /**
594
     * Add a single custom commands path
595
     *
596
     * @param string $path   Custom commands path to add
597
     * @param bool   $before If the path should be prepended or appended to the list
598
     *
599
     * @return \Longman\TelegramBot\Telegram
600
     */
601 42
    public function addCommandsPath($path, $before = true)
602
    {
603 42
        if (!is_dir($path)) {
604 1
            TelegramLog::error('Commands path "%s" does not exist.', $path);
605 42
        } elseif (!in_array($path, $this->commands_paths, true)) {
606 42
            if ($before) {
607 42
                array_unshift($this->commands_paths, $path);
608
            } else {
609
                $this->commands_paths[] = $path;
610
            }
611
        }
612
613 42
        return $this;
614
    }
615
616
    /**
617
     * Add multiple custom commands paths
618
     *
619
     * @param array $paths  Custom commands paths to add
620
     * @param bool  $before If the paths should be prepended or appended to the list
621
     *
622
     * @return \Longman\TelegramBot\Telegram
623
     */
624 1
    public function addCommandsPaths(array $paths, $before = true)
625
    {
626 1
        foreach ($paths as $path) {
627 1
            $this->addCommandsPath($path, $before);
628
        }
629
630 1
        return $this;
631
    }
632
633
    /**
634
     * Return the list of commands paths
635
     *
636
     * @return array
637
     */
638 1
    public function getCommandsPaths()
639
    {
640 1
        return $this->commands_paths;
641
    }
642
643
    /**
644
     * Set custom upload path
645
     *
646
     * @param string $path Custom upload path
647
     *
648
     * @return \Longman\TelegramBot\Telegram
649
     */
650 42
    public function setUploadPath($path)
651
    {
652 42
        $this->upload_path = $path;
653
654 42
        return $this;
655
    }
656
657
    /**
658
     * Get custom upload path
659
     *
660
     * @return string
661
     */
662
    public function getUploadPath()
663
    {
664
        return $this->upload_path;
665
    }
666
667
    /**
668
     * Set custom download path
669
     *
670
     * @param string $path Custom download path
671
     *
672
     * @return \Longman\TelegramBot\Telegram
673
     */
674 42
    public function setDownloadPath($path)
675
    {
676 42
        $this->download_path = $path;
677
678 42
        return $this;
679
    }
680
681
    /**
682
     * Get custom download path
683
     *
684
     * @return string
685
     */
686
    public function getDownloadPath()
687
    {
688
        return $this->download_path;
689
    }
690
691
    /**
692
     * Set command config
693
     *
694
     * Provide further variables to a particular commands.
695
     * For example you can add the channel name at the command /sendtochannel
696
     * Or you can add the api key for external service.
697
     *
698
     * @param string $command
699
     * @param array  $config
700
     *
701
     * @return \Longman\TelegramBot\Telegram
702
     */
703 14
    public function setCommandConfig($command, array $config)
704
    {
705 14
        $this->commands_config[$command] = $config;
706
707 14
        return $this;
708
    }
709
710
    /**
711
     * Get command config
712
     *
713
     * @param string $command
714
     *
715
     * @return array
716
     */
717 26
    public function getCommandConfig($command)
718
    {
719 26
        return isset($this->commands_config[$command]) ? $this->commands_config[$command] : [];
720
    }
721
722
    /**
723
     * Get API key
724
     *
725
     * @return string
726
     */
727 1
    public function getApiKey()
728
    {
729 1
        return $this->api_key;
730
    }
731
732
    /**
733
     * Get Bot name
734
     *
735
     * @return string
736
     */
737 7
    public function getBotUsername()
738
    {
739 7
        return $this->bot_username;
740
    }
741
742
    /**
743
     * Get Bot name
744
     *
745
     * @todo: Left for backwards compatibility, remove in the future
746
     *
747
     * @return string
748
     */
749 2
    public function getBotName()
750
    {
751 2
        TelegramLog::debug('Usage of deprecated method getBotName() detected, please use getBotUsername() instead!');
752 2
        return $this->getBotUsername();
753
    }
754
755
    /**
756
     * Get Bot Id
757
     *
758
     * @return string
759
     */
760
    public function getBotId()
761
    {
762
        return $this->bot_id;
763
    }
764
765
    /**
766
     * Get Version
767
     *
768
     * @return string
769
     */
770 2
    public function getVersion()
771
    {
772 2
        return $this->version;
773
    }
774
775
    /**
776
     * Set Webhook for bot
777
     *
778
     * @param string $url
779
     * @param array  $data Optional parameters.
780
     *
781
     * @return \Longman\TelegramBot\Entities\ServerResponse
782
     * @throws \Longman\TelegramBot\Exception\TelegramException
783
     */
784
    public function setWebhook($url, array $data = [])
785
    {
786
        if (empty($url)) {
787
            throw new TelegramException('Hook url is empty!');
788
        }
789
790
        $result = Request::setWebhook($url, $data);
791
792 View Code Duplication
        if (!$result->isOk()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
793
            throw new TelegramException(
794
                'Webhook was not set! Error: ' . $result->getErrorCode() . ' ' . $result->getDescription()
795
            );
796
        }
797
798
        return $result;
799
    }
800
801
    /**
802
     * Deprecated alias for deleteWebhook
803
     *
804
     * This is kept for backwards compatibility!
805
     *
806
     * @return mixed
807
     * @throws \Longman\TelegramBot\Exception\TelegramException
808
     */
809
    public function unsetWebhook()
810
    {
811
        return $this->deleteWebhook();
812
    }
813
814
    /**
815
     * Delete any assigned webhook
816
     *
817
     * @return mixed
818
     * @throws \Longman\TelegramBot\Exception\TelegramException
819
     */
820
    public function deleteWebhook()
821
    {
822
        $result = Request::deleteWebhook();
823
824 View Code Duplication
        if (!$result->isOk()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
825
            throw new TelegramException(
826
                'Webhook was not deleted! Error: ' . $result->getErrorCode() . ' ' . $result->getDescription()
827
            );
828
        }
829
830
        return $result;
831
    }
832
833
    /**
834
     * Replace function `ucwords` for UTF-8 characters in the class definition and commands
835
     *
836
     * @param string $str
837
     * @param string $encoding (default = 'UTF-8')
838
     *
839
     * @return string
840
     */
841 11
    protected function ucwordsUnicode($str, $encoding = 'UTF-8')
842
    {
843 11
        return mb_convert_case($str, MB_CASE_TITLE, $encoding);
844
    }
845
846
    /**
847
     * Replace function `ucfirst` for UTF-8 characters in the class definition and commands
848
     *
849
     * @param string $str
850
     * @param string $encoding (default = 'UTF-8')
851
     *
852
     * @return string
853
     */
854 12
    protected function ucfirstUnicode($str, $encoding = 'UTF-8')
855
    {
856
        return
857 12
            mb_strtoupper(mb_substr($str, 0, 1, $encoding), $encoding)
858 12
            . mb_strtolower(mb_substr($str, 1, mb_strlen($str), $encoding), $encoding);
859
    }
860
861
    /**
862
     * Enable Botan.io integration
863
     *
864
     * @param  string $token
865
     * @param  array  $options
866
     *
867
     * @return \Longman\TelegramBot\Telegram
868
     * @throws \Longman\TelegramBot\Exception\TelegramException
869
     */
870
    public function enableBotan($token, array $options = [])
871
    {
872
        Botan::initializeBotan($token, $options);
873
        $this->botan_enabled = true;
874
875
        return $this;
876
    }
877
878
    /**
879
     * Enable requests limiter
880
     */
881
    public function enableLimiter()
882
    {
883
        Request::setLimiter(true);
884
885
        return $this;
886
    }
887
888
    /**
889
     * Run provided commands
890
     *
891
     * @param array $commands
892
     *
893
     * @throws TelegramException
894
     */
895
    public function runCommands($commands)
896
    {
897
        if (!is_array($commands) || empty($commands)) {
898
            throw new TelegramException('No command(s) provided!');
899
        }
900
901
        $this->botan_enabled = false;   // Force disable Botan.io integration, we don't want to track self-executed commands!
902
903
        $result = Request::getMe()->getResult();
904
905
        if (!$result->getId()) {
906
            throw new TelegramException('Received empty/invalid getMe result!');
907
        }
908
909
        $bot_id       = $result->getId();
910
        $bot_name     = $result->getFirstName();
911
        $bot_username = $result->getUsername();
912
913
        $this->enableAdmin($bot_id);    // Give bot access to admin commands
914
        $this->getCommandsList();       // Load full commands list
915
916
        foreach ($commands as $command) {
917
            $this->update = new Update(
918
                [
919
                    'update_id' => 0,
920
                    'message'   => [
921
                        'message_id' => 0,
922
                        'from'       => [
923
                            'id'         => $bot_id,
924
                            'first_name' => $bot_name,
925
                            'username'   => $bot_username,
926
                        ],
927
                        'date'       => time(),
928
                        'chat'       => [
929
                            'id'   => $bot_id,
930
                            'type' => 'private',
931
                        ],
932
                        'text'       => $command,
933
                    ],
934
                ]
935
            );
936
937
            $this->executeCommand($this->update->getMessage()->getCommand());
0 ignored issues
show
Bug introduced by
It seems like $this->update->getMessage()->getCommand() targeting Longman\TelegramBot\Entities\Message::getCommand() can also be of type boolean; however, Longman\TelegramBot\Telegram::executeCommand() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
938
        }
939
    }
940
}
941