fwolf /
fwlib
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | namespace Fwlib\Util\Common; |
||
| 3 | |||
| 4 | /** |
||
| 5 | * Number util |
||
| 6 | * |
||
| 7 | * @copyright Copyright 2006-2015 Fwolf |
||
| 8 | * @license http://www.gnu.org/licenses/lgpl.html LGPL-3.0+ |
||
| 9 | */ |
||
| 10 | class NumberUtil |
||
| 11 | { |
||
| 12 | public $baseConvertMap = [ |
||
| 13 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', |
||
| 14 | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', |
||
| 15 | 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', |
||
| 16 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', |
||
| 17 | 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', |
||
| 18 | ]; |
||
| 19 | |||
| 20 | public $baseConvertMapReverse = [ |
||
| 21 | '0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, |
||
| 22 | '5' => 5, '6' => 6, '7' => 7, '8' => 8, '9' => 9, |
||
| 23 | 'a' => 10, 'b' => 11, 'c' => 12, 'd' => 13, 'e' => 14, |
||
| 24 | 'f' => 15, 'g' => 16, 'h' => 17, 'i' => 18, 'j' => 19, |
||
| 25 | 'k' => 20, 'l' => 21, 'm' => 22, 'n' => 23, 'o' => 24, |
||
| 26 | 'p' => 25, 'q' => 26, 'r' => 27, 's' => 28, 't' => 29, |
||
| 27 | 'u' => 30, 'v' => 31, 'w' => 32, 'x' => 33, 'y' => 34, |
||
| 28 | 'z' => 35, |
||
| 29 | 'A' => 36, 'B' => 37, 'C' => 38, 'D' => 39, 'E' => 40, |
||
| 30 | 'F' => 41, 'G' => 42, 'H' => 43, 'I' => 44, 'J' => 45, |
||
| 31 | 'K' => 46, 'L' => 47, 'M' => 48, 'N' => 49, 'O' => 50, |
||
| 32 | 'P' => 51, 'Q' => 52, 'R' => 53, 'S' => 54, 'T' => 55, |
||
| 33 | 'U' => 56, 'V' => 57, 'W' => 58, 'X' => 59, 'Y' => 60, |
||
| 34 | 'Z' => 61, |
||
| 35 | ]; |
||
| 36 | |||
| 37 | /** |
||
| 38 | * Number equal or larger than 100000000000000(1.0E+14) will represent by |
||
| 39 | * Scientific Notation(ç§‘å¦è®°æ•°æ³•), cause base_convert() loose precision. |
||
| 40 | * So for larger number, use BC Math or GMP. |
||
| 41 | * |
||
| 42 | * This array is used to check number string length per base, if string is |
||
| 43 | * longer than the array value, it should not use build-in base_convert(). |
||
| 44 | * |
||
| 45 | * @link https://gist.github.com/fwolf/7250392 |
||
| 46 | */ |
||
| 47 | public $baseConvertSafeLength = [ |
||
| 48 | 2 => 46, // 2^46 = 70368744177664 |
||
| 49 | 3 => 29, // 3^29 = 68630377364883 |
||
| 50 | 4 => 23, // 4^23 = 70368744177664 |
||
| 51 | 5 => 20, // 5^20 = 95367431640625 |
||
| 52 | 6 => 17, // 6^17 = 16926659444736 |
||
| 53 | 7 => 16, // 7^16 = 33232930569601 |
||
| 54 | 8 => 15, // 8^15 = 35184372088832 |
||
| 55 | 9 => 14, // 9^14 = 22876792454961 |
||
| 56 | 10 => 13, // 10^13 = 10000000000000 |
||
| 57 | 11 => 13, // 11^13 = 34522712143931 |
||
| 58 | 12 => 12, // 12^12 = 8916100448256 |
||
| 59 | 13 => 12, // 13^12 = 23298085122481 |
||
| 60 | 14 => 12, // 14^12 = 56693912375296 |
||
| 61 | 15 => 11, // 15^11 = 8649755859375 |
||
| 62 | 16 => 11, // 16^11 = 17592186044416 |
||
| 63 | 17 => 11, // 17^11 = 34271896307633, |
||
| 64 | 18 => 11, // 18^11 = 64268410079232, |
||
| 65 | 19 => 11, // 19^10 = 6131066257801, |
||
| 66 | 20 => 10, // 20^10 = 10240000000000, |
||
| 67 | 21 => 10, // 21^10 = 16679880978201, |
||
| 68 | 22 => 10, // 22^10 = 26559922791424, |
||
| 69 | 23 => 10, // 23^10 = 41426511213649, |
||
| 70 | 24 => 10, // 24^10 = 63403380965376, |
||
| 71 | 25 => 10, // 25^10 = 95367431640625, |
||
| 72 | 26 => 9, // 26^9 = 5429503678976, |
||
| 73 | 27 => 9, // 27^9 = 7625597484987, |
||
| 74 | 28 => 9, // 28^9 = 10578455953408, |
||
| 75 | 29 => 9, // 29^9 = 14507145975869, |
||
| 76 | 30 => 9, // 30^9 = 19683000000000, |
||
| 77 | 31 => 9, // 31^9 = 26439622160671, |
||
| 78 | 32 => 9, // 32^9 = 35184372088832, |
||
| 79 | 33 => 9, // 33^9 = 46411484401953, |
||
| 80 | 34 => 9, // 34^9 = 60716992766464, |
||
| 81 | 35 => 9, // 35^9 = 78815638671875, |
||
| 82 | 36 => 8, // 36^8 = 2821109907456, |
||
| 83 | 37 => 8, // 37^8 = 3512479453921, |
||
| 84 | 38 => 8, // 38^8 = 4347792138496, |
||
| 85 | 39 => 8, // 39^8 = 5352009260481, |
||
| 86 | 40 => 8, // 40^8 = 6553600000000, |
||
| 87 | 41 => 8, // 41^8 = 7984925229121, |
||
| 88 | 42 => 8, // 42^8 = 9682651996416, |
||
| 89 | 43 => 8, // 43^8 = 11688200277601, |
||
| 90 | 44 => 8, // 44^8 = 14048223625216, |
||
| 91 | 45 => 8, // 45^8 = 16815125390625, |
||
| 92 | 46 => 8, // 46^8 = 20047612231936, |
||
| 93 | 47 => 8, // 47^8 = 23811286661761, |
||
| 94 | 48 => 8, // 48^8 = 28179280429056, |
||
| 95 | 49 => 8, // 49^8 = 33232930569601, |
||
| 96 | 50 => 8, // 50^8 = 39062500000000, |
||
| 97 | 51 => 8, // 51^8 = 45767944570401, |
||
| 98 | 52 => 8, // 52^8 = 53459728531456, |
||
| 99 | 53 => 8, // 53^8 = 62259690411361, |
||
| 100 | 54 => 8, // 54^8 = 72301961339136, |
||
| 101 | 55 => 8, // 55^8 = 83733937890625, |
||
| 102 | 56 => 8, // 56^8 = 96717311574016, |
||
| 103 | 57 => 7, // 57^7 = 1954897493193, |
||
| 104 | 58 => 7, // 58^7 = 2207984167552, |
||
| 105 | 59 => 7, // 59^7 = 2488651484819, |
||
| 106 | 60 => 7, // 60^7 = 2799360000000, |
||
| 107 | 61 => 7, // 61^7 = 3142742836021, |
||
| 108 | 62 => 7, // 62^7 = 3521614606208, |
||
| 109 | ]; |
||
| 110 | |||
| 111 | |||
| 112 | /** |
||
| 113 | * Convert number string base, 2 to 62 |
||
| 114 | * |
||
| 115 | * @param string $number |
||
| 116 | * @param int $fromBase |
||
| 117 | * @param int $toBase |
||
| 118 | * @return string |
||
| 119 | */ |
||
| 120 | public function baseConvert($number, $fromBase, $toBase) |
||
| 121 | { |
||
| 122 | if (2 > $fromBase || 2 > $toBase || 62 < $fromBase || 62 < $toBase) { |
||
| 123 | throw new \InvalidArgumentException('Base must between 2 and 62.'); |
||
| 124 | } |
||
| 125 | |||
| 126 | |||
| 127 | $number = trim((string)$number); |
||
| 128 | if (empty($number)) { |
||
| 129 | return '0'; |
||
| 130 | } |
||
| 131 | |||
| 132 | |||
| 133 | // Simple convert use build-in base_convert() |
||
| 134 | if (36 >= $fromBase && 36 >= $toBase && |
||
| 135 | strlen($number) <= $this->baseConvertSafeLength[$fromBase] |
||
| 136 | ) { |
||
| 137 | return strtolower(base_convert($number, $fromBase, $toBase)); |
||
| 138 | } |
||
| 139 | |||
| 140 | |||
| 141 | $number = ltrim($number, '0'); // GMP treat leading 0 different. |
||
| 142 | |||
| 143 | // Convert using BC Math or GMP, sort by benchmark speed |
||
| 144 | // @codeCoverageIgnoreStart |
||
| 145 | if (extension_loaded('gmp') && version_compare(PHP_VERSION, '5.3.2', '>=')) { |
||
| 146 | // In PHP 5.3.2, base was extended to 2~62 |
||
| 147 | return $this->baseConvertGmpSimple($number, $fromBase, $toBase); |
||
| 148 | |||
| 149 | } elseif (extension_loaded('bcmath')) { |
||
| 150 | return $this->baseConvertBcmath($number, $fromBase, $toBase); |
||
| 151 | |||
| 152 | } elseif (extension_loaded('gmp')) { |
||
| 153 | return $this->baseConvertGmp($number, $fromBase, $toBase); |
||
| 154 | |||
| 155 | } else { |
||
| 156 | throw new \Exception('Number too large and BC Math or GMP not loaded.'); |
||
| 157 | } |
||
| 158 | // @codeCoverageIgnoreEnd |
||
| 159 | } |
||
| 160 | |||
| 161 | |||
| 162 | /** |
||
| 163 | * Convert number string base using BC Math |
||
| 164 | * |
||
| 165 | * @requires extension bcmath |
||
| 166 | */ |
||
| 167 | public function baseConvertBcmath($number, $fromBase, $toBase) |
||
| 168 | { |
||
| 169 | if (empty($number)) { |
||
| 170 | return '0'; |
||
| 171 | } |
||
| 172 | |||
| 173 | // @codeCoverageIgnoreStart |
||
| 174 | |||
| 175 | if (10 == $fromBase) { |
||
| 176 | $base10 = $number; |
||
| 177 | } else { |
||
| 178 | $base10 = 0; |
||
| 179 | View Code Duplication | for ($i = 0, $j = strlen($number); $i < $j; $i ++) { |
|
|
0 ignored issues
–
show
|
|||
| 180 | $n = $this->baseConvertMapReverse[$number{$i}]; |
||
| 181 | $base10 = bcadd($n, bcmul($base10, $fromBase)); |
||
| 182 | } |
||
| 183 | } |
||
| 184 | |||
| 185 | View Code Duplication | if (10 == $toBase) { |
|
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. Loading history...
|
|||
| 186 | return $base10; |
||
| 187 | } else { |
||
| 188 | $baseN = ''; |
||
| 189 | while (0 < bccomp($base10, '0', 0)) { |
||
| 190 | $r = intval(bcmod($base10, $toBase)); |
||
| 191 | $baseN = $this->baseConvertMap[$r] . $baseN; |
||
| 192 | $base10 = bcdiv($base10, $toBase, 0); |
||
| 193 | } |
||
| 194 | return $baseN; |
||
| 195 | } |
||
| 196 | |||
| 197 | // @codeCoverageIgnoreEnd |
||
| 198 | } |
||
| 199 | |||
| 200 | |||
| 201 | /** |
||
| 202 | * Convert number string base using GMP |
||
| 203 | * |
||
| 204 | * @requires extension gmp |
||
| 205 | */ |
||
| 206 | public function baseConvertGmp($number, $fromBase, $toBase) |
||
| 207 | { |
||
| 208 | if (empty($number)) { |
||
| 209 | return '0'; |
||
| 210 | } |
||
| 211 | |||
| 212 | // @codeCoverageIgnoreStart |
||
| 213 | |||
| 214 | // Almost same as bcmath, not fully tested |
||
| 215 | if (10 == $fromBase) { |
||
| 216 | $base10 = gmp_init("$number"); |
||
| 217 | } else { |
||
| 218 | $base10 = gmp_init('0'); |
||
| 219 | View Code Duplication | for ($i = 0, $j = strlen($number); $i < $j; $i ++) { |
|
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. Loading history...
|
|||
| 220 | $n = $this->baseConvertMapReverse[$number{$i}]; |
||
| 221 | $base10 = gmp_add("$n", gmp_mul($base10, "$fromBase")); |
||
| 222 | } |
||
| 223 | } |
||
| 224 | |||
| 225 | View Code Duplication | if (10 == $toBase) { |
|
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. Loading history...
|
|||
| 226 | return gmp_strval($base10); |
||
| 227 | } else { |
||
| 228 | $baseN = ''; |
||
| 229 | while (0 < gmp_cmp($base10, '0')) { |
||
| 230 | list($base10, $r) = gmp_div_qr($base10, "$toBase"); |
||
| 231 | $r = intval(gmp_strval($r)); |
||
| 232 | $baseN = $this->baseConvertMap[$r] . $baseN; |
||
| 233 | } |
||
| 234 | return $baseN; |
||
| 235 | } |
||
| 236 | |||
| 237 | // @codeCoverageIgnoreEnd |
||
| 238 | } |
||
| 239 | |||
| 240 | |||
| 241 | /** |
||
| 242 | * Convert number string base using GMP gmp_strval() |
||
| 243 | * |
||
| 244 | * @requires extension gmp |
||
| 245 | * @requires PHP 5.3.2 |
||
| 246 | */ |
||
| 247 | public function baseConvertGmpSimple($number, $fromBase, $toBase) |
||
| 248 | { |
||
| 249 | if (empty($number)) { |
||
| 250 | return '0'; |
||
| 251 | } |
||
| 252 | |||
| 253 | // @codeCoverageIgnoreStart |
||
| 254 | |||
| 255 | // GMP use 0-9a-z for base 11~36, and 0-9A-Za-z for base 37~62, so we |
||
| 256 | // need swap upper and lower case. |
||
| 257 | // @link http://stackoverflow.com/questions/2259666 |
||
| 258 | if (36 < $fromBase) { |
||
| 259 | $number = strtolower($number) ^ strtoupper($number) ^ $number; |
||
| 260 | } |
||
| 261 | |||
| 262 | $number = gmp_strval(gmp_init($number, $fromBase), $toBase); |
||
| 263 | |||
| 264 | if (36 < $toBase) { |
||
| 265 | $number = strtolower($number) ^ strtoupper($number) ^ $number; |
||
| 266 | } |
||
| 267 | |||
| 268 | return $number; |
||
| 269 | |||
| 270 | // @codeCoverageIgnoreEnd |
||
| 271 | } |
||
| 272 | |||
| 273 | |||
| 274 | /** |
||
| 275 | * Convert size to human readable format string |
||
| 276 | * |
||
| 277 | * @param int $size |
||
| 278 | * @param int $precision |
||
| 279 | * @param int $step Compute by 1024 or 1000 ? |
||
| 280 | * @return string |
||
| 281 | */ |
||
| 282 | public function toHumanSize($size, $precision = 1, $step = 1024) |
||
| 283 | { |
||
| 284 | $ranks = ['B', 'K', 'M', 'G', 'T', 'P']; |
||
| 285 | // Total 6 levels, loop from 0 to 5 just fit $ranks index |
||
| 286 | $i = 0; |
||
| 287 | while ($size > $step && $i <5) { |
||
| 288 | $size = $size / $step; |
||
| 289 | $i ++; |
||
| 290 | } |
||
| 291 | |||
| 292 | // Cut zero tail |
||
| 293 | $size = round($size, $precision); |
||
| 294 | if (0 == ($size - floor($size))) { |
||
| 295 | $size = floor($size); |
||
| 296 | } |
||
| 297 | |||
| 298 | return $size . $ranks[$i]; |
||
| 299 | } |
||
| 300 | } |
||
| 301 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.