您的位置:首页 > 编程语言 > PHP开发

微博URL短网址生成算法原理及(java版、php版实现实例)

2017-06-09 11:03 1071 查看
短网址(Short URL),顾名思义就是在形式上比较短的网址。通常用的是asp或者php转向,在Web 2.0的今天,不得不说,这是一个潮流。目前已经有许多类似服务,借助短网址您可以用简短的网址替代原来冗长的网址,让使用者可以更容易的分享链接。
例如:http://t.cn/SzjPjA
 

短网址服务,可能很多朋友都已经不再陌生,现在大部分微博、手机邮件提醒等地方已经有很多应用模式了,并占据了一定的市场。估计很多朋友现在也正在使用。 
       看过新浪的短连接服务,发现后面主要有6个字符串组成,于是第一个想到的就是原来公司写的一个游戏激活码规则,也就是下面的算法2,
26个大写字母 26小写字母,10个数字,随机生成6个然后插入数据库对应一个id,短连接跳转的时候,根据字符串查询到对应id,即可实现相应的跳转!不过2的62次方,不知道有没有重复的,小概率可以,但是对应不是很大的网站应该足够了
自从twitter推出短网址(shorturl),继之国内各大微博跟风,google公开goo.gl使用API,短网址之风愈演愈烈.不得不说这是一个新兴又一大热门web2.0服务.现整理一下,包括完整短网址网站,短网址生成原理,算法举例,以及优劣比较,同时还介绍几个phper个人实现的。
 
短链接的好处
 
1、内容需要;2、用户友好;3、便于管理。
 

为什么要这样做的,原因我想有这样几点:
微博限制字数为140字一条,那么如果我们需要发一些连接上去,但是这个连接非常的长,以至于将近要占用我们内容的一半篇幅,这肯定是不能被允许的,所以短网址应运而生了。
短网址可以在我们项目里可以很好的对开放级URL进行管理。有一部分网址可以会涵盖暴力,广告等信息,这样我们可以通过用户的举报,完全管理这个连接将不出现在我们的应用中,应为同样的URL通过加密算法之后,得到的地址是一样的。
我们可以对一系列的网址进行流量,点击等统计,挖掘出大多数用户的关注点,这样有利于我们对项目的后续工作更好的作出决策。

算法原理
算法一
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算法,算法四可以算作是此算法的一种实现,此算法一般不会重复,但是如果是统计的话,就有很大问题,特别是对域名相关的统计,就抓瞎了。

 
java语言实现:

Java代码

public class ShortUrlGenerator {

/**
* @param args
*/
public static void main(String[] args) {

String sLongUrl = "http://474515923.qzone.qq.com" ; //长链接
String[] aResult = shortUrl (sLongUrl);
// 打印出结果
for ( int i = 0; i < aResult. length ; i++) {
System. out .println( "[" + i + "]:::" + aResult[i]);
}
}

public static String[] shortUrl(String url) {
// 可以自定义生成 MD5 加密字符传前的混合 KEY
String key = "mengdelong" ;
// 要使用生成 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 sMD5EncryptResult = ( new CMyEncrypt()).md5(key + url);
String hex = sMD5EncryptResult;

String[] resUrl = new String[4];
for ( int i = 0; i < 4; i++) {

// 把加密字符按照 8 位一组 16 进制与 0x3FFFFFFF 进行位与运算
String sTempSubString = hex.substring(i * 8, i * 8 + 8);

// 这里需要使用 long 型来转换,因为 Inteper .parseInt() 只能处理 31 位 , 首位为符号位 , 如果不用 long ,则会越界
long lHexLong = 0x3FFFFFFF & Long.parseLong (sTempSubString, 16);
String outChars = "" ;
for ( int j = 0; j < 6; j++) {
// 把得到的值与 0x0000003D 进行位与运算,取得字符数组 chars 索引
long index = 0x0000003D & lHexLong;
// 把取得的字符相加
outChars += chars[( int ) index];
// 每次循环按位右移 5 位
lHexLong = lHexLong >> 5;
}
// 把字符串存入对应索引的输出数组
resUrl[i] = outChars;
}
return resUrl;
}
}


 

以下为php语言实现:

Php代码 

<?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代码 

