PluginProbe
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions / 260927
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions v260927
260927 260917 260913 260909 260829 260814 260805 110710 110731 110812 110815 110912 110913 110915 110926 110927 111002 111003 111011 111017 111029 111105 111206 111216 111220 All 190 releases
s2member / src / vendor / paragonie / random_compat / lib / random_int.php

random_int.php in s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions 260927, at src/vendor/paragonie/random_compat/lib/random_int.php

191 lines 6.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!is_callable('random_int')) {
4 /**
5 * Random_* Compatibility Library
6 * for using the new PHP 7 random_* API in PHP 5 projects
7 *
8 * The MIT License (MIT)
9 *
10 * Copyright (c) 2015 - 2017 Paragon Initiative Enterprises
11 *
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
14 * in the Software without restriction, including without limitation the rights
15 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 * copies of the Software, and to permit persons to whom the Software is
17 * furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included in
20 * all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 * SOFTWARE.
29 */
30
31 /**
32 * Fetch a random integer between $min and $max inclusive
33 *
34 * @param int $min
35 * @param int $max
36 *
37 * @throws Exception
38 *
39 * @return int
40 */
41 function random_int($min, $max)
42 {
43 /**
44 * Type and input logic checks
45 *
46 * If you pass it a float in the range (~PHP_INT_MAX, PHP_INT_MAX)
47 * (non-inclusive), it will sanely cast it to an int. If you it's equal to
48 * ~PHP_INT_MAX or PHP_INT_MAX, we let it fail as not an integer. Floats
49 * lose precision, so the <= and => operators might accidentally let a float
50 * through.
51 */
52
53 try {
54 $min = RandomCompat_intval($min);
55 } catch (TypeError $ex) {
56 throw new TypeError(
57 'random_int(): $min must be an integer'
58 );
59 }
60
61 try {
62 $max = RandomCompat_intval($max);
63 } catch (TypeError $ex) {
64 throw new TypeError(
65 'random_int(): $max must be an integer'
66 );
67 }
68
69 /**
70 * Now that we've verified our weak typing system has given us an integer,
71 * let's validate the logic then we can move forward with generating random
72 * integers along a given range.
73 */
74 if ($min > $max) {
75 throw new Error(
76 'Minimum value must be less than or equal to the maximum value'
77 );
78 }
79
80 if ($max === $min) {
81 return $min;
82 }
83
84 /**
85 * Initialize variables to 0
86 *
87 * We want to store:
88 * $bytes => the number of random bytes we need
89 * $mask => an integer bitmask (for use with the &) operator
90 * so we can minimize the number of discards
91 */
92 $attempts = $bits = $bytes = $mask = $valueShift = 0;
93
94 /**
95 * 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
97 * a float and we will lose some precision.
98 */
99 $range = $max - $min;
100
101 /**
102 * Test for integer overflow:
103 */
104 if (!is_int($range)) {
105
106 /**
107 * Still safely calculate wider ranges.
108 * Provided by @CodesInChaos, @oittaa
109 *
110 * @ref https://gist.github.com/CodesInChaos/03f9ea0b58e8b2b8d435
111 *
112 * We use ~0 as a mask in this case because it generates all 1s
113 *
114 * @ref https://eval.in/400356 (32-bit)
115 * @ref http://3v4l.org/XX9r5 (64-bit)
116 */
117 $bytes = PHP_INT_SIZE;
118 $mask = ~0;
119
120 } else {
121
122 /**
123 * $bits is effectively ceil(log($range, 2)) without dealing with
124 * type juggling
125 */
126 while ($range > 0) {
127 if ($bits % 8 === 0) {
128 ++$bytes;
129 }
130 ++$bits;
131 $range >>= 1;
132 $mask = $mask << 1 | 1;
133 }
134 $valueShift = $min;
135 }
136
137 $val = 0;
138 /**
139 * Now that we have our parameters set up, let's begin generating
140 * random integers until one falls between $min and $max
141 */
142 do {
143 /**
144 * The rejection probability is at most 0.5, so this corresponds
145 * to a failure probability of 2^-128 for a working RNG
146 */
147 if ($attempts > 128) {
148 throw new Exception(
149 'random_int: RNG is broken - too many rejections'
150 );
151 }
152
153 /**
154 * Let's grab the necessary number of random bytes
155 */
156 $randomByteString = random_bytes($bytes);
157
158 /**
159 * Let's turn $randomByteString into an integer
160 *
161 * This uses bitwise operators (<< and |) to build an integer
162 * out of the values extracted from ord()
163 *
164 * Example: [9F] | [6D] | [32] | [0C] =>
165 * 159 + 27904 + 3276800 + 201326592 =>
166 * 204631455
167 */
168 $val &= 0;
169 for ($i = 0; $i < $bytes; ++$i) {
170 $val |= ord($randomByteString[$i]) << ($i * 8);
171 }
172
173 /**
174 * Apply mask
175 */
176 $val &= $mask;
177 $val += $valueShift;
178
179 ++$attempts;
180 /**
181 * If $val overflows to a floating point number,
182 * ... or is larger than $max,
183 * ... or smaller than $min,
184 * then try again.
185 */
186 } while (!is_int($val) || $val > $max || $val < $min);
187
188 return (int)$val;
189 }
190 }
191