微博短網址生成算法原理 by cubeking

      短網址(Short URL),顧名思義就是在形式上比較短的網址。通常用的是asp或者php轉向,在Web 2.0的今天,不得不說,這是一個潮流。目前已經有許多類似服務,藉助短網址您可以用簡短的網址替代原來冗長的網址,讓使用者可以更容易的分享鏈接。

例如:http://t.cn/SzjPjA  表示http://hi.baidu.com/cubeking/

  短網址服務,可能很多朋友都已經不再陌生,現在大部分微博、手機郵件提醒等地方已經有很多應用模式了,並佔據了一定的市場。估計很多朋友現在也正在使用。 

       看過新浪的短連接服務,發現後面主要有6個字符串組成,於是第一個想到的就是原來公司寫的一個遊戲激活碼規則,也就是下面的算法2,

26個大寫字母 26小寫字母,10個數字,隨機生成6個然後插入數據庫對應一個id,短連接跳轉的時候,根據字符串查詢到對應id,即可實現相應的跳轉!不過2的62次方,不知道有沒有重複的,小概率可以,但是對應不是很大的網站應該足夠了

自從twitter推出短網址(shorturl),繼之國內各大微博跟風,google公開goo.gl使用API,短網址之風愈演愈烈.不得不說這是一個新興又一大熱門web2.0服務.現整理一下,包括完整短網址網站,短網址生成原理,算法舉例,以及優劣比較,同時還介紹幾個phper個人實現的.

算法原理
算法一
1)將長網址md5生成32位簽名串,分爲4段, 每段8個字節;
2)對這四段循環處理, 取8個字節, 將他看成16進制串與0x3fffffff(30位1)與操作, 即超過30位的忽略處理;
3)這30位分成6段, 每5位的數字作爲字母表的索引取得特定字符, 依次進行獲得6位字符串;
4)總的md5串可以獲得4個6位串; 取裏面的任意一個就可作爲這個長url的短url地址;

這種算法,雖然會生成4個,但是仍然存在重複機率,下面的算法一和三,就是這種的實現.

算法二
a-zA-Z0-9 這64位取6位組合,可產生500多億個組合數量.把數字和字符組合做一定的映射,就可以產生唯一的字符串,如第62個組合就是aaaaa9,第63個組合就是aaaaba,再利用洗牌算法,把原字符串打亂後保存,那麼對應位置的組合字符串就會是無序的組合。
把長網址存入數據庫,取返回的id,找出對應的字符串,例如返回ID爲1,那麼對應上面的字符串組合就是bbb,同理 ID爲2時,字符串組合爲bba,依次類推,直至到達64種組合後纔會出現重複的可能,所以如果用上面的62個字符,任意取6個字符組合成字符串的話,你的數據存量達到500多億後纔會出現重複的可能。
具體參看這裏徹底完善新浪微博接口和超短URL算法,算法四可以算作是此算法的一種實現,此算法一般不會重複,但是如果是統計的話,就有很大問題,特別是對域名相關的統計,就抓瞎了.

簡單生成短網址方法

<?php

02function base62($x)03{04    $show= '';05    while($x> 0) {06        $s= $x% 62;07        if($s> 35) {08            $s= chr($s+61);            09        } elseif($s> 9 && $s<=35) {10            $s= chr($s+ 55);11        }12        $show.= $s;13        $x= floor($x/62);14    }15    return $show;    16}17  18function urlShort($url)19{20    $url= crc32($url);21    $result= sprintf("%u", $url);22    return base62($result);23}24  25echo urlShort("http://hi.baidu.com/cubeking/");?>
短網址算法枚舉

代碼如下:
<?php 
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; 

?>

另一個是純隨機數算法
<?php 
function random($length, $pool = '') 
    { 
        $random = ''; 
  
        if (empty($pool)) { 
            $pool    = 'abcdefghkmnpqrstuvwxyz'; 
            $pool   .= '23456789'; 
        } 
  
        srand ((double)microtime()*1000000); 
  
        for($i = 0; $i < $length; $i++)  
        { 
            $random .= substr($pool,(rand()%(strlen ($pool))), 1); 
        } 
  
        return $random; 
    } 
?>

