Completed
Pull Request — develop (#1045)
by Armando
02:10
created

Telegram::getCommandConfig()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 1
nc 2
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * This file is part of the TelegramBot package.
5
 *
6
 * (c) Avtandil Kikabidze aka LONGMAN <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Longman\TelegramBot;
13
14 1
defined('TB_BASE_PATH') || define('TB_BASE_PATH', __DIR__);
15 1
defined('TB_BASE_COMMANDS_PATH') || define('TB_BASE_COMMANDS_PATH', TB_BASE_PATH . '/Commands');
16
17
use Exception;
18
use Longman\TelegramBot\Commands\Command;
19
use Longman\TelegramBot\Entities\ServerResponse;
20
use Longman\TelegramBot\Entities\Update;
21
use Longman\TelegramBot\Exception\TelegramException;
22
use PDO;
23
use RecursiveDirectoryIterator;
24
use RecursiveIteratorIterator;
25
use RegexIterator;
26
27
class Telegram
28
{
29
    /**
30
     * Version
31
     *
32
     * @var string
33
     */
34
    protected $version = '0.62.0';
35
36
    /**
37
     * Telegram API key
38
     *
39
     * @var string
40
     */
41
    protected $api_key = '';
42
43
    /**
44
     * Telegram Bot username
45
     *
46
     * @var string
47
     */
48
    protected $bot_username = '';
49
50
    /**
51
     * Telegram Bot id
52
     *
53
     * @var string
54
     */
55
    protected $bot_id = '';
56
57
    /**
58
     * Raw request data (json) for webhook methods
59
     *
60
     * @var string
61
     */
62
    protected $input;
63
64
    /**
65
     * Custom commands paths
66
     *
67
     * @var array
68
     */
69
    protected $commands_paths = [];
70
71
    /**
72
     * Current Update object
73
     *
74
     * @var Update
75
     */
76
    protected $update;
77
78
    /**
79
     * Upload path
80
     *
81
     * @var string
82
     */
83
    protected $upload_path;
84
85
    /**
86
     * Download path
87
     *
88
     * @var string
89
     */
90
    protected $download_path;
91
92
    /**
93
     * MySQL integration
94
     *
95
     * @var bool
96
     */
97
    protected $mysql_enabled = false;
98
99
    /**
100
     * PDO object
101
     *
102
     * @var PDO
103
     */
104
    protected $pdo;
105
106
    /**
107
     * Commands config
108
     *
109
     * @var array
110
     */
111
    protected $commands_config = [];
112
113
    /**
114
     * Admins list
115
     *
116
     * @var array
117
     */
118
    protected $admins_list = [];
119
120
    /**
121
     * ServerResponse of the last Command execution
122
     *
123
     * @var ServerResponse
124
     */
125
    protected $last_command_response;
126
127
    /**
128
     * Check if runCommands() is running in this session
129
     *
130
     * @var bool
131
     */
132
    protected $run_commands = false;
133
134
    /**
135
     * Is running getUpdates without DB enabled
136
     *
137
     * @var bool
138
     */
139
    protected $getupdates_without_database = false;
140
141
    /**
142
     * Last update ID
143
     * Only used when running getUpdates without a database
144
     *
145
     * @var integer
146
     */
147
    protected $last_update_id;
148
149
    /**
150
     * The command to be executed when there's a new message update and nothing more suitable is found
151
     */
152
    const GENERIC_MESSAGE_COMMAND = 'genericmessage';
153
154
    /**
155
     * The command to be executed by default (when no other relevant commands are applicable)
156
     */
157
    const GENERIC_COMMAND = 'generic';
158
159
    /**
160
     * Update filter
161
     * Filter updates
162
     *
163
     * @var callback
164
     */
165
    protected $update_filter;
166
167
    /**
168
     * Telegram constructor.
169
     *
170
     * @param string $api_key
171
     * @param string $bot_username
172
     *
173
     * @throws TelegramException
174
     */
175 30
    public function __construct($api_key, $bot_username = '')
176
    {
177 30
        if (empty($api_key)) {
178 1
            throw new TelegramException('API KEY not defined!');
179
        }
180 30
        preg_match('/(\d+)\:[\w\-]+/', $api_key, $matches);
181 30
        if (!isset($matches[1])) {
182 1
            throw new TelegramException('Invalid API KEY defined!');
183
        }
184 30
        $this->bot_id  = $matches[1];
185 30
        $this->api_key = $api_key;
186
187 30
        if (!empty($bot_username)) {
188 30
            $this->bot_username = $bot_username;
189
        }
190
191
        //Add default system commands path
192 30
        $this->addCommandsPath(TB_BASE_COMMANDS_PATH . '/SystemCommands');
193
194 30
        Request::initialize($this);
195 30
    }
196
197
    /**
198
     * Initialize Database connection
199
     *
200
     * @param array  $credential
201
     * @param string $table_prefix
202
     * @param string $encoding
203
     *
204
     * @return Telegram
205
     * @throws TelegramException
206
     */
207 9
    public function enableMySql(array $credential, $table_prefix = null, $encoding = 'utf8mb4')
208
    {
209 9
        $this->pdo = DB::initialize($credential, $this, $table_prefix, $encoding);
210 9
        ConversationDB::initializeConversation();
211 9
        $this->mysql_enabled = true;
212
213 9
        return $this;
214
    }
215
216
    /**
217
     * Initialize Database external connection
218
     *
219
     * @param PDO    $external_pdo_connection PDO database object
220
     * @param string $table_prefix
221
     *
222
     * @return Telegram
223
     * @throws TelegramException
224
     */
225
    public function enableExternalMySql($external_pdo_connection, $table_prefix = null)
226
    {
227
        $this->pdo = DB::externalInitialize($external_pdo_connection, $this, $table_prefix);
228
        ConversationDB::initializeConversation();
229
        $this->mysql_enabled = true;
230
231
        return $this;
232
    }
233
234
    /**
235
     * Get commands list
236
     *
237
     * @return array $commands
238
     * @throws TelegramException
239
     */
240 1
    public function getCommandsList()
241
    {
242 1
        $commands = [];
243
244 1
        foreach ($this->commands_paths as $path) {
245
            try {
246
                //Get all "*Command.php" files
247 1
                $files = new RegexIterator(
248 1
                    new RecursiveIteratorIterator(
249 1
                        new RecursiveDirectoryIterator($path)
250
                    ),
251 1
                    '/^.+Command.php$/'
252
                );
253
254 1
                foreach ($files as $file) {
255
                    //Remove "Command.php" from filename
256 1
                    $command      = $this->sanitizeCommand(substr($file->getFilename(), 0, -11));
257 1
                    $command_name = mb_strtolower($command);
258
259 1
                    if (array_key_exists($command_name, $commands)) {
260
                        continue;
261
                    }
262
263 1
                    require_once $file->getPathname();
264
265 1
                    $command_obj = $this->getCommandObject($command);
266 1
                    if ($command_obj instanceof Command) {
267 1
                        $commands[$command_name] = $command_obj;
268
                    }
269
                }
270
            } catch (Exception $e) {
271
                throw new TelegramException('Error getting commands from path: ' . $path, $e);
0 ignored issues
show
Bug introduced by
$e of type Exception is incompatible with the type integer expected by parameter $code of Longman\TelegramBot\Exce...xception::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

271
                throw new TelegramException('Error getting commands from path: ' . $path, /** @scrutinizer ignore-type */ $e);
Loading history...
272
            }
273
        }
274
275 1
        return $commands;
276
    }
277
278
    /**
279
     * Get an object instance of the passed command
280
     *
281
     * @param string $command
282
     *
283
     * @return Command|null
284
     */
285 1
    public function getCommandObject($command)
286
    {
287 1
        $which = ['System'];
288 1
        $this->isAdmin() && $which[] = 'Admin';
289 1
        $which[] = 'User';
290
291 1
        foreach ($which as $auth) {
292 1
            $command_namespace = __NAMESPACE__ . '\\Commands\\' . $auth . 'Commands\\' . $this->ucfirstUnicode($command) . 'Command';
293 1
            if (class_exists($command_namespace)) {
294 1
                return new $command_namespace($this, $this->update);
295
            }
296
        }
297
298
        return null;
299
    }
300
301
    /**
302
     * Set custom input string for debug purposes
303
     *
304
     * @param string $input (json format)
305
     *
306
     * @return Telegram
307
     */
308
    public function setCustomInput($input)
309
    {
310
        $this->input = $input;
311
312
        return $this;
313
    }
314
315
    /**
316
     * Get custom input string for debug purposes
317
     *
318
     * @return string
319
     */
320
    public function getCustomInput()
321
    {
322
        return $this->input;
323
    }
324
325
    /**
326
     * Get the ServerResponse of the last Command execution
327
     *
328
     * @return ServerResponse
329
     */
330
    public function getLastCommandResponse()
331
    {
332
        return $this->last_command_response;
333
    }
334
335
    /**
336
     * Handle getUpdates method
337
     *
338
     * @param int|null $limit
339
     * @param int|null $timeout
340
     *
341
     * @return ServerResponse
342
     * @throws TelegramException
343
     */
344
    public function handleGetUpdates($limit = null, $timeout = null)
345
    {
346
        if (empty($this->bot_username)) {
347
            throw new TelegramException('Bot Username is not defined!');
348
        }
349
350
        if (!DB::isDbConnected() && !$this->getupdates_without_database) {
351
            return new ServerResponse(
352
                [
353
                    'ok'          => false,
354
                    'description' => 'getUpdates needs MySQL connection! (This can be overridden - see documentation)',
355
                ],
356
                $this->bot_username
357
            );
358
        }
359
360
        $offset = 0;
361
362
        //Take custom input into account.
363
        if ($custom_input = $this->getCustomInput()) {
364
            $response = new ServerResponse(json_decode($custom_input, true), $this->bot_username);
365
        } else {
366
            if (DB::isDbConnected() && $last_update = DB::selectTelegramUpdate(1)) {
367
                //Get last update id from the database
368
                $last_update = reset($last_update);
369
370
                $this->last_update_id = isset($last_update['id']) ? $last_update['id'] : null;
371
            }
372
373
            if ($this->last_update_id !== null) {
374
                $offset = $this->last_update_id + 1;    //As explained in the telegram bot API documentation
375
            }
376
377
            $response = Request::getUpdates(
378
                [
379
                    'offset'  => $offset,
380
                    'limit'   => $limit,
381
                    'timeout' => $timeout,
382
                ]
383
            );
384
        }
385
386
        if ($response->isOk()) {
387
            $results = $response->getResult();
388
389
            //Process all updates
390
            /** @var Update $result */
391
            foreach ($results as $result) {
392
                $this->processUpdate($result);
393
            }
394
395
            if (!DB::isDbConnected() && !$custom_input && $this->last_update_id !== null && $offset === 0) {
396
                //Mark update(s) as read after handling
397
                Request::getUpdates(
398
                    [
399
                        'offset'  => $this->last_update_id + 1,
400
                        'limit'   => 1,
401
                        'timeout' => $timeout,
402
                    ]
403
                );
404
            }
405
        }
406
407
        return $response;
408
    }
409
410
    /**
411
     * Handle bot request from webhook
412
     *
413
     * @return bool
414
     *
415
     * @throws TelegramException
416
     */
417
    public function handle()
418
    {
419
        if (empty($this->bot_username)) {
420
            throw new TelegramException('Bot Username is not defined!');
421
        }
422
423
        $this->input = Request::getInput();
424
425
        if (empty($this->input)) {
426
            throw new TelegramException('Input is empty!');
427
        }
428
429
        $post = json_decode($this->input, true);
430
        if (empty($post)) {
431
            throw new TelegramException('Invalid JSON!');
432
        }
433
434
        if ($response = $this->processUpdate(new Update($post, $this->bot_username))) {
435
            return $response->isOk();
436
        }
437
438
        return false;
439
    }
440
441
    /**
442
     * Get the command name from the command type
443
     *
444
     * @param string $type
445
     *
446
     * @return string
447
     */
448
    protected function getCommandFromType($type)
449
    {
450
        return $this->ucfirstUnicode(str_replace('_', '', $type));
451
    }
452
453
    /**
454
     * Process bot Update request
455
     *
456
     * @param Update $update
457
     *
458
     * @return ServerResponse
459
     * @throws TelegramException
460
     */
461 1
    public function processUpdate(Update $update)
462
    {
463 1
        $this->update         = $update;
464 1
        $this->last_update_id = $update->getUpdateId();
465
466 1
        if (is_callable($this->update_filter)) {
467 1
            $reason = 'Update denied by update_filter';
468
            try {
469 1
                $allowed = (bool) call_user_func_array($this->update_filter, [$update, $this, &$reason]);
470
            } catch (\Exception $e) {
471
                $allowed = false;
472
            }
473
474 1
            if (!$allowed) {
475 1
                TelegramLog::debug($reason);
476 1
                return new ServerResponse(['ok' => false, 'description' => 'denied'], null);
477
            }
478
        }
479
480
        //Load admin commands
481
        if ($this->isAdmin()) {
482
            $this->addCommandsPath(TB_BASE_COMMANDS_PATH . '/AdminCommands', false);
483
        }
484
485
        //Make sure we have an up-to-date command list
486
        //This is necessary to "require" all the necessary command files!
487
        $this->getCommandsList();
488
489
        //If all else fails, it's a generic message.
490
        $command = self::GENERIC_MESSAGE_COMMAND;
491
492
        $update_type = $this->update->getUpdateType();
493
        if ($update_type === 'message') {
494
            $message = $this->update->getMessage();
495
            $type    = $message->getType();
496
497
            // Let's check if the message object has the type field we're looking for...
498
            $command_tmp = $type === 'command' ? $message->getCommand() : $this->getCommandFromType($type);
499
            // ...and if a fitting command class is available.
500
            $command_obj = $this->getCommandObject($command_tmp);
501
502
            // Empty usage string denotes a non-executable command.
503
            // @see https://github.com/php-telegram-bot/core/issues/772#issuecomment-388616072
504
            if (
505
                ($command_obj === null && $type === 'command')
506
                || ($command_obj !== null && $command_obj->getUsage() !== '')
507
            ) {
508
                $command = $command_tmp;
509
            }
510
        } else {
511
            $command = $this->getCommandFromType($update_type);
512
        }
513
514
        //Make sure we don't try to process update that was already processed
515
        $last_id = DB::selectTelegramUpdate(1, $this->update->getUpdateId());
516
        if ($last_id && count($last_id) === 1) {
517
            TelegramLog::debug('Duplicate update received, processing aborted!');
518
            return Request::emptyResponse();
519
        }
520
521
        DB::insertRequest($this->update);
522
523
        return $this->executeCommand($command);
524
    }
525
526
    /**
527
     * Execute /command
528
     *
529
     * @param string $command
530
     *
531
     * @return ServerResponse
532
     * @throws TelegramException
533
     */
534
    public function executeCommand($command)
535
    {
536
        $command     = mb_strtolower($command);
537
        $command_obj = $this->getCommandObject($command);
538
539
        if (!$command_obj || !$command_obj->isEnabled()) {
540
            //Failsafe in case the Generic command can't be found
541
            if ($command === self::GENERIC_COMMAND) {
542
                throw new TelegramException('Generic command missing!');
543
            }
544
545
            //Handle a generic command or non existing one
546
            $this->last_command_response = $this->executeCommand(self::GENERIC_COMMAND);
547
        } else {
548
            //execute() method is executed after preExecute()
549
            //This is to prevent executing a DB query without a valid connection
550
            $this->last_command_response = $command_obj->preExecute();
551
        }
552
553
        return $this->last_command_response;
554
    }
555
556
    /**
557
     * Sanitize Command
558
     *
559
     * @param string $command
560
     *
561
     * @return string
562
     */
563 1
    protected function sanitizeCommand($command)
564
    {
565 1
        return str_replace(' ', '', $this->ucwordsUnicode(str_replace('_', ' ', $command)));
566
    }
567
568
    /**
569
     * Enable a single Admin account
570
     *
571
     * @param integer $admin_id Single admin id
572
     *
573
     * @return Telegram
574
     */
575 1
    public function enableAdmin($admin_id)
576
    {
577 1
        if (!is_int($admin_id) || $admin_id <= 0) {
0 ignored issues
show
introduced by
The condition is_int($admin_id) is always true.
Loading history...
578 1
            TelegramLog::error('Invalid value "' . $admin_id . '" for admin.');
579 1
        } elseif (!in_array($admin_id, $this->admins_list, true)) {
580 1
            $this->admins_list[] = $admin_id;
581
        }
582
583 1
        return $this;
584
    }
585
586
    /**
587
     * Enable a list of Admin Accounts
588
     *
589
     * @param array $admin_ids List of admin ids
590
     *
591
     * @return Telegram
592
     */
593 1
    public function enableAdmins(array $admin_ids)
594
    {
595 1
        foreach ($admin_ids as $admin_id) {
596 1
            $this->enableAdmin($admin_id);
597
        }
598
599 1
        return $this;
600
    }
601
602
    /**
603
     * Get list of admins
604
     *
605
     * @return array
606
     */
607 1
    public function getAdminList()
608
    {
609 1
        return $this->admins_list;
610
    }
611
612
    /**
613
     * Check if the passed user is an admin
614
     *
615
     * If no user id is passed, the current update is checked for a valid message sender.
616
     *
617
     * @param int|null $user_id
618
     *
619
     * @return bool
620
     */
621 1
    public function isAdmin($user_id = null)
622
    {
623 1
        if ($user_id === null && $this->update !== null) {
624
            //Try to figure out if the user is an admin
625
            $update_methods = [
626
                'getMessage',
627
                'getEditedMessage',
628
                'getChannelPost',
629
                'getEditedChannelPost',
630
                'getInlineQuery',
631
                'getChosenInlineResult',
632
                'getCallbackQuery',
633
            ];
634
            foreach ($update_methods as $update_method) {
635
                $object = call_user_func([$this->update, $update_method]);
636
                if ($object !== null && $from = $object->getFrom()) {
637
                    $user_id = $from->getId();
638
                    break;
639
                }
640
            }
641
        }
642
643 1
        return ($user_id === null) ? false : in_array($user_id, $this->admins_list, true);
644
    }
645
646
    /**
647
     * Check if user required the db connection
648
     *
649
     * @return bool
650
     */
651
    public function isDbEnabled()
652
    {
653
        if ($this->mysql_enabled) {
654
            return true;
655
        } else {
656
            return false;
657
        }
658
    }
659
660
    /**
661
     * Add a single custom commands path
662
     *
663
     * @param string $path   Custom commands path to add
664
     * @param bool   $before If the path should be prepended or appended to the list
665
     *
666
     * @return Telegram
667
     */
668 30
    public function addCommandsPath($path, $before = true)
669
    {
670 30
        if (!is_dir($path)) {
671 1
            TelegramLog::error('Commands path "' . $path . '" does not exist.');
672 30
        } elseif (!in_array($path, $this->commands_paths, true)) {
673 30
            if ($before) {
674 30
                array_unshift($this->commands_paths, $path);
675
            } else {
676
                $this->commands_paths[] = $path;
677
            }
678
        }
679
680 30
        return $this;
681
    }
682
683
    /**
684
     * Add multiple custom commands paths
685
     *
686
     * @param array $paths  Custom commands paths to add
687
     * @param bool  $before If the paths should be prepended or appended to the list
688
     *
689
     * @return Telegram
690
     */
691 1
    public function addCommandsPaths(array $paths, $before = true)
692
    {
693 1
        foreach ($paths as $path) {
694 1
            $this->addCommandsPath($path, $before);
695
        }
696
697 1
        return $this;
698
    }
699
700
    /**
701
     * Return the list of commands paths
702
     *
703
     * @return array
704
     */
705 1
    public function getCommandsPaths()
706
    {
707 1
        return $this->commands_paths;
708
    }
709
710
    /**
711
     * Set custom upload path
712
     *
713
     * @param string $path Custom upload path
714
     *
715
     * @return Telegram
716
     */
717
    public function setUploadPath($path)
718
    {
719
        $this->upload_path = $path;
720
721
        return $this;
722
    }
723
724
    /**
725
     * Get custom upload path
726
     *
727
     * @return string
728
     */
729
    public function getUploadPath()
730
    {
731
        return $this->upload_path;
732
    }
733
734
    /**
735
     * Set custom download path
736
     *
737
     * @param string $path Custom download path
738
     *
739
     * @return Telegram
740
     */
741
    public function setDownloadPath($path)
742
    {
743
        $this->download_path = $path;
744
745
        return $this;
746
    }
747
748
    /**
749
     * Get custom download path
750
     *
751
     * @return string
752
     */
753
    public function getDownloadPath()
754
    {
755
        return $this->download_path;
756
    }
757
758
    /**
759
     * Set command config
760
     *
761
     * Provide further variables to a particular commands.
762
     * For example you can add the channel name at the command /sendtochannel
763
     * Or you can add the api key for external service.
764
     *
765
     * @param string $command
766
     * @param array  $config
767
     *
768
     * @return Telegram
769
     */
770 13
    public function setCommandConfig($command, array $config)
771
    {
772 13
        $this->commands_config[$command] = $config;
773
774 13
        return $this;
775
    }
776
777
    /**
778
     * Get command config
779
     *
780
     * @param string $command
781
     *
782
     * @return array
783
     */
784 14
    public function getCommandConfig($command)
785
    {
786 14
        return isset($this->commands_config[$command]) ? $this->commands_config[$command] : [];
787
    }
788
789
    /**
790
     * Get API key
791
     *
792
     * @return string
793
     */
794 1
    public function getApiKey()
795
    {
796 1
        return $this->api_key;
797
    }
798
799
    /**
800
     * Get Bot name
801
     *
802
     * @return string
803
     */
804 2
    public function getBotUsername()
805
    {
806 2
        return $this->bot_username;
807
    }
808
809
    /**
810
     * Get Bot Id
811
     *
812
     * @return string
813
     */
814
    public function getBotId()
815
    {
816
        return $this->bot_id;
817
    }
818
819
    /**
820
     * Get Version
821
     *
822
     * @return string
823
     */
824
    public function getVersion()
825
    {
826
        return $this->version;
827
    }
828
829
    /**
830
     * Set Webhook for bot
831
     *
832
     * @param string $url
833
     * @param array  $data Optional parameters.
834
     *
835
     * @return ServerResponse
836
     * @throws TelegramException
837
     */
838
    public function setWebhook($url, array $data = [])
839
    {
840
        if (empty($url)) {
841
            throw new TelegramException('Hook url is empty!');
842
        }
843
844
        $data        = array_intersect_key($data, array_flip([
845
            'certificate',
846
            'max_connections',
847
            'allowed_updates',
848
        ]));
849
        $data['url'] = $url;
850
851
        // If the certificate is passed as a path, encode and add the file to the data array.
852
        if (!empty($data['certificate']) && is_string($data['certificate'])) {
853
            $data['certificate'] = Request::encodeFile($data['certificate']);
854
        }
855
856
        $result = Request::setWebhook($data);
857
858
        if (!$result->isOk()) {
859
            throw new TelegramException(
860
                'Webhook was not set! Error: ' . $result->getErrorCode() . ' ' . $result->getDescription()
861
            );
862
        }
863
864
        return $result;
865
    }
866
867
    /**
868
     * Delete any assigned webhook
869
     *
870
     * @return mixed
871
     * @throws TelegramException
872
     */
873
    public function deleteWebhook()
874
    {
875
        $result = Request::deleteWebhook();
876
877
        if (!$result->isOk()) {
878
            throw new TelegramException(
879
                'Webhook was not deleted! Error: ' . $result->getErrorCode() . ' ' . $result->getDescription()
880
            );
881
        }
882
883
        return $result;
884
    }
885
886
    /**
887
     * Replace function `ucwords` for UTF-8 characters in the class definition and commands
888
     *
889
     * @param string $str
890
     * @param string $encoding (default = 'UTF-8')
891
     *
892
     * @return string
893
     */
894 1
    protected function ucwordsUnicode($str, $encoding = 'UTF-8')
895
    {
896 1
        return mb_convert_case($str, MB_CASE_TITLE, $encoding);
897
    }
898
899
    /**
900
     * Replace function `ucfirst` for UTF-8 characters in the class definition and commands
901
     *
902
     * @param string $str
903
     * @param string $encoding (default = 'UTF-8')
904
     *
905
     * @return string
906
     */
907 1
    protected function ucfirstUnicode($str, $encoding = 'UTF-8')
908
    {
909 1
        return mb_strtoupper(mb_substr($str, 0, 1, $encoding), $encoding)
910 1
               . mb_strtolower(mb_substr($str, 1, mb_strlen($str), $encoding), $encoding);
911
    }
912
913
    /**
914
     * Enable requests limiter
915
     *
916
     * @param array $options
917
     *
918
     * @return Telegram
919
     * @throws TelegramException
920
     */
921
    public function enableLimiter(array $options = [])
922
    {
923
        Request::setLimiter(true, $options);
924
925
        return $this;
926
    }
927
928
    /**
929
     * Run provided commands
930
     *
931
     * @param array $commands
932
     *
933
     * @throws TelegramException
934
     */
935
    public function runCommands($commands)
936
    {
937
        if (!is_array($commands) || empty($commands)) {
0 ignored issues
show
introduced by
The condition is_array($commands) is always true.
Loading history...
938
            throw new TelegramException('No command(s) provided!');
939
        }
940
941
        $this->run_commands = true;
942
943
        $result = Request::getMe();
944
945
        if ($result->isOk()) {
946
            $result = $result->getResult();
947
948
            $bot_id       = $result->getId();
949
            $bot_name     = $result->getFirstName();
950
            $bot_username = $result->getUsername();
951
        } else {
952
            $bot_id       = $this->getBotId();
953
            $bot_name     = $this->getBotUsername();
954
            $bot_username = $this->getBotUsername();
955
        }
956
957
958
        $this->enableAdmin($bot_id);    // Give bot access to admin commands
959
        $this->getCommandsList();       // Load full commands list
960
961
        foreach ($commands as $command) {
962
            $this->update = new Update(
963
                [
964
                    'update_id' => 0,
965
                    'message'   => [
966
                        'message_id' => 0,
967
                        'from'       => [
968
                            'id'         => $bot_id,
969
                            'first_name' => $bot_name,
970
                            'username'   => $bot_username,
971
                        ],
972
                        'date'       => time(),
973
                        'chat'       => [
974
                            'id'   => $bot_id,
975
                            'type' => 'private',
976
                        ],
977
                        'text'       => $command,
978
                    ],
979
                ]
980
            );
981
982
            $this->executeCommand($this->update->getMessage()->getCommand());
983
        }
984
    }
985
986
    /**
987
     * Is this session initiated by runCommands()
988
     *
989
     * @return bool
990
     */
991
    public function isRunCommands()
992
    {
993
        return $this->run_commands;
994
    }
995
996
    /**
997
     * Switch to enable running getUpdates without a database
998
     *
999
     * @param bool $enable
1000
     */
1001
    public function useGetUpdatesWithoutDatabase($enable = true)
1002
    {
1003
        $this->getupdates_without_database = $enable;
1004
    }
1005
1006
    /**
1007
     * Return last update id
1008
     *
1009
     * @return int
1010
     */
1011
    public function getLastUpdateId()
1012
    {
1013
        return $this->last_update_id;
1014
    }
1015
1016
    /**
1017
     * Set an update filter callback
1018
     *
1019
     * @param callable $callback
1020
     *
1021
     * @return Telegram
1022
     */
1023 1
    public function setUpdateFilter(callable $callback)
1024
    {
1025 1
        $this->update_filter = $callback;
1026
1027 1
        return $this;
1028
    }
1029
1030
    /**
1031
     * Return update filter callback
1032
     *
1033
     * @return callable|null
1034
     */
1035
    public function getUpdateFilter()
1036
    {
1037
        return $this->update_filter;
1038
    }
1039
}
1040