Test Setup Failed
Branch b0.24.0 (75b6bf)
by Sebastian
02:59
created

PasswordGenerator::getFromRandom()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 6
nc 2
nop 1
1
<?php
2
3
/**
4
 * Linna Framework.
5
 *
6
 * @author Sebastian Rapetti <[email protected]>
7
 * @copyright (c) 2017, Sebastian Rapetti
8
 * @license http://opensource.org/licenses/MIT MIT License
9
 */
10
declare(strict_types=1);
11
12
namespace Linna\Authentication;
13
14
use InvalidArgumentException;
15
16
/**
17
 * Generate random password with random topology, this class use php7
18
 * random_int() function for generate random numbers.
19
 */
20
class PasswordGenerator
21
{
22
    /**
23
     * @var array Characters intervall utf8 dec rappresentation
24
     */
25
    private $chars = [
26
        [[65, 90]], //u 117
27
        [[97, 122]], //l 108
28
        [[48, 57]], //d 100
29
        [[33, 47], [58, 64], [91, 96], [123, 126]], //s 115
30
    ];
31
32
    /**
33
     * @var array Characters utf8 dec rappresentation
34
     */
35
    private $groups = [
36
        117 => 0, //u
37
        108 => 1, //l
38
        100 => 2, //d
39
        115 => 3  //s
40
    ];
41
42
    
43
    /**
44
     * Generate a random password.
45
     * <pre><code class="php">use Linna\Auth\PasswordGenerator;
46
     *
47
     * $passwordGenerator = new PasswordGenerator();
48
     * $random = $passwordGenerator->getFromRandom(20);
49
     *
50
     * //var_dump result
51
     * //r4Q,1J*tM7D_99q0u>61
52
     * var_dump($random);
53
     * </code></pre>
54
     *
55
     * @param int $length Desiderated password length.
56
     * @return string Random password.
57
     */
58
    public function getFromRandom(int $length): string
59
    {
60
        $password = [];
61
62
        while ($length) {
63
            $password[] = $this->getRandomChar($this->chars[random_int(0, 3)]);
64
            
65
            $length--;
66
        }
67
        
68
        return implode($password);
69
    }
70
71
    /**
72
     * Return topology for given password.
73
     * <pre><code class="php">use Linna\Auth\PasswordGenerator;
74
     *
75
     * $passwordGenerator = new PasswordGenerator();
76
     * $topology = $passwordGenerator->getTopology('r4Q,1J*tM7D_99q0u>61');
77
     *
78
     * //var_dump result
79
     * //ldusdusludusddldlsdd
80
     * var_dump($topology);
81
     * </code></pre>
82
     * @param string $password Password.
83
     *
84
     * @return string Topology for the argument passed password.
85
     */
86
    public function getTopology(string $password): string
87
    {
88
        $array = str_split($password);
89
        $topology = [];
90
91
        foreach ($array as $char) {
92
            $int = ord($char);
93
94
            if ($this->inRanges($int, $this->chars[0])) {
95
                $topology[] = 'u';
96
                continue;
97
            }
98
99
            if ($this->inRanges($int, $this->chars[1])) {
100
                $topology[] = 'l';
101
                continue;
102
            }
103
104
            if ($this->inRanges($int, $this->chars[2])) {
105
                $topology[] = 'd';
106
                continue;
107
            }
108
109
            if ($this->inRanges($int, $this->chars[3])) {
110
                $topology[] = 's';
111
                continue;
112
            }
113
        }
114
115
        return implode($topology);
116
    }
117
118
    /**
119
     * Generate a random password corresponding at the given topology.
120
     * <pre><code class="php">use Linna\Auth\PasswordGenerator;
121
     *
122
     * $passwordGenerator = new PasswordGenerator();
123
     * $random = $passwordGenerator->getFromTopology('ldusdusludusddldlsdd');
124
     *
125
     * //var_dump result
126
     * //r4Q,1J*tM7D_99q0u>61
127
     * var_dump($random);
128
     * </code></pre>
129
     *
130
     * @param string $topology Topology for generate password.
131
     * @return string Random password corresponding the given topology.
132
     *
133
     * @throws InvalidArgumentException If invalid pattern is provided.
134
     */
135
    public function getFromTopology(string $topology): string
136
    {
137
        $array = str_split(strtolower($topology));
138
        $password = [];
139
140
        foreach ($array as $char) {
141
            $int = ord($char);
142
143
            if (isset($this->groups[$int])) {
144
                $key = $this->groups[$int];
145
                $password[] = $this->getRandomChar($this->chars[$key]);
146
147
                continue;
148
            }
149
150
            throw new InvalidArgumentException('Invalid pattern provided, accepted only u, l, d and s');
151
        }
152
153
        return implode($password);
154
    }
155
156
    /**
157
     * Get random char between.
158
     *
159
     * @param array $interval
160
     * @return string
161
     */
162
    private function getRandomChar(array $interval): string
163
    {
164
        while ($int = random_int(33, 122)) {
165
            if ($this->inRanges($int, $interval)) {
166
                break;
167
            }
168
        }
169
170
        return chr($int);
171
    }
172
173
    /**
174
     * Check if value is between given range.
175
     *
176
     * @param mixed $value
177
     * @param array $ranges
178
     *
179
     * @return bool
180
     */
181
    private function inRanges($value, array $ranges): bool
182
    {
183
        foreach ($ranges as $range) {
184
            if ($value >= $range[0] && $value <= $range[1]) {
185
                return true;
186
            }
187
        }
188
189
        return false;
190
    }
191
}
192