Completed
Push — master ( 4d4232...ffcfa4 )
by Anthony
14:02 queued 11:53
created

Factory::findSources()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 14
rs 8.8571
cc 5
eloc 8
nc 6
nop 1
1
<?php
2
/**
3
 * The Random Factory
4
 *
5
 * Use this factory to instantiate random number generators, sources and mixers.
6
 *
7
 * PHP version 5.3
8
 *
9
 * @category   PHPPasswordLib
10
 * @package    Random
11
 * @author     Anthony Ferrara <[email protected]>
12
 * @copyright  2011 The Authors
13
 * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
14
 * @version    Build @@version@@
15
 */
16
17
namespace RandomLib;
18
19
use SecurityLib\Strength;
20
21
/**
22
 * The Random Factory
23
 *
24
 * Use this factory to instantiate random number generators, sources and mixers.
25
 *
26
 * @category   PHPPasswordLib
27
 * @package    Random
28
 * @author     Anthony Ferrara <[email protected]>
29
 */
30
class Factory extends \SecurityLib\AbstractFactory {
31
32
    /**
33
     * @var array A list of available random number mixing strategies
34
     */
35
    protected $mixers = array();
36
37
    /**
38
     * @var array A list of available random number sources
39
     */
40
    protected $sources = array();
41
42
    /**
43
     * Build a new instance of the factory, loading core mixers and sources
44
     *
45
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
46
     */
47
    public function __construct() {
48
        $this->loadMixers();
49
        $this->loadSources();
50
    }
51
52
    /**
53
     * Get a generator for the requested strength
54
     *
55
     * @param Strength $strength The requested strength of the random number
56
     *
57
     * @return Generator The instantiated generator
58
     * @throws RuntimeException If an appropriate mixing strategy isn't found
59
     */
60
    public function getGenerator(\SecurityLib\Strength $strength) {
61
        $sources = $this->findSources($strength);
62
        $mixer   = $this->findMixer($strength);
63
        return new Generator($sources, $mixer);
64
    }
65
66
    /**
67
     * Get a high strength random number generator
68
     *
69
     * High Strength keys should ONLY be used for generating extremely strong
70
     * cryptographic keys.  Generating them is very resource intensive and may
71
     * take several minutes or more depending on the requested size.
72
     *
73
     * @return Generator The instantiated generator
74
     */
75
    public function getHighStrengthGenerator() {
76
        return $this->getGenerator(new Strength(Strength::HIGH));
77
    }
78
79
    /**
80
     * Get a low strength random number generator
81
     *
82
     * Low Strength should be used anywhere that random strings are needed in a
83
     * non-cryptographical setting.  They are not strong enough to be used as
84
     * keys or salts.  They are however useful for one-time use tokens.
85
     *
86
     * @return Generator The instantiated generator
87
     */
88
    public function getLowStrengthGenerator() {
89
        return $this->getGenerator(new Strength(Strength::LOW));
90
    }
91
92
    /**
93
     * Get a medium strength random number generator
94
     *
95
     * Medium Strength should be used for most needs of a cryptographic nature.
96
     * They are strong enough to be used as keys and salts.  However, they do
97
     * take some time and resources to generate, so they should not be over-used
98
     *
99
     * @return Generator The instantiated generator
100
     */
101
    public function getMediumStrengthGenerator() {
102
        return $this->getGenerator(new Strength(Strength::MEDIUM));
103
    }
104
105
    /**
106
     * Get all loaded mixing strategies
107
     *
108
     * @return array An array of mixers
109
     */
110
    public function getMixers() {
111
        return $this->mixers;
112
    }
113
114
    /**
115
     * Get all loaded random number sources
116
     *
117
     * @return array An array of sources
118
     */
119
    public function getSources() {
120
        return $this->sources;
121
    }
122
123
    /**
124
     * Register a mixing strategy for this factory instance
125
     *
126
     * @param string $name  The name of the stategy
127
     * @param string $class The class name of the implementation
128
     *
129
     * @return Factory $this The current factory instance
130
     */
131
    public function registerMixer($name, $class) {
132
        $this->registerType(
133
            'mixers',
134
            __NAMESPACE__ . '\\Mixer',
135
            $name,
136
            $class
137
        );
138
        return $this;
139
    }
140
141
    /**
142
     * Register a random number source for this factory instance
143
     *
144
     * Note that this class must implement the Source interface
145
     *
146
     * @param string $name  The name of the stategy
147
     * @param string $class The class name of the implementation
148
     *
149
     * @return Factory $this The current factory instance
150
     */
151
    public function registerSource($name, $class) {
152
        $this->registerType(
153
            'sources',
154
            __NAMESPACE__ . '\\Source',
155
            $name,
156
            $class
157
        );
158
        return $this;
159
    }
160
161
    /**
162
     * Find a sources based upon the requested strength
163
     *
164
     * @param Strength $strength The strength mixer to find
165
     *
166
     * @return Source The found source
0 ignored issues
show
Documentation introduced by
Should the return type not be array?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
167
     * @throws RuntimeException if a valid source cannot be found
168
     */
169
    protected function findSources(\SecurityLib\Strength $strength) {
170
        $sources = array();
171
        foreach ($this->getSources() as $source) {
172
            if ($strength->compare($source::getStrength()) <= 0 && $source::isSupported()) {
173
                $sources[] = new $source;
174
            }
175
        }
176
177
        if (0 === count($sources)) {
178
            throw new \RuntimeException('Could not find sources');
179
        }
180
181
        return $sources;
182
    }
183
184
    /**
185
     * Find a mixer based upon the requested strength
186
     *
187
     * @param Strength $strength The strength mixer to find
188
     *
189
     * @return Mixer The found mixer
190
     * @throws RuntimeException if a valid mixer cannot be found
191
     */
192
    protected function findMixer(\SecurityLib\Strength $strength) {
193
        $newMixer = null;
194
        $fallback = null;
195
        foreach ($this->getMixers() as $mixer) {
196
            if ($strength->compare($mixer::getStrength()) == 0) {
197
                $newMixer = new $mixer;
198
            } elseif ($strength->compare($mixer::getStrength()) == 1) {
199
                $fallback = new $mixer;
200
            }
201
        }
202
        if (is_null($newMixer)) {
203
            if (is_null($fallback)) {
204
                throw new \RuntimeException('Could not find mixer');
205
            }
206
            return $fallback;
207
        }
208
        return $newMixer;
209
    }
210
211
    /**
212
     * Load all core mixing strategies
213
     *
214
     * @return void
215
     */
216
    protected function loadMixers() {
217
        $this->loadFiles(
218
            __DIR__ . '/Mixer',
219
            __NAMESPACE__ . '\\Mixer\\',
220
            array($this, 'registerMixer')
0 ignored issues
show
Documentation introduced by
array($this, 'registerMixer') is of type array<integer,this<Rando...actory>","1":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
221
        );
222
    }
223
224
    /**
225
     * Load all core random number sources
226
     *
227
     * @return void
228
     */
229
    protected function loadSources() {
230
        $this->loadFiles(
231
            __DIR__ . '/Source',
232
            __NAMESPACE__ . '\\Source\\',
233
            array($this, 'registerSource')
0 ignored issues
show
Documentation introduced by
array($this, 'registerSource') is of type array<integer,this<Rando...actory>","1":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
234
        );
235
    }
236
237
}
238
239