php创建短ID PHPで短いIDを作成する - YoutubeやTinyURL
など
?
?
アルファベットは 26 文字です。それは10桁をはるかに超えています。大文字と小文字も区別し、その束または全体に数字を追加すると、位置ごとに (26 x 2 + 10)?62 個のオプション? を使用できるようになります。 ?ID 内にあります。
もちろん、- / * & # のような面白い文字を「束」に追加することもできますが、それらは URL で問題を引き起こす可能性があるため、現時点ではそれが私たちのターゲットです。
それでは、おおよそ?6 倍以上の文字があるので、位置ごとに使用します。ID は大幅に?短くなります。 各位置により多くのデータを当てはめることができます。
これは基本的に tinyurl、is.gd、bit.ly などの URL 短縮サービスが行うことです。ただし、同様の ID は YouTube:?http://www.youtube.com/watch?v=yzNjIBEdyww
でも見つかります。データベース サーバーとは異なります。Web サーバーは拡張が簡単なので、データベースを数値で高速に保ちながら、ユーザーの負担を軽減するために少しの変換を実行させることができます (MySQL は単純な数値を非常に好みます ; )。
変換を行うために、大きな数値を短い文字列に、またはその逆に変換できる PHP 関数を作成しました。私はそれを alphaID と呼びます。
結果の文字列を解読するのは難しくありませんが、URL やディレクトリ構造をよりコンパクトで重要なものにするための非常に優れた機能となります。
基本的には次のとおりです。
?
?
<?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; }
?
実行中:
alphaID<span style="color: #66cc66; padding: 0px; margin: 0px;">(</span><span style="color: #cc66cc; padding: 0px; margin: 0px;">9007199254740989</span><span style="color: #66cc66; padding: 0px; margin: 0px;">)</span>;
は「PpQXn7COf」と次の内容を返します:
alphaID<span style="color: #66cc66; padding: 0px; margin: 0px;">(</span><span style="color: #ff0000; padding: 0px; margin: 0px;">'PpQXn7COf'</span>, <span style="font-weight: 700; color: #000000; padding: 0px; margin: 0px;">true</span><span style="color: #66cc66; padding: 0px; margin: 0px;">)</span>;
は「9007199254740989」
を返します簡単ですよね?
$pad_up
もあります。これにより、結果の alphaId を少なくとも?X? 文字長にすることができます。$index
?var に文字を追加すると、さらに多くの文字をサポートできます (結果の alphaID をさらに小さくできます)。?
?
?
Even Simon のおかげで、JavaScript が実装されました。ここには、エンコード関数とデコード関数をクラス内の別個のメソッドとして実装する PHP バージョンもあります。
<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>
?
?
?wessite のおかげで、Python 実装があります。
?
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)
?
Andy Li のおかげで、HaXe が実装されました。
?/** * 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/
?
?