探寻后端技术之广之深
url中把业务id转为5位密文短链的算法

使用场景:

买家通过电商app下单后,会受到一条短信,短信内容中包括改订单详情页面的h5地址连接,因为是出现在短信中,所以对连接有要求:1.尽量短;2.安全性考虑,订单在数据库中对应的自增主键id不能暴露出来;3. url中id加密串位数要固定

解决思路:

  1. 要满足第2条要求,肯定是要对id进行某种加密后来展现到url中,其实方法有很多,可以通过把10进制id转为高进制(比如36进制)串;也可以直接对id进行md5加密。但是转换高进制的方式会位数不固定,这样不符合第3个条件。直接md5加密太长不满足条件2。鉴于此,要继续往下深入思考一下了
  2. 在搜索引擎如此发达的时代,如果什么事情都想着自己去原创,那样会显得太傻,于是,当你当前所能想出的方案不能解决问题时候,那就去度娘或者谷歌吧
  3. 于是去度娘敲下“微博短链”,深深可以借鉴,先粘上微博中url短链算法思路及代码如下:

    • 将长网址md5生成32位签名串,分为4段,每段8个字节;
    • 对这四段循环处理,取8个字节,将他看成16进制串与0x3fffffff(30位1)与操作,即超过30位的忽略处理;
    • 这30位分成6段,每5位的数字作为字母表的索引取得特定字符,依次进行获得6位字符串;
    • 总的md5串可以获得4个6位串;取里面的任意一个就可作为这个长url的短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;
      }
  4. 看了之后,真是啧啧称赞,肯定就用这个思路了,但是需要稍稍改良一下,因为 这个加密后有6位,而我们要求5位,需要注意的事:要满足不同id加密后的唯一性(其实是尽量保持低碰撞率);他的短链可表示的连接数为32的6次方约等于10亿个,我们改成6位后至少也要可以表示这个量级。
    废话少说,修改后的算法如下:

    function shortUrl($id='', $salt='') {
    
    $base64 = 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',
    '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' 
    );  
    $hex = md5($id.$salt);
    
    $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 < 5; $j++) {
    
            $val = 0x0000003F & $int;
            $val = $val % 62; 
            $out .= $base64[$val];
            $int = $int >> 6;
        }   
        $output[] = $out;
    }
    $in = 0x3 & (1 * ('0x'.substr($hex, 0, 1)));
    return $output[$in];
    }

nginx公众号也会推送好文,主要聊聊后端技术,扫描或者搜索nginx即可添加。 nginx公众号

暂无评论~~