Completed
Push — no_default_commands_fix_merge ( 97f0a8 )
by Armando
02:57 queued 10s
created

Telegram::sanitizeCommand()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
rs 10
ccs 2
cts 2
cp 1
cc 1
eloc 2
nc 1
nop 1
crap 1
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.42.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 31
    public function __construct($api_key, $bot_username)
142
    {
143 31
        if (empty($api_key)) {
144 1
            throw new TelegramException('API KEY not defined!');
145
        }
146 31
        preg_match('/(\d+)\:[\w\-]+/', $api_key, $matches);
147 31
        if (!isset($matches[1])) {
148 1
            throw new TelegramException('Invalid API KEY defined!');
149
        }
150 31
        $this->bot_id  = $matches[1];
151 31
        $this->api_key = $api_key;
152
153 31
        if (empty($bot_username)) {
154 1
            throw new TelegramException('Bot Username not defined!');
155
        }
156 31
        $this->bot_username = $bot_username;
157
158
        //Set default download and upload path
159 31
        $this->setDownloadPath(BASE_PATH . '/../Download');
160 31
        $this->setUploadPath(BASE_PATH . '/../Upload');
161
162
        //Add default system commands path
163 31
        $this->addCommandsPath(BASE_COMMANDS_PATH . '/SystemCommands');
164
165 31
        Request::initialize($this);
166 31
    }
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 1
    public function getCommandsList()
