Completed
Push — master ( 977662...cec073 )
by Sebastian
03:01
created

PasswordGenerator   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 161
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
wmc 17
lcom 1
cbo 0
dl 0
loc 161
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A getFromRandom() 0 12 2
A getTopology() 0 11 2
A getTopologyGroup() 0 11 3
A getFromTopology() 0 20 3
A getRandomChar() 0 11 3
A inRanges() 0 10 4
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
     * Generate a random password.
34
     * <pre><code class="php">use Linna\Auth\PasswordGenerator;
35
     *
36
     * $passwordGenerator = new PasswordGenerator();
37
     * $random = $passwordGenerator->getFromRandom(20);
38
     *
39
     * //var_dump result
40
     * //r4Q,1J*tM7D_99q0u>61
41
     * var_dump($random);
42
     * </code></pre>
43
     *
44
     * @param int $length Desiderated password length.
45
     * @return string Random password.
46
     */
47
    public function getFromRandom(int $length): string
48
    {
49
        $password = [];
50
51
        while ($length) {
52
            $password[] = $this->getRandomChar($this->chars[random_int(0, 3)]);
53
            
54
            $length--;
55
        }
56
        
57
        return implode($password);
58
    }
59
60
    /**
61
     * Return topology for given password.
62
     * <pre><code class="php">use Linna\Auth\PasswordGenerator;
63
     *
64
     * $passwordGenerator = new PasswordGenerator();
65
     * $topology = $passwordGenerator->getTopology('r4Q,1J*tM7D_99q0u>61');
66
     *
67
     * //var_dump result
68
     * //ldusdusludusddldlsdd
69
     * var_dump($topology);
70
     * </code></pre>
71
     * @param string $password Password.
72
     *
73
     * @return string Topology for the argument passed password.
74
     */
75
    public function getTopology(string $password): string
76
    {
77
        $array = str_split($password);
78
        $topology = [];
79
        
80
        foreach ($array as $char) {
81
            $topology[] = $this->getTopologyGroup($char);
82
        }
83
84
        return implode($topology);
85
    }
86
87
    /**
88
     * Return topology group for the given char.
89
     *
90
     * @param string $char
91
     *
92
     * @return string
93
     */
94
    private function getTopologyGroup(string $char) : string
95
    {
96
        $int = ord($char);
97
        $groups = ['u', 'l', 'd', 's'];
98
        
99
        foreach ($groups as $key => $group) {
100
            if ($this->inRanges($int, $this->chars[$key])) {
101
                return $group;
102
            }
103
        }
104
    }
105
    
106
    /**
107
     * Generate a random password corresponding at the given topology.
108
     * <pre><code class="php">use Linna\Auth\PasswordGenerator;
109
     *
110
     * $passwordGenerator = new PasswordGenerator();
111
     * $random = $passwordGenerator->getFromTopology('ldusdusludusddldlsdd');
112
     *
113
     * //var_dump result
114
     * //r4Q,1J*tM7D_99q0u>61
115
     * var_dump($random);
116
     * </code></pre>
117
     *
118
     * @param string $topology Topology for generate password.
119
     * @return string Random password corresponding the given topology.
120
     *
121
     * @throws InvalidArgumentException If invalid pattern is provided.
122
     */
123
    public function getFromTopology(string $topology): string
124
    {
125
        $array = str_split(strtolower($topology));
126
        $groups = [117 => 0, 108 => 1, 100 => 2, 115 => 3];
127
        $password = [];
128
129
        foreach ($array as $char) {
130
            $int = ord($char);
131
132
            if (isset($groups[$int])) {
133
                $password[] = $this->getRandomChar($this->chars[$groups[$int]]);
134
135
                continue;
136
            }
137
138
            throw new InvalidArgumentException('Invalid pattern provided, accepted only u, l, d and s');
139
        }
140
141
        return implode($password);
142
    }
143
144
    /**
145
     * Get random char between.
146
     *
147
     * @param array $interval
148
     * @return string
149
     */
150
    private function getRandomChar(array $interval): string
151
    {
152
        do {
153
            $int = random_int(33, 122);
154
            if ($this->inRanges($int, $interval)) {
155
                break;
156
            }
157
        } while (true);
158
            
159
        return chr($int);
160
    }
161
162
    /**
163
     * Check if value is between given range.
164
     *
165
     * @param mixed $value
166
     * @param array $ranges
167
     *
168
     * @return bool
169
     */
170
    private function inRanges($value, array $ranges): bool
171
    {
172
        foreach ($ranges as $range) {
173
            if ($value >= $range[0] && $value <= $range[1]) {
174
                return true;
175
            }
176
        }
177
178
        return false;
179
    }
180
}
181