对短信验证码发送次数的限制,用PHP是如何实现
场景
在注册,修改密码,找回密码等场景里,我们都会遇到发送手机短信进行验证码验证,我们都知道,手机的这个短信接口是需要购买了,为了防刷,我们就会对短信验证码发送次数的限制,我们应该如何防止呢?
很多人都会这样做:对用户获取短信验证码的手机号、ip、和浏览器(使用唯一标识)进行限制。
本文介绍的方法是对用户每天只能通过同一浏览器或同一ip地址获取验证码10次或者同一手机号只能获取3次短信验证码,三种限制为“或”关系,一条超限就不发验证码。方法是通过在服务器端将用户的手机号、ip、ur_r标识记录并写入文件,再通过读取文件记录判断用户请求发送验证码的次数来做限制。
方法如下:
这里是获取短信验证码页面:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> </head> <body> <!-- 隐藏表单uv_r标识,用于对获取验证码的浏览器进行限制,唯一标识存储于浏览器cookie中。在用户进行获取短信验证码操作时将标识传入后台代码(可以通过js传入后台,此处未提供js代码) --> <form action="./chuli.php" method="post"> <input type="hidden" name="uv_r" value="" id="uv_r"> <input type="text" name="tel" value="" > 电话 <input type="submit" value="提交"> </form> </body> <script> /** 使用js获取cookie中ur_r唯一标识,如果不存在,生成唯一标识,js写入cookie,并将唯一标识赋给隐藏表单。 */ //唯一标识存入cookie var _uuid = getUUID(); if (getCookie("_UUID_UV") != null && getCookie("_UUID_UV") != undefined) { _uuid = getCookie("_UUID_UV"); } else { setCookie("_UUID_UV", _uuid); } document.getElementById("uv_r").value = _uuid;//赋给hidden表单 //生成唯一标识 function getUUID() { var uuid = new Date().getTime(); var randomNum = parseInt(Math.random() * 1000); return uuid + randomNum.toString(); } //写cookie function setCookie(name, value) { var Days = 365;//这里设置cookie存在时间为一年 var exp = new Date(); exp.setTime(exp.getTime() + Days * 24 * 60 * 60 * 1000); document.cookie = name + "=" + escape(value) + ";expires=" + exp.toGMTString(); } //获取cookie function getCookie(name) { var arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)"); console.log(document.cookie.match(reg)); if (arr = document.cookie.match(reg)) return unescape(arr[2]); else return null; } console.log(_uuid); </script> </html>
后端PHP短信限制次数等的封装类(这个类还有点问题看你是怎么调用了 稍作修改,太懒,不想弄)
<?php Class regMod { //定义全局变量,用于设置记录文件的路径 Protected $Root = null; Public function __construct() { $this->Root = "./";//自己定义的文件存放位置 } //获取短信验证码操作(Ajax方法为好) Public function get_authentication_code($ip = '',$tel = '', $uv_r = '') { if ($uv_r && $tel) { if (empty($uv_r)) { $uv_r = 0; } } //判断数据是否超过了限制 $uvr_num = $this->checkUvr($uv_r); $tel_num = $this->checkTel($tel); $ip_num = $this->checkIp($ip); if ($uvr_num < 10 && $tel_num < 4 && $ip_num < 10) { echo "发送验证码";//符合发送条件,发送验证码的操作 return 1; //验证码发送成功,返回1 } else { //当不发送验证码时,将数据存入文件,用于方便查询 $data = $tel . "|" . $ip . "|" . $uv_r . "|"; if ($uv_r > 0 && $uvr_num >= 10) { $data = $data . "A@"; } if ($tel_num >= 4) { $data = $data . "B@"; } if ($ip_num >= 10) { $data = $data . "C@"; } $this->wirteFile("", $data); return 2; //发送次数过多 } } //以下方法为私有方法 //检测ur_r在文件中出现的次数 Private function checkUvr($data) { $fileName = "Uv_" . date("Ymd", time()) . ".dat"; $filePath = ($this->Root) . $fileName;//组装要写入的文件的路径 $c_sum = 0; if (file_exists($filePath)) {//文件存在获取次数并将此次请求的数据写入 $arr = file_get_contents($filePath); $row = explode("|", $arr); $countArr = array_count_values($row); $c_sum = $countArr[$data]; if ($c_sum < 10) { $this->wirteFile($filePath, $data . "|"); } return $c_sum; } else {//文件不存在创建文件并写入本次数据,返回次数0 $this->wirteFile($filePath, $data . "|"); return $c_sum; } } //检测Tel在文件中出现的次数 Private function checkTel(string $data) { $fileName = "Tel_" . date("Ymd", time()) . ".dat"; $filePath = ($this->Root) . $fileName; $c_sum = 0; if (file_exists($filePath)) { $arr = file_get_contents($filePath); $row = explode("|", $arr); $countArr = array_count_values($row); $c_sum = $countArr[$data]; if ($c_sum < 4) { $this->wirteFile($filePath, $data . "|"); } return $c_sum; } else { $this->wirteFile($filePath, $data . "|"); return $c_sum; } } //检测IP在文件中存在的次数 Private function checkIp($data) { $fileName = "Ip_" . date("Ymd", time()) . ".dat"; $filePath = ($this->Root) . $fileName; $c_sum = 0; if (file_exists($filePath)) { $arr = file_get_contents($filePath); $row = explode("|", $arr); $countArr = array_count_values($row); $c_sum = $countArr[$data]; if ($c_sum < 10) { $this->wirteFile($filePath, $data . "|"); } return $c_sum; } else { $this->wirteFile($filePath, $data . "|"); return $c_sum; } } /** * 将数据写入本地文件 * @param $filePath 要写入文件的路径 * @param $data 写入的数据 */ Private function wirteFile($filePath, $data) { try { if (!is_dir($this->Root)) {//判断文件所在目录是否存在,不存在就创建 mkdir($this->Root, 0777, true); } if ($filePath == "") {//此处是不发送验证码时,记录日志创建的文件 $filePath = ($this->Root) . "N" . date("Ymd", time()) . ".dat"; } //写入文件操作 $fp = fopen($filePath, "a+");//得到指针 fwrite($fp, $data);//写 fclose($fp);//关闭 } catch (Exception $e) { print $e->getMessage(); } } } ?>调用方法(上面说了看你怎么调用 你用ajax可以改下,类里面的方法都是测试过实现没问题)
<?php /** * Created by PhpStorm. * User: Administrator * Date: 2019/6/13 0013 * Time: 10:23 */ include_once './index.php'; $y = new regMod(); $tel = 13980718991; $uv_r = $_POST['uv_r']; $ip = '117.45.123.58'; $a = $y->get_authentication_code($ip, $tel ,$uv_r); var_dump($a);
- 版权申明:此文如未标注转载均为本站原创,自由转载请表明出处《龙行博客》。
- 本文网址:https://www.liaotaoo.cn/249.html
- 上篇文章:jquery实现左侧伸缩菜单
- 下篇文章:php-curl各种请求