212
    {
213 1
        $commands = [];
214
215 1
        foreach ($this->commands_paths as $path) {
216
            try {
217
                //Get all "*Command.php" files
218 1
                $files = new RegexIterator(
219 1
                    new RecursiveIteratorIterator(
220 1
                        new RecursiveDirectoryIterator($path)
221
                    ),
222 1
                    '/^.+Command.php$/'
223
                );
224
225 1
                foreach ($files as $file) {
226
                    //Remove "Command.php" from filename
227 1
                    $command      = $this->sanitizeCommand(substr($file->getFilename(), 0, -11));
228 1
                    $command_name = strtolower($command);
229
230 1
                    if (array_key_exists($command_name, $commands)) {
231
                        continue;
232
                    }
233
234 1
                    require_once $file->getPathname();
235
236 1
                    $command_obj = $this->getCommandObject($command);
237 1
                    if ($command_obj instanceof Command) {
238 1
                        $commands[$command_name] = $command_obj;
239
                    }
240
                }
241
            } catch (Exception $e) {
242 1
                throw new TelegramException('Error getting commands from path: ' . $path);
243
            }
244
        }
245
246 1
        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 1
    public function getCommandObject($command)
257
    {
258 1
        $which = ['System'];
259 1
        $this->isAdmin() && $which[] = 'Admin';
260 1
        $which[] = 'User';
261
262 1
        foreach ($which as $auth) {
263 1
            $command_namespace = __NAMESPACE__ . '\\Commands\\' . $auth . 'Commands\\' . $this->ucfirstUnicode($command) . 'Command';
264 1
            if (class_exists($command_namespace)) {
265 1
                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
            $type = $message->getType();
419
            if ($type === 'command') {
420
                $command = $message->getCommand();
421
            } elseif (in_array($type, [
422
                'channel_chat_created',
423
                'delete_chat_photo',
424
                'group_chat_created',
425
                'left_chat_member',
426
                'migrate_from_chat_id',
427
                'migrate_to_chat_id',
428
                'new_chat_member',
429
                'new_chat_photo',
430
                'new_chat_title',
431
                'pinned_message',
432
                'supergroup_chat_created',
433
            ], true)
434
            ) {
435
                $command = $this->getCommandFromType($type);
436
            }
437
        }
438
439
        //Make sure we have an up-to-date command list
440
        //This is necessary to "require" all the necessary command files!
441
        $this->getCommandsList();
442
443
        DB::insertRequest($this->update);
444
445
        return $this->executeCommand($command);
0 ignored issues
show
Bug introduced by
It seems like $command defined by $message->getCommand() on line 420 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...
446
    }
447
448
    /**
449
     * Execute /command
450
     *
451
     * @param string $command
452
     *
453
     * @return mixed
454
     * @throws \Longman\TelegramBot\Exception\TelegramException
455
     */
456
    public function executeCommand($command)
457
    {
458
        $command_obj = $this->getCommandObject($command);
459
460
        if (!$command_obj || !$command_obj->isEnabled()) {
461
            //Failsafe in case the Generic command can't be found
462
            if ($command === 'Generic') {
463
                throw new TelegramException('Generic command missing!');
464
            }
465
466
            //Handle a generic command or non existing one
467
            $this->last_command_response = $this->executeCommand('Generic');
468
        } else {
469
            //Botan.io integration, make sure only the actual command user executed is reported
470
            if ($this->botan_enabled) {
471
                Botan::lock($command);
472
            }
473
474
            //execute() method is executed after preExecute()
475
            //This is to prevent executing a DB query without a valid connection
476
            $this->last_command_response = $command_obj->preExecute();
477
478
            //Botan.io integration, send report after executing the command
479
            if ($this->botan_enabled) {
480
                Botan::track($this->update, $command);
481
            }
482
        }
483
484
        return $this->last_command_response;
485
    }
486
487
    /**
488
     * Sanitize Command
489
     *
490
     * @param string $command
491
     *
492
     * @return string
493
     */
494 1
    protected function sanitizeCommand($command)
495
    {
496 1
        return str_replace(' ', '', $this->ucwordsUnicode(str_replace('_', ' ', $command)));
497
    }
498
499
    /**
500
     * Enable a single Admin account
501
     *
502
     * @param integer $admin_id Single admin id
503
     *
504
     * @return \Longman\TelegramBot\Telegram
505
     */
506 1
    public function enableAdmin($admin_id)
507
    {
508 1
        if (is_int($admin_id) && $admin_id > 0 && !in_array($admin_id, $this->admins_list, true)) {
509 1
            $this->admins_list[] = $admin_id;
510
        } else {
511 1
            TelegramLog::error('Invalid value "%s" for admin.', $admin_id);
512
        }
513
514 1
        return $this;
515
    }
516
517
    /**
518
     * Enable a list of Admin Accounts
519
     *
520
     * @param array $admin_ids List of admin ids
521
     *
522
     * @return \Longman\TelegramBot\Telegram
523
     */
524 1
    public function enableAdmins(array $admin_ids)
525
    {
526 1
        foreach ($admin_ids as $admin_id) {
527 1
            $this->enableAdmin($admin_id);
528
        }
529
530 1
        return $this;
531
    }
532
533
    /**
534
     * Get list of admins
535
     *
536
     * @return array
537
     */
538 1
    public function getAdminList()
539
    {
540 1
        return $this->admins_list;
541
    }
542
543
    /**
544
     * Check if the passed user is an admin
545
     *
546
     * If no user id is passed, the current update is checked for a valid message sender.
547
     *
548
     * @param int|null $user_id
549
     *
550
     * @return bool
551
     */
552 1
    public function isAdmin($user_id = null)
553
    {
554 1
        if ($user_id === null && $this->update !== null) {
555
            //Try to figure out if the user is an admin
556
            $update_methods = [
557
                'getMessage',
558
                'getEditedMessage',
559
                'getChannelPost',
560
                'getEditedChannelPost',
561
                'getInlineQuery',
562
                'getChosenInlineResult',
563
                'getCallbackQuery',
564
            ];
565
            foreach ($update_methods as $update_method) {
566
                $object = call_user_func([$this->update, $update_method]);
567
                if ($object !== null && $from = $object->getFrom()) {
568
                    $user_id = $from->getId();
569
                    break;
570
                }
571
            }
572
        }
573
574 1
        return ($user_id === null) ? false : in_array($user_id, $this->admins_list, true);
575
    }
576
577
    /**
578
     * Check if user required the db connection
579
     *
580
     * @return bool
581
     */
582
    public function isDbEnabled()
583
    {
584
        if ($this->mysql_enabled) {
585
            return true;
586
        } else {
587
            return false;
588
        }
589
    }
590
591
    /**
592
     * Add a single custom commands path
593
     *
594
     * @param string $path   Custom commands path to add
595
     * @param bool   $before If the path should be prepended or appended to the list
596
     *
597
     * @return \Longman\TelegramBot\Telegram
598
     */
599 31
    public function addCommandsPath($path, $before = true)
600
    {
601 31
        if (!is_dir($path)) {
602 1
            TelegramLog::error('Commands path "%s" does not exist.', $path);
603 31
        } elseif (!in_array($path, $this->commands_paths, true)) {
604 31
            if ($before) {
605 31
                array_unshift($this->commands_paths, $path);
606
            } else {
607
                $this->commands_paths[] = $path;
608
            }
609
        }
610
611 31
        return $this;
612
    }
613
614
    /**
615
     * Add multiple custom commands paths
616
     *
617
     * @param array $paths  Custom commands paths to add
618
     * @param bool  $before If the paths should be prepended or appended to the list
619
     *
620
     * @return \Longman\TelegramBot\Telegram
621
     */
622 1
    public function addCommandsPaths(array $paths, $before = true)
623
    {
624 1
        foreach ($paths as $path) {
625 1
            $this->addCommandsPath($path, $before);
626
        }
627
628 1
        return $this;
629
    }
630
631
    /**
632
     * Return the list of commands paths
633
     *
634
     * @return array
635
     */
636 1
    public function getCommandsPaths()
637
    {
638 1
        return $this->commands_paths;
639
    }
640
641
    /**
642
     * Set custom upload path
643
     *
644
     * @param string $path Custom upload path
645
     *
646
     * @return \Longman\TelegramBot\Telegram
647
     */
648 31
    public function setUploadPath($path)
649
    {
650 31
        $this->upload_path = $path;
651
652 31
        return $this;
653
    }
654
655
    /**
656
     * Get custom upload path
657
     *
658
     * @return string
659
     */
660
    public function getUploadPath()
661
    {
662
        return $this->upload_path;
663
    }
664
665
    /**
666
     * Set custom download path
667
     *
668
     * @param string $path Custom download path
669
     *
670
     * @return \Longman\TelegramBot\Telegram
671
     */
672 31
    public function setDownloadPath($path)
673
    {
674 31
        $this->download_path = $path;
675
676 31
        return $this;
677
    }
678
679
    /**
680
     * Get custom download path
681
     *
682
     * @return string
683
     */
684
    public function getDownloadPath()
685
    {
686
        return $this->download_path;
687
    }
688
689
    /**
690
     * Set command config
691
     *
692
     * Provide further variables to a particular commands.
693
     * For example you can add the channel name at the command /sendtochannel
694
     * Or you can add the api key for external service.
695
     *
696
     * @param string $command
697
     * @param array  $config
698
     *
699
     * @return \Longman\TelegramBot\Telegram
700
     */
701 14
    public function setCommandConfig($command, array $config)
702
    {
703 14
        $this->commands_config[$command] = $config;
704
705 14
        return $this;
706
    }
707
708
    /**
709
     * Get command config
710
     *
711
     * @param string $command
712
     *
713
     * @return array
714
     */
715 15
    public function getCommandConfig($command)
716
    {
717 15
        return isset($this->commands_config[$command]) ? $this->commands_config[$command] : [];
718
    }
719
720
    /**
721
     * Get API key
722
     *
723
     * @return string
724
     */
725 1
    public function getApiKey()
726
    {
727 1
        return $this->api_key;
728
    }
729
730
    /**
731
     * Get Bot name
732
     *
733
     * @return string
734
     */
735 1
    public function getBotUsername()
736
    {
737 1
        return $this->bot_username;
738
    }
739
740
    /**
741
     * Get Bot name
742
     *
743
     * @todo: Left for backwards compatibility, remove in the future
744
     *
745
     * @return string
746
     */
747
    public function getBotName()
748
    {
749
        TelegramLog::debug('Usage of deprecated method getBotName() detected, please use getBotUsername() instead!');
750
        return $this->getBotUsername();
751
    }
752
753
    /**
754
     * Get Bot Id
755
     *
756
     * @return string
757
     */
758
    public function getBotId()
759
    {
760
        return $this->bot_id;
761
    }
762
763
    /**
764
     * Get Version
765
     *
766
     * @return string
767
     */
768
    public function getVersion()
769
    {
770
        return $this->version;
771
    }
772
773
    /**
774
     * Set Webhook for bot
775
     *
776
     * @param string $url
777
     * @param array  $data Optional parameters.
778
     *
779
     * @return \Longman\TelegramBot\Entities\ServerResponse
780
     * @throws \Longman\TelegramBot\Exception\TelegramException
781
     */
782
    public function setWebhook($url, array $data = [])
783
    {
784
        if (empty($url)) {
785
            throw new TelegramException('Hook url is empty!');
786
        }
787
788
        $result = Request::setWebhook($url, $data);
789
790 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...
791
            throw new TelegramException(
792
                'Webhook was not set! Error: ' . $result->getErrorCode() . ' ' . $result->getDescription()
793
            );
794
        }
795
796
        return $result;
797
    }
798
799
    /**
800
     * Deprecated alias for deleteWebhook
801
     *
802
     * This is kept for backwards compatibility!
803
     *
804
     * @return mixed
805
     * @throws \Longman\TelegramBot\Exception\TelegramException
806
     */
807
    public function unsetWebhook()
808
    {
809
        return $this->deleteWebhook();
810
    }
811
812
    /**
813
     * Delete any assigned webhook
814
     *
815
     * @return mixed
816
     * @throws \Longman\TelegramBot\Exception\TelegramException
817
     */
818
    public function deleteWebhook()
819
    {
820
        $result = Request::deleteWebhook();
821
822 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...
823
            throw new TelegramException(
824
                'Webhook was not deleted! Error: ' . $result->getErrorCode() . ' ' . $result->getDescription()
825
            );
826
        }
827
828
        return $result;
829
    }
