Issues (99)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/support/Tools.php (2 issues)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
namespace Childish\support;
3
4
/**
5
 * Tools
6
 *
7
 * @author    Pu ShaoWei <[email protected]>
8
 * @date      2017/12/12
9
 * @package   Childish\support
10
 * @version   1.0
11
 */
12
class Tools
13
{
14
    /**
15
     * Uncountable word forms.
16
     *
17
     * @var array
18
     */
19
    public static $uncountable = [
20
        'audio',
21
        'bison',
22
        'chassis',
23
        'compensation',
24
        'coreopsis',
25
        'data',
26
        'deer',
27
        'education',
28
        'emoji',
29
        'equipment',
30
        'evidence',
31
        'feedback',
32
        'firmware',
33
        'fish',
34
        'furniture',
35
        'gold',
36
        'hardware',
37
        'information',
38
        'jedi',
39
        'knowledge',
40
        'love',
41
        'metadata',
42
        'money',
43
        'moose',
44
        'news',
45
        'nutrition',
46
        'offspring',
47
        'plankton',
48
        'pokemon',
49
        'police',
50
        'rain',
51
        'rice',
52
        'series',
53
        'sheep',
54
        'software',
55
        'species',
56
        'swine',
57
        'traffic',
58
        'wheat',
59
    ];
60
    /**
61
     * Singular inflector rules.
62
     *
63
     * @var array
64
     */
65
    private static $singular = array (
66
        'rules'       => array (
67
            '/(s)tatuses$/i'                                                          => '\1\2tatus',
68
            '/^(.*)(menu)s$/i'                                                        => '\1\2',
69
            '/(quiz)zes$/i'                                                           => '\\1',
70
            '/(matr)ices$/i'                                                          => '\1ix',
71
            '/(vert|ind)ices$/i'                                                      => '\1ex',
72
            '/^(ox)en/i'                                                              => '\1',
73
            '/(alias)(es)*$/i'                                                        => '\1',
74
            '/(buffal|her|potat|tomat|volcan)oes$/i'                                  => '\1o',
75
            '/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|viri?)i$/i' => '\1us',
76
            '/([ftw]ax)es/i'                                                          => '\1',
77
            '/(analys|ax|cris|test|thes)es$/i'                                        => '\1is',
78
            '/(shoe|slave)s$/i'                                                       => '\1',
79
            '/(o)es$/i'                                                               => '\1',
80
            '/ouses$/'                                                                => 'ouse',
81
            '/([^a])uses$/'                                                           => '\1us',
82
            '/([m|l])ice$/i'                                                          => '\1ouse',
83
            '/(x|ch|ss|sh)es$/i'                                                      => '\1',
84
            '/(m)ovies$/i'                                                            => '\1\2ovie',
85
            '/(s)eries$/i'                                                            => '\1\2eries',
86
            '/([^aeiouy]|qu)ies$/i'                                                   => '\1y',
87
            '/([lr])ves$/i'                                                           => '\1f',
88
            '/(tive)s$/i'                                                             => '\1',
89
            '/(hive)s$/i'                                                             => '\1',
90
            '/(drive)s$/i'                                                            => '\1',
91
            '/(dive)s$/i'                                                             => '\1',
92
            '/([^fo])ves$/i'                                                          => '\1fe',
93
            '/(^analy)ses$/i'                                                         => '\1sis',
94
            '/(analy|diagno|^ba|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i'             => '\1\2sis',
95
            '/([ti])a$/i'                                                             => '\1um',
96
            '/(p)eople$/i'                                                            => '\1\2erson',
97
            '/(m)en$/i'                                                               => '\1an',
98
            '/(c)hildren$/i'                                                          => '\1\2hild',
99
            '/(f)eet$/i'                                                              => '\1oot',
100
            '/(n)ews$/i'                                                              => '\1\2ews',
101
            '/eaus$/'                                                                 => 'eau',
102
            '/^(.*us)$/'                                                              => '\\1',
103
            '/s$/i'                                                                   => '',
104
        ),
105
        'uninflected' => array (
106
            '.*[nrlm]ese',
107
            '.*deer',
108
            '.*fish',
109
            '.*measles',
110
            '.*ois',
111
            '.*pox',
112
            '.*sheep',
113
            '.*ss',
114
            'police',
115
            'pants',
116
            'clothes',
117
        ),
118
        'irregular'   => array (
119
            'caches'   => 'cache',
120
            'criteria' => 'criterion',
121
            'curves'   => 'curve',
122
            'emphases' => 'emphasis',
123
            'foes'     => 'foe',
124
            'hoaxes'   => 'hoax',
125
            'media'    => 'medium',
126
            'neuroses' => 'neurosis',
127
            'waves'    => 'wave',
128
            'oases'    => 'oasis',
129
        )
130
    );
131
132
    /**
133
     * Method cache array.
134
     *
135
     * @var array
136
     */
137
    private static $cache = array ();
138
139
    /**
140
     * Determine whether the given value is array accessible.
141
     *
142
     * @param  mixed $value
143
     * @return bool
144
     */
145
    public static function accessible($value)
146
    {
147
        return is_array($value) || $value instanceof \ArrayAccess;
148
    }
149
150
    /**
151
     * Get all of the given array except for a specified array of keys.
152
     *
153
     * @param  array        $array
154
     * @param  array|string $keys
155
     * @return array
156
     */
157
    public static function except($array, $keys)
158
    {
159
        static::forget($array, $keys);
160
161
        return $array;
162
    }
163
164
    /**
165
     * Determine if the given key exists in the provided array.
166
     *
167
     * @param  \ArrayAccess|array $array
168
     * @param  string|int         $key
169
     * @return bool
170
     */
171
    public static function exists($array, $key)
172
    {
173
        if ($array instanceof \ArrayAccess) {
174
            return $array->offsetExists($key);
175
        }
176
177
        return array_key_exists($key, $array);
178
    }
179
180
    /**
181
     * Return the first element in an array passing a given truth test.
182
     *
183
     * @param  array         $array
184
     * @param  callable|null $callback
185
     * @param  mixed         $default
186
     * @return mixed
187
     */
188
    public static function first($array, callable $callback = null, $default = null)
189
    {
190
        if (is_null($callback)) {
191
            if (empty($array)) {
192
                return self::toValue($default);
193
            }
194
195
            foreach ($array as $item) {
196
                return $item;
197
            }
198
        }
199
200
        foreach ($array as $key => $value) {
201
            if (call_user_func($callback, $value, $key)) {
202
                return $value;
203
            }
204
        }
205
206
        return self::toValue($default);
207
    }
208
209
    /**
210
     * Flatten a multi-dimensional array into a single level.
211
     *
212
     * @param  array $array
213
     * @param  int   $depth
214
     * @return array
215
     */
216
    public static function flatten($array, $depth = INF)
217
    {
218
        return array_reduce($array, function ($result, $item) use ($depth) {
219
            $item = $item instanceof Collection ? $item->all() : $item;
220
221
            if (!is_array($item)) {
222
                return array_merge($result, [$item]);
223
            } else if ($depth === 1) {
224
                return array_merge($result, array_values($item));
225
            } else {
226
                return array_merge($result, static::flatten($item, $depth - 1));
227
            }
228
        }, []);
229
    }
230
231
    /**
232
     * Remove one or many array items from a given array using "dot" notation.
233
     *
234
     * @param  array        $array
235
     * @param  array|string $keys
236
     * @return void
237
     */
238
    public static function forget(&$array, $keys)
239
    {
240
        $original = &$array;
241
242
        $keys = (array)$keys;
243
244
        if (count($keys) === 0) {
245
            return;
246
        }
247
248
        foreach ($keys as $key) {
249
            // if the exact key exists in the top-level, remove it
250
            if (static::exists($array, $key)) {
251
                unset($array[$key]);
252
253
                continue;
254
            }
255
256
            $parts = explode('.', $key);
257
258
            // clean up before each pass
259
            $array = &$original;
260
261
            while (count($parts) > 1) {
262
                $part = array_shift($parts);
263
264
                if (isset($array[$part]) && is_array($array[$part])) {
265
                    $array = &$array[$part];
266
                } else {
267
                    continue 2;
268
                }
269
            }
270
271
            unset($array[array_shift($parts)]);
272
        }
273
    }
274
275
    /**
276
     * Get an item from an array using "dot" notation.
277
     *
278
     * @param  \ArrayAccess|array $array
279
     * @param  string             $key
280
     * @param  mixed              $default
281
     * @return mixed
282
     */
283
    public static function get($array, $key, $default = null)
284
    {
285
        if (!static::accessible($array)) {
286
            return self::toValue($default);
287
        }
288
289
        if (is_null($key)) {
290
            return $array;
291
        }
292
293
        if (static::exists($array, $key)) {
294
            return $array[$key];
295
        }
296
297
        if (strpos($key, '.') === false) {
298
            return $array[$key] ??  $default instanceof Closure ? $default() : $default;
0 ignored issues
show
The class Childish\support\Closure does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
299
300
        }
301
302
        foreach (explode('.', $key) as $segment) {
303
            if (static::accessible($array) && static::exists($array, $segment)) {
304
                $array = $array[$segment];
305
            } else {
306
                return self::toValue($default);
307
            }
308
        }
309
310
        return $array;
311
    }
312
313
    /**
314
     * Shuffle the given array and return the result.
315
     *
316
     * @param  array $array
317
     * @return array
318
     */
319
    public static function shuffle($array)
320
    {
321
        shuffle($array);
322
323
        return $array;
324
    }
325
326
    /**
327
     * Filter the array using the given callback.
328
     *
329
     * @param  array    $array
330
     * @param  callable $callback
331
     * @return array
332
     */
333
    public static function where($array, callable $callback)
334
    {
335
        return array_filter($array, $callback, ARRAY_FILTER_USE_BOTH);
336
    }
337
338
    /**
339
     * If the given value is not an array, wrap it in one.
340
     *
341
     * @param  mixed $value
342
     * @return array
343
     */
344
    public static function wrap($value)
345
    {
346
        return !is_array($value) ? [$value] : $value;
347
    }
348
349
    /**
350
     * Determine if a given string contains a given substring.
351
     *
352
     * @param  string       $haystack
353
     * @param  string|array $needles
354
     * @return bool
355
     */
356
    public static function contains($haystack, $needles)
357
    {
358
        foreach ((array)$needles as $needle) {
359
            if ($needle !== '' && mb_strpos($haystack, $needle) !== false) {
360
                return true;
361
            }
362
        }
363
364
        return false;
365
    }
366
367
    /**
368
     * toValue
369
     *
370
     * @static
371
     * @param $value
372
     * @return mixed
373
     */
374
    public static function toValue($value)
375
    {
376
        return $value instanceof \Closure ? $value() : $value;
377
    }
378
379
    /**
380
     * Determine if a given string ends with a given substring.
381
     *
382
     * @param  string       $haystack
383
     * @param  string|array $needles
384
     * @return bool
385
     */
386
    public static function endsWith($haystack, $needles)
387
    {
388
        foreach ((array)$needles as $needle) {
389
            if (mb_substr($haystack, -mb_strlen($needle)) === (string)$needle) {
390
                return true;
391
            }
392
        }
393
394
        return false;
395
    }
396
397
    /**
398
     * Add an element to an array using "dot" notation if it doesn't exist.
399
     *
400
     * @param  array  $array
401
     * @param  string $key
402
     * @param  mixed  $value
403
     * @return array
404
     */
405
    public static function add($array, $key, $value)
406
    {
407
        if (is_null(static::get($array, $key))) {
408
            static::set($array, $key, $value);
409
        }
410
411
        return $array;
412
    }
413
414
    /**
415
     * Set an array item to a given value using "dot" notation.
416
     * If no key is given to the method, the entire array will be replaced.
417
     *
418
     * @param  array  $array
419
     * @param  string $key
420
     * @param  mixed  $value
421
     * @return array
422
     */
423
    public static function set(&$array, $key, $value)
424
    {
425
        if (is_null($key)) {
426
            return $array = $value;
427
        }
428
429
        $keys = explode('.', $key);
430
431
        while (count($keys) > 1) {
432
            $key = array_shift($keys);
433
434
            // If the key doesn't exist at this depth, we will just create an empty array
435
            // to hold the next value, allowing us to create the arrays to hold final
436
            // values at the correct depth. Then we'll keep digging into the array.
437
            if (!isset($array[$key]) || !is_array($array[$key])) {
438
                $array[$key] = [];
439
            }
440
441
            $array = &$array[$key];
442
        }
443
444
        $array[array_shift($keys)] = $value;
445
446
        return $array;
447
    }
448
449
    /**
450
     * Get one or a specified number of random values from an array.
451
     *
452
     * @param  array    $array
453
     * @param  int|null $number
454
     * @return mixed
455
     * @throws \InvalidArgumentException
456
     */
457
    public static function random($array, $number = null)
458
    {
459
        $requested = is_null($number) ? 1 : $number;
460
461
        $count = count($array);
462
463
        if ($requested > $count) {
464
            throw new \InvalidArgumentException(
465
                "You requested {$requested} items, but there are only {$count} items available."
466
            );
467
        }
468
469
        if (is_null($number)) {
470
            return $array[array_rand($array)];
471
        }
472
473
        if ((int)$number === 0) {
474
            return [];
475
        }
476
477
        $keys = array_rand($array, $number);
478
479
        $results = [];
480
481
        foreach ((array)$keys as $key) {
482
            $results[] = $array[$key];
483
        }
484
485
        return $results;
486
    }
487
488
    /**
489
     * Replace a given value in the string sequentially with an array.
490
     *
491
     * @param  string $search
492
     * @param  array  $replace
493
     * @param  string $subject
494
     * @return string
495
     */
496
    public static function replaceArray($search, array $replace, $subject)
497
    {
498
        foreach ($replace as $value) {
499
            $subject = static::replaceFirst($search, $value, $subject);
500
        }
501
502
        return $subject;
503
    }
504
505
    /**
506
     * Replace the first occurrence of a given value in the string.
507
     *
508
     * @param  string $search
509
     * @param  string $replace
510
     * @param  string $subject
511
     * @return string
512
     */
513
    public static function replaceFirst($search, $replace, $subject)
514
    {
515
        if ($search == '') {
516
            return $subject;
517
        }
518
519
        $position = mb_strpos($subject, $search);
520
521
        if ($position !== false) {
522
            return mb_substr($subject, 0, $position) . $replace . mb_substr($subject, $position + mb_strlen($search));
523
        }
524
525
        return $subject;
526
    }
527
528
    /**
529
     * Convert a string to snake case.
530
     *
531
     * @param  string $value
532
     * @param  string $delimiter
533
     * @return string
534
     */
535
    public static function snake($value, $delimiter = '_')
536
    {
537
        $key = $value;
538
539
        if (isset(static::$snakeCache[$key][$delimiter])) {
540
            return static::$snakeCache[$key][$delimiter];
541
        }
542
543
        if (!ctype_lower($value)) {
544
            $value = preg_replace('/\s+/u', '', ucwords($value));
545
546
            $value = static::lower(preg_replace('/(.)(?=[A-Z])/u', '$1' . $delimiter, $value));
0 ignored issues
show
The method lower() does not seem to exist on object<Childish\support\Tools>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
547
        }
548
549
        return static::$snakeCache[$key][$delimiter] = $value;
550
    }
551
552
    /**
553
     * Get the plural form of an English word.
554
     *
555
     * @param  string $value
556
     * @param  int    $count
557
     * @return string
558
     */
559
    public static function plural($value, $count = 2)
560
    {
561
        if ((int)$count === 1 || static::uncountable($value)) {
562
            return $value;
563
        }
564
565
        $plural = static::pluralize($value);
566
567
        return static::matchCase($plural, $value);
568
    }
569
570
    /**
571
     * Attempt to match the case on two strings.
572
     *
573
     * @param  string $value
574
     * @param  string $comparison
575
     * @return string
576
     */
577
    protected static function matchCase($value, $comparison)
578
    {
579
        $functions = ['mb_strtolower', 'mb_strtoupper', 'ucfirst', 'ucwords'];
580
581
        foreach ($functions as $function) {
582
            if (call_user_func($function, $comparison) === $comparison) {
583
                return call_user_func($function, $value);
584
            }
585
        }
586
587
        return $value;
588
    }
589
590
    /**
591
     * Determine if the given value is uncountable.
592
     *
593
     * @param  string $value
594
     * @return bool
595
     */
596
    protected static function uncountable($value)
597
    {
598
        return in_array(strtolower($value), static::$uncountable);
599
    }
600
601
    /**
602
     * Returns a word in singular form.
603
     *
604
     * @param string $word The word in plural form.
605
     * @return string The word in singular form.
606
     */
607
    public static function pluralize($word)
608
    {
609
        if (isset(self::$cache['singularize'][$word])) {
610
            return self::$cache['singularize'][$word];
611
        }
612
613
        if (!isset(self::$singular['merged']['uninflected'])) {
614
            self::$singular['merged']['uninflected'] = array_merge(
615
                self::$singular['uninflected'],
616
                self::$uninflected
617
            );
618
        }
619
620
        if (!isset(self::$singular['merged']['irregular'])) {
621
            self::$singular['merged']['irregular'] = array_merge(
622
                self::$singular['irregular'],
623
                array_flip(self::$plural['irregular'])
624
            );
625
        }
626
627
        if (!isset(self::$singular['cacheUninflected']) || !isset(self::$singular['cacheIrregular'])) {
628
            self::$singular['cacheUninflected'] = '(?:' . join('|', self::$singular['merged']['uninflected']) . ')';
629
            self::$singular['cacheIrregular']   = '(?:' . join('|',
630
                    array_keys(self::$singular['merged']['irregular'])) . ')';
631
        }
632
633
        if (preg_match('/(.*)\\b(' . self::$singular['cacheIrregular'] . ')$/i', $word, $regs)) {
634
            self::$cache['singularize'][$word] = $regs[1] . substr($word, 0,
635
                    1) . substr(self::$singular['merged']['irregular'][strtolower($regs[2])], 1);
636
637
            return self::$cache['singularize'][$word];
638
        }
639
640
        if (preg_match('/^(' . self::$singular['cacheUninflected'] . ')$/i', $word, $regs)) {
641
            self::$cache['singularize'][$word] = $word;
642
643
            return $word;
644
        }
645
646
        foreach (self::$singular['rules'] as $rule => $replacement) {
647
            if (preg_match($rule, $word)) {
648
                self::$cache['singularize'][$word] = preg_replace($rule, $replacement, $word);
649
650
                return self::$cache['singularize'][$word];
651
            }
652
        }
653
654
        self::$cache['singularize'][$word] = $word;
655
656
        return $word;
657
    }
658
659
    /**
660
     * Basename
661
     *
662
     * @static
663
     * @param $class
664
     * @return string
665
     */
666
    public static function Basename($class)
667
    {
668
        $class = is_object($class) ? get_class($class) : $class;
669
670
        return basename(str_replace('\\', '/', $class));
671
    }
672
673
    /**
674
     * ClassRecursive
675
     *
676
     * @static
677
     * @param $class
678
     * @return array
679
     */
680
    public static function ClassRecursive($class)
681
    {
682
        if (is_object($class)) {
683
            $class = get_class($class);
684
        }
685
        $results = [];
686
        foreach (array_merge([$class => $class], class_parents($class)) as $class) {
687
            $results += self::UsesRecursive($class);
688
        }
689
690
        return array_unique($results);
691
    }
692
693
    /**
694
     * UsesRecursive
695
     *
696
     * @static
697
     * @param $trait
698
     * @return array
699
     */
700
    public static function UsesRecursive($trait)
701
    {
702
        $traits = class_uses($trait);
703
704
        foreach ($traits as $trait) {
705
            $traits += self::UsesRecursive($trait);
706
        }
707
708
        return $traits;
709
    }
710
}