<?php
function random($length, $pool = '')
{
$random = '';

if (emptyempty($pool)) {
$pool    = 'abcdefghkmnpqrstuvwxyz';
$pool   .= '23456789';
}

srand ((double)microtime()*1000000);

for($i = 0; $i < $length; $i++)
{
$random .= substr($pool,(rand()%(strlen ($pool))), 1);
}

return $random;
}
?>


 

 

跳转原理

当我们生成短链接之后,只需要在表中(数据库或者NoSql )存储原始链接与短链接的映射关系即可。当我们访问短链接时,只需要从映射关系中找到原始链接,即可跳转到原始链接。

 

 

 

附:控制长度?

package testjava;

import java.util.HashMap;
import java.util.Random;

/*
* URL Shortener
*/
public class URLShortener {
// storage for generated keys
private HashMap<String, String> keyMap; // key-url map
private HashMap<String, String> valueMap;// url-key map to quickly check
// whether an url is
// already entered in our system
private String domain; // Use this attribute to generate urls for a custom
// domain name defaults to http://fkt.in private char myChars[]; // This array is used for character to number
// mapping
private Random myRand; // Random object used to generate random integers
private int keyLength; // the key length in URL defaults to 8

// Default Constructor
URLShortener() {
keyMap = new HashMap<String, String>();
valueMap = new HashMap<String, String>();
myRand = new Random();
keyLength = 8;
myChars = new char[62];
for (int i = 0; i < 62; i++) {
int j = 0;
if (i < 10) {
j = i + 48;
} else if (i > 9 && i <= 35) {
j = i + 55;
} else {
j = i + 61;
}
myChars[i] = (char) j;
}
domain = "http://fkt.in";
}

// Constructor which enables you to define tiny URL key length and base URL
// name
URLShortener(int length, String newDomain) {
this();
this.keyLength = length;
if (!newDomain.isEmpty()) {
newDomain = sanitizeURL(newDomain);
domain = newDomain;
}
}

// shortenURL
// the public method which can be called to shorten a given URL
public String shortenURL(String longURL) {
String shortURL = "";
if (validateURL(longURL)) {
longURL = sanitizeURL(longURL);
if (valueMap.containsKey(longURL)) {
shortURL = domain + "/" + valueMap.get(longURL);
} else {
shortURL = domain + "/" + getKey(longURL);
}
}
// add http part
return shortURL;
}

// expandURL
// public method which returns back the original URL given the shortened url
public String expandURL(String shortURL) {
String longURL = "";
String key = shortURL.substring(domain.length() + 1);
longURL = keyMap.get(key);
return longURL;
}

// Validate URL
// not implemented, but should be implemented to check whether the given URL
// is valid or not
boolean validateURL(String url) {
return true;
}

// sanitizeURL
// This method should take care various issues with a valid url
// e.g. www.google.com,www.google.com/, http://www.google.com, // http://www.google.com/ // all the above URL should point to same shortened URL
// There could be several other cases like these.
String sanitizeURL(String url) {
if (url.substring(0, 7).equals("http://"))
url = url.substring(7);

if (url.substring(0, 8).equals("https://"))
url = url.substring(8);

if (url.charAt(url.length() - 1) == '/')
url = url.substring(0, url.length() - 1);
return url;
}

/*
* Get Key method
*/
private String getKey(String longURL) {
String key;
key = generateKey();
keyMap.put(key, longURL);
valueMap.put(longURL, key);
return key;
}

// generateKey
private String generateKey() {
String key = "";
boolean flag = true;
while (flag) {
key = "";
for (int i = 0; i <= keyLength; i++) {
key += myChars[myRand.nextInt(62)];
}
// System.out.println("Iteration: "+ counter + "Key: "+ key);
if (!keyMap.containsKey(key)) {
flag = false;
}
}
return key;
}

// test the code
public static void main(String args[]) {
URLShortener u = new URLShortener(5, "www.tinyurl.com/");
String urls[] = { "www.google.com/", "www.google.com",
"http://www.yahoo.com", "www.yahoo.com/", "www.amazon.com",
"www.amazon.com/page1.php", "www.amazon.com/page2.php",
"www.flipkart.in", "www.rediff.com", "www.techmeme.com",
"www.techcrunch.com", "www.lifehacker.com", "www.icicibank.com" };

for (int i = 0; i < urls.length; i++) {
System.out.println("URL:" + urls[i] + "\tTiny: "
+ u.shortenURL(urls[i]) + "\tExpanded: "
+ u.expandURL(u.shortenURL(urls[i])));
}
}
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: