home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress2 / wp-includes / random_compat / random_bytes_dev_urandom.php < prev    next >
Encoding:
PHP Script  |  2017-11-30  |  4.5 KB  |  151 lines

  1. <?php
  2. /**
  3.  * Random_* Compatibility Library 
  4.  * for using the new PHP 7 random_* API in PHP 5 projects
  5.  * 
  6.  * The MIT License (MIT)
  7.  * 
  8.  * Copyright (c) 2015 Paragon Initiative Enterprises
  9.  * 
  10.  * Permission is hereby granted, free of charge, to any person obtaining a copy
  11.  * of this software and associated documentation files (the "Software"), to deal
  12.  * in the Software without restriction, including without limitation the rights
  13.  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  14.  * copies of the Software, and to permit persons to whom the Software is
  15.  * furnished to do so, subject to the following conditions:
  16.  * 
  17.  * The above copyright notice and this permission notice shall be included in
  18.  * all copies or substantial portions of the Software.
  19.  * 
  20.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  21.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  22.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  23.  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  24.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  25.  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  26.  * SOFTWARE.
  27.  */
  28.  
  29. if (!defined('RANDOM_COMPAT_READ_BUFFER')) {
  30.     define('RANDOM_COMPAT_READ_BUFFER', 8);
  31. }
  32.  
  33. if ( ! is_callable( 'random_bytes' ) ):
  34. /**
  35.  * Unless open_basedir is enabled, use /dev/urandom for
  36.  * random numbers in accordance with best practices
  37.  * 
  38.  * Why we use /dev/urandom and not /dev/random
  39.  * @ref http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers
  40.  * 
  41.  * @param int $bytes
  42.  * 
  43.  * @throws Exception
  44.  * 
  45.  * @return string
  46.  */
  47. function random_bytes($bytes)
  48. {
  49.     static $fp = null;
  50.     /**
  51.      * This block should only be run once
  52.      */
  53.     if (empty($fp)) {
  54.         /**
  55.          * We use /dev/urandom if it is a char device.
  56.          * We never fall back to /dev/random
  57.          */
  58.         $fp = fopen('/dev/urandom', 'rb');
  59.         if (!empty($fp)) {
  60.             $st = fstat($fp);
  61.             if (($st['mode'] & 0170000) !== 020000) {
  62.                 fclose($fp);
  63.                 $fp = false;
  64.             }
  65.         }
  66.  
  67.         if (!empty($fp)) {
  68.             /**
  69.              * stream_set_read_buffer() does not exist in HHVM
  70.              * 
  71.              * If we don't set the stream's read buffer to 0, PHP will
  72.              * internally buffer 8192 bytes, which can waste entropy
  73.              * 
  74.              * stream_set_read_buffer returns 0 on success
  75.              */
  76.             if (function_exists('stream_set_read_buffer')) {
  77.                 stream_set_read_buffer($fp, RANDOM_COMPAT_READ_BUFFER);
  78.             }
  79.             if (function_exists('stream_set_chunk_size')) {
  80.                 stream_set_chunk_size($fp, RANDOM_COMPAT_READ_BUFFER);
  81.             }
  82.         }
  83.     }
  84.  
  85.     try {
  86.         $bytes = RandomCompat_intval($bytes);
  87.     } catch (TypeError $ex) {
  88.         throw new TypeError(
  89.             'random_bytes(): $bytes must be an integer'
  90.         );
  91.     }
  92.  
  93.     if ($bytes < 1) {
  94.         throw new Error(
  95.             'Length must be greater than 0'
  96.         );
  97.     }
  98.  
  99.     /**
  100.      * This if() block only runs if we managed to open a file handle
  101.      * 
  102.      * It does not belong in an else {} block, because the above 
  103.      * if (empty($fp)) line is logic that should only be run once per
  104.      * page load.
  105.      */
  106.     if (!empty($fp)) {
  107.         $remaining = $bytes;
  108.         $buf = '';
  109.  
  110.         /**
  111.          * We use fread() in a loop to protect against partial reads
  112.          */
  113.         do {
  114.             $read = fread($fp, $remaining); 
  115.             if ($read === false) {
  116.                 /**
  117.                  * We cannot safely read from the file. Exit the
  118.                  * do-while loop and trigger the exception condition
  119.                  */
  120.                 $buf = false;
  121.                 break;
  122.             }
  123.             /**
  124.              * Decrease the number of bytes returned from remaining
  125.              */
  126.             $remaining -= RandomCompat_strlen($read);
  127.             $buf .= $read;
  128.         } while ($remaining > 0);
  129.         
  130.         /**
  131.          * Is our result valid?
  132.          */
  133.         if ($buf !== false) {
  134.             if (RandomCompat_strlen($buf) === $bytes) {
  135.                 /**
  136.                  * Return our random entropy buffer here:
  137.                  */
  138.                 return $buf;
  139.             }
  140.         }
  141.     }
  142.  
  143.     /**
  144.      * If we reach here, PHP has failed us.
  145.      */
  146.     throw new Exception(
  147.         'Error reading from source device'
  148.     );
  149. }
  150. endif;
  151.