做过一个需求:广告主后台发起调查活动,普通用户参加此调查后跳转值某个网址领取1Q点(1角钱);上线一段时间以后,广告主反馈得到的很多手机号都是伪造的(我们开始只用正则匹配判断手机号正确与否),然后产品让我们加上手机短信验证,就变成了下面的样子.




刚开始的思路应该很正常的那种,用rand生成随机码,然后存在redis里边,设置expire为60秒;后来考虑考虑,用户为了1角钱不至于如此,需要验证码的时候也不会瞎填写,系统还限制某ID用户明天每天只能参加5次这种活动,也为了不浪费系统资源的原则,公司发的短信已经需要2分钱一条,决定不用redis,用下面的思路:

用用户帐号+活动ID+手机号进行处理生成一个固定的数字,然后驾驶时间戳进行干扰生成4位数的数字,干扰以后只保证4位数对应的二进制的1、5、6、7、8、9位不被干扰,这样对应会生出pow(2,6)个不一样的4位数字,随机发送给用户一个。

用户验证验证码时候也只验证验证码的1、5、6、7、8、9位是否正确,为用户帐号+活动ID+手机号进行处理生成,这样就不用存储验证码,达到验证手机号的号码。

具体的测试例子在下面,为啥说是测试例子呢,因为最后还没有用,我就去封闭开发其他项目去了,下面代码也是偶尔翻到,看代码竟然是我工作一周年的时候写的  ,测试的代码生成的验证码散列的不是很好,也没有时间进行改善,主要介绍一下上面的思路。

    1. <?php  
    2. /** 
    3.  * 
    4.  * User: shikiliu 
    5.  * Date: 13-7-11 
    6.  */  
    7. class TelephoneCheck  
    8. {  
    9.   
    10.   
    11.     /** 
    12.      * 取得某个用户某次活动的手机验证码 
    13.      * @param $uin 用户ID 小于10000系统保留 
    14.      * @param $actId 活动ID  小于1000系统保留 
    15.      * @param $telephone 用户手机号 
    16.      * @return bool|int 4位数的验证码 
    17.      */  
    18.     public function getTelephoneCode($uin, $actId, $telephone)  
    19.     {  
    20.   
    21.         if ($uin < 10000 || $actId < 1000 || empty($telephone)) {  
    22.             return false;  
    23.         }  
    24.   
    25.         $time = time();  
    26.   
    27.         $timeFeature = hexdec(substr(md5($time), 0, 3)) & 0x1F1;  
    28.   
    29.         $telephoneFeature = hexdec(substr(md5($telephone), 8, 4));  
    30.   
    31.         $actIdFeature = hexdec(substr(md5($actId), 16, 4));  
    32.   
    33.         $uinFeature = hexdec(substr(md5($uin), 24, 4));  
    34.   
    35.         $sumFeature = $telephoneFeature + $actIdFeature + $uinFeature;  
    36.   
    37.         $sumFeature = $sumFeature % 10000;  
    38.   
    39.         if ($sumFeature < 1000) {  
    40.             $sumFeature = 5145;  
    41.         }  
    42.   
    43.         $result = $sumFeature | $timeFeature;  
    44.   
    45.         return $result;  
    46.     }  
    47.   
    48.   
    49.     /** 
    50.      * 验证用户的手机验证码 
    51.      * @param $uin 用户ID 小于10000系统保留 
    52.      * @param $actId 活动ID  小于1000系统保留 
    53.      * @param $telephone 用户手机号 
    54.      * @param $code getTelephoneCode生成的验证码 
    55.      * @return bool 是否正确 
    56.      */  
    57.     public function  checkTelephoneCode($uin, $actId, $telephone, $code)  
    58.     {  
    59.   
    60.         if ($uin < 10000 || $actId < 1000 || empty($telephone) || empty($code)) {  
    61.             return false;  
    62.         }  
    63.   
    64.         $telephoneFeature = hexdec(substr(md5($telephone), 8, 4));  
    65.   
    66.         $actIdFeature = hexdec(substr(md5($actId), 16, 4));  
    67.   
    68.         $uinFeature = hexdec(substr(md5($uin), 24, 4));  
    69.   
    70.         $sumFeature = $telephoneFeature + $actIdFeature + $uinFeature;  
    71.   
    72.         $sumFeature = $sumFeature % 10000;  
    73.   
    74.         if ($sumFeature < 1000) {  
    75.             $sumFeature = 5145;  
    76.         }  
    77.   
    78.         $sumFeature = $sumFeature & 0xE0E;  
    79.   
    80.         $code = $code & 0xE0E;  
    81.   
    82.         if ($sumFeature == $code) {  
    83.             return true;  
    84.         }  
    85.         return false;  
    86.     }  
    87. }  
    88.   
    89.   
    90. $actId = 10001;  
    91. $telephone = 13797025562;  
    92. $uin = 514540767;  
    93.   
    94.   
    95. $telCode = new TelephoneCheck();  
    96.   
    97.   
    98. $code = $telCode->getTelephoneCode($uin, $actId, $telephone);  
    99.   
    100. var_dump($code);  
    101.   
    102. var_dump($telCode->checkTelephoneCode($uin, $actId, $telephone, $code));  
    103.   
    104. var_dump($telCode->checkTelephoneCode($uin, $actId, $telephone, $code+10)); 
posted on 2016-10-09 11:03  飘渺的悠远  阅读(295)  评论(0编辑  收藏  举报