Completed
Push — master ( 398e3b...bec142 )
by Peter
04:11
created

Base64UID::random()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 32
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 23.461

Importance

Changes 0
Metric Value
dl 0
loc 32
ccs 3
cts 14
cp 0.2143
rs 8.439
c 0
b 0
f 0
cc 6
eloc 17
nc 6
nop 2
crap 23.461
1
<?php
2
3
/**
4
 * GpsLab component.
5
 *
6
 * @author    Peter Gribanov <[email protected]>
7
 * @copyright Copyright (c) 2011, Peter Gribanov
8
 * @license   http://opensource.org/licenses/MIT
9
 */
10
11
namespace GpsLab\Component\Base64UID;
12
13
class Base64UID
14
{
15
    /**
16
     * @var string
17
     */
18
    private static $default_charset = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-';
19
20
    /**
21
     * @throws \Exception
22
     *
23
     * @param int    $length
24
     * @param string $charset
25
     *
26
     * @return string
27
     */
28 5
    public static function generate($length = 10, $charset = '')
29
    {
30 5
        $charset = $charset ?: self::$default_charset;
31 5
        $charset_size = strlen($charset);
32 5
        $uid = '';
33 5
        while ($length-- > 0) {
34 4
            $uid .= $charset[self::random(0, $charset_size - 1)];
35
        }
36
37 5
        return $uid;
38
    }
39
40
    /**
41
     * Generates cryptographically secure pseudo-random integers.
42
     *
43
     * Follback for PHP < 7.0
44
     *
45
     * @see http://php.net/manual/en/function.random-int.php#119670
46
     *
47
     * @throws \Exception
48
     *
49
     * @param int $min
50
     * @param int $max
51
     *
52
     * @return int|null
53
     */
54 4
    private static function random($min, $max)
55
    {
56 4
        if (function_exists('random_int')) {
57 4
            return random_int($min, $max);
58
        }
59
60
        // @codeCoverageIgnoreStart
61
        if (!function_exists('mcrypt_create_iv')) {
62
            throw new \Exception('mcrypt must be loaded for random_int to work');
63
        }
64
        // @codeCoverageIgnoreEnd
65
66
        $range = $counter = $max - $min;
67
        $bits = 1;
68
69
        while ($counter >>= 1) {
70
            ++$bits;
71
        }
72
73
        $bytes = (int) max(ceil($bits / 8), 1);
74
        $bitmask = pow(2, $bits) - 1;
75
76
        if ($bitmask >= PHP_INT_MAX) {
77
            $bitmask = PHP_INT_MAX;
78
        }
79
80
        do {
81
            $result = hexdec(bin2hex(mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM))) & $bitmask;
82
        } while ($result > $range);
83
84
        return $result + $min;
85
    }
86
}
87