Source of file Hashids.php
Size: 8,187 Bytes - Last Modified: 2021-12-23T10:19:36+00:00
/var/www/docs.ssmods.com/process/src/code/Hashids.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 | <?php /* hashids http://www.hashids.org/php/ (c) 2013 Ivan Akimov https://github.com/ivanakimov/hashids.php hashids may be freely distributed under the MIT license. */ namespace Hashids; class Hashids { const VERSION = '0.3.1'; /* internal settings */ const MIN_ALPHABET_LENGTH = 16; const SEP_DIV = 3.5; const GUARD_DIV = 12; /* error messages */ const E_ALPHABET_LENGTH = 'alphabet must contain at least %d unique characters'; const E_ALPHABET_SPACE = 'alphabet cannot contain spaces'; /* set at constructor */ private $_alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'; private $_seps = 'cfhistuCFHISTU'; private $_min_hash_length = 0; private $_math_functions = array(); private $_max_int_value = 1000000000; function __construct($salt = '', $min_hash_length = 0, $alphabet = '') { /* if either math precision library is present, raise $this->_max_int_value */ if (function_exists('gmp_add')) { $this->_math_functions['add'] = 'gmp_add'; $this->_math_functions['div'] = 'gmp_div'; $this->_math_functions['str'] = 'gmp_strval'; } else if (function_exists('bcadd')) { $this->_math_functions['add'] = 'bcadd'; $this->_math_functions['div'] = 'bcdiv'; $this->_math_functions['str'] = 'strval'; } $this->_lower_max_int_value = $this->_max_int_value; if ($this->_math_functions) $this->_max_int_value = PHP_INT_MAX; /* handle parameters */ $this->_salt = $salt; if ((int)$min_hash_length > 0) $this->_min_hash_length = (int)$min_hash_length; if ($alphabet) $this->_alphabet = implode('', array_unique(str_split($alphabet))); if (strlen($this->_alphabet) < self::MIN_ALPHABET_LENGTH) throw new \Exception(sprintf(self::E_ALPHABET_LENGTH, self::MIN_ALPHABET_LENGTH)); if (is_int(strpos($this->_alphabet, ' '))) throw new \Exception(self::E_ALPHABET_SPACE); $alphabet_array = str_split($this->_alphabet); $seps_array = str_split($this->_seps); $this->_seps = implode('', array_intersect($alphabet_array, $seps_array)); $this->_alphabet = implode('', array_diff($alphabet_array, $seps_array)); $this->_seps = $this->_consistent_shuffle($this->_seps, $this->_salt); if (!$this->_seps || (strlen($this->_alphabet) / strlen($this->_seps)) > self::SEP_DIV) { $seps_length = (int)ceil(strlen($this->_alphabet) / self::SEP_DIV); if ($seps_length == 1) $seps_length++; if ($seps_length > strlen($this->_seps)) { $diff = $seps_length - strlen($this->_seps); $this->_seps .= substr($this->_alphabet, 0, $diff); $this->_alphabet = substr($this->_alphabet, $diff); } else $this->_seps = substr($this->_seps, 0, $seps_length); } $this->_alphabet = $this->_consistent_shuffle($this->_alphabet, $this->_salt); $guard_count = (int)ceil(strlen($this->_alphabet) / self::GUARD_DIV); if (strlen($this->_alphabet) < 3) { $this->_guards = substr($this->_seps, 0, $guard_count); $this->_seps = substr($this->_seps, $guard_count); } else { $this->_guards = substr($this->_alphabet, 0, $guard_count); $this->_alphabet = substr($this->_alphabet, $guard_count); } } function encrypt() { $ret = ''; $numbers = func_get_args(); if (!$numbers) return $ret; foreach ($numbers as $number) { $is_number = ctype_digit((string)$number); if (!$is_number || $number < 0 || $number > $this->_max_int_value) return $ret; } return $this->_encode($numbers); } function decrypt($hash) { $ret = array(); if (!$hash || !is_string($hash) || !trim($hash)) return $ret; return $this->_decode(trim($hash), $this->_alphabet); } function encrypt_hex($str) { if (!ctype_xdigit((string)$str)) return ''; $numbers = trim(chunk_split($str, 12, ' ')); $numbers = explode(' ', $numbers); foreach ($numbers as $i => $number) $numbers[$i] = hexdec('1' . $number); return call_user_func_array(array($this, 'encrypt'), $numbers); } function decrypt_hex($hash) { $ret = ""; $numbers = $this->decrypt($hash); foreach ($numbers as $i => $number) $ret .= substr(dechex($number), 1); return $ret; } function get_max_int_value() { return $this->_max_int_value; } private function _encode(array $numbers) { $alphabet = $this->_alphabet; $numbers_size = sizeof($numbers); $numbers_hash_int = 0; foreach ($numbers as $i => $number) $numbers_hash_int += ($number % ($i + 100)); $lottery = $ret = $alphabet[$numbers_hash_int % strlen($alphabet)]; foreach ($numbers as $i => $number) { $alphabet = $this->_consistent_shuffle($alphabet, substr($lottery . $this->_salt . $alphabet, 0, strlen($alphabet))); $ret .= $last = $this->_hash($number, $alphabet); if ($i + 1 < $numbers_size) { $number %= (ord($last) + $i); $seps_index = $number % strlen($this->_seps); $ret .= $this->_seps[$seps_index]; } } if (strlen($ret) < $this->_min_hash_length) { $guard_index = ($numbers_hash_int + ord($ret[0])) % strlen($this->_guards); $guard = $this->_guards[$guard_index]; $ret = $guard . $ret; if (strlen($ret) < $this->_min_hash_length) { $guard_index = ($numbers_hash_int + ord($ret[2])) % strlen($this->_guards); $guard = $this->_guards[$guard_index]; $ret .= $guard; } } $half_length = (int)(strlen($alphabet) / 2); while (strlen($ret) < $this->_min_hash_length) { $alphabet = $this->_consistent_shuffle($alphabet, $alphabet); $ret = substr($alphabet, $half_length) . $ret . substr($alphabet, 0, $half_length); $excess = strlen($ret) - $this->_min_hash_length; if ($excess > 0) $ret = substr($ret, $excess / 2, $this->_min_hash_length); } return $ret; } private function _decode($hash, $alphabet) { $ret = array(); $hash_breakdown = str_replace(str_split($this->_guards), ' ', $hash); $hash_array = explode(' ', $hash_breakdown); $i = 0; if (sizeof($hash_array) == 3 || sizeof($hash_array) == 2) $i = 1; $hash_breakdown = $hash_array[$i]; if (isset($hash_breakdown[0])) { $lottery = $hash_breakdown[0]; $hash_breakdown = substr($hash_breakdown, 1); $hash_breakdown = str_replace(str_split($this->_seps), ' ', $hash_breakdown); $hash_array = explode(' ', $hash_breakdown); foreach ($hash_array as $sub_hash) { $alphabet = $this->_consistent_shuffle($alphabet, substr($lottery . $this->_salt . $alphabet, 0, strlen($alphabet))); $ret[] = (int)$this->_unhash($sub_hash, $alphabet); } if ($this->_encode($ret) != $hash) $ret = array(); } return $ret; } private function _consistent_shuffle($alphabet, $salt) { if (!strlen($salt)) return $alphabet; for ($i = strlen($alphabet) - 1, $v = 0, $p = 0; $i > 0; $i--, $v++) { $v %= strlen($salt); $p += $int = ord($salt[$v]); $j = ($int + $v + $p) % $i; $temp = $alphabet[$j]; $alphabet[$j] = $alphabet[$i]; $alphabet[$i] = $temp; } return $alphabet; } private function _hash($input, $alphabet) { $hash = ''; $alphabet_length = strlen($alphabet); do { $hash = $alphabet[$input % $alphabet_length] . $hash; if ($input > $this->_lower_max_int_value && $this->_math_functions) $input = $this->_math_functions['str']($this->_math_functions['div']($input, $alphabet_length)); else $input = (int)($input / $alphabet_length); } while ($input); return $hash; } private function _unhash($input, $alphabet) { $number = 0; if (strlen($input) && $alphabet) { $alphabet_length = strlen($alphabet); $input_chars = str_split($input); foreach ($input_chars as $i => $char) { $pos = strpos($alphabet, $char); if ($this->_math_functions) $number = $this->_math_functions['str']($this->_math_functions['add']($number, $pos * pow($alphabet_length, (strlen($input) - $i - 1)))); else $number += $pos * pow($alphabet_length, (strlen($input) - $i - 1)); } } return $number; } } |