| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420 | 
							- <?php
 
- /*
 
-  * This file is part of Hashids.
 
-  *
 
-  * (c) Ivan Akimov <ivan@barreleye.com>
 
-  *
 
-  * For the full copyright and license information, please view the LICENSE
 
-  * file that was distributed with this source code.
 
-  */
 
- namespace Hashids;
 
- use Hashids\Math\Bc;
 
- use Hashids\Math\Gmp;
 
- use RuntimeException;
 
- /**
 
-  * This is the hashids class.
 
-  *
 
-  * @author Ivan Akimov <ivan@barreleye.com>
 
-  * @author Vincent Klaiber <hello@vinkla.com>
 
-  * @author Johnson Page <jwpage@gmail.com>
 
-  */
 
- class Hashids implements HashidsInterface
 
- {
 
-     /**
 
-      * The seps divider.
 
-      *
 
-      * @var float
 
-      */
 
-     const SEP_DIV = 3.5;
 
-     /**
 
-      * The guard divider.
 
-      *
 
-      * @var float
 
-      */
 
-     const GUARD_DIV = 12;
 
-     /**
 
-      * The alphabet string.
 
-      *
 
-      * @var string
 
-      */
 
-     protected $alphabet;
 
-     /**
 
-      * Shuffled alphabets, referenced by alphabet and salt.
 
-      *
 
-      * @var array
 
-      */
 
-     protected $shuffledAlphabets;
 
-     /**
 
-      * The seps string.
 
-      *
 
-      * @var string
 
-      */
 
-     protected $seps = 'cfhistuCFHISTU';
 
-     /**
 
-      * The guards string.
 
-      *
 
-      * @var string
 
-      */
 
-     protected $guards;
 
-     /**
 
-      * The minimum hash length.
 
-      *
 
-      * @var int
 
-      */
 
-     protected $minHashLength;
 
-     /**
 
-      * The salt string.
 
-      *
 
-      * @var string
 
-      */
 
-     protected $salt;
 
-     /**
 
-      * The math class.
 
-      *
 
-      * @var \Hashids\Math\MathInterface
 
-      */
 
-     protected $math;
 
-     /**
 
-      * Create a new hashids instance.
 
-      *
 
-      * @param string $salt
 
-      * @param int $minHashLength
 
-      * @param string $alphabet
 
-      *
 
-      * @throws \Hashids\HashidsException
 
-      *
 
-      * @return void
 
-      */
 
-     public function __construct($salt = '', $minHashLength = 0, $alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890')
 
-     {
 
-         $this->salt = $salt;
 
-         $this->minHashLength = $minHashLength;
 
-         $this->alphabet = implode('', array_unique(str_split($alphabet)));
 
-         $this->math = $this->getMathExtension();
 
-         if (strlen($this->alphabet) < 16) {
 
-             throw new HashidsException('Alphabet must contain at least 16 unique characters.');
 
-         }
 
-         if (strpos($this->alphabet, ' ') !== false) {
 
-             throw new HashidsException('Alphabet can\'t contain spaces.');
 
-         }
 
-         $alphabetArray = str_split($this->alphabet);
 
-         $sepsArray = str_split($this->seps);
 
-         $this->seps = implode('', array_intersect($sepsArray, $alphabetArray));
 
-         $this->alphabet = implode('', array_diff($alphabetArray, $sepsArray));
 
-         $this->seps = $this->shuffle($this->seps, $this->salt);
 
-         if (!$this->seps || (strlen($this->alphabet) / strlen($this->seps)) > self::SEP_DIV) {
 
-             $sepsLength = (int) ceil(strlen($this->alphabet) / self::SEP_DIV);
 
-             if ($sepsLength > strlen($this->seps)) {
 
-                 $diff = $sepsLength - strlen($this->seps);
 
-                 $this->seps .= substr($this->alphabet, 0, $diff);
 
-                 $this->alphabet = substr($this->alphabet, $diff);
 
-             }
 
-         }
 
-         $this->alphabet = $this->shuffle($this->alphabet, $this->salt);
 
-         $guardCount = (int) ceil(strlen($this->alphabet) / self::GUARD_DIV);
 
-         if (strlen($this->alphabet) < 3) {
 
-             $this->guards = substr($this->seps, 0, $guardCount);
 
-             $this->seps = substr($this->seps, $guardCount);
 
-         } else {
 
-             $this->guards = substr($this->alphabet, 0, $guardCount);
 
-             $this->alphabet = substr($this->alphabet, $guardCount);
 
-         }
 
-     }
 
-     /**
 
-      * Encode parameters to generate a hash.
 
-      *
 
-      * @param mixed $numbers
 
-      *
 
-      * @return string
 
-      */
 
-     public function encode(...$numbers)
 
-     {
 
-         $ret = '';
 
-         if (1 === count($numbers) && is_array($numbers[0])) {
 
-             $numbers = $numbers[0];
 
-         }
 
-         if (!$numbers) {
 
-             return $ret;
 
-         }
 
-         foreach ($numbers as $number) {
 
-             $isNumber = ctype_digit((string) $number);
 
-             if (!$isNumber) {
 
-                 return $ret;
 
-             }
 
-         }
 
-         $alphabet = $this->alphabet;
 
-         $numbersSize = count($numbers);
 
-         $numbersHashInt = 0;
 
-         foreach ($numbers as $i => $number) {
 
-             $numbersHashInt += $this->math->intval($this->math->mod($number, ($i + 100)));
 
-         }
 
-         $lottery = $ret = $alphabet[$numbersHashInt % strlen($alphabet)];
 
-         foreach ($numbers as $i => $number) {
 
-             $alphabet = $this->shuffle($alphabet, substr($lottery.$this->salt.$alphabet, 0, strlen($alphabet)));
 
-             $ret .= $last = $this->hash($number, $alphabet);
 
-             if ($i + 1 < $numbersSize) {
 
-                 $number %= (ord($last) + $i);
 
-                 $sepsIndex = $this->math->intval($this->math->mod($number, strlen($this->seps)));
 
-                 $ret .= $this->seps[$sepsIndex];
 
-             }
 
-         }
 
-         if (strlen($ret) < $this->minHashLength) {
 
-             $guardIndex = ($numbersHashInt + ord($ret[0])) % strlen($this->guards);
 
-             $guard = $this->guards[$guardIndex];
 
-             $ret = $guard.$ret;
 
-             if (strlen($ret) < $this->minHashLength) {
 
-                 $guardIndex = ($numbersHashInt + ord($ret[2])) % strlen($this->guards);
 
-                 $guard = $this->guards[$guardIndex];
 
-                 $ret .= $guard;
 
-             }
 
-         }
 
-         $halfLength = (int) (strlen($alphabet) / 2);
 
-         while (strlen($ret) < $this->minHashLength) {
 
-             $alphabet = $this->shuffle($alphabet, $alphabet);
 
-             $ret = substr($alphabet, $halfLength).$ret.substr($alphabet, 0, $halfLength);
 
-             $excess = strlen($ret) - $this->minHashLength;
 
-             if ($excess > 0) {
 
-                 $ret = substr($ret, $excess / 2, $this->minHashLength);
 
-             }
 
-         }
 
-         return $ret;
 
-     }
 
-     /**
 
-      * Decode a hash to the original parameter values.
 
-      *
 
-      * @param string $hash
 
-      *
 
-      * @return array
 
-      */
 
-     public function decode($hash)
 
-     {
 
-         $ret = [];
 
-         if (!is_string($hash) || !($hash = trim($hash))) {
 
-             return $ret;
 
-         }
 
-         $alphabet = $this->alphabet;
 
-         $ret = [];
 
-         $hashBreakdown = str_replace(str_split($this->guards), ' ', $hash);
 
-         $hashArray = explode(' ', $hashBreakdown);
 
-         $i = count($hashArray) == 3 || count($hashArray) == 2 ? 1 : 0;
 
-         $hashBreakdown = $hashArray[$i];
 
-         if (isset($hashBreakdown[0])) {
 
-             $lottery = $hashBreakdown[0];
 
-             $hashBreakdown = substr($hashBreakdown, 1);
 
-             $hashBreakdown = str_replace(str_split($this->seps), ' ', $hashBreakdown);
 
-             $hashArray = explode(' ', $hashBreakdown);
 
-             foreach ($hashArray as $subHash) {
 
-                 $alphabet = $this->shuffle($alphabet, substr($lottery.$this->salt.$alphabet, 0, strlen($alphabet)));
 
-                 $result = $this->unhash($subHash, $alphabet);
 
-                 if ($this->math->greaterThan($result, PHP_INT_MAX)) {
 
-                     $ret[] = $this->math->strval($result);
 
-                 } else {
 
-                     $ret[] = $this->math->intval($result);
 
-                 }
 
-             }
 
-             if ($this->encode($ret) != $hash) {
 
-                 $ret = [];
 
-             }
 
-         }
 
-         return $ret;
 
-     }
 
-     /**
 
-      * Encode hexadecimal values and generate a hash string.
 
-      *
 
-      * @param string $str
 
-      *
 
-      * @return string
 
-      */
 
-     public function encodeHex($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([$this, 'encode'], $numbers);
 
-     }
 
-     /**
 
-      * Decode a hexadecimal hash.
 
-      *
 
-      * @param string $hash
 
-      *
 
-      * @return string
 
-      */
 
-     public function decodeHex($hash)
 
-     {
 
-         $ret = '';
 
-         $numbers = $this->decode($hash);
 
-         foreach ($numbers as $i => $number) {
 
-             $ret .= substr(dechex($number), 1);
 
-         }
 
-         return $ret;
 
-     }
 
-     /**
 
-      * Shuffle alphabet by given salt.
 
-      *
 
-      * @param string $alphabet
 
-      * @param string $salt
 
-      *
 
-      * @return string
 
-      */
 
-     protected function shuffle($alphabet, $salt)
 
-     {
 
-         $key = $alphabet.' '.$salt;
 
-         if (isset($this->shuffledAlphabets[$key])) {
 
-             return $this->shuffledAlphabets[$key];
 
-         }
 
-         $saltLength = strlen($salt);
 
-         if (!$saltLength) {
 
-             return $alphabet;
 
-         }
 
-         for ($i = strlen($alphabet) - 1, $v = 0, $p = 0; $i > 0; $i--, $v++) {
 
-             $v %= $saltLength;
 
-             $p += $int = ord($salt[$v]);
 
-             $j = ($int + $v + $p) % $i;
 
-             $temp = $alphabet[$j];
 
-             $alphabet[$j] = $alphabet[$i];
 
-             $alphabet[$i] = $temp;
 
-         }
 
-         $this->shuffledAlphabets[$key] = $alphabet;
 
-         return $alphabet;
 
-     }
 
-     /**
 
-      * Hash given input value.
 
-      *
 
-      * @param string $input
 
-      * @param string $alphabet
 
-      *
 
-      * @return string
 
-      */
 
-     protected function hash($input, $alphabet)
 
-     {
 
-         $hash = '';
 
-         $alphabetLength = strlen($alphabet);
 
-         do {
 
-             $hash = $alphabet[$this->math->intval($this->math->mod($input, $alphabetLength))].$hash;
 
-             $input = $this->math->divide($input, $alphabetLength);
 
-         } while ($this->math->greaterThan($input, 0));
 
-         return $hash;
 
-     }
 
-     /**
 
-      * Unhash given input value.
 
-      *
 
-      * @param string $input
 
-      * @param string $alphabet
 
-      *
 
-      * @return int
 
-      */
 
-     protected function unhash($input, $alphabet)
 
-     {
 
-         $number = 0;
 
-         $inputLength = strlen($input);
 
-         if ($inputLength && $alphabet) {
 
-             $alphabetLength = strlen($alphabet);
 
-             $inputChars = str_split($input);
 
-             foreach ($inputChars as $char) {
 
-                 $position = strpos($alphabet, $char);
 
-                 $number = $this->math->multiply($number, $alphabetLength);
 
-                 $number = $this->math->add($number, $position);
 
-             }
 
-         }
 
-         return $number;
 
-     }
 
-     /**
 
-      * Get BC Math or GMP extension.
 
-      *
 
-      * @codeCoverageIgnore
 
-      *
 
-      * @throws \RuntimeException
 
-      *
 
-      * @return \Hashids\Math\Bc|\Hashids\Math\Gmp
 
-      */
 
-     protected function getMathExtension()
 
-     {
 
-         if (extension_loaded('gmp')) {
 
-             return new Gmp();
 
-         }
 
-         if (extension_loaded('bcmath')) {
 
-             return new Bc();
 
-         }
 
-         throw new RuntimeException('Missing BC Math or GMP extension.');
 
-     }
 
- }
 
 
  |