scratch – Blame information for rev 66

Subversion Repositories:
Rev:
Rev Author Line No. Line
4 office 1 <?php
2 /**
3 * PseudoCrypt by KevBurns (http://blog.kevburnsjr.com/php-unique-hash)
4 * Reference/source: http://stackoverflow.com/a/1464155/933782
5 *
6 * I want a short alphanumeric hash that’s unique and who’s sequence is difficult to deduce.
7 * I could run it out to md5 and trim the first n chars but that’s not going to be very unique.
8 * Storing a truncated checksum in a unique field means that the frequency of collisions will increase
9 * geometrically as the number of unique keys for a base 62 encoded integer approaches 62^n.
10 * I’d rather do it right than code myself a timebomb. So I came up with this.
11 *
12 * Sample Code:
13 *
14 * echo "<pre>";
15 * foreach(range(1, 10) as $n) {
16 * echo $n." - ";
17 * $hash = PseudoCrypt::hash($n, 6);
18 * echo $hash." - ";
19 * echo PseudoCrypt::unhash($hash)."<br/>";
20 * }
21 *
22 * Sample Results:
23 * 1 - cJinsP - 1
24 * 2 - EdRbko - 2
25 * 3 - qxAPdD - 3
26 * 4 - TGtDVc - 4
27 * 5 - 5ac1O1 - 5
28 * 6 - huKpGQ - 6
29 * 7 - KE3d8p - 7
30 * 8 - wXmR1E - 8
31 * 9 - YrVEtd - 9
32 * 10 - BBE2m2 - 10
33 */
34  
35 class PseudoCrypt
36 {
37  
38 /* Key: Next prime greater than 62 ^ n / 1.618033988749894848 */
39 /* Value: modular multiplicative inverse */
40 private static $golden_primes = array(
41 '1' => '1',
42 '41' => '59',
43 '2377' => '1677',
44 '147299' => '187507',
45 '9132313' => '5952585',
46 '566201239' => '643566407',
47 '35104476161' => '22071637057',
48 '2176477521929' => '294289236153',
49 '134941606358731' => '88879354792675',
50 '8366379594239857' => '7275288500431249',
51 '518715534842869223' => '280042546585394647'
52 );
53  
54 /* Ascii : 0 9, A Z, a z */
55 /* $chars = array_merge(range(48,57), range(65,90), range(97,122)) */
56 private static $chars62 = array(
57 0=>48,1=>49,2=>50,3=>51,4=>52,5=>53,6=>54,7=>55,8=>56,9=>57,10=>65,
58 11=>66,12=>67,13=>68,14=>69,15=>70,16=>71,17=>72,18=>73,19=>74,20=>75,
59 21=>76,22=>77,23=>78,24=>79,25=>80,26=>81,27=>82,28=>83,29=>84,30=>85,
60 31=>86,32=>87,33=>88,34=>89,35=>90,36=>97,37=>98,38=>99,39=>100,40=>101,
61 41=>102,42=>103,43=>104,44=>105,45=>106,46=>107,47=>108,48=>109,49=>110,
62 50=>111,51=>112,52=>113,53=>114,54=>115,55=>116,56=>117,57=>118,58=>119,
63 59=>120,60=>121,61=>122
64 );
65  
66 public static function base62($int)
67 {
68 $key = "";
69 while (bccomp($int, 0) > 0) {
70 $mod = bcmod($int, 62);
71 $key .= chr(self::$chars62[$mod]);
72 $int = bcdiv($int, 62);
73 }
74 return strrev($key);
75 }
76  
77 public static function hash($num, $len = 5)
78 {
79 $ceil = bcpow(62, $len);
80 $primes = array_keys(self::$golden_primes);
81 $prime = $primes[$len];
82 $dec = bcmod(bcmul($num, $prime), $ceil);
83 $hash = self::base62($dec);
84 return str_pad($hash, $len, "0", STR_PAD_LEFT);
85 }
86  
87 public static function unbase62($key)
88 {
89 $int = 0;
90 foreach (str_split(strrev($key)) as $i => $char) {
91 $dec = array_search(ord($char), self::$chars62);
92 $int = bcadd(bcmul($dec, bcpow(62, $i)), $int);
93 }
94 return $int;
95 }
96  
97 public static function unhash($hash)
98 {
99 $len = strlen($hash);
100 $ceil = bcpow(62, $len);
101 $mmiprimes = array_values(self::$golden_primes);
102 $mmi = $mmiprimes[$len];
103 $num = self::unbase62($hash);
104 $dec = bcmod(bcmul($num, $mmi), $ceil);
105 return $dec;
106 }
107 }