我想出了以 90 为底的方法,用于将 md5 减少到 20 个多字节字符(我测试它可以正确地放入 mysql 的 varchar(20) 列中)。不幸的是,这实际上使字符串可能比 php 的 md5 中的 32 个字节还要大,唯一的优点是它们可以存储在 varchar(20) 列中。当然,如果您担心存储问题,您可以将字母表替换为单字节字母...
如果您的想法是在 mysql 之类的东西和其他类型的处理中使用这个简化的哈希作为查找键,则需要牢记一些重要的规则:
-
默认情况下,MySQL 不会在典型的 where 子句中区分大写和小写,该子句从可能的目标字母表中取出大量字符。这不仅包括英文字符,还包括几乎所有其他语言的字符。
-
重要的是,您的哈希可以透明地大写和小写,因为许多系统将这些键大写,因此为了在这个意义上保持它与 md5 一致,您应该在使用可区分大小写的字符时只使用小写。
这是我使用的字母表(我精心挑选了每个字符以使哈希值尽可能好):
define('NICIESTCHARS', [
"0","1","2","3","4","5","6","7","8","9",
"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z",
"¢","£","¥","§","¶","ø","œ","ƒ","α","δ","ε","η","θ","ι","λ","μ","ν","π","σ","τ","φ","ψ","ω","ћ","џ","ѓ","ѝ","й","ќ","ў","ф","э","ѣ","ѷ","ѻ","ѿ","ҁ","∂","∆","∑","√","∫",
"!","#","$","%","&","*","+","=","@","~","¤","±"
]);
这是 PHP 中的代码(我想它不是最好的代码,但可以完成工作)。请记住,它仅适用于长度为 8 的倍数的六进制 (0-F) 字符串,例如 php 中的 md5,即 32 个 0-f 字节:
function mbStringToArray ($string) {
$strlen = mb_strlen($string);
while ($strlen) {
$array[] = mb_substr($string,0,1,"UTF-8");
$string = mb_substr($string,1,$strlen,"UTF-8");
$strlen = mb_strlen($string);
}
return $array;
}
class Base90{
static function toHex5($s){
// Converts a base 90 number with a multiple of 5 digits to hex (compatible with "hexdec").
$chars = preg_split('//u', $s, null, PREG_SPLIT_NO_EMPTY);
$map = array_flip(NICIESTCHARS);
$rt = '';
$part = [];
$b90part = '';
foreach($chars as $c){
$b90part .= $c;
$part[] = $map[$c];
if(count($part) == 5){
$int = base90toInt($part);
$rt .= str_pad(dechex($int), 8, "0", STR_PAD_LEFT);
$part = [];
$b90part = '';
}
}
return $rt;
}
static function fromHex8($m){
// Converts an hexadecimal number compatible with "hexdec" to base 90
$parts = [];
$part = '';
foreach(str_split($m) as $i => $c){
$part.= $c;
if(strlen($part) === 8){
$parts[] = intToBase90(hexdec($part));
$part = '';
}
}
return implode('', $parts);
}
}
function intToBase90($int){
$residue = $int;
$result = [];
while($residue){
$digit = $residue % 90;
$residue -= $digit;
$residue = $residue / 90;
array_unshift($result, NICIESTCHARS[$digit]);
}
$result = implode('', $result);
return $result;
}
function base90toInt($digits){
$weight = 1;
$rt = 0;
while(count($digits)){
$rt += array_pop($digits)*$weight;
$weight *= 90;
}
return $rt;
}