dede自定义表单如何实现短信验证?

99ANYc3cd6
预计阅读时长 41 分钟
位置: 首页 DEDE建站 正文
  1. 前端:用户在网页上填写表单,并触发短信发送和验证逻辑。
  2. 后端:DedeCMS处理表单提交,并调用短信接口发送验证码。
  3. 数据库:存储验证码和其状态(是否已使用、过期时间等)。

下面我将为你提供一个完整、详细的实现方案,包含代码示例和步骤说明。


核心思路

  1. 分离验证码逻辑:在用户点击“获取验证码”按钮时,通过AJAX请求后端接口,后端生成验证码、调用短信接口发送,并将验证码和相关信息存入数据库。
  2. 二次验证:在用户最终提交整个表单时,后端再次验证用户输入的验证码是否与数据库中存储的、且未过期的验证码匹配。
  3. 使用DedeCMS的自定义表单功能:我们将在DedeCMS原有的表单处理流程上,增加验证码的校验环节。

第一步:准备工作

  1. 短信平台账号:你需要先注册一个短信服务提供商(如:阿里云短信、腾讯云短信、SendCloud等),获取你的 API IDAPI Key短信签名
  2. DedeCMS环境:确保你的网站已经安装并可以正常运行DedeCMS。
  3. 创建自定义表单
    • 进入DedeCMS后台 -> 核心 -> 内容模型管理 -> 自定义表单
    • 创建一个新的自定义表单,例如命名为 feedback
    • 在表单字段管理中,添加以下字段:
      • tel (手机号码) - varchar(20) - 必填
      • code (短信验证码) - varchar(10) - 必填
      • code_time (验证码时间戳) - int(11) - 用于判断是否过期
    • 保存并生成表单,你会得到类似 plus/diy.php?action=list&diyid=1 的列表页和表单提交页 (plus/diy.php)。

第二步:创建短信发送接口(后端核心)

这是最关键的一步,我们需要一个PHP文件来专门处理验证码的生成、发送和存储。

  1. 在你的网站根目录下创建一个新文件,/plus/send_sms.php

  2. 修改 /plus/send_sms.php 文件内容

<?php
require_once(dirname(__FILE__)."/../include/common.inc.php");
// 引入短信平台SDK(这里以阿里云短信为例,你需要根据你的短信平台修改)
// 假设你已经将阿里云的SDK文件放在 /include/aliyun-php-sdk/ 目录下
// include_once 'aliyun-php-sdk-core/Config.php';
// use Dysmsapi\V20250525\Dysmsapi;
// use DefaultProfile;
// use DefaultAcsClient;
// --- 配置信息 ---
$smsConfig = array(
    'accessKeyId'     => '你的AccessKeyId',          // 阿里云AccessKeyId
    'accessKeySecret' => '你的AccessKeySecret',      // 阿里云AccessKeySecret
    'signName'        => '你的短信签名',              // 短信签名
    'templateCode'    => 'SMS_123456789',             // 短信模板ID (模板内容需包含变量: ${code})
    'expireMinutes'   => 5,                          // 验证码有效期(分钟)
);
// --- 获取前端传来的参数 ---
$mobile = isset($mobile) ? trim($mobile) : '';
if(empty($mobile) || !preg_match("/^1[3-9]\d{9}$/", $mobile)) {
    // 返回JSON错误信息
    exit(json_encode(array('status' => -1, 'msg' => '手机号码格式错误')));
}
// --- 生成随机验证码 ---
$code = rand(100000, 999999);
// --- 调用短信接口发送(伪代码,需替换为实际SDK调用) ---
try {
    // 1. 初始化AcsClient
    // $profile = DefaultProfile::getProfile("cn-hangzhou", $smsConfig['accessKeyId'], $smsConfig['accessKeySecret']);
    // $acclient = new DefaultAcsClient($profile);
    // $request = new Dysmsapi\SendSmsRequest();
    // $request->setPhoneNumbers($mobile);
    // $request->setSignName($smsConfig['signName']);
    // $request->setTemplateCode($smsConfig['templateCode']);
    // $request->setTemplateParam(json_encode(array('code' => $code)));
    // 2. 发送短信
    // $response = $acclient->getAcsResponse($request);
    // 为了演示,我们假设发送总是成功
    // $sendResult = json_decode(json_encode($response), true);
    // if($sendResult['Code'] != 'OK') {
    //     exit(json_encode(array('status' => -2, 'msg' => '短信发送失败: ' . $sendResult['Message'])));
    // }
    // --- 3. 将验证码存入数据库 ---
    $tableName = '#@__diyform'; // DedeCMS自定义表单的数据表前缀
    $dsql = new DedeSql(false);
    // 先删除该手机号旧的验证码记录
    $dsql->ExecuteNoneQuery("DELETE FROM `{$tableName}` WHERE `tel` = '{$mobile}' AND `type` = 'sms_verify'");
    // 插入新的验证码记录
    $now_time = time();
    $expire_time = $now_time + ($smsConfig['expireMinutes'] * 60);
    $sql = "INSERT INTO `{$tableName}` (`tel`, `code`, `code_time`, `type`, `addtime`) 
            VALUES ('{$mobile}', '{$code}', '{$expire_time}', 'sms_verify', '{$now_time}');";
    $dsql->ExecuteNoneQuery($sql);
    // --- 返回成功信息 ---
    exit(json_encode(array('status' => 1, 'msg' => '验证码已发送,请注意查收')));
} catch (Exception $e) {
    exit(json_encode(array('status' => -3, 'msg' => '系统错误: ' . $e->getMessage())));
}
?>

