`
天梯梦
  • 浏览: 13635346 次
  • 性别: Icon_minigender_2
  • 来自: 洛杉矶
社区版块
存档分类
最新评论

php创建短ID Create short IDs with PHP - Like Youtube or TinyURL

 
阅读更多

 

 

More is Less - the 'math'

The alphabet has 26 characters. That's a lot more than 10 digits. If we also distinguish upper- and lowercase, and add digits to the bunch or the heck of it, we already have (26 x 2 + 10) 62 options we can use per position in the ID.

Now of course we can also add additional funny characters to 'the bunch' like - / * & # but those may cause problems in URLs and that's our target audience for now.

OK so because there are roughly 6x more characters we will use per position, IDs will get much shorter. We can just fit a lot more data in each position.

This is basically what url shortening services do like tinyurl, is.gd, or bit.ly. But similar IDs can also be found at youtube: http://www.youtube.com/watch?v=yzNjIBEdyww

Convert your IDs

Now unlike Database servers: webservers are easy to scale so you can let them do a bit of converting to ease the life of your users, while keeping your database fast with numbers (MySQL really likes them plain numbers ; ).

To do the conversion I've written a PHP function that can translate big numbers to short strings and vice versa. I call it: alphaID.

The resulting string is not hard to decipher, but it can be a very nice feature to make URLs or directorie structures more compact and significant.

So basically:

  • when someone requests rLHWfKd
  • alphaID() converts it to 999999999999
  • you lookup the record for id 999999999999 in your database

 

 

Source

<?php
/**
 * Translates a number to a short alhanumeric version
 *
 * Translated any number up to 9007199254740992
 * to a shorter version in letters e.g.:
 * 9007199254740989 --> PpQXn7COf
 *
 * specifiying the second argument true, it will
 * translate back e.g.:
 * PpQXn7COf --> 9007199254740989
 *
 * this function is based on any2dec && dec2any by
 * fragmer[at]mail[dot]ru
 * see: http://nl3.php.net/manual/en/function.base-convert.php#52450
 *
 * If you want the alphaID to be at least 3 letter long, use the
 * $pad_up = 3 argument
 *
 * In most cases this is better than totally random ID generators
 * because this can easily avoid duplicate ID's.
 * For example if you correlate the alpha ID to an auto incrementing ID
 * in your database, you're done.
 *
 * The reverse is done because it makes it slightly more cryptic,
 * but it also makes it easier to spread lots of IDs in different
 * directories on your filesystem. Example:
 * $part1 = substr($alpha_id,0,1);
 * $part2 = substr($alpha_id,1,1);
 * $part3 = substr($alpha_id,2,strlen($alpha_id));
 * $destindir = "/".$part1."/".$part2."/".$part3;
 * // by reversing, directories are more evenly spread out. The
 * // first 26 directories already occupy 26 main levels
 *
 * more info on limitation:
 * - http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/165372
 *
 * if you really need this for bigger numbers you probably have to look
 * at things like: http://theserverpages.com/php/manual/en/ref.bc.php
 * or: http://theserverpages.com/php/manual/en/ref.gmp.php
 * but I haven't really dugg into this. If you have more info on those
 * matters feel free to leave a comment.
 *
 * The following code block can be utilized by PEAR's Testing_DocTest
 * <code>
 * // Input //
 * $number_in = 2188847690240;
 * $alpha_in  = "SpQXn7Cb";
 *
 * // Execute //
 * $alpha_out  = alphaID($number_in, false, 8);
 * $number_out = alphaID($alpha_in, true, 8);
 *
 * if ($number_in != $number_out) {
 *	 echo "Conversion failure, ".$alpha_in." returns ".$number_out." instead of the ";
 *	 echo "desired: ".$number_in."\n";
 * }
 * if ($alpha_in != $alpha_out) {
 *	 echo "Conversion failure, ".$number_in." returns ".$alpha_out." instead of the ";
 *	 echo "desired: ".$alpha_in."\n";
 * }
 *
 * // Show //
 * echo $number_out." => ".$alpha_out."\n";
 * echo $alpha_in." => ".$number_out."\n";
 * echo alphaID(238328, false)." => ".alphaID(alphaID(238328, false), true)."\n";
 *
 * // expects:
 * // 2188847690240 => SpQXn7Cb
 * // SpQXn7Cb => 2188847690240
 * // aaab => 238328
 *
 * </code>
 *
 * @author	Kevin van Zonneveld <kevin@vanzonneveld.net>
 * @author	Simon Franz
 * @author	Deadfish
 * @copyright 2008 Kevin van Zonneveld (http://kevin.vanzonneveld.net)
 * @license   http://www.opensource.org/licenses/bsd-license.php New BSD Licence
 * @version   SVN: Release: $Id: alphaID.inc.php 344 2009-06-10 17:43:59Z kevin $
 * @link	  http://kevin.vanzonneveld.net/
 *
 * @param mixed   $in	  String or long input to translate
 * @param boolean $to_num  Reverses translation when true
 * @param mixed   $pad_up  Number or boolean padds the result up to a specified length
 * @param string  $passKey Supplying a password makes it harder to calculate the original ID
 *
 * @return mixed string or long
 */
function alphaID($in, $to_num = false, $pad_up = false, $passKey = null)
{
	$index = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	if ($passKey !== null) {
		// Although this function's purpose is to just make the
		// ID short - and not so much secure,
		// with this patch by Simon Franz (http://blog.snaky.org/)
		// you can optionally supply a password to make it harder
		// to calculate the corresponding numeric ID

		for ($n = 0; $n<strlen($index); $n++) $i[] = substr( $index,$n ,1);

		$passhash = hash('sha256',$passKey);
		$passhash = (strlen($passhash) < strlen($index))
			? hash('sha512',$passKey)
			: $passhash;

		for ($n=0; $n < strlen($index); $n++) $p[] =  substr($passhash, $n ,1);

		array_multisort($p,  SORT_DESC, $i);
		$index = implode($i);
	}

	$base  = strlen($index);

	if ($to_num) {
		// Digital number  <<--  alphabet letter code
		$in  = strrev($in);
		$out = 0;
		$len = strlen($in) - 1;
		for ($t = 0; $t <= $len; $t++) {
			$bcpow = bcpow($base, $len - $t);
			$out   = $out + strpos($index, substr($in, $t, 1)) * $bcpow;
		}

		if (is_numeric($pad_up)) {
			$pad_up--;
			if ($pad_up > 0) $out -= pow($base, $pad_up);
		}
		$out = sprintf('%F', $out);
		$out = substr($out, 0, strpos($out, '.'));
	} 
	else 
	{
		// Digital number  -->>  alphabet letter code
		if (is_numeric($pad_up)) {
			$pad_up--;
			if ($pad_up > 0) $in += pow($base, $pad_up);
		}

		$out = "";
		for ($t = floor(log($in, $base)); $t >= 0; $t--) {
			$bcp = bcpow($base, $t);
			$a   = floor($in / $bcp) % $base;
			$out = $out . substr($index, $a, 1);
			$in  = $in - ($a * $bcp);
		}
		$out = strrev($out); // reverse
	}

	return $out;
}

 

Example

Running:

alphaID(9007199254740989);

will return 'PpQXn7COf' and:

alphaID('PpQXn7COf', true);

will return '9007199254740989'

Easy right?

More features

  • There also is an optional third argument: $pad_up. This enables you to make the resulting alphaId at least X characters long.
  • You can support even more characters (making the resulting alphaID even smaller) by adding characters to the $index var at the top of the function body.

 

 

 

JavaScript Implementation

Thanks to Even Simon, there's a JavaScript implementation. You will also find PHP version there, that implements the encode & decode functions as separate methods in a class.

<script>
/**
 *  Javascript AlphabeticID class
 *  (based on a script by Kevin van Zonneveld <kevin@vanzonneveld.net>)
 *
 *  Author: Even Simon <even.simon@gmail.com>
 *
 *  Description: Translates a numeric identifier into a short string and backwords.
 *
 *  Usage:
 *    var str = AlphabeticID.encode(9007199254740989); // str = 'fE2XnNGpF'
 *    var id = AlphabeticID.decode('fE2XnNGpF'); // id = 9007199254740989;
 **/
 
var AlphabeticID = {
  index:'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ',
 
  /**
   *  <a href="http://twitter.com/function">@function</a> AlphabeticID.encode
   *  <a href="http://twitter.com/description">@description</a> Encode a number into short string
   *  <a href="http://twitter.com/param">@param</a> integer
   *  <a href="http://twitter.com/return">@return</a> string
   **/
  encode:function(_number){
    if('undefined' == typeof _number){
      return null;
    }
    else if('number' != typeof(_number)){
      throw new Error('Wrong parameter type');
    }
 
    var ret = '';
 
    for(var i=Math.floor(Math.log(parseInt(_number))/Math.log(AlphabeticID.index.length));i>=0;i--){
      ret = ret + AlphabeticID.index.substr((Math.floor(parseInt(_number) / AlphabeticID.bcpow(AlphabeticID.index.length, i)) % AlphabeticID.index.length),1);
    }
 
    return ret.reverse();
  },
 
  /**
   *  <a href="http://twitter.com/function">@function</a> AlphabeticID.decode
   *  <a href="http://twitter.com/description">@description</a> Decode a short string and return number
   *  <a href="http://twitter.com/param">@param</a> string
   *  <a href="http://twitter.com/return">@return</a> integer
   **/
  decode:function(_string){
    if('undefined' == typeof _string){
      return null;
    }
    else if('string' != typeof _string){
      throw new Error('Wrong parameter type');
    }
 
    var str = _string.reverse();
    var ret = 0;
 
    for(var i=0;i<=(str.length - 1);i++){
      ret = ret + AlphabeticID.index.indexOf(str.substr(i,1)) * (AlphabeticID.bcpow(AlphabeticID.index.length, (str.length - 1) - i));
    }
 
    return ret;
  },
 
  /**
   *  <a href="http://twitter.com/function">@function</a> AlphabeticID.bcpow
   *  <a href="http://twitter.com/description">@description</a> Raise _a to the power _b
   *  <a href="http://twitter.com/param">@param</a> float _a
   *  <a href="http://twitter.com/param">@param</a> integer _b
   *  <a href="http://twitter.com/return">@return</a> string
   **/
  bcpow:function(_a, _b){
    return Math.floor(Math.pow(parseFloat(_a), parseInt(_b)));
  }
};
 
/**
 *  <a href="http://twitter.com/function">@function</a> String.reverse
 *  <a href="http://twitter.com/description">@description</a> Reverse a string
 *  <a href="http://twitter.com/return">@return</a> string
 **/
String.prototype.reverse = function(){
  return this.split('').reverse().join('');
};
</script>

 

 

Python Implementation

Thanks to wessite, there's a Python implementation.

 

ALPHABET = "bcdfghjklmnpqrstvwxyz0123456789BCDFGHJKLMNPQRSTVWXYZ"
BASE = len(ALPHABET)
MAXLEN = 6
 
def encode_id(self, n):
 
    pad = self.MAXLEN - 1
    n = int(n + pow(self.BASE, pad))
 
    s = []
    t = int(math.log(n, self.BASE))
    while True:
        bcp = int(pow(self.BASE, t))
        a = int(n / bcp) % self.BASE
        s.append(self.ALPHABET[a:a+1])
        n = n - (a * bcp)
        t -= 1
        if t < 0: break
 
    return "".join(reversed(s))
 
def decode_id(self, n):
 
    n = "".join(reversed(n))
    s = 0
    l = len(n) - 1
    t = 0
    while True:
        bcpow = int(pow(self.BASE, l - t))
        s = s + self.ALPHABET.index(n[t:t+1]) * bcpow
        t += 1
        if t > l: break
 
    pad = self.MAXLEN - 1
    s = int(s - pow(self.BASE, pad))
 
    return int(s)

 

Python Implementation

Thanks to Andy Li, there's a HaXe implementation.

 
/**
 *  HaXe version of AlphabeticID
 *  Author: Andy Li <andy@onthewings.net>
 *  ported from...
 *
 *  Javascript AlphabeticID class
 *  Author: Even Simon <even.simon@gmail.com>
 *  which is based on a script by Kevin van Zonneveld <kevin@vanzonneveld.net>)
 *
 *  Description: Translates a numeric identifier into a short string and backwords.
 *  http://kevin.vanzonneveld.net/techblog/article/create_short_ids_with_php_like_youtube_or_tinyurl/
 **/
 
class AlphaID {
    static public var index:String = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
 
    static public function encode(_number:Int):String {        
        var strBuf = new StringBuf();
 
        var i = 0;
        var end = Math.floor(Math.log(_number)/Math.log(index.length));
        while(i <= end) {
            strBuf.add(index.charAt((Math.floor(_number / bcpow(index.length, i++)) % index.length)));
        }
 
        return strBuf.toString();
    }
 
    static public function decode(_string:String):Int {
        var str = reverseString(_string);
        var ret = 0;
 
        var i = 0;
        var end = str.length - 1;
        while(i <= end) {
            ret += Std.int(index.indexOf(str.charAt(i)) * (bcpow(index.length, end-i)));
            ++i;
        }
 
        return ret;
    }
 
    inline static private function bcpow(_a:Float, _b:Float):Float {
        return Math.floor(Math.pow(_a, _b));
    }
 
    inline static private function reverseString(inStr:String):String {
        var ary = inStr.split("");
        ary.reverse();
        return ary.join("");
    }
}

 

 来源: http://kevin.vanzonneveld.net/techblog/article/create_short_ids_with_php_like_youtube_or_tinyurl/

 

 

分享到:
评论

相关推荐

    Laravel开发-laravel-tinyurl

    Laravel开发-laravel-tinyurl 用于Laravel的Tinyurl包。

    go-tinyurl:go-tinyurl

    go-tinyurl go-tinyurl:使用golang,gin和mongodb的URL缩短器

    Go-TinyUrl一个Golang开发的短网址服务

    一个很简单的短网址服务,支持自定义短链接规则,后台使用Golang 缓存 连接池,保功能简单的同时兼顾性能

    php短网址urlShortv2.0.0

    urlShort是一个类似于TinyURL,可以提供短网址服务的系统。urlShort基于PHP与MySQL开发,支持mod_rewrite,提供自定义短网址名称和API来创建短网址。

    tinyurl-client:在您JavaScript应用中轻松使用TinyURL。 该库不再维护

    $ npm install @kulkul/tinyurl-client 用它 import shortenUrl from "@kulkul/tinyurl-client" ; shortenUrl ( "https://kulkul.tech" ) . then ( ( result ) =&gt; { console . log ( { result } ) ; // ...

    php编写的tinyurl,网址压缩,域名压缩

    网址压缩,tinyUrl 基本环境要求: Mysql 3.x以上 PHP4以上 Apache ModRewrite Engine ON 安装步骤: 将所有文件上传到网站根目录(包括.htaccess) 设置根目录性为:777 设置config.php属性为:777 运行install.php...

    【PHP项目源码-毕业设计期末大作业】拓网短网址系统 v1.0_topwang_tinyurl_v1.zip

    PHP后端项目整站源码毕业设计期末大作业 PHP后端项目整站源码毕业设计期末大作业 PHP后端项目整站源码毕业设计期末大作业 PHP后端项目整站源码毕业设计期末大作业 PHP后端项目整站源码毕业设计期末大作业 PHP后端...

    discord-tinyurl:ord Discord机器人为链接,嵌入和附件创建微小的URL

    docker run -d -e " TOKEN=&lt;YOUR&gt; " --name discord-tinyurl --restart=always wlamason/discord-tinyurl 作者 :bust_in_silhouette: 威尔·拉马森 网站: : //wlamason.github.io/ GitHub : @wlamason 表示...

    dwz.cn,tinyurl.com短网址生成软件

    dwz.cn,tinyurl.com短网址生成软件,软件自动生成。

    Tinyurl-crx插件

    通过使用附加菜单或上下文菜单(右键单击)为当前页面创建一个简短的URL。 您可以在随机的tinyurl链接之间进行选择,也可以定义自定义别名。 之后,它将自动将结果URL复制到剪贴板。 此扩展是基于TinyURL URL缩短...

    TinyURL-crx插件

    从当今的嘲弄巨大URL创建一个微小的URL,在从电子邮件客户端和其他URI的软件启动时经常失败。 只需单击一下,活动选项卡中的URL将被发送到https://tinyurl.com,然后将微小的URL直接返回到剪贴板,准备粘贴。 没有...

    TinyURL Pro-crx插件

    tinyurl pro - 最优秀的URL缩短服务 顶部特点: - 绝对免费 - 不需要注册或登录 - 只需单击一次即可获得短USL - 将短URL自动复制到剪贴板 - 分享社交网络[很快..] - 直接链接和选定文本的上下文菜单(自动提取第一...

    Earth Engine UI Coding (tinyurl.com-g4g-ui-coding).pptx

    Earth Engine UI Coding (tinyurl.com-g4g-ui-coding).pptx

    URL -> TinyURL-crx插件

    语言:English (UK) 将长网址转换为可自定义的tinyurl.com/customName 帮助用户将当前页面的URL转换为可自定义的tinyURL! 例如:google.com-&gt; tinyurl.com/customName okkarmin.github.io-&gt; tinyurl.com/okkarmin

    tinyApp:Lighthouse W2项目-TinyURL克隆

    TinyApp是使用Node和Express构建的全栈Web应用程序,允许用户缩短URL(类似于goo.gl或tinyURL.com) 屏幕截图 依存关系 核心语言: "Node.js": "^9.4.0" 节点依赖关系(可通过npm ): " bcrypt " : " ^1.0.3 " ,...

    tinyurl-kubernetes:使用minikube在AWS中部署的tinyurl应用程序

    给定长网址,将其转换为短网址 给定短网址,返回原始网址 就是这样,但是请不要小看这里的挑战,您仍然会遇到在“复杂”应用程序中几乎会遇到的所有瓶颈:) 我们的“微型网址”应用程序将由3个服务组成: Django...

    TinyURL Maker-crx插件

    为您所在的当前选项卡创建一个全新的tinyurl! 您是否讨厌长链接,那么这是您的扩展。 Tinyurl Maker使用TinyURL API冷凝并缩短长URL。 简单的扩展,用于制作小型且易于共享的链接。 它将缩短您目前的任何网站。 ...

    urlShort v1.1.1.rar

    urlShort是一个类似于TinyURL,可以提供短网址服务的系统。urlShort基于PHP与MySQL开发,支持mod_rewrite,提供自定义短网址名称和API来创建短网址。

    urlShort v2.0.0.rar

    urlShort是一个类似于TinyURL,可以提供短网址服务的系统。urlShort基于PHP与MySQL开发,支持mod_rewrite,提供自定义短网址名称和API来创建短网址。

Global site tag (gtag.js) - Google Analytics