PHP短信验证

一、前言

现在很多网站的注册和登录都是用了短信验证的原理,例如在输入框中输入自己的手机号,然后手机就收入了4个数字,在界面上的验证框上输入收到的数字,就登录成功了,错误的话则让你重新输入(接收验证码之后会有倒计时)。

二、实现原理

其实现原理很简单,如下图所示:


短信验证实现原理.png

三、连接短信第三方验证接口发送短信

1.申请短信发送平台,获得API接口

本文使用的是五指CMS短信通短信验证平台,网址为:
http://sms.phpip.com/
当然国内还有很多别的平台,某度搜一下就能搜到。

2.了解短信接口基本知识

在平台内,通常都会有接口文档,叫你怎样调用短信平台的API来发送短信。
此API就是一个URL,通过访问此URL,并传输平台要求传入的参数,即可发送短信,根据参数的不同可发送不同类型的短信。
例如美联软通的短信调用API为:
http://sms.phpip.com/api.php?op=sms_service_vip&sms_uid=【$sms_uid】&sms_pid=【$sms_pid】&sms_passwd=【$sms_passwd】&charset=gbk&send_txt=12334&mobile=18900000000&tplid=1
其中的【】就是需要替换的参数,根据中文提示替换完参数之后,即可发送短信成功,并返回一条返回值。

3.简单发送一条短信

如果返回0,就说明短信发送成功了。
关于短信平台的使用方法,详见各平台的接口文档,本文不做重点讲解。

四、实现一个简单的短信注册功能

1.编写短信发送的核心功能

(1)使用file函数接收url的返回值(跨域获取)

php中有一个函数是file_get_contents(),这是一个用于读取文件内容的函数,但是当他的参数为一个url的时候,也能够获取访问此url时接受到的流。下面我们就通过实验证明一下:

<?php
class Sms{
    public function sendSms(){
        $file = file_get_contents("http://www.baidu.com");
        echo $file;
    } 
}

$sms = new Sms();
$sms->sendSms();

当我们通过访问这个文件的时候,其效果如下(注意浏览器的地址栏):


使用file函数获得的流.png

(2)使用file_get_contents()函数调用短信平台发送接口并在本地记录

我们直接使用该函数调用短信平带api接口即可,同时在本地的数据库中记录发送记录,代码如下所示,本代码中的数据库操作使用的是PHP的PDO操作,若对其不了解的朋友可以去看我关于PHP的PDO操作的文章。
首先我们新建一个数据库sms,新建一个sms_message表,具体属性如下图所示:

sms_message表的属性.png

编写一个调用接口发送短信的方法并调用,代码如下:

<?php
class Sms{
    public function sendSms(){
        $sms_uid="301903";
        $sms_pid="6699";
        $sms_passwd="65b6fb60cee529a11e6e55e3ed30cd9d";
        $mobile_phone="18610062316";
        $code = urlencode(rand(1000,9999));
        $sms_url="http://sms.phpip.com/api.php?op=sms_service_vip&sms_uid=".$sms_uid."&sms_pid=".$sms_pid."&sms_passwd=".$sms_passwd."&mobile=".$mobile_phone."&send_txt=".$code."&tplid=1";
        $file = file_get_contents($sms_url);
        //将结果转换为数组
        
        $data = explode("#",$file);
        //如果返回0(#前的数字),则说明调用成功,将记录存入数据库
         if($data[0]==0 || $data[0]==12){
            //获取当前时间戳
            $time = time();
            //使用PDO数据库操作。
            //1. 创建PDO
            try{ //捕获异常
                $pdo = new PDO("mysql:host=localhost;dbname=sms;charset=utf8","root","123456");
            }catch(PDOException $pe){
                //异常处理
                die("数据库连接失败!原因:".$pe->getMessage());
            }

            //2. 插入发送记录
            $sql = "insert into sms_message( phone, code, time) values( {$mobile_phone}, {$code}, {$time})";
            $stmt = $pdo->exec($sql); //执行插入语句

            //3. 解析结果(以关联数组解析)
            if($stmt==1){
                echo "短信发送并记录成功";
            }else{
                echo "PDO出错,错误代码:";
                print_r($stmt);
            }

            //4. 释放结果
            $stmt=null;
            $pdo=null;
        }else{
            echo "调取接口出错,代码:";
            print_r($data);
        }
    } 
}
//调用接口
$sms = new Sms();
$sms->sendSms();

调用完之后的结果为:

短信发送并记录成功

数据库记录为:
数据库记录的短信.png

2.与前端对接

(1)前端页面

首先我们只做一个注册的前端操作界面,代码如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <style type="text/css">
            * {
                margin:0px;
                padding:0px;
            }
            #main_body{
                margin:0px auto;
                width:100%;
                height:2048px;
            }
            #main_gui{
                position:relative;
                top:100px;
                margin:0px auto;
                padding-top:30px;
                width:600px;
                height:370px;
                background-color:#DDD;
            }
            #phone{
                width:170px;
            }
            #sms_code{
                width:100px;
            }
            h3{
                text-align:center
            }
        </style>
        <script src="./jquery/jquery-1.8.3.js"></script>
        <script src="./jquery/jquery-1.8.3.min.js"></script>
    </head>
    <body>
        <div id="main_body">
            <div id="main_gui">
                <form method="post" action="verifySms.php" />
                <center>
                    <h3>会员注册</h3><br/><br/>
                    <p>手&nbsp; 机:<input type="text" id="phone" /></p><br/><br/>
                    <p>验证码:<input type="text" id="sms_code" /><input type="button" id="btn" value="点击获取验证码" /></p><br/><br/>
                    <p><input type="submit" value="点击注册" /></p>
                </center>
                </form>
            </div>
        </div>
    </body>
