GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Issues (910)

framework/helpers/BaseStringHelper.php (4 issues)

1
<?php
2
/**
3
 * @link https://www.yiiframework.com/
4
 * @copyright Copyright (c) 2008 Yii Software LLC
5
 * @license https://www.yiiframework.com/license/
6
 */
7
8
namespace yii\helpers;
9
10
use Yii;
11
12
/**
13
 * BaseStringHelper provides concrete implementation for [[StringHelper]].
14
 *
15
 * Do not use BaseStringHelper. Use [[StringHelper]] instead.
16
 *
17
 * @author Qiang Xue <[email protected]>
18
 * @author Alex Makarov <[email protected]>
19
 * @since 2.0
20
 */
21
class BaseStringHelper
22
{
23
    /**
24
     * Returns the number of bytes in the given string.
25
     * This method ensures the string is treated as a byte array by using `mb_strlen()`.
26
     *
27
     * @param string $string the string being measured for length
28
     * @return int the number of bytes in the given string.
29
     */
30 424
    public static function byteLength($string)
31
    {
32 424
        return mb_strlen((string)$string, '8bit');
33
    }
34
35
    /**
36
     * Returns the portion of string specified by the start and length parameters.
37
     * This method ensures the string is treated as a byte array by using `mb_substr()`.
38
     *
39
     * @param string $string the input string. Must be one character or longer.
40
     * @param int $start the starting position
41
     * @param int|null $length the desired portion length. If not specified or `null`, there will be
42
     * no limit on length i.e. the output will be until the end of the string.
43
     * @return string the extracted part of string, or FALSE on failure or an empty string.
44
     * @see https://www.php.net/manual/en/function.substr.php
45
     */
46 154
    public static function byteSubstr($string, $start, $length = null)
47
    {
48 154
        if ($length === null) {
49 47
            $length = static::byteLength($string);
50
        }
51
52 154
        return mb_substr((string)$string, $start, $length, '8bit');
53
    }
54
55
    /**
56
     * Returns the trailing name component of a path.
57
     * This method is similar to the php function `basename()` except that it will
58
     * treat both \ and / as directory separators, independent of the operating system.
59
     * This method was mainly created to work on php namespaces. When working with real
60
     * file paths, php's `basename()` should work fine for you.
61
     * Note: this method is not aware of the actual filesystem, or path components such as "..".
62
     *
63
     * @param string $path A path string.
64
     * @param string $suffix If the name component ends in suffix this will also be cut off.
65
     * @return string the trailing name component of the given path.
66
     * @see https://www.php.net/manual/en/function.basename.php
67
     */
68 23
    public static function basename($path, $suffix = '')
69
    {
70 23
        $path = (string)$path;
71
72 23
        $len = mb_strlen($suffix);
73 23
        if ($len > 0 && mb_substr($path, -$len) === $suffix) {
74 1
            $path = mb_substr($path, 0, -$len);
75
        }
76
77 23
        $path = rtrim(str_replace('\\', '/', $path), '/');
78 23
        $pos = mb_strrpos($path, '/');
79 23
        if ($pos !== false) {
80 23
            return mb_substr($path, $pos + 1);
81
        }
82
83 1
        return $path;
84
    }
85
86
    /**
87
     * Returns parent directory's path.
88
     * This method is similar to `dirname()` except that it will treat
89
     * both \ and / as directory separators, independent of the operating system.
90
     *
91
     * @param string $path A path string.
92
     * @return string the parent directory's path.
93
     * @see https://www.php.net/manual/en/function.basename.php
94
     */
95 11
    public static function dirname($path)
96
    {
97 11
        $normalizedPath = rtrim(
98 11
            str_replace('\\', '/', (string)$path),
99 11
            '/'
100 11
        );
101 11
        $separatorPosition = mb_strrpos($normalizedPath, '/');
102
103 11
        if ($separatorPosition !== false) {
104 9
            return mb_substr($path, 0, $separatorPosition);
105
        }
106
107 2
        return '';
108
    }
109
110
    /**
111
     * Truncates a string to the number of characters specified.
112
     *
113
     * In order to truncate for an exact length, the $suffix char length must be counted towards the $length. For example
114
     * to have a string which is exactly 255 long with $suffix `...` of 3 chars, then `StringHelper::truncate($string, 252, '...')`
115
     * must be used to ensure you have 255 long string afterwards.
116
     *
117
     * @param string $string The string to truncate.
118
     * @param int $length How many characters from original string to include into truncated string.
119
     * @param string $suffix String to append to the end of truncated string.
120
     * @param string|null $encoding The charset to use, defaults to charset currently used by application.
121
     * @param bool $asHtml Whether to treat the string being truncated as HTML and preserve proper HTML tags.
122
     * This parameter is available since version 2.0.1.
123
     * @return string the truncated string.
124
     */
125 1
    public static function truncate($string, $length, $suffix = '...', $encoding = null, $asHtml = false)
126
    {
127 1
        $string = (string)$string;
128
129 1
        if ($encoding === null) {
130 1
            $encoding = Yii::$app ? Yii::$app->charset : 'UTF-8';
131
        }
132 1
        if ($asHtml) {
133 1
            return static::truncateHtml($string, $length, $suffix, $encoding);
134
        }
135
136 1
        if (mb_strlen($string, $encoding) > $length) {
137 1
            return rtrim(mb_substr($string, 0, $length, $encoding)) . $suffix;
138
        }
139
140 1
        return $string;
141
    }
142
143
    /**
144
     * Truncates a string to the number of words specified.
145
     *
146
     * @param string $string The string to truncate.
147
     * @param int $count How many words from original string to include into truncated string.
148
     * @param string $suffix String to append to the end of truncated string.
149
     * @param bool $asHtml Whether to treat the string being truncated as HTML and preserve proper HTML tags.
150
     * This parameter is available since version 2.0.1.
151
     * @return string the truncated string.
152
     */
153 1
    public static function truncateWords($string, $count, $suffix = '...', $asHtml = false)
154
    {
155 1
        if ($asHtml) {
156 1
            return static::truncateHtml($string, $count, $suffix);
157
        }
158
159 1
        $words = preg_split('/(\s+)/u', trim($string), 0, PREG_SPLIT_DELIM_CAPTURE);
160 1
        if (count($words) / 2 > $count) {
161 1
            return implode('', array_slice($words, 0, ($count * 2) - 1)) . $suffix;
162
        }
163
164 1
        return $string;
165
    }
166
167
    /**
168
     * Truncate a string while preserving the HTML.
169
     *
170
     * @param string $string The string to truncate
171
     * @param int $count The counter
172
     * @param string $suffix String to append to the end of the truncated string.
173
     * @param string|bool $encoding Encoding flag or charset.
174
     * @return string
175
     * @since 2.0.1
176
     */
177 2
    protected static function truncateHtml($string, $count, $suffix, $encoding = false)
178
    {
179 2
        $config = \HTMLPurifier_Config::create(null);
180 2
        if (Yii::$app !== null) {
181
            $config->set('Cache.SerializerPath', Yii::$app->getRuntimePath());
182
        }
183 2
        $lexer = \HTMLPurifier_Lexer::create($config);
184 2
        $tokens = $lexer->tokenizeHTML($string, $config, new \HTMLPurifier_Context());
185 2
        $openTokens = [];
186 2
        $totalCount = 0;
187 2
        $depth = 0;
188 2
        $truncated = [];
189 2
        foreach ($tokens as $token) {
190 2
            if ($token instanceof \HTMLPurifier_Token_Start) { //Tag begins
191 2
                $openTokens[$depth] = $token->name;
192 2
                $truncated[] = $token;
193 2
                ++$depth;
194 2
            } elseif ($token instanceof \HTMLPurifier_Token_Text && $totalCount <= $count) { //Text
195 2
                if (false === $encoding) {
196 1
                    preg_match('/^(\s*)/um', $token->data, $prefixSpace) ?: $prefixSpace = ['', ''];
197 1
                    $token->data = $prefixSpace[1] . self::truncateWords(ltrim($token->data), $count - $totalCount, '');
198 1
                    $currentCount = self::countWords($token->data);
199
                } else {
200 1
                    $token->data = self::truncate($token->data, $count - $totalCount, '', $encoding);
0 ignored issues
show
It seems like $encoding can also be of type true; however, parameter $encoding of yii\helpers\BaseStringHelper::truncate() does only seem to accept null|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

200
                    $token->data = self::truncate($token->data, $count - $totalCount, '', /** @scrutinizer ignore-type */ $encoding);
Loading history...
201 1
                    $currentCount = mb_strlen($token->data, $encoding);
0 ignored issues
show
It seems like $encoding can also be of type true; however, parameter $encoding of mb_strlen() does only seem to accept null|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

201
                    $currentCount = mb_strlen($token->data, /** @scrutinizer ignore-type */ $encoding);
Loading history...
202
                }
203 2
                $totalCount += $currentCount;
204 2
                $truncated[] = $token;
205 2
            } elseif ($token instanceof \HTMLPurifier_Token_End) { //Tag ends
206 2
                if ($token->name === $openTokens[$depth - 1]) {
207 2
                    --$depth;
208 2
                    unset($openTokens[$depth]);
209 2
                    $truncated[] = $token;
210
                }
211 2
            } elseif ($token instanceof \HTMLPurifier_Token_Empty) { //Self contained tags, i.e. <img/> etc.
212 2
                $truncated[] = $token;
213
            }
214 2
            if ($totalCount >= $count) {
215 2
                if (0 < count($openTokens)) {
216 2
                    krsort($openTokens);
217 2
                    foreach ($openTokens as $name) {
218 2
                        $truncated[] = new \HTMLPurifier_Token_End($name);
219
                    }
220
                }
221 2
                break;
222
            }
223
        }
224 2
        $context = new \HTMLPurifier_Context();
225 2
        $generator = new \HTMLPurifier_Generator($config, $context);
226 2
        return $generator->generateFromTokens($truncated) . ($totalCount >= $count ? $suffix : '');
227
    }
228
229
    /**
230
     * Check if given string starts with specified substring. Binary and multibyte safe.
231
     *
232
     * @param string $string Input string
233
     * @param string $with Part to search inside the $string
234
     * @param bool $caseSensitive Case sensitive search. Default is true. When case sensitive is enabled, `$with` must
235
     * exactly match the starting of the string in order to get a true value.
236
     * @return bool Returns true if first input starts with second input, false otherwise
237
     */
238 20
    public static function startsWith($string, $with, $caseSensitive = true)
239
    {
240 20
        $string = (string)$string;
241 20
        $with = (string)$with;
242
243 20
        if (!$bytes = static::byteLength($with)) {
244 3
            return true;
245
        }
246 17
        if ($caseSensitive) {
247 16
            return strncmp($string, $with, $bytes) === 0;
248
        }
249
250 15
        $encoding = Yii::$app ? Yii::$app->charset : 'UTF-8';
251 15
        $string = static::byteSubstr($string, 0, $bytes);
252
253 15
        return mb_strtolower($string, $encoding) === mb_strtolower($with, $encoding);
254
    }
255
256
    /**
257
     * Check if given string ends with specified substring. Binary and multibyte safe.
258
     *
259
     * @param string $string Input string to check
260
     * @param string $with Part to search inside of the `$string`.
261
     * @param bool $caseSensitive Case sensitive search. Default is true. When case sensitive is enabled, `$with` must
262
     * exactly match the ending of the string in order to get a true value.
263
     * @return bool Returns true if first input ends with second input, false otherwise
264
     */
265 30
    public static function endsWith($string, $with, $caseSensitive = true)
266
    {
267 30
        $string = (string)$string;
268 30
        $with = (string)$with;
269
270 30
        if (!$bytes = static::byteLength($with)) {
271 3
            return true;
272
        }
273 27
        if ($caseSensitive) {
274
            // Warning check, see https://php.net/substr-compare#refsect1-function.substr-compare-returnvalues
275 16
            if (static::byteLength($string) < $bytes) {
276 3
                return false;
277
            }
278
279 13
            return substr_compare($string, $with, -$bytes, $bytes) === 0;
280
        }
281
282 25
        $encoding = Yii::$app ? Yii::$app->charset : 'UTF-8';
283 25
        $string = static::byteSubstr($string, -$bytes);
284
285 25
        return mb_strtolower($string, $encoding) === mb_strtolower($with, $encoding);
286
    }
287
288
    /**
289
     * Explodes string into array, optionally trims values and skips empty ones.
290
     *
291
     * @param string $string String to be exploded.
292
     * @param string $delimiter Delimiter. Default is ','.
293
     * @param mixed $trim Whether to trim each element. Can be:
294
     *   - boolean - to trim normally;
295
     *   - string - custom characters to trim. Will be passed as a second argument to `trim()` function.
296
     *   - callable - will be called for each value instead of trim. Takes the only argument - value.
297
     * @param bool $skipEmpty Whether to skip empty strings between delimiters. Default is false.
298
     * @return array
299
     * @since 2.0.4
300
     */
301 1
    public static function explode($string, $delimiter = ',', $trim = true, $skipEmpty = false)
302
    {
303 1
        $result = explode($delimiter, $string);
304 1
        if ($trim !== false) {
305 1
            if ($trim === true) {
306 1
                $trim = 'trim';
307 1
            } elseif (!is_callable($trim)) {
308 1
                $trim = function ($v) use ($trim) {
309 1
                    return trim($v, $trim);
310 1
                };
311
            }
312 1
            $result = array_map($trim, $result);
313
        }
314 1
        if ($skipEmpty) {
315
            // Wrapped with array_values to make array keys sequential after empty values removing
316 1
            $result = array_values(array_filter($result, function ($value) {
317 1
                return $value !== '';
318 1
            }));
319
        }
320
321 1
        return $result;
322
    }
323
324
    /**
325
     * Counts words in a string.
326
     *
327
     * @param string $string the text to calculate
328
     * @return int
329
     * @since 2.0.8
330
     */
331 2
    public static function countWords($string)
332
    {
333 2
        return count(preg_split('/\s+/u', $string, 0, PREG_SPLIT_NO_EMPTY));
334
    }
335
336
    /**
337
     * Returns string representation of number value with replaced commas to dots, if decimal point
338
     * of current locale is comma.
339
     *
340
     * @param int|float|string $value the value to normalize.
341
     * @return string
342
     * @since 2.0.11
343
     */
344 34
    public static function normalizeNumber($value)
345
    {
346 34
        $value = (string) $value;
347
348 34
        $localeInfo = localeconv();
349 34
        $decimalSeparator = isset($localeInfo['decimal_point']) ? $localeInfo['decimal_point'] : null;
350
351 34
        if ($decimalSeparator !== null && $decimalSeparator !== '.') {
352 4
            $value = str_replace($decimalSeparator, '.', $value);
353
        }
354
355 34
        return $value;
356
    }
357
358
    /**
359
     * Encodes string into "Base 64 Encoding with URL and Filename Safe Alphabet" (RFC 4648).
360
     *
361
     * > Note: Base 64 padding `=` may be at the end of the returned string.
362
     * > `=` is not transparent to URL encoding.
363
     *
364
     * @param string $input the string to encode.
365
     * @return string encoded string.
366
     * @see https://tools.ietf.org/html/rfc4648#page-7
367
     * @since 2.0.12
368
     */
369 112
    public static function base64UrlEncode($input)
370
    {
371 112
        return strtr(base64_encode($input), '+/', '-_');
372
    }
373
374
    /**
375
     * Decodes "Base 64 Encoding with URL and Filename Safe Alphabet" (RFC 4648).
376
     *
377
     * @param string $input encoded string.
378
     * @return string decoded string.
379
     * @see https://tools.ietf.org/html/rfc4648#page-7
380
     * @since 2.0.12
381
     */
382 13
    public static function base64UrlDecode($input)
383
    {
384 13
        return base64_decode(strtr($input, '-_', '+/'));
385
    }
386
387
    /**
388
     * Safely casts a float to string independent of the current locale.
389
     * The decimal separator will always be `.`.
390
     *
391
     * @param float|int $number a floating point number or integer.
392
     * @return string the string representation of the number.
393
     * @since 2.0.13
394
     */
395 10
    public static function floatToString($number)
396
    {
397
        // . and , are the only decimal separators known in ICU data,
398
        // so its safe to call str_replace here
399 10
        return str_replace(',', '.', (string) $number);
400
    }
401
402
    /**
403
     * Checks if the passed string would match the given shell wildcard pattern.
404
     * This function emulates [[fnmatch()]], which may be unavailable at certain environment, using PCRE.
405
     *
406
     * @param string $pattern the shell wildcard pattern.
407
     * @param string $string the tested string.
408
     * @param array $options options for matching. Valid options are:
409
     *
410
     * - caseSensitive: bool, whether pattern should be case sensitive. Defaults to `true`.
411
     * - escape: bool, whether backslash escaping is enabled. Defaults to `true`.
412
     * - filePath: bool, whether slashes in string only matches slashes in the given pattern. Defaults to `false`.
413
     *
414
     * @return bool whether the string matches pattern or not.
415
     * @since 2.0.14
416
     */
417 244
    public static function matchWildcard($pattern, $string, $options = [])
418
    {
419 244
        if ($pattern === '*' && empty($options['filePath'])) {
420 5
            return true;
421
        }
422
423 240
        $replacements = [
424 240
            '\\\\\\\\' => '\\\\',
425 240
            '\\\\\\*' => '[*]',
426 240
            '\\\\\\?' => '[?]',
427 240
            '\*' => '.*',
428 240
            '\?' => '.',
429 240
            '\[\!' => '[^',
430 240
            '\[' => '[',
431 240
            '\]' => ']',
432 240
            '\-' => '-',
433 240
        ];
434
435 240
        if (isset($options['escape']) && !$options['escape']) {
436 9
            unset($replacements['\\\\\\\\']);
437 9
            unset($replacements['\\\\\\*']);
438 9
            unset($replacements['\\\\\\?']);
439
        }
440
441 240
        if (!empty($options['filePath'])) {
442 12
            $replacements['\*'] = '[^/\\\\]*';
443 12
            $replacements['\?'] = '[^/\\\\]';
444
        }
445
446 240
        $pattern = strtr(preg_quote($pattern, '#'), $replacements);
447 240
        $pattern = '#^' . $pattern . '$#us';
448
449 240
        if (isset($options['caseSensitive']) && !$options['caseSensitive']) {
450 2
            $pattern .= 'i';
451
        }
452
453 240
        return preg_match($pattern, (string)$string) === 1;
454
    }
455
456
    /**
457
     * This method provides a unicode-safe implementation of built-in PHP function `ucfirst()`.
458
     *
459
     * @param string $string the string to be proceeded
460
     * @param string $encoding Optional, defaults to "UTF-8"
461
     * @return string
462
     * @see https://www.php.net/manual/en/function.ucfirst.php
463
     * @since 2.0.16
464
     * @phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
465
     */
466 229
    public static function mb_ucfirst($string, $encoding = 'UTF-8')
467
    {
468 229
        $firstChar = mb_substr((string)$string, 0, 1, $encoding);
469 229
        $rest = mb_substr((string)$string, 1, null, $encoding);
470
471 229
        return mb_strtoupper($firstChar, $encoding) . $rest;
472
    }
473
474
    /**
475
     * This method provides a unicode-safe implementation of built-in PHP function `ucwords()`.
476
     *
477
     * @param string $string the string to be proceeded
478
     * @param string $encoding Optional, defaults to "UTF-8"
479
     * @return string
480
     * @see https://www.php.net/manual/en/function.ucwords
481
     * @since 2.0.16
482
     * @phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
483
     */
484 226
    public static function mb_ucwords($string, $encoding = 'UTF-8')
485
    {
486 226
        $string = (string) $string;
487 226
        if (empty($string)) {
488 3
            return $string;
489
        }
490
491 223
        $parts = preg_split('/(\s+\W+\s+|^\W+\s+|\s+)/u', $string, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
492 223
        $ucfirstEven = trim(mb_substr($parts[0], -1, 1, $encoding)) === '';
493 223
        foreach ($parts as $key => $value) {
494 223
            $isEven = (bool)($key % 2);
495 223
            if ($ucfirstEven === $isEven) {
496 223
                $parts[$key] = static::mb_ucfirst($value, $encoding);
497
            }
498
        }
499
500 223
        return implode('', $parts);
501
    }
502
503
    /**
504
     * Masks a portion of a string with a repeated character.
505
     * This method is multibyte-safe.
506
     *
507
     * @param string $string The input string.
508
     * @param int $start The starting position from where to begin masking.
509
     * This can be a positive or negative integer.
510
     * Positive values count from the beginning,
511
     * negative values count from the end of the string.
512
     * @param int $length The length of the section to be masked.
513
     * The masking will start from the $start position
514
     * and continue for $length characters.
515
     * @param string $mask The character to use for masking. The default is '*'.
516
     * @return string The masked string.
517
     */
518 1
    public static function mask($string, $start, $length, $mask = '*')
519
    {
520 1
        $strLength = mb_strlen($string, 'UTF-8');
521
522
        // Return original string if start position is out of bounds
523 1
        if ($start >= $strLength || $start < -$strLength) {
524 1
            return $string;
525
        }
526
527 1
        $masked = mb_substr($string, 0, $start, 'UTF-8');
528 1
        $masked .= str_repeat($mask, abs($length));
0 ignored issues
show
It seems like abs($length) can also be of type double; however, parameter $times of str_repeat() does only seem to accept integer, 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

528
        $masked .= str_repeat($mask, /** @scrutinizer ignore-type */ abs($length));
Loading history...
529 1
        $masked .= mb_substr($string, $start + abs($length), null, 'UTF-8');
0 ignored issues
show
$start + abs($length) of type double is incompatible with the type integer expected by parameter $start of mb_substr(). ( Ignorable by Annotation )

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

529
        $masked .= mb_substr($string, /** @scrutinizer ignore-type */ $start + abs($length), null, 'UTF-8');
Loading history...
530
531 1
        return $masked;
532
    }
533
534
    /**
535
     * Returns the portion of the string that lies between the first occurrence of the start string
536
     * and the last occurrence of the end string after that.
537
     *
538
     * @param string $string The input string.
539
     * @param string $start The string marking the start of the portion to extract.
540
     * @param string $end The string marking the end of the portion to extract.
541
     * @return string|null The portion of the string between the first occurrence of
542
     * start and the last occurrence of end, or null if either start or end cannot be found.
543
     */
544 12
    public static function findBetween($string, $start, $end)
545
    {
546 12
        $startPos = mb_strpos($string, $start);
547
548 12
        if ($startPos === false) {
549 3
            return null;
550
        }
551
552 9
        $startPos += mb_strlen($start);
553 9
        $endPos = mb_strrpos($string, $end, $startPos);
554
555 9
        if ($endPos === false) {
556 2
            return null;
557
        }
558
559 7
        return mb_substr($string, $startPos, $endPos - $startPos);
560
    }
561
}
562