Issues (236)

src/database/json.php (6 issues)

Labels
Severity
1
<?php
2
3
namespace BPT\database;
4
5
use BPT\BPT;
6
use BPT\constants\chatMemberStatus;
7
use BPT\constants\chatType;
8
use BPT\constants\fields;
9
use BPT\database\json\groupUserInterface;
10
use BPT\database\json\userInterface;
11
use BPT\exception\bptException;
12
use BPT\telegram\telegram;
13
use BPT\tools\tools;
14
use BPT\types\callbackQuery;
15
use BPT\types\chatMemberUpdated;
16
use BPT\types\inlineQuery;
17
use BPT\types\message;
18
19
class json {
20
    /**
21
     * Global data will be loaded here automatically, And your changes will be saved automatically too
22
     *
23
     *  
24
     *
25
     * Always loaded when db started, no matter what
26
     */
27
    public static ?object $global = null;
28
    private static ?object $old_global = null;
29
30
    /**
31
     * User data will be loaded here automatically, And your changes will be saved automatically too
32
     *
33
     *  
34
     *
35
     * Will be loaded in Private chats. Will be loaded in Groups and SuperGroups if user started bot in private chat
36
     * @var userInterface $user
37
     */
38
    public static ?object $user = null;
39
    private static ?object $old_user = null;
40
    private static int $user_id;
41
42
    /**
43
     * Group data will be loaded here automatically, And your changes will be saved automatically too
44
     *
45
     *  
46
     *
47
     * Will be loaded in groups only.
48
     */
49
    public static ?object $group = null;
50
    private static ?object $old_group = null;
51
    private static int $group_id;
52
53
    /**
54
     * Supergroup data will be loaded here automatically, And your changes will be saved automatically too
55
     *
56
     *  
57
     *
58
     * Will be loaded in Supergroups only.
59
     */
60
    public static ?object $supergroup = null;
61
    private static ?object $old_supergroup = null;
62
    private static int $supergroup_id;
63
64
    /**
65
     * User data in group will be loaded here automatically, And your changes will be saved automatically too
66
     *
67
     *  
68
     *
69
     * Will be loaded in group and supergroups
70
     * @var groupUserInterface $group_user
71
     */
72
    public static ?object $group_user = null;
73
    private static ?object $old_group_user = null;
74
    private static int $group_user_id;
75
76
    /**
77
     * Channel data will be loaded here automatically, And your changes will be saved automatically too
78
     *
79
     *  
80
     *
81
     * Will be loaded in Channel only.
82
     */
83
    public static ?object $channel = null;
84
    private static ?object $old_channel = null;
85
    private static int $channel_id;
86
87
    private static string $folder = '';
88
89
    private static array $ids = [];
90
    private static array $old_ids = [];
91
92
    private static array $group_ids = [];
93
    private static array $old_group_ids = [];
94
95
    private static array $global_default_data = [];
96
    private static array $user_default_data = ['step' => 'none', 'value' => '', 'phone_number' => '', 'first_active' => 0, 'last_active' => 0, 'referral' => null];
97
    private static array $group_user_default_data = ['step' => 'none', 'value' => '', 'last_active' => 0, 'presence' => true, 'removed' => false, 'removed_by' => null, 'invite_link' => null, 'accepted_by' => null, 'invited_by' => null];
98
    private static array $group_default_data = [];
99
    private static array $supergroup_default_data = [];
100
    private static array $channel_default_data = [];
101
102
    /**
103
     * @internal Only for BPT self usage , Don't use it in your source!
104
     */
105
    public static function init (string $bot_name, array $global = [], array $user = [], array $group_user = [], array $group = [], array $supergroup = [], array $channel = []): void {
106
        self::$folder = $bot_name . 'database';
107
        self::$global_default_data = $global ?? self::$global_default_data;
108
        self::setUserDefaultData($user);
109
        self::setGroupUserDefaultData($group_user);
110
        self::$group_default_data = $group ?? self::$group_default_data;
111
        self::$supergroup_default_data = $supergroup ?? self::$supergroup_default_data;
112
        self::$channel_default_data = $channel ?? self::$channel_default_data;
113
        self::create();
114
        self::load();
115
    }
116
117
    private static function setUserDefaultData (array $user = []): void {
118
        self::$user_default_data = $user ?? self::$user_default_data;
119
        if (!isset(self::$user_default_data['step'])) {
120
            self::$user_default_data['step'] = 'none';
121
        }
122
        if (!isset(self::$user_default_data['value'])) {
123
            self::$user_default_data['value'] = '';
124
        }
125
        if (!isset(self::$user_default_data['phone_number'])) {
126
            self::$user_default_data['phone_number'] = '';
127
        }
128
        if (!isset(self::$user_default_data['first_active'])) {
129
            self::$user_default_data['first_active'] = 0;
130
        }
131
        if (!isset(self::$user_default_data['last_active'])) {
132
            self::$user_default_data['last_active'] = 0;
133
        }
134
    }
135
136
    private static function setGroupUserDefaultData (array $group_user = []): void {
137
        self::$group_user_default_data = $group_user ?? self::$group_user_default_data;
138
        if (!isset(self::$group_user_default_data['step'])) {
139
            self::$group_user_default_data['step'] = 'none';
140
        }
141
        if (!isset(self::$group_user_default_data['value'])) {
142
            self::$group_user_default_data['value'] = '';
143
        }
144
    }
145
146
    private static function create(): void {
147
        if (!is_dir(realpath(self::$folder))) {
148
            mkdir(self::$folder);
149
        }
150
        if (!is_dir(realpath(self::$folder.'/privates'))) {
151
            mkdir(self::$folder.'/privates');
152
        }
153
        if (!is_dir(realpath(self::$folder.'/groups'))) {
154
            mkdir(self::$folder.'/groups');
155
        }
156
        if (!is_dir(realpath(self::$folder.'/supergroups'))) {
157
            mkdir(self::$folder.'/supergroups');
158
        }
159
        if (!is_dir(realpath(self::$folder.'/channels'))) {
160
            mkdir(self::$folder.'/channels');
161
        }
162
163
        if (!file_exists(realpath(self::$folder.'/global.json'))) {
164
            file_put_contents(self::$folder.'/global.json',self::$global_default_data);
165
        }
166
        if (!file_exists(realpath(self::$folder.'/ids.json'))) {
167
            file_put_contents(self::$folder.'/ids.json',json_encode([
168
                'privates' => [],
169
                'groups' => [],
170
                'supergroups' => [],
171
                'channels' => []
172
            ]));
173
        }
174
    }
175
176
    private static function load (): void {
177
        self::$global = json_decode(file_get_contents(self::$folder.'/global.json'));
178
        self::$old_global = clone self::$global;
179
        self::$ids = json_decode(file_get_contents(self::$folder.'/ids.json'),true);
180
        self::$old_ids = clone self::$ids;
181
    }
182
183
    private static function read (string $address) {
184
        return file_exists(realpath(self::$folder.'/'.$address.'.json')) ? json_decode(file_get_contents(self::$folder.'/'.$address.'.json'), false) : null;
185
    }
186
187
    private static function write (string $address,string $data): void {
188
        file_put_contents(self::$folder.'/'.$address.'.json',$data);
189
    }
190
191
    /**
192
     * @internal Only for BPT self usage , Don't use it in your source!
193
     */
194
    public static function process (): void {
195
        if (isset(BPT::$update->message)) {
196
            self::processMessage(BPT::$update->message);
0 ignored issues
show
It seems like BPT\BPT::update->message can also be of type null; however, parameter $update of BPT\database\json::processMessage() does only seem to accept BPT\types\message, maybe add an additional type check? ( Ignorable by Annotation )

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

196
            self::processMessage(/** @scrutinizer ignore-type */ BPT::$update->message);
Loading history...
197
        }
198
        elseif (isset(BPT::$update->edited_message)) {
199
            self::processMessage(BPT::$update->edited_message);
200
        }
201
        elseif (isset(BPT::$update->callback_query)) {
202
            self::processCallbackQuery(BPT::$update->callback_query);
0 ignored issues
show
It seems like BPT\BPT::update->callback_query can also be of type null; however, parameter $update of BPT\database\json::processCallbackQuery() does only seem to accept BPT\types\callbackQuery, maybe add an additional type check? ( Ignorable by Annotation )

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

202
            self::processCallbackQuery(/** @scrutinizer ignore-type */ BPT::$update->callback_query);
Loading history...
203
        }
204
        elseif (isset(BPT::$update->inline_query)) {
205
            self::processInlineQuery(BPT::$update->inline_query);
0 ignored issues
show
It seems like BPT\BPT::update->inline_query can also be of type null; however, parameter $update of BPT\database\json::processInlineQuery() does only seem to accept BPT\types\inlineQuery, maybe add an additional type check? ( Ignorable by Annotation )

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

205
            self::processInlineQuery(/** @scrutinizer ignore-type */ BPT::$update->inline_query);
Loading history...
206
        }
207
        elseif (isset(BPT::$update->chat_member)) {
208
            self::processChatMember(BPT::$update->chat_member);
0 ignored issues
show
It seems like BPT\BPT::update->chat_member can also be of type null; however, parameter $update of BPT\database\json::processChatMember() does only seem to accept BPT\types\chatMemberUpdated, maybe add an additional type check? ( Ignorable by Annotation )

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

208
            self::processChatMember(/** @scrutinizer ignore-type */ BPT::$update->chat_member);
Loading history...
209
        }
210
    }
211
212
    /**
213
     * @internal Only for BPT self usage , Don't use it in your source!
214
     */
215
    public static function save(): void {
216
        if (self::$user !== self::$old_user && !empty(self::$user_id)) {
217
            self::write('privates/' . self::$user_id,json_encode(self::$user));
218
        }
219
        if (self::$group !== self::$old_group && !empty(self::$group_id)) {
220
            self::write('groups/' . self::$group_id,json_encode(self::$group));
221
        }
222
        if (self::$supergroup !== self::$old_supergroup && !empty(self::$supergroup_id)) {
223
            self::write('supergroups/' . self::$supergroup_id,json_encode(self::$supergroup));
224
        }
225
        if (self::$channel !== self::$old_channel && !empty(self::$channel_id)) {
226
            self::write('channels/' . self::$channel_id,json_encode(self::$channel));
227
        }
228
        if (self::$group_user !== self::$old_group_user && !empty(self::$group_user_id)) {
229
            if (empty(self::$group)) {
230
                $category = 'supergroups';
231
                $group_id = self::$supergroup_id;
232
            }
233
            else {
234
                $category = 'groups';
235
                $group_id = self::$group_id;
236
            }
237
            self::write($category . '/' . $group_id . '/' . self::$group_user_id,json_encode(self::$group_user));
238
        }
239
        if (self::$ids !== self::$old_ids) {
240
            self::write('ids',json_encode(self::$ids));
241
        }
242
        if (self::$global !== self::$old_global) {
243
            self::write('global',json_encode(self::$global));
244
        }
245
        if (self::$group_ids !== self::$old_group_ids) {
246
            if (empty(self::$group)) {
247
                $category = 'supergroups';
248
                $group_id = self::$supergroup_id;
249
            }
250
            else {
251
                $category = 'groups';
252
                $group_id = self::$group_id;
253
            }
254
            self::write($category . '/' . $group_id . '/users',json_encode(self::$group_user));
255
        }
256
    }
257
258
    private static function processMessage(message $update): void {
259
        $type = $update->chat->type;
260
        $category = $type . 's';
261
        if ($type === chatType::PRIVATE) {
262
            self::$user_id = $update->from->id;
263
            if (in_array(self::$user_id,self::$ids[$category])) {
264
                self::$user = self::read($category . '/' . self::$user_id);
265
                self::$old_user = clone self::$user;
266
                self::$user->last_active = time();
267
            }
268
            else {
269
                self::$ids[$category][] = self::$user_id;
270
                self::$user = (object) self::$user_default_data;
271
                self::$user->first_active = self::$user->last_active = time();
272
                if (isset($update->command) && isset($update->command_payload) && $update->command === 'start' && str_starts_with($update->command_payload,'ref_')) {
0 ignored issues
show
It seems like $update->command_payload can also be of type null; however, parameter $haystack of str_starts_with() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

272
                if (isset($update->command) && isset($update->command_payload) && $update->command === 'start' && str_starts_with(/** @scrutinizer ignore-type */ $update->command_payload,'ref_')) {
Loading history...
273
                    if (tools::isShorted(substr($update->command_payload,4))) {
0 ignored issues
show
It seems like $update->command_payload can also be of type null; however, parameter $string of substr() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

273
                    if (tools::isShorted(substr(/** @scrutinizer ignore-type */ $update->command_payload,4))) {
Loading history...
274
                        $referral = tools::shortDecode(substr($update->command_payload,4));
275
                        if (in_array($referral,self::$ids[$category])) {
276
                            self::$user->referral = $referral;
277
                        }
278
                    }
279
                }
280
            }
281
        }
282
        elseif ($type === chatType::CHANNEL) {
283
            self::$channel_id = $update->chat->id;
284
            if (in_array(self::$channel_id,self::$ids[$category])) {
285
                self::$channel = self::read($category . '/' . self::$channel_id);
286
                self::$old_channel = clone self::$channel;
287
            }
288
            else {
289
                self::$ids[$category][] = self::$channel_id;
290
                self::$channel = (object) self::$channel_default_data;
291
            }
292
        }
293
        else {
294
            self::$user_id = $update->from->id;
295
            self::$group_user_id = self::$user_id;
296
            $chat_id = $update->chat->id;
297
            if ($type === chatType::SUPERGROUP) {
298
                self::$supergroup_id = $update->chat->id;
299
                if (in_array($chat_id,self::$ids[$category])) {
300
                    self::$supergroup = self::read($category . '/' . $chat_id);
301
                    self::$old_supergroup = clone self::$supergroup;
302
                    self::$group_ids = self::read($category . '/' . $chat_id . '/users');
303
                    self::$old_group_ids = clone self::$group_ids;
304
                }
305
                else {
306
                    self::$ids[$category][] = $chat_id;
307
                    self::$supergroup = (object) self::$supergroup_default_data;
308
                    self::$group_ids = [];
309
                }
310
            }
311
            else {
312
                self::$group_id = $update->chat->id;
313
                if (in_array($chat_id,self::$ids[$category])) {
314
                    self::$group = self::read($category . '/' . $chat_id);
315
                    self::$old_group = clone self::$group;
316
                    self::$group_ids = self::read($category . '/' . $chat_id . '/users');
317
                    self::$old_group_ids = clone self::$group_ids;
318
                }
319
                else {
320
                    self::$ids[$category][] = $chat_id;
321
                    self::$group = (object) self::$group_default_data;
322
                    self::$group_ids = [];
323
                }
324
            }
325
326
            if (in_array(self::$user_id,self::$group_ids)) {
327
                self::$group_user = self::read($category . '/' . $chat_id . '/' . self::$user_id);
328
                self::$old_group_user = clone self::$group_user;
329
            }
330
            else {
331
                self::$group_ids[] = self::$user_id;
332
                self::$group_user = (object) self::$group_user_default_data;
333
            }
334
335
            self::$user = self::read($category.'/'.self::$user_id);
336
            self::$old_user = clone self::$user;
337
            if (!empty(self::$user)) self::$user->last_active = time();
338
        }
339
    }
340
341
    private static function processCallbackQuery(callbackQuery $update): void {
342
        $type = $update->message->chat->type;
343
        $category = $type . 's';
344
        if ($type === chatType::PRIVATE) {
345
            self::$user_id = $update->from->id;
346
            if (in_array(self::$user_id,self::$ids[$category])) {
347
                self::$user = self::read($category . '/' . self::$user_id);
348
                self::$old_user = clone self::$user;
349
                self::$user->last_active = time();
350
            }
351
        }
352
        elseif ($type === chatType::CHANNEL) {
353
            self::$channel_id = $update->message->chat->id;
354
            if (in_array(self::$channel_id,self::$ids[$category])) {
355
                self::$channel = self::read($category . '/' . self::$channel_id);
356
                self::$old_channel = clone self::$channel;
357
            }
358
        }
359
        else {
360
            self::$user_id = $update->from->id;
361
            $chat_id = $update->message->chat->id;
362
            if (in_array($chat_id,self::$ids[$category])) {
363
                if ($type === chatType::SUPERGROUP) {
364
                    self::$supergroup_id = $update->message->chat->id;
365
                    self::$supergroup = self::read($category . '/' . $chat_id);
366
                    self::$old_supergroup = clone self::$supergroup;
367
                }
368
                else {
369
                    self::$group_id = $update->message->chat->id;
370
                    self::$group = self::read($category . '/' . $chat_id);
371
                    self::$old_group = clone self::$group;
372
                }
373
                self::$group_ids = self::read($category . '/' . $chat_id . '/users');
374
                self::$old_group_ids = clone self::$group_ids;
375
            }
376
377
            if (in_array(self::$user_id,self::$group_ids)) {
378
                self::$group_user = self::read($category . '/' . $chat_id . '/' . self::$user_id);
379
                self::$group_user_id = self::$user_id;
380
                self::$old_group_user = clone self::$group_user;
381
            }
382
383
            self::$user = self::read($category.'/'.self::$user_id);
384
            self::$old_user = clone self::$user;
385
            if (!empty(self::$user)) self::$user->last_active = time();
386
        }
387
    }
388
389
    private static function processInlineQuery(inlineQuery $update): void {
390
        $type = $update->chat_type;
391
        if ($type === chatType::PRIVATE || $type === chatType::SENDER) {
392
            $category = chatType::PRIVATE . 's';
393
            self::$user_id = $update->from->id;
394
            if (in_array(self::$user_id,self::$ids[$category])) {
395
                self::$user = self::read($category . '/' . self::$user_id);
396
                self::$old_user = clone self::$user;
397
                self::$user->last_active = time();
398
            }
399
        }
400
    }
401
402
    private static function processChatMember(chatMemberUpdated $update): void {
403
        $type = $update->chat->type;
404
405
        $category = $type . 's';
406
        if ($type === chatType::CHANNEL) {
407
            self::$channel_id = $update->chat->id;
408
            if (in_array(self::$channel_id,self::$ids[$category])) {
409
                self::$channel = self::read($category . '/' . self::$channel_id);
410
                self::$old_channel = clone self::$channel;
411
            }
412
            else {
413
                self::$ids[$category][] = self::$channel_id;
414
                self::$channel = (object) self::$channel_default_data;
415
            }
416
        }
417
        else {
418
            $chat_id = $update->chat->id;
419
            $by_id = $update->from->id;
420
            $old_user = $update->old_chat_member;
421
            $new_user = $update->new_chat_member;
422
            $user_id = $old_user->user->id;
423
            $invite_link = $update->invite_link;
424
425
426
            if ($type === chatType::SUPERGROUP) {
427
                self::$supergroup_id = $chat_id;
428
                if (in_array($chat_id,self::$ids[$category])) {
429
                    self::$supergroup = self::read($category . '/' . $chat_id);
430
                    self::$old_supergroup = clone self::$supergroup;
431
                    self::$group_ids = self::read($category . '/' . $chat_id . '/users');
432
                    self::$old_group_ids = clone self::$group_ids;
433
                }
434
                else {
435
                    self::$ids[$category][] = $chat_id;
436
                    self::$supergroup = (object) self::$supergroup_default_data;
437
                    self::$group_ids = [];
438
                }
439
            }
440
            elseif ($type === chatType::GROUP) {
441
                self::$group_id = $chat_id;
442
                if (in_array($chat_id,self::$ids[$category])) {
443
                    self::$group = self::read($category . '/' . $chat_id);
444
                    self::$old_group = clone self::$group;
445
                    self::$group_ids = self::read($category . '/' . $chat_id . '/users');
446
                    self::$old_group_ids = clone self::$group_ids;
447
                }
448
                else {
449
                    self::$ids[$category][] = $chat_id;
450
                    self::$group = (object) self::$group_default_data;
451
                    self::$group_ids = [];
452
                }
453
            }
454
455
            if (!in_array($user_id,self::$group_ids)) {
456
                self::$group_ids[] = $user_id;
457
                self::$group_user = (object) self::$group_user_default_data;
458
            }
459
            else {
460
                self::$group_user_id = $by_id == $user_id ? $user_id : $by_id;
461
                self::$group_user = self::read($category . '/' . $chat_id . '/' . self::$group_user_id);
462
            }
463
464
            if ($new_user->status === chatMemberStatus::LEFT || $new_user->status === chatMemberStatus::KICKED) {
465
                if ($old_user->status !== chatMemberStatus::LEFT && $old_user->status !== chatMemberStatus::KICKED) {
466
                    self::$group_user->presence = false;
467
                    self::$group_user->removed = $new_user->status === chatMemberStatus::KICKED;
468
                    if ($new_user->status === chatMemberStatus::KICKED) {
469
                        self::$group_user->removed_by = $by_id;
470
                    }
471
                }
472
            }
473
            elseif ($old_user->status === chatMemberStatus::LEFT || $old_user->status === chatMemberStatus::KICKED) {
474
                self::$group_user->presence = true;
475
                self::$group_user->removed = false;
476
                self::$group_user->removed_by = null;
477
                self::$group_user->invite_link = !empty($invite_link) ? $invite_link->invite_link : null;
478
                if ($by_id !== $user_id) {
479
                    if (!empty($invite_link)) {
480
                        self::$group_user->accepted_by = $by_id;
481
                        self::$group_user->invited_by = null;
482
                    }
483
                    else {
484
                        self::$group_user->invited_by = $by_id;
485
                        self::$group_user->accepted_by = null;
486
                    }
487
                }
488
            }
489
        }
490
    }
491
492
    /**
493
     * delete user completely from database
494
     *
495
     * @param null|int $user_id
496
     *
497
     * @return bool
498
     * @throws bptException
499
     */
500
    public static function deleteUser (int $user_id = null): bool {
501
        if (empty($user_id)) $user_id = telegram::catchFields(fields::USER_ID);
502
        if (!file_exists(realpath(self::$folder . '/privates/' . $user_id . '.json'))) {
503
            return false;
504
        }
505
        unset(self::$ids['privates'][array_search($user_id, self::$ids['privates'])]);
506
        sort(self::$ids['privates']);
507
        if ($user_id === self::$user_id) {
508
            self::$user = self::$old_user = null;
509
        }
510
        return tools::delete(self::$folder . '/privates/' . $user_id . '.json');
511
    }
512
513
    /**
514
     * delete group and its user from database
515
     *
516
     * @param null|int $group_id
517
     *
518
     * @return bool
519
     * @throws bptException
520
     */
521
    public static function deleteGroup (int $group_id = null): bool {
522
        if (empty($group_id)) $group_id = telegram::catchFields(fields::CHAT_ID);
523
        if (!file_exists(realpath(self::$folder . '/groups/' . $group_id . '.json'))) {
524
            return false;
525
        }
526
        unset(self::$ids['groups'][array_search($group_id, self::$ids['groups'])]);
527
        sort(self::$ids['groups']);
528
        tools::delete(self::$folder . '/groups/' . $group_id);
529
        if ($group_id === self::$group_id) {
530
            self::$group = self::$old_group = null;
531
        }
532
        return tools::delete(self::$folder . '/groups/' . $group_id . '.json');
533
    }
534
535
    /**
536
     * delete supergroup and its user from database
537
     *
538
     * @param null|int $group_id
539
     *
540
     * @return bool
541
     * @throws bptException
542
     */
543
    public static function deleteSuperGroup (int $group_id = null): bool {
544
        if (empty($group_id)) $group_id = telegram::catchFields(fields::CHAT_ID);
545
        if (!file_exists(realpath(self::$folder . '/supergroups/' . $group_id . '.json'))) {
546
            return false;
547
        }
548
        unset(self::$ids['supergroups'][array_search($group_id, self::$ids['supergroups'])]);
549
        sort(self::$ids['supergroups']);
550
        tools::delete(self::$folder . '/supergroups/' . $group_id);
551
        if ($group_id === self::$supergroup_id) {
552
            self::$supergroup = self::$old_supergroup = null;
553
        }
554
        return tools::delete(self::$folder . '/supergroups/' . $group_id . '.json');
555
    }
556
557
    /**
558
     * delete channel from database
559
     *
560
     * @param null|int $channel_id
561
     *
562
     * @return bool
563
     * @throws bptException
564
     */
565
    public static function deleteChannel (int $channel_id = null): bool {
566
        if (empty($channel_id)) $channel_id = telegram::catchFields(fields::CHAT_ID);
567
        if (!file_exists(realpath(self::$folder . '/channels/' . $channel_id . '.json'))) {
568
            return false;
569
        }
570
        unset(self::$ids['channels'][array_search($channel_id, self::$ids['channels'])]);
571
        sort(self::$ids['channels']);
572
        if ($channel_id === self::$channel_id) {
573
            self::$channel = self::$old_channel = null;
574
        }
575
        return tools::delete(self::$folder . '/channels/' . $channel_id . '.json');
576
    }
577
578
    /**
579
     * get users list
580
     *
581
     * @return int[]
582
     */
583
    public static function getUsers (): array {
584
        return self::$ids['privates'] ?? [];
585
    }
586
587
    /**
588
     * get groups list
589
     *
590
     * @return int[]
591
     */
592
    public static function getGroups (): array {
593
        return self::$ids['groups'] ?? [];
594
    }
595
596
    /**
597
     * get supergroups list
598
     *
599
     * @return int[]
600
     */
601
    public static function getSuperGroups (): array {
602
        return self::$ids['supergroups'] ?? [];
603
    }
604
605
    /**
606
     * get channels list
607
     *
608
     * @return int[]
609
     */
610
    public static function getChannels (): array {
611
        return self::$ids['channels'] ?? [];
612
    }
613
}
614