Completed
Push — master ( afbd03...df7fcc )
by Riikka
01:15
created

ByteNumberGenerator::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
3
namespace Riimu\Kit\SecureRandom\Generator;
4
5
use Riimu\Kit\SecureRandom\GeneratorException;
6
7
/**
8
 * A random number generator that wraps the given byte generator for generating integers.
9
 *
10
 * @author Riikka Kalliomäki <[email protected]>
11
 * @copyright Copyright (c) 2017 Riikka Kalliomäki
12
 * @license http://opensource.org/licenses/mit-license.php MIT License
13
 */
14
class ByteNumberGenerator implements NumberGenerator
15
{
16
    /** @var Generator The underlying byte generator */
17
    private $byteGenerator;
18
19
    /**
20
     * NumberByteGenerator constructor.
21
     * @param Generator $generator The underlying byte generator used to generate random bytes
22
     */
23 91
    public function __construct(Generator $generator)
24
    {
25 91
        $this->byteGenerator = $generator;
26 91
    }
27
28
    /**
29
     * Tells if the underlying byte generator is supported by the system.
30
     * @return bool True if the generator is supported, false if not
31
     */
32 3
    public function isSupported()
33
    {
34 3
        return $this->byteGenerator->isSupported();
35
    }
36
37
    /**
38
     * Returns bytes read from the provided byte generator.
39
     * @param int $count The number of bytes to read
40
     * @return string A string of bytes
41
     * @throws GeneratorException If there was an error generating the bytes
42
     */
43 12
    public function getBytes($count)
44
    {
45 12
        return $this->byteGenerator->getBytes($count);
46
    }
47
48
    /**
49
     * Returns a random integer between given minimum and maximum.
50
     * @param int $min The minimum possible value to return
51
     * @param int $max The maximum possible value to return
52
     * @return int A random number between the lower and upper limit (inclusive)
53
     * @throws \InvalidArgumentException If the provided values are invalid
54
     * @throws GeneratorException If an error occurs generating the number
55
     */
56 36
    public function getNumber($min, $max)
57
    {
58 36
        $min = (int) $min;
59 36
        $max = (int) $max;
60
61 36
        if ($min > $max) {
62 3
            throw new \InvalidArgumentException('Invalid minimum and maximum value');
63
        }
64
65 33
        if ($min === $max) {
66 12
            return $min;
67
        }
68
69 24
        return $min + $this->getByteNumber($max - $min);
70
    }
71
72
    /**
73
     * Returns a random number generated using the random byte generator.
74
     * @param int $limit Maximum value for the random number
75
     * @return int The generated random number between 0 and the limit
76
     * @throws GeneratorException If error occurs generating the random number
77
     */
78 24
    private function getByteNumber($limit)
79
    {
80 24
        $bits = 1;
81 24
        $mask = 1;
82
83 24
        while ($limit >> $bits > 0) {
84 24
            $mask |= 1 << $bits;
85 24
            $bits++;
86 8
        }
87
88 24
        $bytes = (int) ceil($bits / 8);
89
90
        do {
91 24
            $result = hexdec(bin2hex($this->byteGenerator->getBytes($bytes))) & $mask;
92 24
        } while ($result > $limit);
93
94 24
        return $result;
95
    }
96
}
97