今天遇到了一个将长链接转化成短链接的问题,苦思没有得到较好的无重复url的方案,遂到网上查了一个。
算法大致如下:
1)将长网址md5生成32位签名串,分为4段, 每段8个字节;
2)对这四段循环处理, 取8个字节, 将他看成16进制串与0x3fffffff(30位1)与操作, 即超过30位的忽略处理;
3)这30位分成6段, 每5位的数字作为字母表的索引取得特定字符, 依次进行获得6位字符串;
4)总的md5串可以获得4个6位串; 取里面的任意一个就可作为这个长url的短url地址;
实现如下:
1. 正则表达式匹配url,验证该长链接是否为正常url,最初写了一个preg_match pattern, /^http:\/\/([\w-]+\.)+[\w-]+([\w-.\/?%&=]*)?$/ 。这种可以直接匹配http开头的url,后来想了一下好像url不止http协议的吧,改成了/^(http|https|ftp):\/\/([\w-]+\.)+[\w-]+([\w-.\/?%&=]*)?$/。这样可以匹配ftp协议了。当然协议还有很多,就不一一列述了。代码实现:
const URL_PATTERN = "|^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$|"; const URL_PATTERN_MUTI = /^(http|https|ftp):\/\/([\w-]+\.)+[\w-]+([\w-.\/?%&=]*)?$/; $url = 'http://www.jb51.net/tools/zhengze.html'; $result = test_pregmatch_url($url); function test_pregmatch_url($url) { preg_match(self::URL_PATTERN_MUTI, $url, $match); return array_shift($match); }
2. 实现上述url转换短链算法。
function shorturl($input) { $base32 = array ( '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', '0', '1', '2', '3', '4', '5' ); $hex = md5($input); $hexLen = strlen($hex); $subHexLen = $hexLen / 8; $output = array(); for ($i = 0; $i < $subHexLen; $i++) { $subHex = substr ($hex, $i * 8, 8); $int = 0x3FFFFFFF & (1 * ('0x'.$subHex)); $out = ''; for ($j = 0; $j < 6; $j++) { $val = 0x0000001F & $int; $out .= $base32[$val]; $int = $int >> 5; } $output[] = $out; } return $output; }
3. 将生成短链作为redis的key,长链作为value存在redis中。同步到对应数据库表中。
4. 这样当浏览器通过该短链访问时,可从对应存储中得到长链然后parse_url提供服务。