diff --git a/modules/openid/openid.inc b/modules/openid/openid.inc
index 44cdde2c36c..ff34f021914 100644
--- a/modules/openid/openid.inc
+++ b/modules/openid/openid.inc
@@ -283,15 +283,15 @@ function _openid_dh_binary_to_long($str) {
$n = 0;
foreach ($bytes as $byte) {
- $n = bcmul($n, pow(2, 8));
- $n = bcadd($n, $byte);
+ $n = _openid_math_mul($n, pow(2, 8));
+ $n = _openid_math_add($n, $byte);
}
return $n;
}
function _openid_dh_long_to_binary($long) {
- $cmp = bccomp($long, 0);
+ $cmp = _openid_math_cmp($long, 0);
if ($cmp < 0) {
return FALSE;
}
@@ -302,9 +302,9 @@ function _openid_dh_long_to_binary($long) {
$bytes = array();
- while (bccomp($long, 0) > 0) {
- array_unshift($bytes, bcmod($long, 256));
- $long = bcdiv($long, pow(2, 8));
+ while (_openid_math_cmp($long, 0) > 0) {
+ array_unshift($bytes, _openid_math_mod($long, 256));
+ $long = _openid_math_div($long, pow(2, 8));
}
if ($bytes && ($bytes[0] > 127)) {
@@ -347,11 +347,11 @@ function _openid_dh_rand($stop) {
$nbytes = strlen($rbytes);
}
- $mxrand = bcpow(256, $nbytes);
+ $mxrand = _openid_math_pow(256, $nbytes);
// If we get a number less than this, then it is in the
// duplicated range.
- $duplicate = bcmod($mxrand, $stop);
+ $duplicate = _openid_math_mod($mxrand, $stop);
if (count($duplicate_cache) > 10) {
$duplicate_cache = array();
@@ -364,9 +364,9 @@ function _openid_dh_rand($stop) {
$bytes = "\x00". _openid_get_bytes($nbytes);
$n = _openid_dh_binary_to_long($bytes);
// Keep looping if this value is in the low duplicated range.
- } while (bccomp($n, $duplicate) < 0);
+ } while (_openid_math_cmp($n, $duplicate) < 0);
- return bcmod($n, $stop);
+ return _openid_math_mod($n, $stop);
}
function _openid_get_bytes($num_bytes) {
@@ -391,7 +391,7 @@ function _openid_get_bytes($num_bytes) {
function _openid_response($str = NULL) {
$data = array();
-
+
if (isset($_SERVER['REQUEST_METHOD'])) {
$data = _openid_get_params($_SERVER['QUERY_STRING']);
@@ -442,3 +442,112 @@ if (!function_exists('bcpowmod')) {
return $result;
}
}
+
+/**
+ * Determine the available math library GMP vs. BCMath, favouring GMP for performance.
+ */
+function _openid_get_math_library() {
+ $library = &drupal_static(__FUNCTION__);
+
+ if (empty($library)) {
+ if (function_exists('gmp_add')) {
+ $library = 'gmp';
+ }
+ elseif (function_exists('bcadd')) {
+ $library = 'bcmath';
+ }
+ }
+
+ return $library;
+}
+
+/**
+ * Calls the add function from the available math library for OpenID.
+ */
+function _openid_math_add($x, $y) {
+ $library = _openid_get_math_library();
+ switch ($library) {
+ case 'gmp':
+ return gmp_strval(gmp_add($x, $y));
+ case 'bcmath':
+ return bcadd($x, $y);
+ }
+}
+
+/**
+ * Calls the mul function from the available math library for OpenID.
+ */
+function _openid_math_mul($x, $y) {
+ $library = _openid_get_math_library();
+ switch ($library) {
+ case 'gmp':
+ return gmp_mul($x, $y);
+ case 'bcmath':
+ return bcmul($x, $y);
+ }
+}
+
+/**
+ * Calls the div function from the available math library for OpenID.
+ */
+function _openid_math_div($x, $y) {
+ $library = _openid_get_math_library();
+ switch ($library) {
+ case 'gmp':
+ return gmp_div($x, $y);
+ case 'bcmath':
+ return bcdiv($x, $y);
+ }
+}
+
+/**
+ * Calls the cmp function from the available math library for OpenID.
+ */
+function _openid_math_cmp($x, $y) {
+ $library = _openid_get_math_library();
+ switch ($library) {
+ case 'gmp':
+ return gmp_cmp($x, $y);
+ case 'bcmath':
+ return bccomp($x, $y);
+ }
+}
+
+/**
+ * Calls the mod function from the available math library for OpenID.
+ */
+function _openid_math_mod($x, $y) {
+ $library = _openid_get_math_library();
+ switch ($library) {
+ case 'gmp':
+ return gmp_mod($x, $y);
+ case 'bcmath':
+ return bcmod($x, $y);
+ }
+}
+
+/**
+ * Calls the pow function from the available math library for OpenID.
+ */
+function _openid_math_pow($x, $y) {
+ $library = _openid_get_math_library();
+ switch ($library) {
+ case 'gmp':
+ return gmp_pow($x, $y);
+ case 'bcmath':
+ return bcpow($x, $y);
+ }
+}
+
+/**
+ * Calls the mul function from the available math library for OpenID.
+ */
+function _openid_math_powmod($x, $y, $z) {
+ $library = _openid_get_math_library();
+ switch ($library) {
+ case 'gmp':
+ return gmp_powm($x, $y, $z);
+ case 'bcmath':
+ return bcpowmod($x, $y, $z);
+ }
+}
diff --git a/modules/openid/openid.install b/modules/openid/openid.install
index 0abc24f6f29..b62e3e32e89 100644
--- a/modules/openid/openid.install
+++ b/modules/openid/openid.install
@@ -94,6 +94,40 @@ function openid_schema() {
return $schema;
}
+/**
+ * Implements hook_requirements().
+ */
+function openid_requirements($phase) {
+ $requirements = array();
+
+ if ($phase == 'runtime') {
+ // Check for the PHP BC Math library.
+ if (!function_exists('bcadd') && !function_exists('gmp_add')) {
+ $requirements['openid_math'] = array(
+ 'value' => t('Not installed'),
+ 'severity' => REQUIREMENT_INFO,
+ 'description' => t('OpenID suggests the use of either the GMP Math (recommended for performance) or BC Math libraries to enable OpenID associations.', array('@gmp' => 'http://php.net/manual/en/book.gmp.php', '@bc' => 'http://www.php.net/manual/en/book.bc.php')),
+ );
+ }
+ elseif (!function_exists('gmp_add')) {
+ $requirements['openid_math'] = array(
+ 'value' => t('Not optimized'),
+ 'severity' => REQUIREMENT_INFO,
+ 'description' => t('OpenID suggests the use of the GMP Math library for PHP for optimal performance. Check the GMP Math Library documentation for installation instructions.', array('@url' => 'http://www.php.net/manual/en/book.gmp.php')),
+ );
+ }
+ else {
+ $requirements['openid_math'] = array(
+ 'value' => t('Installed'),
+ 'severity' => REQUIREMENT_OK,
+ );
+ }
+ $requirements['openid_math']['title'] = t('OpenID Math library');
+ }
+
+ return $requirements;
+}
+
/**
* @addtogroup updates-6.x-extra
* @{
diff --git a/modules/openid/openid.module b/modules/openid/openid.module
index 88c4df6b7cc..3f669b5c013 100644
--- a/modules/openid/openid.module
+++ b/modules/openid/openid.module
@@ -178,9 +178,9 @@ function openid_begin($claimed_id, $return_to = '', $form_values = array()) {
$_SESSION['openid']['user_login_values'] = $form_values;
$op_endpoint = $services[0]['uri'];
- // If bcmath is present, then create an association
+ // If a supported math library is present, then create an association.
$assoc_handle = '';
- if (function_exists('bcadd')) {
+ if (_openid_get_math_library()) {
$assoc_handle = openid_association($op_endpoint);
}
@@ -373,8 +373,8 @@ function openid_association($op_endpoint) {
$mod = OPENID_DH_DEFAULT_MOD;
$gen = OPENID_DH_DEFAULT_GEN;
$r = _openid_dh_rand($mod);
- $private = bcadd($r, 1);
- $public = bcpowmod($gen, $private, $mod);
+ $private = _openid_math_add($r, 1);
+ $public = _openid_math_powmod($gen, $private, $mod);
// If there is no existing association, then request one
$assoc_request = openid_association_request($public);
@@ -393,7 +393,7 @@ function openid_association($op_endpoint) {
if ($assoc_response['session_type'] == 'DH-SHA1') {
$spub = _openid_dh_base64_to_long($assoc_response['dh_server_public']);
$enc_mac_key = base64_decode($assoc_response['enc_mac_key']);
- $shared = bcpowmod($spub, $private, $mod);
+ $shared = _openid_math_powmod($spub, $private, $mod);
$assoc_response['mac_key'] = base64_encode(_openid_dh_xorsecret($shared, $enc_mac_key));
}
db_query("INSERT INTO {openid_association} (idp_endpoint_uri, session_type, assoc_handle, assoc_type, expires_in, mac_key, created) VALUES('%s', '%s', '%s', '%s', %d, '%s', %d)",