PHP表单TOKEN防止重复提交

来源:互联网 发布:高达模型淘宝店 编辑:程序博客网 时间:2024/06/07 05:16

PHP表单TOKEN防止重复提交

一 简介

1. 什么是表单token?
Token(人家就叫这名,记住就行)是服务端生成的一串字符串,以作客户端进行请求的一个令牌和依据。
2. 表单token用来干什么?
第一:防止提交表单是为外部提交。也叫(跨站点请求伪造)。
第二:防止表单重复提交,造成数据错乱。
3. 表单token的实现原理是什么?
在用户进入任何一个表单页面的时候,服务器端就会生成一段针对该用户的唯一token码,同时该token码会保存到该用户session_id下session数据中。这个token码就在表单的隐藏域中。在用户提交该表单的时候会跟随其他数据一并提交。后台会进行数据验证,包括什么用户名验证(不为空,不能包含中文等),密码验证(不能全为数字,不能少于10位等),还有其他乱其八糟的验证。其中就包括token验证(与该用户session_id下储存的token码进行比对),如果token为空或者不等于当前session中存储的token码,就说明该表单为外部提交表单或者是重复提交表单,将不在进行数据库操作。如果token和其他数据都验证通过了,(先把session中的token码清空)进行数据库操作,提交数据。

注意:不论token码验证失败还是成功,都必须进行清空。如果验证失败了没有清空session中的token,如果你的验证规则不好(token不唯一),可能多试几次就会通过了。如果验证成功了,页面没有进行跳转,你也没清空session中的token,多点几次提交,这些数据也都会提交。

二实例

这里我那TP5框架里的表单验证来举例。
商品分类表单提交页面:
这里写图片描述
表单后台代码(只贴一部分):

<div class="ncap-form-default">                    <div class="bot">                            <input type="hidden" name="id" value="{$Info.id}">                <input type="hidden" name="__token__" value="{$Request.token}" />                <a href="JavaScript:void(0);" class="ncap-btn-big ncap-btn-green" onClick="ajax_submit_form('addEditCoordinatesForm','{:U('Coordinates/addEditCoordinates?is_ajax=1')}');">确认提交</a>            </div>        </div>      </form>

后台代码:

if((I('is_ajax')==1) && IS_POST){          $data = I('post.');          $validate = \think\Loader::validate('Goods');          if (!$validate->batch()->check($data)) {//数据验证                $error = $validate->getError();                $error_msg = array_values($error);                $return_arr = array(                    'status' => -1,                    'msg' => $error_msg[0],                    'data' => $error,                );                $this->ajaxReturn($return_arr);            }

这段代码是后台调取验证规则的,以下是我的验证规则:

<?phpnamespace app\admin\validate;use think\Validate;class Goods extends Validate{    // 验证规则    protected $rule = [        ['Goods_name','require|unique:goods','商品名称必填|商品名称重复'],        ['Goods_sn', 'unique:goods', '商品货号重复'], // 更多 内置规则 http://www.kancloud.cn/manual/thinkphp5/129356        ['shop_price','regex:\d{1,10}(\.\d{1,2})?$','本店售价格式不对。'],        ['market_price','regex:\d{1,10}(\.\d{1,2})?$','市场价格式不对。'],        ['weight','regex:\d{1,10}(\.\d{1,2})?$','重量格式不对。'],        ['exchange_integral','checkExchangeIntegral','积分抵扣金额不能超过商品总额'],        ['__token__','token','正在拼了死命的加载中······'],    ];

验证规则数组中的一个值是要验证的字段,第二个值时要调用的规则(可以自定义规则),第三个是提示信息。TP5的官方手册的写法让人困惑感觉好像是token验证是追加到了某个字段(如name字段)的后边,好像必须要依附于某个字段才能进行验证。
这里写图片描述
先不提官方文档。我这样写是标准格式,绝对没有问题的。

注意:这里需要注意一个细节,观察token源码,发现生成token是在Request类里:

/**     * 生成请求令牌     * @access public     * @param string $name 令牌名称     * @param mixed  $type 令牌生成方法     * @return string     */    public function token($name = '__token__', $type = 'md5')    {        $type  = is_callable($type) ? $type : 'md5';        $token = call_user_func($type, $_SERVER['REQUEST_TIME_FLOAT']);        if ($this->isAjax()) {            header($name . ': ' . $token);        }        Session::set($name, $token);        return $token;    }

然后验证token是在Validate类里:

/**     * 验证表单令牌     * @access protected     * @param mixed     $value  字段值     * @param mixed     $rule  验证规则     * @param array     $data  数据     * @return bool     */    protected function token($value, $rule, $data)    {        $rule = !empty($rule) ? $rule : '__token__';        if (!isset($data[$rule]) || !Session::has($rule)) {            // 令牌数据无效            return false;        }        // 令牌验证        if (isset($data[$rule]) && Session::get($rule) === $data[$rule]) {            // 防止重复提交            Session::delete($rule); // 验证完成销毁session            return true;        }        // 开启TOKEN重置        Session::delete($rule);        return false;    }

而每次验证完token,都会进行清空,所以所有的其他验证规则到要放到token验证之前,不然token验证完成了,而其他有的字段验证未通过,你的表单是需要重新填写的,否则会永远提交不上。放到最后边,即使其他字段验证失败,从新修改那个字段继续提交即可,不需要重新填写表单。哒哒······结束啦。

原创粉丝点击