830
831
    /**
832
     * Replace function `ucwords` for UTF-8 characters in the class definition and commands
833
     *
834
     * @param string $str
835
     * @param string $encoding (default = 'UTF-8')
836
     *
837
     * @return string
838
     */
839 1
    protected function ucwordsUnicode($str, $encoding = 'UTF-8')
840
    {
841 1
        return mb_convert_case($str, MB_CASE_TITLE, $encoding);
842
    }
843
844
    /**
845
     * Replace function `ucfirst` for UTF-8 characters in the class definition and commands
846
     *
847
     * @param string $str
848
     * @param string $encoding (default = 'UTF-8')
849
     *
850
     * @return string
851
     */
852 1
    protected function ucfirstUnicode($str, $encoding = 'UTF-8')
853
    {
854
        return
855 1
            mb_strtoupper(mb_substr($str, 0, 1, $encoding), $encoding)
856 1
            . mb_strtolower(mb_substr($str, 1, mb_strlen($str), $encoding), $encoding);
857
    }
858
859
    /**
860
     * Enable Botan.io integration
861
     *
862
     * @param  string $token
863
     * @param  array  $options
864
     *
865
     * @return \Longman\TelegramBot\Telegram
866
     * @throws \Longman\TelegramBot\Exception\TelegramException
867
     */
868
    public function enableBotan($token, array $options = [])
869
    {
870
        Botan::initializeBotan($token, $options);
871
        $this->botan_enabled = true;
872
873
        return $this;
874
    }
875
876
    /**
877
     * Enable requests limiter
878
     */
879
    public function enableLimiter()
880
    {
881
        Request::setLimiter(true);
882
883
        return $this;
884
    }
885
886
    /**
887
     * Run provided commands
888
     *
889
     * @param array $commands
890
     *
891
     * @throws TelegramException
892
     */
893
    public function runCommands($commands)
894
    {
895
        if (!is_array($commands) || empty($commands)) {
896
            throw new TelegramException('No command(s) provided!');
897
        }
898
899
        $this->botan_enabled = false;   // Force disable Botan.io integration, we don't want to track self-executed commands!
900
901
        $result = Request::getMe()->getResult();
902
903
        if (!$result->getId()) {
904
            throw new TelegramException('Received empty/invalid getMe result!');
905
        }
906
907
        $bot_id       = $result->getId();
908
        $bot_name     = $result->getFirstName();
909
        $bot_username = $result->getUsername();
910
911
        $this->enableAdmin($bot_id);    // Give bot access to admin commands
912
        $this->getCommandsList();       // Load full commands list
913
914
        foreach ($commands as $command) {
915
            $this->update = new Update(
916
                [
917
                    'update_id' => 0,
918
                    'message'   => [
919
                        'message_id' => 0,
920
                        'from'       => [
921
                            'id'         => $bot_id,
922
                            'first_name' => $bot_name,
923
                            'username'   => $bot_username,
924
                        ],
925
                        'date'       => time(),
926
                        'chat'       => [
927
                            'id'   => $bot_id,
928
                            'type' => 'private',
929
                        ],
930
                        'text'       => $command,
931
                    ],
932
                ]
933
            );
934
935
            $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...
936
        }
937
    }
938
}
939