Passed
Branch main (01a6e7)
by Miaad
01:27
created

tools.php (2 issues)

1
<?php
2
3
namespace BPT;
4
5
use BPT\api\telegram;
6
use BPT\constants\parseMode;
7
8
class tools {
9
    /**
10
     * Check the given username format
11
     *
12
     * e.g. => tools::isUsername('BPT_CH');
13
     *
14
     * e.g. => tools::isUsername(username: 'BPT_CH');
15
     *
16
     * @param string $username Your text to be check is username or not e.g. : 'BPT_CH' | '@BPT_CH'
17
     * @return bool
18
     */
19
    public static function isUsername(string $username): bool {
20
        $length = strlen($username);
21
        return strpos($username, '__') === false && $length >= 5 && $length <= 33 && preg_match('/^@?([a-zA-Z])(\w{4,31})$/', $username);
22
    }
23
24
    /**
25
     * Check given IP is in the given IP range or not
26
     *
27
     * e.g. => tools::ipInRange('192.168.1.1','149.154.160.0/20');
28
     *
29
     * e.g. => tools::ipInRange(ip: '192.168.1.1',range: '149.154.160.0/20');
30
     *
31
     * @param string $ip Your ip
32
     * @param string $range Your range ip for check , if you didn't specify the block , it will be 32
33
     * @return bool
34
     */
35
    public static function ipInRange (string $ip, string $range): bool {
36
        if (!str_contains($range, '/')) {
37
            $range .= '/32';
38
        }
39
        $range_full = explode('/', $range, 2);
40
        $netmask_decimal = ~(pow(2, (32 - $range_full[1])) - 1);
41
        return (ip2long($ip) & $netmask_decimal) == (ip2long($range_full[0]) & $netmask_decimal);
42
    }
43
44
    /**
45
     * Check the given IP is from telegram or not
46
     *
47
     * e.g. => tools::isTelegram('192.168.1.1');
48
     *
49
     * e.g. => tools::isTelegram(ip: '192.168.1.1');
50
     *
51
     * @param string $ip     Your ip to be check is telegram or not e.g. '192.168.1.1'
52
     * @return bool
53
     */
54
    public static function isTelegram (string $ip): bool {
55
        return self::ipInRange($ip, '149.154.160.0/20') || self::ipInRange($ip, '91.108.4.0/22');
56
    }
57
58
    /**
59
     * Check the given IP is from CloudFlare or not
60
     *
61
     * e.g. => tools::isCloudFlare('192.168.1.1');
62
     *
63
     * e.g. =>tools::isCloudFlare(ip: '192.168.1.1');
64
     *
65
     * @param string $ip Your ip to be check is CloudFlare or not e.g. '192.168.1.1'
66
     * @return bool
67
     */
68
    public static function isCloudFlare (string $ip): bool {
69
        $cf_ips = ['173.245.48.0/20', '103.21.244.0/22', '103.22.200.0/22', '103.31.4.0/22', '141.101.64.0/18', '108.162.192.0/18', '190.93.240.0/20', '188.114.96.0/20', '197.234.240.0/22', '198.41.128.0/17', '162.158.0.0/15', '104.16.0.0/12', '172.64.0.0/13', '131.0.72.0/22'];
70
        foreach ($cf_ips as $cf_ip) {
71
            if (self::ipInRange($ip,$cf_ip)) {
72
                return true;
73
            }
74
        }
75
        return false;
76
    }
77
78
    /**
79
     * Check the given token format
80
     *
81
     * if you want to verify token with telegram , you should set verify parameter => true
82
     *
83
     * in that case , if token was right , you will receive getMe result , otherwise you will receive false
84
     *
85
     * verify parameter has default value => false
86
     *
87
     * e.g. => tools::isToken('123123123:abcabcabcabc');
88
     * @param string $token your token e.g. => '123123123:abcabcabcabc'
89
     * @param bool $verify check token with telegram or not
90
     * @return bool|array return array when verify is active and token is true array of telegram getMe result
91
     */
92
    public static function isToken (string $token, bool $verify = false): bool|array {
93
        if (preg_match('/^(\d{8,10}):[\w\-]{35}$/', $token)) {
94
            if ($verify){
95
                $res = telegram::me($token);
96
                if ($res['ok']) {
97
                    return $res['result'];
98
                }
99
                return false;
100
            }
101
            return true;
102
        }
103
        return false;
104
    }
105
106
    /**
107
     * Generate random string
108
     *
109
     * you can use this method without any input
110
     *
111
     * length parameter have default value => 16
112
     *
113
     * characters parameter have default value => aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ
114
     *
115
     * e.g. => tools::randomString();
116
     *
117
     * e.g. => tools::randomString(16,'abcdefg');
118
     *
119
     * e.g. => tools::randomString(length: 16,characters: 'abcdefg');
120
     *
121
     * @param int $length e.g. => 16
122
     * @param string $characters e.g. => 'abcdefg'
123
     * @return string
124
     */
125
    public static function randomString (int $length = 16, string $characters = 'aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ'): string {
126
        $rand_string = '';
127
        $char_len = strlen($characters) - 1;
128
        for ($i = 0; $i < $length; $i ++) {
129
            $rand_string .= $characters[rand(0, $char_len)];
130
        }
131
        return $rand_string;
132
    }
133
134
    /**
135
     * Escape text for different parse_modes
136
     *
137
     * type parameter can be : `MarkdownV2` , `Markdown` , `HTML` , default : `parseMode::HTML`(`HTML`)
138
     *
139
     * e.g. => tools::modeEscape('hello men! *I* Have nothing anymore');
140
     *
141
     * e.g. => tools::modeEscape(text: 'hello men! *I* Have nothing anymore');
142
     *
143
     * @param string $text Your text e.g. => 'hello men! *I* Have nothing anymore'
144
     * @param string $mode Your selected mode e.g. => `parseMode::HTML` | `HTML`
145
     * @return string|false return false when mode is incorrect
146
     */
147
    public static function modeEscape (string $text, string $mode = parseMode::HTML): string|false {
148
        return match ($mode) {
149
            parseMode::HTML => str_replace(['&', '<', '>',], ["&amp;", "&lt;", "&gt;",], $text),
150
            parseMode::MARKDOWN => str_replace(['\\', '_', '*', '`', '['], ['\\\\', '\_', '\*', '\`', '\[',], $text),
151
            parseMode::MARKDOWNV2 => str_replace(
152
                ['_', '*', '[', ']', '(', ')', '~', '`', '>', '#', '+', '-', '=', '|', '{', '}', '.', '!', '\\'],
153
                ['\_', '\*', '\[', '\]', '\(', '\)', '\~', '\`', '\>', '\#', '\+', '\-', '\=', '\|', '\{', '\}', '\.', '\!', '\\\\'],
154
                $text),
155
            default => false
156
        };
157
    }
158
159
    /**
160
     * Convert byte to symbolic size like 2.98 MB
161
     *
162
     * Supp
163
     *
164
     * You could set `precision` to configure decimals after number(2 for 2.98 and 3 for 2.987)
165
     *
166
     * `precision` parameter have default value => 2
167
     *
168
     * e.g. => tools::byteFormat(123456789);
169
     *
170
     * e.g. => tools::byteFormat(byte: 123456789);
171
     *
172
     * @param int $byte e.g. => 29123452912
173
     * @param int $precision e.g. => 2
174
     * @return string
175
     */
176
    public static function byteFormat (int $byte, int $precision = 2): string {
177
        $rate_counter = 0;
178
179
        while ($byte > 1024){
180
            $byte /= 1024;
181
            $rate_counter++;
182
        }
183
184
        if ($rate_counter !== 0) {
185
            $byte = round($byte, $precision);
186
        }
187
188
        return $byte . ' ' . ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB'][$rate_counter];
189
    }
190
191
    /**
192
     * receive size from path(can be url or file path)
193
     *
194
     * if format parameter has true value , the returned size converted to symbolic format
195
     *
196
     * format parameter have default value => true
197
     *
198
     * NOTE : some url will not return real size!
199
     *
200
     * e.g. => tools::size('xFile.zip');
201
     *
202
     * e.g. => tools::size(path: 'xFile.zip');
203
     *
204
     * @param string $path e.g. => 'xFile.zip'
205
     * @param bool $format if you set this true , you will receive symbolic string like 2.76MB
206
     * @return string|int|false string for formatted data , int for normal data , false when size can not be found(file not found or ...)
207
     */
208
    public static function size (string $path, bool $format = true): string|int|false {
209
        if (filter_var($path, FILTER_VALIDATE_URL)) {
210
            $ch = curl_init($path);
211
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
212
            curl_setopt($ch, CURLOPT_HEADER, true);
213
            curl_setopt($ch, CURLOPT_NOBODY, true);
214
            curl_exec($ch);
215
            $size = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
216
            curl_close($ch);
217
        }
218
        else {
219
            $size = file_exists($path) ? filesize($path) : false;
220
        }
221
222
        if (isset($size) && is_numeric($size)) {
223
            return $format ? tools::rateConverter($size) : $size;
224
        }
225
        else return false;
226
    }
227
228
    public static function error2trace (\Throwable $error,$seen = null): string {
229
        $starter = $seen ? 'Caused by: ' : '';
0 ignored issues
show
The assignment to $starter is dead and can be removed.
Loading history...
230
        $result = [];
231
        if (!$seen) $seen = [];
232
        $trace = $error->getTrace();
233
        $prev = $error->getPrevious();
234
        //$result[] = sprintf('%s%s: %s', $starter, get_class($error), $error->getMessage());
235
        $file = $error->getFile();
236
        $line = $error->getLine();
237
238
        while (true){
239
            $current = "$file:$line";
240
            if (is_array($seen) && in_array($current, $seen)) {
241
                $result[] = sprintf(' ... %d more', count($trace) + 1);
242
                break;
243
            }
244
            $result[] = sprintf(' at %s%s%s(%s%s%s)',
245
                count($trace) && array_key_exists('class', $trace[0]) ? $trace[0]['class'] : '',
246
                count($trace) && array_key_exists('class', $trace[0]) && array_key_exists('function', $trace[0]) ? (isset($trace[0]['type']) ? $trace[0]['type'] : '.') : '',
247
                count($trace) && array_key_exists('function', $trace[0]) ? str_replace('\\', '.', $trace[0]['function']) : '(main)',
248
                $file,
249
                $line === null ? '' : ':',
250
                $line === null ? '' : $line);
251
            if (is_array($seen)) {
252
                $seen[] = "$file:$line";
253
            }
254
            if (!count($trace)) {
255
                break;
256
            }
257
            $file = array_key_exists('file', $trace[0]) ? $trace[0]['file'] : 'Unknown Source';
258
            $line = array_key_exists('file', $trace[0]) && array_key_exists('line', $trace[0]) && $trace[0]['line'] ? $trace[0]['line'] : null;
259
            array_shift($trace);
260
        }
261
262
        $result = join("\n", $result);
263
        if ($prev) {
0 ignored issues
show
$prev is of type Throwable, thus it always evaluated to true.
Loading history...
264
            $result .= "\n" . self::error2trace($prev, $seen);
265
        }
266
        return $result;
267
    }
268
}