各大微博短網址(ShortUrl)的算法 ,第一種算法的C#實現
<?php 
// 這是c#代碼,受編輯器的限制,只能用php 
public static string[] ShortUrl(string url) 
        { 
            //可以自定義生成MD5加密字符傳前的混合KEY 
            string key = "Leejor"; 
            //要使用生成URL的字符 
            string[] chars = new string[]{ 
                "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"

              }; 
            //對傳入網址進行MD5加密 
            string hex = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(key + url, "md5");

            string[] resUrl = new string[4];

            for (int i = 0; i < 4; i++) 
            { 
                //把加密字符按照8位一組16進制與0x3FFFFFFF進行位與運算 
                int hexint = 0x3FFFFFFF & Convert.ToInt32("0x" + hex.Substring(i * 8, 8), 16); 
                string outChars = string.Empty; 
                for (int j = 0; j < 6; j++) 
                { 
                    //把得到的值與0x0000003D進行位與運算,取得字符數組chars索引 
                    int index = 0x0000003D & hexint; 
                    //把取得的字符相加 
                    outChars += chars[index]; 
                    //每次循環按位右移5位 
                    hexint = hexint >> 5; 
                } 
                //把字符串存入對應索引的輸出數組 
                resUrl[i] = outChars; 
            }

            return resUrl; 
        } 
?>

高進制數字轉換,使用六十二進制將十進制數字變“短”。例如數據庫中第 56800235583 條信息,對應的短網址後綴可以是 ZZZZZZ 。
下面是存儲示例:

<?php 
//id 自增序列/自增編號 
//url 目標鏈接 
//*suffix* 短網址後綴 (並不需要存儲在數據庫內) 
+------------+-----------------------+---------+ 
|id          | url                   | *suffix*| 
+------------+-----------------------+---------+ 
|123456      | http://zoeey.com/     | w7e     | 
+------------+-----------------------+---------+ 
|123457      | http://www.zoeey.com/ | w7f     | 
+------------+-----------------------+---------+ 
|56800235582 | http://zoeey.org/     | ZZZZZY  | 
+------------+-----------------------+---------+ 
|56800235583 | http://www.zoeey.org/ | ZZZZZZ  | 
+------------+-----------------------+---------+ 
?> 
短網址使用流程:


提交網址存儲後獲取其編號 如:123456
用dec2Any將編號轉換爲62進制,並拼接網址 如:http://go.to/w7e
用戶訪問到 http://go.to/w7e 時,提取短網址後綴 w7e
用any2Dec將短網址後綴轉換爲10進制,得到鏈接編號 如:123456
使用編號查詢鏈接,並進行跳轉[/list]


下面是進制轉換所需要的源碼:
<?php 
/* 
* MoXie ([email protected]) 2010-6-30 17:53:57 
*  
* Copyright &copy; 2008-2010 Zoeey.Org . All rights are reserved. 
* Code license: Apache License  Version 2.0 
* http://www.apache.org/licenses/LICENSE-2.0.txt
*/ 
error_reporting(E_ALL);

/** 
* 返回一字符串,十進制 number 以 radix 進制的表示。 
* @param dec       需要轉換的數字 
* @param toRadix    輸出進制。當不在轉換範圍內時,此參數會被設定爲 2,以便及時發現。 
* @return    指定輸出進制的數字 
*/ 
function dec2Any($dec, $toRadix) { 
    $MIN_RADIX = 2; 
    $MAX_RADIX = 62; 
    $num62 = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; 
    if ($toRadix < $MIN_RADIX || $toRadix > $MAX_RADIX) { 
        $toRadix = 2; 
    } 
    if ($toRadix == 10) { 
        return $dec; 
    } 
    // -Long.MIN_VALUE 轉換爲 2 進制時長度爲65 
    $buf = array(); 
    $charPos = 64; 
    $isNegative = $dec < 0; //(bccomp($dec, 0) < 0); 
    if (!$isNegative) { 
        $dec = -$dec; // bcsub(0, $dec); 
    }

    while (bccomp($dec, -$toRadix) <= 0) { 
        $buf[$charPos--] = $num62[-bcmod($dec, $toRadix)]; 
        $dec = bcdiv($dec, $toRadix); 
    } 
    $buf[$charPos] = $num62[-$dec]; 
    if ($isNegative) { 
        $buf[--$charPos] = '-'; 
    } 
    $_any = ''; 
    for ($i = $charPos; $i < 65; $i++) { 
        $_any .= $buf[$i]; 
    } 
    return $_any; 
}

