php中通过Hashids将整数转化为唯一字符串
这个类主要是前台显示的主键ID转化成一串无规律的字符串,比较像 Youtube、Youku、Weibo之类的 id 名,从某种意义上可以防采集
在项目中,暴露给用户真实的项目ID,很有可能被恶意采集,很有可能被猜到目前有多少量(对造假不利)。
<?php
/*
    Hashids
    http://hashids.org/php
    (c) 2013 Ivan Akimov
    https://github.com/ivanakimov/hashids.php
    hashids may be freely distributed under the MIT license.
*/
/**
 * HashGenerator is a contract for generating hashes
 */
interface HashGenerator {
    /**
     * Encodes a variable number of parameters to generate a hash
     *
     * @param mixed ...
     *
     * @return string the generated hash
     */
    public function encode();
    /**
     * Decodes a hash to the original parameter values
     *
     * @param string $hash the hash to decode
     *
     * @return array
     */
    public function decode($hash);
    /**
     * Encodes hexadecimal values to generate a hash
     *
     * @param string $str hexadecimal string
     *
     * @return string the generated hash
     */
    public function encode_hex($str);
    /**
     * Decodes hexadecimal hash
     *
     * @param string $hash
     *
     * @return string hexadecimal string
     */
    public function decode_hex($hash);
}
class Hashids implements HashGenerator {
    const VERSION = '1.0.5';
    /* 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;
    const hashids_length = 6;           // 加密字符串长度
    const hashids_salt = 'test';      // 加密钥匙
    const hashids_alphabet = '';         // 字符仓库,不填写默认为扩展里的字符仓库
    private static $instance; //单例
    /**
     * 初始化
     * @param array $options
     * @return static
     */
    public static function instance($length = null, $salt = null, $alphabet = null)
    {
        if (is_null(self::$instance)) {
            if ($length === null) $length = self::hashids_length;
            if ($salt === null) $salt = self::hashids_salt;
            if ($alphabet === null) self::hashids_alphabet;
            self::$instance = new static($salt, $length, $alphabet);
        }
        return self::$instance;
    }
    public function __construct($salt = '', $min_hash_length = 8, $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);
        }
    }
    public function encode() {
        $ret = '';
        $numbers = func_get_args();
        if (func_num_args() == 1 && is_array(func_get_arg(0))) {
            $numbers = $numbers[0];
        }
        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);
    }
    public function decode($hash) {
        $ret = array();
        if (!$hash || !is_string($hash) || !trim($hash)) {
            return $ret;
        }
        return $this->_decode(trim($hash), $this->_alphabet);
    }
    public function encode_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, 'encode'), $numbers);
    }
    public function decode_hex($hash) {
        $ret = "";
        $numbers = $this->decode($hash);
        foreach ($numbers as $i => $number) {
            $ret .= substr(dechex($number), 1);
        }
        return $ret;
    }
    public 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();
            }
        }
        //修改为直接返回字符串
        if(isset($ret[0])){
            return $ret[0];
        }else{
            return false;
        }
    }
    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;
    }
}
调用Hashids类进行加密解密ID
$user_id = 11;
$hashids = Hashids::instance(8,'test11');
$encode_id = $hashids->encode($user_id); //加密
echo '<pre>';
var_dump($encode_id).PHP_EOL;
$decode_id = $hashids->decode($encode_id); //解密
echo '<pre>';
var_dump($decode_id).PHP_EOL;
exit();
php中通过Hashids将整数转化为唯一字符串的更多相关文章
- Python如何将整数转化成二进制字符串
		Python 如何将整数转化成二进制字符串 1.你可以自己写函数采用 %2 的方式来算. >>> binary = lambda n: '' if n==0 else binary( ... 
- c++中二进制和整数转化
		#1,包含文件 #include<bitset> #2,整数转化成二进制 int a = 63; bitset<6> bs(a); #3,二进制转化成整数 int b = bs ... 
- [LeetCode] Integer to Roman 整数转化成罗马数字
		Given an integer, convert it to a roman numeral. Input is guaranteed to be within the range from 1 t ... 
- c++实现atoi()和itoa()函数(字符串和整数转化)
		(0) c++类型所占的字节和表示范围 c 语言里 类型转换那些事儿(补码 反码) 应届生面试准备之道 最值得学习阅读的10个C语言开源项目代码 一:起因 (1)字符串类型转化为整数型(Integer ... 
- [LeetCode] 12. Integer to Roman 整数转化成罗马数字
		Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M. Symbol Value I 1 ... 
- [转载]JavaScript 中小数和大整数的精度丢失
		标题: JavaScript 中小数和大整数的精度丢失作者: Demon链接: http://demon.tw/copy-paste/javascript-precision.html版权: 本博客的 ... 
- javascript中的隐式类型转化
		javascript中的隐式类型转化 #隐式转换 ## "+" 字符串和数字 如果某个操作数是字符串或者能够通过以下步骤转换为字符串的话,+将进行拼接操作. 如果其中一个操作数是对 ... 
- C++中int与string的转化
		C++中int与string的转化 int本身也要用一串字符表示,前后没有双引号,告诉编译器把它当作一个数解释.缺省情况下,是当成10进制(dec)来解释,如果想用8进制,16进制,怎么办?加上前缀, ... 
- 《剑指Offer》第1题(Java实现):在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
		一.题目描述 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该 ... 
随机推荐
- (转)Fabric 1.0 读写集
			本文译自Fabric 1.0 文档,这篇文档详述了当前读写集语义实现的细节.文档地址为: https://hyperledger-fabric.readthedocs.io/en/latest/rea ... 
- 阿里云RDS备份在本地mysql快速还原
			本地准备: ##安装和RDS相同的mysql版本,拿mysql5.6为例 http://www.cnblogs.com/37yan/p/7513605.html ##安装Xtrabackup 包 cd ... 
- CentOS7安装Jdk1.8
			一.前期准备 a) 首先从官网上下载Jdk 8 for Linux x64到window下. b) 我这边用的最小安装,所以没有安装centos自带的openjdk,如果你安装时,不是最小安装的话,可 ... 
- 网络编程之Socket异步编程
			看了上篇socket入门,相信你已经对socket有一定的了解了http://www.cnblogs.com/nsky/p/4501782.html 现在来回顾一下.上篇在循环接收客户端连接和循环接收 ... 
- ES6学习之 解构赋值
			最近看了一个vue的项目,发现作者大量使用了ES6的语法,包括async, Promise, Set, Map还有一些解构赋值, 才发现自己对于ES6的语法缺乏了总结和运用,看得有点艰难,所以重新学习 ... 
- 有复选框情况下,sql拼写技巧
			复选框选中只取合格的数据,没有选中取所有的数据. string filterOk = (ckbOnlyOk.Checked ? " and (jyjg='合格') " : &quo ... 
- python爬取12306及各参数的使用。完整代码
			import requestsfrom retrying import retryreuquests和retrying的下载及安装可以通过命令行pip install 口令实现 # 调用重连装饰器固定 ... 
- featuremap尺寸的计算
			对于卷积层,向下取整 对于池化层:想上取整 output=((input+2*pad-dilation*(kernel-1)+1)/stride)+1 input:输入尺寸 output:输出尺寸 p ... 
- c#Stream学习笔记
			C# 温故而知新:Stream篇(—) http://www.cnblogs.com/JimmyZheng/archive/2012/03/17/2402814.html 基本概念重点看这一篇. 什么 ... 
- 水题C
			某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,……,L,都种有一棵树. ... 
