|
TYPO3 API
SVNRelease
|
00001 <?php 00002 00003 /** 00004 * BigMath: A math library wrapper that abstracts out the underlying 00005 * long integer library. 00006 * 00007 * PHP versions 4 and 5 00008 * 00009 * LICENSE: See the COPYING file included in this distribution. 00010 * 00011 * @access private 00012 * @package OpenID 00013 * @author JanRain, Inc. <openid@janrain.com> 00014 * @copyright 2005-2008 Janrain, Inc. 00015 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache 00016 */ 00017 00018 /** 00019 * Needed for random number generation 00020 */ 00021 require_once 'Auth/OpenID/CryptUtil.php'; 00022 00023 /** 00024 * Need Auth_OpenID::bytes(). 00025 */ 00026 require_once 'Auth/OpenID.php'; 00027 00028 /** 00029 * The superclass of all big-integer math implementations 00030 * @access private 00031 * @package OpenID 00032 */ 00033 class Auth_OpenID_MathLibrary { 00034 /** 00035 * Given a long integer, returns the number converted to a binary 00036 * string. This function accepts long integer values of arbitrary 00037 * magnitude and uses the local large-number math library when 00038 * available. 00039 * 00040 * @param integer $long The long number (can be a normal PHP 00041 * integer or a number created by one of the available long number 00042 * libraries) 00043 * @return string $binary The binary version of $long 00044 */ 00045 function longToBinary($long) 00046 { 00047 $cmp = $this->cmp($long, 0); 00048 if ($cmp < 0) { 00049 $msg = __FUNCTION__ . " takes only positive integers."; 00050 trigger_error($msg, E_USER_ERROR); 00051 return null; 00052 } 00053 00054 if ($cmp == 0) { 00055 return "\x00"; 00056 } 00057 00058 $bytes = array(); 00059 00060 while ($this->cmp($long, 0) > 0) { 00061 array_unshift($bytes, $this->mod($long, 256)); 00062 $long = $this->div($long, pow(2, 8)); 00063 } 00064 00065 if ($bytes && ($bytes[0] > 127)) { 00066 array_unshift($bytes, 0); 00067 } 00068 00069 $string = ''; 00070 foreach ($bytes as $byte) { 00071 $string .= pack('C', $byte); 00072 } 00073 00074 return $string; 00075 } 00076 00077 /** 00078 * Given a binary string, returns the binary string converted to a 00079 * long number. 00080 * 00081 * @param string $binary The binary version of a long number, 00082 * probably as a result of calling longToBinary 00083 * @return integer $long The long number equivalent of the binary 00084 * string $str 00085 */ 00086 function binaryToLong($str) 00087 { 00088 if ($str === null) { 00089 return null; 00090 } 00091 00092 // Use array_merge to return a zero-indexed array instead of a 00093 // one-indexed array. 00094 $bytes = array_merge(unpack('C*', $str)); 00095 00096 $n = $this->init(0); 00097 00098 if ($bytes && ($bytes[0] > 127)) { 00099 trigger_error("bytesToNum works only for positive integers.", 00100 E_USER_WARNING); 00101 return null; 00102 } 00103 00104 foreach ($bytes as $byte) { 00105 $n = $this->mul($n, pow(2, 8)); 00106 $n = $this->add($n, $byte); 00107 } 00108 00109 return $n; 00110 } 00111 00112 function base64ToLong($str) 00113 { 00114 $b64 = base64_decode($str); 00115 00116 if ($b64 === false) { 00117 return false; 00118 } 00119 00120 return $this->binaryToLong($b64); 00121 } 00122 00123 function longToBase64($str) 00124 { 00125 return base64_encode($this->longToBinary($str)); 00126 } 00127 00128 /** 00129 * Returns a random number in the specified range. This function 00130 * accepts $start, $stop, and $step values of arbitrary magnitude 00131 * and will utilize the local large-number math library when 00132 * available. 00133 * 00134 * @param integer $start The start of the range, or the minimum 00135 * random number to return 00136 * @param integer $stop The end of the range, or the maximum 00137 * random number to return 00138 * @param integer $step The step size, such that $result - ($step 00139 * * N) = $start for some N 00140 * @return integer $result The resulting randomly-generated number 00141 */ 00142 function rand($stop) 00143 { 00144 static $duplicate_cache = array(); 00145 00146 // Used as the key for the duplicate cache 00147 $rbytes = $this->longToBinary($stop); 00148 00149 if (array_key_exists($rbytes, $duplicate_cache)) { 00150 list($duplicate, $nbytes) = $duplicate_cache[$rbytes]; 00151 } else { 00152 if ($rbytes[0] == "\x00") { 00153 $nbytes = Auth_OpenID::bytes($rbytes) - 1; 00154 } else { 00155 $nbytes = Auth_OpenID::bytes($rbytes); 00156 } 00157 00158 $mxrand = $this->pow(256, $nbytes); 00159 00160 // If we get a number less than this, then it is in the 00161 // duplicated range. 00162 $duplicate = $this->mod($mxrand, $stop); 00163 00164 if (count($duplicate_cache) > 10) { 00165 $duplicate_cache = array(); 00166 } 00167 00168 $duplicate_cache[$rbytes] = array($duplicate, $nbytes); 00169 } 00170 00171 do { 00172 $bytes = "\x00" . Auth_OpenID_CryptUtil::getBytes($nbytes); 00173 $n = $this->binaryToLong($bytes); 00174 // Keep looping if this value is in the low duplicated range 00175 } while ($this->cmp($n, $duplicate) < 0); 00176 00177 return $this->mod($n, $stop); 00178 } 00179 } 00180 00181 /** 00182 * Exposes BCmath math library functionality. 00183 * 00184 * {@link Auth_OpenID_BcMathWrapper} wraps the functionality provided 00185 * by the BCMath extension. 00186 * 00187 * @access private 00188 * @package OpenID 00189 */ 00190 class Auth_OpenID_BcMathWrapper extends Auth_OpenID_MathLibrary{ 00191 var $type = 'bcmath'; 00192 00193 function add($x, $y) 00194 { 00195 return bcadd($x, $y); 00196 } 00197 00198 function sub($x, $y) 00199 { 00200 return bcsub($x, $y); 00201 } 00202 00203 function pow($base, $exponent) 00204 { 00205 return bcpow($base, $exponent); 00206 } 00207 00208 function cmp($x, $y) 00209 { 00210 return bccomp($x, $y); 00211 } 00212 00213 function init($number, $base = 10) 00214 { 00215 return $number; 00216 } 00217 00218 function mod($base, $modulus) 00219 { 00220 return bcmod($base, $modulus); 00221 } 00222 00223 function mul($x, $y) 00224 { 00225 return bcmul($x, $y); 00226 } 00227 00228 function div($x, $y) 00229 { 00230 return bcdiv($x, $y); 00231 } 00232 00233 /** 00234 * Same as bcpowmod when bcpowmod is missing 00235 * 00236 * @access private 00237 */ 00238 function _powmod($base, $exponent, $modulus) 00239 { 00240 $square = $this->mod($base, $modulus); 00241 $result = 1; 00242 while($this->cmp($exponent, 0) > 0) { 00243 if ($this->mod($exponent, 2)) { 00244 $result = $this->mod($this->mul($result, $square), $modulus); 00245 } 00246 $square = $this->mod($this->mul($square, $square), $modulus); 00247 $exponent = $this->div($exponent, 2); 00248 } 00249 return $result; 00250 } 00251 00252 function powmod($base, $exponent, $modulus) 00253 { 00254 if (function_exists('bcpowmod')) { 00255 return bcpowmod($base, $exponent, $modulus); 00256 } else { 00257 return $this->_powmod($base, $exponent, $modulus); 00258 } 00259 } 00260 00261 function toString($num) 00262 { 00263 return $num; 00264 } 00265 } 00266 00267 /** 00268 * Exposes GMP math library functionality. 00269 * 00270 * {@link Auth_OpenID_GmpMathWrapper} wraps the functionality provided 00271 * by the GMP extension. 00272 * 00273 * @access private 00274 * @package OpenID 00275 */ 00276 class Auth_OpenID_GmpMathWrapper extends Auth_OpenID_MathLibrary{ 00277 var $type = 'gmp'; 00278 00279 function add($x, $y) 00280 { 00281 return gmp_add($x, $y); 00282 } 00283 00284 function sub($x, $y) 00285 { 00286 return gmp_sub($x, $y); 00287 } 00288 00289 function pow($base, $exponent) 00290 { 00291 return gmp_pow($base, $exponent); 00292 } 00293 00294 function cmp($x, $y) 00295 { 00296 return gmp_cmp($x, $y); 00297 } 00298 00299 function init($number, $base = 10) 00300 { 00301 return gmp_init($number, $base); 00302 } 00303 00304 function mod($base, $modulus) 00305 { 00306 return gmp_mod($base, $modulus); 00307 } 00308 00309 function mul($x, $y) 00310 { 00311 return gmp_mul($x, $y); 00312 } 00313 00314 function div($x, $y) 00315 { 00316 return gmp_div_q($x, $y); 00317 } 00318 00319 function powmod($base, $exponent, $modulus) 00320 { 00321 return gmp_powm($base, $exponent, $modulus); 00322 } 00323 00324 function toString($num) 00325 { 00326 return gmp_strval($num); 00327 } 00328 } 00329 00330 /** 00331 * Define the supported extensions. An extension array has keys 00332 * 'modules', 'extension', and 'class'. 'modules' is an array of PHP 00333 * module names which the loading code will attempt to load. These 00334 * values will be suffixed with a library file extension (e.g. ".so"). 00335 * 'extension' is the name of a PHP extension which will be tested 00336 * before 'modules' are loaded. 'class' is the string name of a 00337 * {@link Auth_OpenID_MathWrapper} subclass which should be 00338 * instantiated if a given extension is present. 00339 * 00340 * You can define new math library implementations and add them to 00341 * this array. 00342 */ 00343 function Auth_OpenID_math_extensions() 00344 { 00345 $result = array(); 00346 00347 if (!defined('Auth_OpenID_BUGGY_GMP')) { 00348 $result[] = 00349 array('modules' => array('gmp', 'php_gmp'), 00350 'extension' => 'gmp', 00351 'class' => 'Auth_OpenID_GmpMathWrapper'); 00352 } 00353 00354 $result[] = array( 00355 'modules' => array('bcmath', 'php_bcmath'), 00356 'extension' => 'bcmath', 00357 'class' => 'Auth_OpenID_BcMathWrapper'); 00358 00359 return $result; 00360 } 00361 00362 /** 00363 * Detect which (if any) math library is available 00364 */ 00365 function Auth_OpenID_detectMathLibrary($exts) 00366 { 00367 $loaded = false; 00368 $hasDl = function_exists('dl'); 00369 00370 foreach ($exts as $extension) { 00371 // See if the extension specified is already loaded. 00372 if ($extension['extension'] && 00373 extension_loaded($extension['extension'])) { 00374 $loaded = true; 00375 } 00376 00377 // Try to load dynamic modules. 00378 if (!$loaded && $hasDl) { 00379 foreach ($extension['modules'] as $module) { 00380 if (@dl($module . "." . PHP_SHLIB_SUFFIX)) { 00381 $loaded = true; 00382 break; 00383 } 00384 } 00385 } 00386 00387 // If the load succeeded, supply an instance of 00388 // Auth_OpenID_MathWrapper which wraps the specified 00389 // module's functionality. 00390 if ($loaded) { 00391 return $extension; 00392 } 00393 } 00394 00395 return false; 00396 } 00397 00398 /** 00399 * {@link Auth_OpenID_getMathLib} checks for the presence of long 00400 * number extension modules and returns an instance of 00401 * {@link Auth_OpenID_MathWrapper} which exposes the module's 00402 * functionality. 00403 * 00404 * Checks for the existence of an extension module described by the 00405 * result of {@link Auth_OpenID_math_extensions()} and returns an 00406 * instance of a wrapper for that extension module. If no extension 00407 * module is found, an instance of {@link Auth_OpenID_MathWrapper} is 00408 * returned, which wraps the native PHP integer implementation. The 00409 * proper calling convention for this method is $lib =& 00410 * Auth_OpenID_getMathLib(). 00411 * 00412 * This function checks for the existence of specific long number 00413 * implementations in the following order: GMP followed by BCmath. 00414 * 00415 * @return Auth_OpenID_MathWrapper $instance An instance of 00416 * {@link Auth_OpenID_MathWrapper} or one of its subclasses 00417 * 00418 * @package OpenID 00419 */ 00420 function &Auth_OpenID_getMathLib() 00421 { 00422 // The instance of Auth_OpenID_MathWrapper that we choose to 00423 // supply will be stored here, so that subseqent calls to this 00424 // method will return a reference to the same object. 00425 static $lib = null; 00426 00427 if (isset($lib)) { 00428 return $lib; 00429 } 00430 00431 if (Auth_OpenID_noMathSupport()) { 00432 $null = null; 00433 return $null; 00434 } 00435 00436 // If this method has not been called before, look at 00437 // Auth_OpenID_math_extensions and try to find an extension that 00438 // works. 00439 $ext = Auth_OpenID_detectMathLibrary(Auth_OpenID_math_extensions()); 00440 if ($ext === false) { 00441 $tried = array(); 00442 foreach (Auth_OpenID_math_extensions() as $extinfo) { 00443 $tried[] = $extinfo['extension']; 00444 } 00445 $triedstr = implode(", ", $tried); 00446 00447 Auth_OpenID_setNoMathSupport(); 00448 00449 $result = null; 00450 return $result; 00451 } 00452 00453 // Instantiate a new wrapper 00454 $class = $ext['class']; 00455 $lib = new $class(); 00456 00457 return $lib; 00458 } 00459 00460 function Auth_OpenID_setNoMathSupport() 00461 { 00462 if (!defined('Auth_OpenID_NO_MATH_SUPPORT')) { 00463 define('Auth_OpenID_NO_MATH_SUPPORT', true); 00464 } 00465 } 00466 00467 function Auth_OpenID_noMathSupport() 00468 { 00469 return defined('Auth_OpenID_NO_MATH_SUPPORT'); 00470 } 00471 00472 ?>
1.8.0