Conditions | 20 |
Paths | 2112 |
Total Lines | 121 |
Code Lines | 62 |
Lines | 0 |
Ratio | 0 % |
Changes | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
1 | <?php |
||
236 | public function generate( $bytes, $forceStrong = false ) { |
||
237 | |||
238 | $bytes = floor( $bytes ); |
||
239 | static $buffer = ''; |
||
240 | if ( is_null( $this->strong ) ) { |
||
241 | // Set strength to false initially until we know what source data is coming from |
||
242 | $this->strong = true; |
||
243 | } |
||
244 | |||
245 | if ( strlen( $buffer ) < $bytes ) { |
||
246 | // If available make use of mcrypt_create_iv URANDOM source to generate randomness |
||
247 | // On unix-like systems this reads from /dev/urandom but does it without any buffering |
||
248 | // and bypasses openbasedir restrictions, so it's preferable to reading directly |
||
249 | // On Windows starting in PHP 5.3.0 Windows' native CryptGenRandom is used to generate |
||
250 | // entropy so this is also preferable to just trying to read urandom because it may work |
||
251 | // on Windows systems as well. |
||
252 | if ( function_exists( 'mcrypt_create_iv' ) ) { |
||
253 | $rem = $bytes - strlen( $buffer ); |
||
254 | $iv = mcrypt_create_iv( $rem, MCRYPT_DEV_URANDOM ); |
||
255 | if ( $iv === false ) { |
||
256 | $this->logger->debug( "mcrypt_create_iv returned false." ); |
||
257 | } else { |
||
258 | $buffer .= $iv; |
||
259 | $this->logger->debug( "mcrypt_create_iv generated " . strlen( $iv ) . |
||
260 | " bytes of randomness." ); |
||
261 | } |
||
262 | } |
||
263 | } |
||
264 | |||
265 | if ( strlen( $buffer ) < $bytes ) { |
||
266 | if ( function_exists( 'openssl_random_pseudo_bytes' ) ) { |
||
267 | $rem = $bytes - strlen( $buffer ); |
||
268 | $openssl_bytes = openssl_random_pseudo_bytes( $rem, $openssl_strong ); |
||
269 | if ( $openssl_bytes === false ) { |
||
270 | $this->logger->debug( "openssl_random_pseudo_bytes returned false." ); |
||
271 | } else { |
||
272 | $buffer .= $openssl_bytes; |
||
273 | $this->logger->debug( "openssl_random_pseudo_bytes generated " . |
||
274 | strlen( $openssl_bytes ) . " bytes of " . |
||
275 | ( $openssl_strong ? "strong" : "weak" ) . " randomness." ); |
||
276 | } |
||
277 | if ( strlen( $buffer ) >= $bytes ) { |
||
278 | // openssl tells us if the random source was strong, if some of our data was generated |
||
279 | // using it use it's say on whether the randomness is strong |
||
280 | $this->strong = !!$openssl_strong; |
||
281 | } |
||
282 | } |
||
283 | } |
||
284 | |||
285 | // Only read from urandom if we can control the buffer size or were passed forceStrong |
||
286 | if ( strlen( $buffer ) < $bytes && |
||
287 | ( function_exists( 'stream_set_read_buffer' ) || $forceStrong ) |
||
288 | ) { |
||
289 | $rem = $bytes - strlen( $buffer ); |
||
290 | if ( !function_exists( 'stream_set_read_buffer' ) && $forceStrong ) { |
||
291 | $this->logger->debug( "Was forced to read from /dev/urandom " . |
||
292 | "without control over the buffer size." ); |
||
293 | } |
||
294 | // /dev/urandom is generally considered the best possible commonly |
||
295 | // available random source, and is available on most *nix systems. |
||
296 | MediaWiki\suppressWarnings(); |
||
297 | $urandom = fopen( "/dev/urandom", "rb" ); |
||
298 | MediaWiki\restoreWarnings(); |
||
299 | |||
300 | // Attempt to read all our random data from urandom |
||
301 | // php's fread always does buffered reads based on the stream's chunk_size |
||
302 | // so in reality it will usually read more than the amount of data we're |
||
303 | // asked for and not storing that risks depleting the system's random pool. |
||
304 | // If stream_set_read_buffer is available set the chunk_size to the amount |
||
305 | // of data we need. Otherwise read 8k, php's default chunk_size. |
||
306 | if ( $urandom ) { |
||
307 | // php's default chunk_size is 8k |
||
308 | $chunk_size = 1024 * 8; |
||
309 | if ( function_exists( 'stream_set_read_buffer' ) ) { |
||
310 | // If possible set the chunk_size to the amount of data we need |
||
311 | stream_set_read_buffer( $urandom, $rem ); |
||
312 | $chunk_size = $rem; |
||
313 | } |
||
314 | $random_bytes = fread( $urandom, max( $chunk_size, $rem ) ); |
||
315 | $buffer .= $random_bytes; |
||
316 | fclose( $urandom ); |
||
317 | $this->logger->debug( "/dev/urandom generated " . strlen( $random_bytes ) . |
||
318 | " bytes of randomness." ); |
||
319 | |||
320 | if ( strlen( $buffer ) >= $bytes ) { |
||
321 | // urandom is always strong, set to true if all our data was generated using it |
||
322 | $this->strong = true; |
||
323 | } |
||
324 | } else { |
||
325 | $this->logger->debug( "/dev/urandom could not be opened." ); |
||
326 | } |
||
327 | } |
||
328 | |||
329 | // If we cannot use or generate enough data from a secure source |
||
330 | // use this loop to generate a good set of pseudo random data. |
||
331 | // This works by initializing a random state using a pile of unstable data |
||
332 | // and continually shoving it through a hash along with a variable salt. |
||
333 | // We hash the random state with more salt to avoid the state from leaking |
||
334 | // out and being used to predict the /randomness/ that follows. |
||
335 | if ( strlen( $buffer ) < $bytes ) { |
||
336 | $this->logger->debug( __METHOD__ . |
||
337 | ": Falling back to using a pseudo random state to generate randomness." ); |
||
338 | } |
||
339 | while ( strlen( $buffer ) < $bytes ) { |
||
340 | $buffer .= MWCryptHash::hmac( $this->randomState(), strval( mt_rand() ) ); |
||
341 | // This code is never really cryptographically strong, if we use it |
||
342 | // at all, then set strong to false. |
||
343 | $this->strong = false; |
||
344 | } |
||
345 | |||
346 | // Once the buffer has been filled up with enough random data to fulfill |
||
347 | // the request shift off enough data to handle the request and leave the |
||
348 | // unused portion left inside the buffer for the next request for random data |
||
349 | $generated = substr( $buffer, 0, $bytes ); |
||
350 | $buffer = substr( $buffer, $bytes ); |
||
351 | |||
352 | $this->logger->debug( strlen( $buffer ) . |
||
353 | " bytes of randomness leftover in the buffer." ); |
||
354 | |||
355 | return $generated; |
||
356 | } |
||
357 | |||
388 |
Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable: