不幸的是,我很不满意在这里和其他地方的答案是base_convert()
和其他基于浮点的转换策略对于加密目的会失去不可接受的精度。而且,这些实现中的大多数都不能处理足够大的密码应用程序数量。以下提供了两种对大型基地应该安全的基地转换方法。例如,将base256(二进制字符串)转换为base85表示并返回。
使用GMP
您可以使用GMP的转化斌<的成本做到这一点 - >十六进制二不需要时间以及局限于base62。
<?php
// Not bits, bytes.
$data = openssl_random_pseudo_bytes(256);
$base62 = gmp_strval(gmp_init(bin2hex($data), 16), 62);
$decoded = hex2bin(gmp_strval(gmp_init($base62, 62), 16));
var_dump(strcmp($decoded, $data) === 0); // true
纯PHP
如果你想超越base62到base85或轻微的性能提升,你需要像下面这样。
<?php
/**
* Divide a large number represented as a binary string in the specified base
* and return the remainder.
*
* @param string &$binary
* @param int $base
* @param int $start
*/
function divmod(&$binary, $base, $divisor, $start = 0)
{
/** @var int $size */
$size = strlen($binary);
// Do long division from most to least significant byte, keep remainder.
$remainder = 0;
for ($i = $start; $i < $size; $i++) {
// Get the byte value, 0-255 inclusive.
$digit = ord($binary[$i]);
// Shift the remainder left by base N bits, append the last byte.
$temp = ($remainder * $base) + $digit;
// Calculate the value for the current byte.
$binary[$i] = chr($temp/$divisor);
// Carry the remainder to the next byte.
$remainder = $temp % $divisor;
}
return $remainder;
}
/**
* Produce a base62 encoded string from a large binary number.
*
* @param string $binary
* return string
*/
function encodeBase62($binary)
{
$charMap = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
$base = strlen($charMap);
$size = strlen($binary);
$start = $size - strlen(ltrim($binary, "\0"));
$encoded = "";
for ($i = $start; $i < $size;) {
// Do long division from most to least significant byte, keep remainder.
$idx = divmod($binary, 256, $base, $i);
$encoded = $charMap[$idx] . $encoded;
if (ord($binary[$i]) == 0) {
$i++; // Skip leading zeros produced by the long division.
}
}
$encoded = str_pad($encoded, $start, "0", STR_PAD_LEFT);
return $encoded;
}
/**
* Produce a large binary number from a base62 encoded string.
*
* @param string $ascii
* return string
*/
function decodeBase62($ascii)
{
$charMap = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
$base = strlen($charMap);
$size = strlen($ascii);
$start = $size - strlen(ltrim($ascii, "0"));
// Convert the ascii representation to binary string.
$binary = "";
for ($i = $start; $i < $size; $i++) {
$byte = strpos($charMap, $ascii[$i]);
if ($byte === false) {
throw new OutOfBoundsException("Invlaid encoding at offset '{$ascii[$i]}'");
}
$binary .= chr($byte);
}
$decode = "";
for ($i = 0; $i < $size;) {
// Do long division from most to least significant byte, keep remainder.
$idx = divmod($binary, $base, 256, $i);
$decode = chr($idx) . $decode;
if (ord($binary[$i]) == 0) {
$i++; // Skip leading zeros produced by the long division.
}
}
$decode = ltrim($decode, "\0");
$decode = str_pad($decode, $start, "\0", STR_PAD_LEFT);
return $decode;
}
// Not bits, bytes.
$data = openssl_random_pseudo_bytes(256);
$base62 = encodeBase62($data);
$decoded = decodeBase62($base62);
var_dump(strcmp($decoded, $data) === 0); // true
感谢您的回复。刚刚得到另一个(相关)的问题。如果我用base_convert'base_convert(100000000,10,36);'转换一个数字,我可以通过更改函数中的基本顺序来取回原始数字,例如。 'base_convert(100000000,36,10);'。 – Roman
是的,当然可以 - 'base_convert('1njchs',36,10)=='100000000''。 – Gedrox