前言:
工作需要,顺带研究下,参考资料 新浪微博地址url字符与mid的相互转换算法及原理 由于原文代码看起来有点挫,所以决定把他代码拿过来改改,自己写一个。
新浪微博链接格式为:http://weibo.com/用户id/mid?其它参数,例如 http://weibo.com/1646512101/A3m18DfFN?mod=weibotime 。而新浪的api有的接口是使用id作为参数,而我们获取的往往是一个url,也就是只能获取mid,所以需要一步转换。显然这一步转换只是个算法问题,新浪也是提供这样的api的,不过api接口调用频率有严格的限制,要是能在本地直接算出来不是更好?其实我觉得新浪把这算法公开不就得了,还省了很多流量。
算法原理:
目的是把 类似 'A3m18DfFN' 这样的串与 '3607996229355043' 这样的纯数字串互相转换。短的串看起来爽一点,而纯数字串在存储方面可能好些。
从纯数字到字母和数字组合的转换非常简单,这里用了62个字符做字典:"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
比如说有个纯数字串 “12153”,那转换结果就是"3a1" ( 12153 = 3 * 62^2 + 10*62^1 + 1*62^0 ),转换回来也是一样的道理。
而新浪的转换是把数字从末尾往前分成每7个数字一组进行转换,转换完再把结果合并起来。暂时还不清楚为什么要分组,直接转不就得了(有知道的告诉一声,谢谢)。
而转换回来把字母数字组合从末尾往前每四个一组进行转换,转换完再把结果合并起来。下面直接看代码吧:
class Str2numeric{
public static $str62 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static function id2mid($id)
{
$result = '';
$len = strlen($id);
$start = $len-7;
$end = $len;
for($i=$len-7;$i>-7;$i-=7){
$start = $i<0?0:$i;
$end = $i + 7;
$result = self::int10to62(substr($id,$start,$end-$start)) . $result;
}
return $result;
}
public static function int10to62($num)
{
$result = '';
while($num){
$result = self::$str62[$num%62] . $result;
$num = floor($num/62);
}
return $result;
}
public static function mid2id($mid)
{
$result = '';
$len = strlen($mid);
for($i=$len-4;$i>-4;$i-=4){
$start = $i<0?0:$i;
$end = $i + 4;
$result = self::str62to10(substr($mid,$start,$end-$start)) . $result;
}
return ltrim($result,0);
}
public static function str62to10($str62)
{
$num = 0;
$len = strlen($str62);
$power = 1;
for($i=$len-1;$i>=0;$i--){
$num += strpos(self::$str62,$str62[$i]) * $power;
$power *= 62;
}
$num = str_pad($num,7,"0",STR_PAD_LEFT);
return $num;
}
}
echo Str2numeric::id2mid('3605852122436718'),"\n",Str2numeric::mid2id('A2seUadTU'),"\n";
echo Str2numeric::id2mid('3607996229355043'),"\n",Str2numeric::mid2id('A3m18DfFN'),"\n";