/** 
* 返回一字符串,包含 number 以 10 進制的表示。<br /> 
* fromBase 只能在 2 和 62 之間(包括 2 和 62)。 
* @param number    輸入數字 
* @param fromRadix    輸入進制 
* @return  十進制數字 
*/ 
function any2Dec($number, $fromRadix) { 
    $num62 = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; 
    $dec = 0; 
    $digitValue = 0; 
    $len = strlen($number) - 1; 
    for ($t = 0; $t <= $len; $t++) { 
        $digitValue = strpos($num62, $number[$t]); 
        $dec = bcadd(bcmul($dec, $fromRadix), $digitValue); 
    } 
    return $dec; 
}

$sol = '<br />' . PHP_EOL; 
echo dec2Any('56800235583', 62), $sol; // ZZZZZZ 
echo any2Dec('ZZZZZZ', 62), $sol; // 56800235583 
echo dec2Any('123456', 62), $sol; // w7e 
echo any2Dec('w7e', 62), $sol; // 123456 
?>

另外,介紹一下goo.gl接口api的應用.
據說此算法是各種短網址服務中 "......(這是)互聯網上最穩定、最安全、最快速的短網址服務。"(google聲稱)

有人做了比較,證明確實如此。

除了速度快,goo.gl還提供詳細的點擊統計。比如,Yahoo首頁的短網址是http://goo.gl/QuXj,那麼它的統計數據就在http://goo.gl/info/QuXj。加上後綴".qr",還能得到這個網址的二維條形碼,Yahoo的就是http://goo.gl/QuXj.qr。

詳細信息可從這查看:http://code.google.com/apis/urlshortener/overview.html

下面是http://www.biaodianfu.com/php-google-urlshortener-api.html弄的一個簡單的PHP調用API生成短網址方法,分享給大家。
在使用前,請先到這裏申請API Key:http://code.google.com/apis/console/
短網址的生成需要使用POST提交數據,所以使用了curl,短網址的還原可以直接使用file_get_contents()函數。不過爲了統一,也使用了curl來處理哈。
<?php 
// 生成 
function shortenGoogleUrl($long_url){ 
 $apiKey = 'API-KEY'; //Get API key from : http://code.google.com/apis/console/
 $postData = array('longUrl' => $long_url, 'key' => $apiKey); 
 $jsonData = json_encode($postData); 
 $curlObj = curl_init(); 
 curl_setopt($curlObj, CURLOPT_URL, 'https://www.googleapis.com/urlshortener/v1/url'); 
 curl_setopt($curlObj, CURLOPT_RETURNTRANSFER, 1); 
 curl_setopt($curlObj, CURLOPT_SSL_VERIFYPEER, 0); 
 curl_setopt($curlObj, CURLOPT_HEADER, 0); 
 curl_setopt($curlObj, CURLOPT_HTTPHEADER, array('Content-type:application/json')); 
 curl_setopt($curlObj, CURLOPT_POST, 1); 
 curl_setopt($curlObj, CURLOPT_POSTFIELDS, $jsonData); 
 $response = curl_exec($curlObj); 
 curl_close($curlObj); 
 $json = json_decode($response); 
 return $json->id; 
}

//還原 
function expandGoogleUrl($short_url){ 
 $curlObj = curl_init(); 
 curl_setopt($curlObj, CURLOPT_URL, 'https://www.googleapis.com/urlshortener/v1/url?shortUrl='.$short_url); 
 curl_setopt($curlObj, CURLOPT_HEADER, 0); 
 curl_setopt($curlObj, CURLOPT_RETURNTRANSFER, 1); 
 curl_setopt($curlObj, CURLOPT_SSL_VERIFYPEER, 0); 
 $response = curl_exec($curlObj); 
 curl_close($curlObj); 
 $json = json_decode($response); 
 return $json->longUrl; 

?>

 PHP SDK

  • 下載地址:http://code.google.com/p/libweibo/

(包含新版接口及OAuth2.0,由SAE提供維護,SAE平臺已集成最新版PHPSDK)


  • Demo使用教程
  1. 在open.weibo.com創建應用,得到AppKey,設置“授權設置”中的“應用回調頁”地址爲"http://host/callback.php",其中host爲網站域名。
  2. 下載Demo,然後解壓,修改config.php中的WB_AKEY爲App Key,WB_SKEY爲App Secret,WB_CALLBACK_URL爲剛纔填入的回調頁地址。
  3. 上傳到PHP空間即可
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章