wp/wp-includes/random_compat/random_int.php
changeset 19 3d72ae0968f4
parent 9 177826044cd9
equal deleted inserted replaced
18:be944660c56a 19:3d72ae0968f4
     5      * Random_* Compatibility Library
     5      * Random_* Compatibility Library
     6      * for using the new PHP 7 random_* API in PHP 5 projects
     6      * for using the new PHP 7 random_* API in PHP 5 projects
     7      *
     7      *
     8      * The MIT License (MIT)
     8      * The MIT License (MIT)
     9      *
     9      *
    10      * Copyright (c) 2015 - 2017 Paragon Initiative Enterprises
    10      * Copyright (c) 2015 - 2018 Paragon Initiative Enterprises
    11      *
    11      *
    12      * Permission is hereby granted, free of charge, to any person obtaining a copy
    12      * Permission is hereby granted, free of charge, to any person obtaining a copy
    13      * of this software and associated documentation files (the "Software"), to deal
    13      * of this software and associated documentation files (the "Software"), to deal
    14      * in the Software without restriction, including without limitation the rights
    14      * in the Software without restriction, including without limitation the rights
    15      * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    15      * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    49          * lose precision, so the <= and => operators might accidentally let a float
    49          * lose precision, so the <= and => operators might accidentally let a float
    50          * through.
    50          * through.
    51          */
    51          */
    52 
    52 
    53         try {
    53         try {
       
    54             /** @var int $min */
    54             $min = RandomCompat_intval($min);
    55             $min = RandomCompat_intval($min);
    55         } catch (TypeError $ex) {
    56         } catch (TypeError $ex) {
    56             throw new TypeError(
    57             throw new TypeError(
    57                 'random_int(): $min must be an integer'
    58                 'random_int(): $min must be an integer'
    58             );
    59             );
    59         }
    60         }
    60 
    61 
    61         try {
    62         try {
       
    63             /** @var int $max */
    62             $max = RandomCompat_intval($max);
    64             $max = RandomCompat_intval($max);
    63         } catch (TypeError $ex) {
    65         } catch (TypeError $ex) {
    64             throw new TypeError(
    66             throw new TypeError(
    65                 'random_int(): $max must be an integer'
    67                 'random_int(): $max must be an integer'
    66             );
    68             );
    88          * $bytes => the number of random bytes we need
    90          * $bytes => the number of random bytes we need
    89          * $mask => an integer bitmask (for use with the &) operator
    91          * $mask => an integer bitmask (for use with the &) operator
    90          *          so we can minimize the number of discards
    92          *          so we can minimize the number of discards
    91          */
    93          */
    92         $attempts = $bits = $bytes = $mask = $valueShift = 0;
    94         $attempts = $bits = $bytes = $mask = $valueShift = 0;
       
    95         /** @var int $attempts */
       
    96         /** @var int $bits */
       
    97         /** @var int $bytes */
       
    98         /** @var int $mask */
       
    99         /** @var int $valueShift */
    93 
   100 
    94         /**
   101         /**
    95          * At this point, $range is a positive number greater than 0. It might
   102          * At this point, $range is a positive number greater than 0. It might
    96          * overflow, however, if $max - $min > PHP_INT_MAX. PHP will cast it to
   103          * overflow, however, if $max - $min > PHP_INT_MAX. PHP will cast it to
    97          * a float and we will lose some precision.
   104          * a float and we will lose some precision.
       
   105          *
       
   106          * @var int|float $range
    98          */
   107          */
    99         $range = $max - $min;
   108         $range = $max - $min;
   100 
   109 
   101         /**
   110         /**
   102          * Test for integer overflow:
   111          * Test for integer overflow:
   113              *
   122              *
   114              * @ref https://eval.in/400356 (32-bit)
   123              * @ref https://eval.in/400356 (32-bit)
   115              * @ref http://3v4l.org/XX9r5  (64-bit)
   124              * @ref http://3v4l.org/XX9r5  (64-bit)
   116              */
   125              */
   117             $bytes = PHP_INT_SIZE;
   126             $bytes = PHP_INT_SIZE;
       
   127             /** @var int $mask */
   118             $mask = ~0;
   128             $mask = ~0;
   119 
   129 
   120         } else {
   130         } else {
   121 
   131 
   122             /**
   132             /**
   127                 if ($bits % 8 === 0) {
   137                 if ($bits % 8 === 0) {
   128                     ++$bytes;
   138                     ++$bytes;
   129                 }
   139                 }
   130                 ++$bits;
   140                 ++$bits;
   131                 $range >>= 1;
   141                 $range >>= 1;
       
   142                 /** @var int $mask */
   132                 $mask = $mask << 1 | 1;
   143                 $mask = $mask << 1 | 1;
   133             }
   144             }
   134             $valueShift = $min;
   145             $valueShift = $min;
   135         }
   146         }
   136 
   147 
       
   148         /** @var int $val */
   137         $val = 0;
   149         $val = 0;
   138         /**
   150         /**
   139          * Now that we have our parameters set up, let's begin generating
   151          * Now that we have our parameters set up, let's begin generating
   140          * random integers until one falls between $min and $max
   152          * random integers until one falls between $min and $max
   141          */
   153          */
       
   154         /** @psalm-suppress RedundantCondition */
   142         do {
   155         do {
   143             /**
   156             /**
   144              * The rejection probability is at most 0.5, so this corresponds
   157              * The rejection probability is at most 0.5, so this corresponds
   145              * to a failure probability of 2^-128 for a working RNG
   158              * to a failure probability of 2^-128 for a working RNG
   146              */
   159              */
   167              */
   180              */
   168             $val &= 0;
   181             $val &= 0;
   169             for ($i = 0; $i < $bytes; ++$i) {
   182             for ($i = 0; $i < $bytes; ++$i) {
   170                 $val |= ord($randomByteString[$i]) << ($i * 8);
   183                 $val |= ord($randomByteString[$i]) << ($i * 8);
   171             }
   184             }
       
   185             /** @var int $val */
   172 
   186 
   173             /**
   187             /**
   174              * Apply mask
   188              * Apply mask
   175              */
   189              */
   176             $val &= $mask;
   190             $val &= $mask;