</html>

以上代码显示出来是这个样子的↓:

短信注册界面.png

注意:代码的<head>里必须引用Jquery文件<script src="./jquery/jquery.js"></script><script src="./jquery/jquery.min.js"></script>,否则后面无法实现按钮的功能。

(2)倒计时功能

接下来对“获取验证码”按钮做倒计时功能,本功能采用Jquery来实现,如果对Jquery不熟悉,可以到我JS的课程中学习Jquery。
我们在上面文档的最后增加<script>标签,在其中使用Jquery对第一个按钮做方法绑定,代码如下:

<script>
    $(function(){
        $("#btn").click(function(){
            $.getSMSCode();
        });
    });
    $.getSMSCode=function(){
        $.setTime=60;
        $.minusSecond=setInterval(function(){
            $("#btn").attr("disabled",true);
            $("#btn").attr("value",$.setTime+"s后获取验证码");
            $.setTime--;
            if($.setTime==-2){
            clearInterval($.minusSecond);
            $("#btn").attr("disabled",false);
            $("#btn").attr("value","点击获取验证码");
            }
        },1000);
    };
</script>

(3)发送验证码

在点击获取验证码的时候,先使用AJAX调用后台接口发送短信验证码,当接口调用成功并发送了短信验证码的时候,才调用上面的方法。因为原生AJAX很麻烦,所以这里还是使用Jquery来写实现AJAX,还是在<script>标签内,给“获取验证码”按钮中绑定的函数中在增加一个新的方法,代码如下:

<script>
    $(function(){
        $("#btn").click(function(){
            $.askSMSCode();
        });
    });
    $.getSMSCode=function(){
        $.setTime=60;
        $.minusSecond=setInterval(function(){
            $("#btn").attr("disabled",true);
            $("#btn").attr("value",$.setTime+"s后获取验证码");
            $.setTime--;
            if($.setTime==-2){
            clearInterval($.minusSecond);
            $("#btn").attr("disabled",false);
            $("#btn").attr("value","点击获取验证码");
            }
        },1000);
    };
    $.askSMSCode=function(){
        $.phone_number=$("#phone").val(); //获取表单中填写的电话号码
        $.post("askSms.php",{phone:$.phone_number},function(data){
                    if(data=="OK"){
                        $.getSMSCode();
                    }
                });
        
    };
</script>

此时点击前端界面的“获取验证码”按钮之后,如不出现错误,即可实现按钮倒计时,同时手机收到验证码。

3.接收验证码并验证

手机收到验证码之后,要对提交的验证码进行验证,验证通过则注册成功,验证失败则跳回注册页面重新获取。

(1)前端页面

我们先制作两个前端页面,第一个是成功页面registSuccess.html,代码如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
    </head>
    <body>
        <h1>:) 注册成功</h1>
    </body>
</html>

运行起来是这个样子:


注册成功页面.png

第二个是成功页面registFail.html,代码如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <script>
        window.onload=setTimeout(function(){window.location.href="sms_tpl.html";},5000);
        </script>
    </head>
    <body>
        <h1>:( 注册失败</h1><br/>
        <h2>请填写正确的验证码</h2>
    </body>
</html>

运行起来是这个样子:
注册失败页面.png

因为里面写了定时调转的JS代码,所以5秒后会跳回注册页面。

(2)后端注册程序

提交表单后,系统会根据表单中的action提交到verifySms.php中去,然后做相应的验证和处理,代码如下:

<?php
class VerifySms{
    public $phone="";
    public $smsCode="";
    public function verify(){
        $this->phone = $_POST["phone"];
        $this->smsCode = $_POST["smsCode"];
        //使用PDO数据库操作。
        //1. 创建PDO
        try{ //捕获异常
            $pdo = new PDO("mysql:host=localhost;dbname=sms;charset=utf8","root","");
        }catch(PDOException $pe){
            //异常处理
            die("数据库连接失败!原因:".$pe->getMessage());
        }

        //2. 插入发送记录
        $sql = "select code from sms_message where phone={$this->phone} and time=(select MAX(time) from sms_message)";
        $stmt = $pdo->query($sql); //执行插入语句

        //3. 解析结果(以关联数组解析)
        if($stmt->rowCount()==1){
            $row = $stmt->fetch(PDO::FETCH_ASSOC);
            if($row['code']==$this->smsCode){
                header("Location:registSuccess.html");
            }else{
                header("Location:registFail.html");
            }
        }else{
            header("Location:registfail.html");
        }

        //4. 释放结果
        $stmt=null;
        $pdo=null;
    }
}

$verifySms = new VerifySms();
$verifySms->verify();

最后该脚本会根据调用短信接口和数据库操作的结果来返回不同的页面。

五、其他功能

除了以上的手机短信注册功能致之外,还有其他用途,例如登录功能和密码找回功能。

1.登录功能实现思路

登录功能的实现和注册功能很类似。如果用户选择手机号加验证码登录,那么在输入手机号之后,点击获取验证码,会受到验证码,在点击提交验证码之后,系统后台先核对该手机号是否已经注册,若注册则核对提交的验证码和系统记录的验证码是否一致,一致则登录成功,不一致则再跳转到登录页面。

2.密码找回实现思路

实现密码找回有个前提,前提就是用户在注册的时候已经填写并确定了密码,或者在短信验证码注册之后完善了自己的密码。
当用户忘记密码之后,点击相应按钮进入找回密码页面,同样输入注册的手机号并获取验证码,然后提交。若手机号和验证码都验证成功后,则跳转到修改密码的页面,在两次输入的密码一样后,修改密码成功。

以上两个功能在本文中不做演示,各位看官可以自己试验并实现。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269