代码说明

  • 短信平台SDK:上面的代码中,阿里云短信的调用部分被注释了并标为“伪代码”,你需要去你选择的短信平台下载对应的PHP SDK,并根据其文档修改这部分代码。
  • 数据库表:我们直接利用了DedeCMS存储自定义表单的数据表 #@__diyform,为了不干扰正常表单数据,我们增加了一个 type 字段,将其值设为 'sms_verify' 来区分。code_time 存储的是过期时间戳,方便后续判断。
  • 安全性:这里为了简化,没有做太复杂的防刷限制(如频率限制),在生产环境中,你应该增加对同一手机号发送频率的限制(60秒内不能重复发送)。

第三步:修改前端表单页面

我们需要修改用户填写表单的页面(通常是 /plus/diy.php 或你生成的静态表单页面),增加获取验证码和AJAX提交的逻辑。

假设你的表单HTML结构如下(从DedeCMS生成的表单中获取):

<form action="/plus/diy.php" enctype="multipart/form-data" method="post">
    <input type="hidden" name="action" value="post" />
    <input type="hidden" name="diyid" value="1" />
    <input type="hidden" name="do" value="2" />
    <div>
        <label for="tel">手机号码:</label>
        <input type="text" name="tel" id="tel" required />
    </div>
    <div>
        <label for="code">短信验证码:</label>
        <input type="text" name="code" id="code" required />
        <button type="button" id="getSmsBtn">获取验证码</button>
    </div>
    <!-- 其他表单字段... -->
    <button type="submit">提交</button>
</form>

修改步骤

  1. 引入jQuery库:确保你的页面有jQuery,如果没有,在<head>中引入:

    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
  2. 编写JavaScript代码:在页面底部</body>标签前,添加以下脚本:

<script>
$(function() {
    var getSmsBtn = $('#getSmsBtn');
    var telInput = $('#tel');
    var countdown = 60;
    // 点击“获取验证码”按钮
    getSmsBtn.on('click', function() {
        var mobile = telInput.val().trim();
        if (!mobile) {
            alert('请先输入手机号码');
            return;
        }
        // 禁用按钮,开始倒计时
        getSmsBtn.prop('disabled', true);
        var timer = setInterval(function() {
            countdown--;
            getSmsBtn.text(countdown + '秒后重试');
            if (countdown <= 0) {
                clearInterval(timer);
                getSmsBtn.prop('disabled', false).text('获取验证码');
                countdown = 60;
            }
        }, 1000);
        // 发送AJAX请求到我们创建的接口
        $.ajax({
            url: '/plus/send_sms.php',
            type: 'POST',
            data: { mobile: mobile },
            dataType: 'json',
            success: function(response) {
                if (response.status == 1) {
                    alert(response.msg);
                } else {
                    alert(response.msg);
                    // 如果发送失败,恢复按钮
                    clearInterval(timer);
                    getSmsBtn.prop('disabled', false).text('获取验证码');
                    countdown = 60;
                }
            },
            error: function() {
                alert('网络错误,请稍后重试');
                clearInterval(timer);
                getSmsBtn.prop('disabled', false).text('获取验证码');
                countdown = 60;
            }
        });
    });
    // 原有的表单提交逻辑可以保留,也可以改为AJAX提交
    // 如果是AJAX提交,你需要阻止默认的form提交行为,然后用$.ajax提交整个表单数据
    // 这里为了简单,我们假设还是用传统的form提交,验证码的校验将在下一步的后端PHP中完成
});
</script>

第四步:修改DedeCMS表单处理逻辑(后端校验)

也是最关键的一步,我们需要修改DedeCMS处理表单提交的文件,在数据入库前,先校验验证码。

  1. 找到并备份文件/plus/diy.php务必先备份!

  2. 修改 /plus/diy.php: 我们需要找到处理 do=2(即表单提交)的代码段,在 if($dsql->ExecuteNoneQuery($query)) 之前,插入我们的验证码校验逻辑。

    diy.php 中找到类似这样的代码块(大约在第150-200行,具体版本可能略有不同):

    // ... 前面的代码 ...
    if($do == 2)
    {
        $dede_fields = empty($dede_fields) ? '' : trim($dede_fields);
        $dede_fieldshash = empty($dede_fieldshash) ? '' : trim($dede_fieldshash);
        if($dede_fields && $dede_fieldshash)
        {
            $fdhash = md5($dede_fields.$cfg_cookie_encode);
            if($fdhash != $dede_fieldshash)
            {
                ShowMsg('数据校验不对,程序返回', '-1');
                exit();
            }
        }
        $fieldarr = explode(';', $dede_fields);
        if(is_array($fieldarr))
        {
            foreach($fieldarr as $field)
            {
                if($field == '') continue;
                $fieldinfo = explode(',', $field);
                ${$fieldinfo[0]} = FilterSearch(${$fieldinfo[0]});
                ${$fieldinfo[0]} = ${$fieldinfo[0]} ? ${$fieldinfo[0]} : ${$fieldinfo[2]};
                if($fieldinfo[1] == 'textdata')
                {
                    ${$fieldinfo[0]} = HtmlReplace(${$fieldinfo[0]}, 1);
                }
            }
        }
        // 在这里插入我们的验证码校验代码!
        $addvar = '';
        $inadd_f = '';
        $inadd_v = '';
        if(is_array($fieldarr))
        {
            foreach($fieldarr as $field)
            {
                if($field == '') continue;
                $fieldinfo = explode(',', $field);
                if(${$fieldinfo[0]} != '' && $fieldinfo[1] != 'textdata')
                {
                    $inadd_f .= ','.$fieldinfo[0];
                    $inadd_v .= " ,'".${$fieldinfo[0]}."'";
                }
            }
        }
        $query = "INSERT INTO `{$diy->table}` (`id`, `ifcheck` $inadd_f ) VALUES (NULL, $ifcheck $inadd_v );";
        if($dsql->ExecuteNoneQuery($query))
        {
    // ... 后面的代码 ...
  3. 在指定位置插入校验代码

    在上面代码注释 // 在这里插入我们的验证码校验代码! 的位置,粘贴以下PHP代码:

    // --- 开始:短信验证码校验逻辑 ---
    $mobile = isset($tel) ? $tel : '';
    $user_code = isset($code) ? $code : '';
    if (empty($mobile) || empty($user_code)) {
        ShowMsg('手机号和验证码不能为空!', '-1');
        exit();
    }
    $dsql->SetQuery("SELECT `code`, `code_time` FROM `{$diy->table}` WHERE `tel` = '{$mobile}' AND `type` = 'sms_verify' ORDER BY `id` DESC LIMIT 1");
    $dsql->Execute();
    if($row = $dsql->GetArray()) {
        $db_code = $row['code'];
        $code_time = $row['code_time'];
        $current_time = time();
        // 验证码是否过期
        if ($current_time > $code_time) {
            ShowMsg('验证码已过期,请重新获取!', '-1');
            exit();
        }
        // 验证码是否正确
        if ($db_code != $user_code) {
            ShowMsg('验证码错误,请重新输入!', '-1');
            exit();
        }
        // 验证成功,删除已使用的验证码记录(防止重复使用)
        $dsql->ExecuteNoneQuery("DELETE FROM `{$diy->table}` WHERE `tel` = '{$mobile}' AND `type` = 'sms_verify'");
    } else {
        ShowMsg('未找到有效的验证码记录,请先获取验证码!', '-1');
        exit();
    }
    // --- 结束:短信验证码校验逻辑 ---
  4. 保存文件


总结与流程回顾

整个流程已经打通:

  1. 用户操作:用户输入手机号,点击“获取验证码”。
  2. AJAX请求:前端JS向 /plus/send_sms.php 发送请求。
  3. 发送短信send_sms.php 生成验证码,调用短信平台API发送,并将验证码和过期时间存入 #@__diyform 表,标记 type='sms_verify'
  4. 用户输入:用户收到短信,将验证码填入表单。
  5. 表单提交:用户点击提交,表单数据POST到 /plus/diy.php
  6. 后端校验diy.php 在处理数据前,先从数据库中查询该手机号对应的最新验证码记录,检查用户输入的验证码是否匹配且未过期。
  7. 成功/失败
    • 成功:校验通过,删除数据库中的验证码记录,然后继续执行原有的DedeCMS表单入库逻辑。
    • 失败:校验不通过(错误/过期),使用 ShowMsg 返回错误提示,并终止后续流程。

重要提示

  • 短信费用:发送短信会产生费用,请合理控制发送频率。
  • 安全性:此方案为基本实现,对于高安全要求的场景,还需要考虑更多的安全措施,如IP限制、验证码复杂度等。
  • 数据库表:直接操作 #@__diyform 表是一种“取巧”的方法,为了更规范,你也可以创建一个专门的验证码表来存储,这样逻辑会更清晰,也不会影响自定义表单数据的查询。
-- 展开阅读全文 --
头像
织梦调用文件保存目录如何设置?
« 上一篇 02-08
织梦后台打开404,如何解决?
下一篇 » 02-08
取消
微信二维码
支付宝二维码

目录[+]