- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章ThinkPHP下表单令牌错误与解决方法分析由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
本文实例讲述了ThinkPHP下表单令牌错误与解决方法。分享给大家供大家参考,具体如下:
在项目的开发过程中,添加、编辑数据时偶尔会遇到系统提示的“表单令牌错误”,一开始没怎么在意,直到今天下午QA把此问题提到bug系统了,正好时间也有空余,就追着TP3.13的源码看了下去,几分钟后,便知道原委了.
在项目中开启表单令牌,通常要在配置文件中做如下配置 。
1
2
3
4
5
6
7
8
|
// 是否开启令牌验证
'TOKEN_ON'
=> true,
// 令牌验证的表单隐藏字段名称
'TOKEN_NAME'
=>
'__hash__'
,
//令牌哈希验证规则 默认为MD5
'TOKEN_TYPE'
=>
'md5'
,
//令牌验证出错后是否重置令牌 默认为true
'TOKEN_RESET'
=> true
|
以编辑数据为例,通常在服务端有个Model写上字段过滤规则,Action写上数据检测的代码,如 。
1
2
3
4
|
$table
= D(
'table'
);
if
(!
$table
->create()){
exit
(
$this
->error(
$table
->getError()));
}
|
这时在IDE上双击create()定位到TP框架中Model.class.php中的create方法 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
/**
* 创建数据对象 但不保存到数据库
* @access public
* @param mixed $data 创建数据
* @param string $type 状态
* @return mixed
*/
public
function
create(
$data
=
''
,
$type
=
''
) {
……省略……
// 表单令牌验证
if
(!
$this
->autoCheckToken(
$data
)) {
$this
->error = L(
'_TOKEN_ERROR_'
);
return
false;
}
……省略……
}
|
看到代码会理解当autoCheckToken方法检测失败时会报错,那么就接着跟踪此方法 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
// 自动表单令牌验证
// TODO ajax无刷新多次提交暂不能满足
public
function
autoCheckToken(
$data
) {
// 支持使用token(false) 关闭令牌验证
// 如果在Action写了D方法,但没有对应的Model文件,那么$this->options为空
if
(isset(
$this
->options[
'token'
]) && !
$this
->options[
'token'
])
return
true;
if
(C(
'TOKEN_ON'
)){
$name
= C(
'TOKEN_NAME'
);
if
(!isset(
$data
[
$name
]) || !isset(
$_SESSION
[
$name
])) {
// 令牌数据无效
return
false;
}
// 令牌验证
list(
$key
,
$value
) =
explode
(
'_'
,
$data
[
$name
]);
if
(
$value
&&
$_SESSION
[
$name
][
$key
] ===
$value
) {
// 防止重复提交
unset(
$_SESSION
[
$name
][
$key
]);
// 验证完成销毁session
return
true;
}
// 开启TOKEN重置
if
(C(
'TOKEN_RESET'
)) unset(
$_SESSION
[
$name
][
$key
]);
return
false;
}
return
true;
}
|
看了这段代码,会发现第一个判断中有$_SESSION[$name],那么这个seesion变量时从哪里过来的呢,这还得从生成令牌时说起,定位TokenBuildBehavior.class.php文件 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
// 创建表单令牌
private
function
buildToken() {
$tokenName
= C(
'TOKEN_NAME'
);
$tokenType
= C(
'TOKEN_TYPE'
);
if
(!isset(
$_SESSION
[
$tokenName
])) {
$_SESSION
[
$tokenName
] =
array
();
}
// 标识当前页面唯一性
$tokenKey
= md5(
$_SERVER
[
'REQUEST_URI'
]);
if
(isset(
$_SESSION
[
$tokenName
][
$tokenKey
])) {
// 相同页面不重复生成session
$tokenValue
=
$_SESSION
[
$tokenName
][
$tokenKey
];
}
else
{
$tokenValue
=
$tokenType
(microtime(TRUE));
$_SESSION
[
$tokenName
][
$tokenKey
] =
$tokenValue
;
}
$token
=
'<input type="hidden" name="'
.
$tokenName
.
'" value="'
.
$tokenKey
.
'_'
.
$tokenValue
.
'" />'
;
return
$token
;
}
|
此段代码主要是在TP开启表单验证的情况下,以TOKEN_NAME和当前URI的md5为健生成令牌值,再在用户提交表单时,先验证下是否存在该session,没有则返回false,有则紧接着和表单字段TOKEN_NAME验证下,如果一致先删除此session(作用时避免下次提交出先表单令牌错误),返回ture,否则返回false.
ok,回到主题,TP下表单提交之所以会出现令牌错误,那么就只有两种可能 。
1. 在令牌开启的状态下,提交的表单中,没有TOKEN_NAME字段或是没有相应session(当前提交表单环境下,没有生成相应session,这个主要是在用户提交后报错用户紧接着又刷新当前页面,同时编辑页面和展示页面是在同一个方法里) 。
2. 有session变量,但前后值不一样 。
我们项目之所以出现此错误,可以看看下面配置 。
1
2
3
4
5
6
7
|
return
array
(
'TOKEN_ON'
=>
'false'
,
'TOKEN_NAME'
=>
'__hash__'
,
'TOKEN_TYPE'
=>
'md5'
,
'TOKEN_RESET'
=>
'true'
,
'DB_FIELDTYPE_CHECK'
=>
'true'
);
|
本来应该写成布尔值的false,不知道哪位大侠任性的写成字符串的false了,那么判断时当然会按开启表单令牌的逻辑来,而且项目中,添加、编辑和展示都是同一个方法,一旦验证出错,一般程序处理逻辑会返回原有的界面,那么就和上次是同一个表单了,连续提交同一个表单也就相当于重复提交,那么便会报“表单令牌错误”.
希望本文所述对大家基于ThinkPHP框架的PHP程序设计有所帮助.
最后此篇关于ThinkPHP下表单令牌错误与解决方法分析的文章就讲到这里了,如果你想了解更多关于ThinkPHP下表单令牌错误与解决方法分析的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我在 mongodb 中的玩家和锦标赛之间存在多对多关系。 我希望能够一次将许多玩家添加到锦标赛中。如果没有 ajax,这很简单,但我们有一个包含数千名玩家的数据库,因此表单选择变得巨大。 我们想为此
这个问题已经有答案了: When should I use html's and when spring's in Spring MVC web app? (3 个回答) 已关闭 6 年前。 我正
我正在 C++ Builder XE4 上使用 VCL。 我有以下组件。 FormMain 具有 TButton *B_select; FormSelect(或DialogSelect)具有 TCom
如何在不影响表单控件的情况下更改表单的 alphablend? 德尔福XE7 最佳答案 此问题的一个解决方案是使用多设备应用程序(如果无法使用VCL)。 如果您需要保留透明的TForm,只需更改属性T
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
我正在尝试扩展 Django 注册以包含我自己的注册表单。原则上这是相当简单的。我只需要编写自己的表单( CustomRegistrationForm ),它是原始表单( RegistrationFo
我正在尝试为我的网站实现聊天功能。为了做到这一点,我遵循了以下教程:https://channels.readthedocs.io/en/latest/tutorial/ 然后我稍微更改了代码以实现它
有一个问题,我需要用一个 html 表单提交两个相互关联的模型表单。我知道如何提交两个单独的表格,但是在相关模型表格的情况下外键让我发疯。 问题是,第二个表单应该用外键填充字段到第一个表单的实例。 在
我正在创建一个工具,允许某人输入食谱,然后将其保存为 XML 文件,我已经创建了 XSD,但我想知道如何在我的网页上制作一个表单以允许用户输入他们的食谱并遵守模式。我一直在研究 Ajax 和 Jque
在 .net win 表单(如 asp.net web 表单)中是否有可用的验证控件? 因为很难为我的每个控件设置正确的条件,所以我的表单中也有很多重复的代码。 正确的做法是什么? 最佳答案 看看这个
我有一个简短的问题。我正在学习如何使用 javascript 制作注册表,发现此链接非常有用。 http://www.w3resource.com/javascript/form/javascript
我正在开发一个项目,该项目将使用循环将许多表单添加到 mysql 数据库中。在 javascript 部分中,我无法让 var i 在函数 updatesum() 中工作。有人可以帮我吗? 我试图避免
在我的应用程序上有一个包含 2 个字段和一个保存按钮的表单。 在我的 onClick 结束时我需要什么来将光标返回到第一个字段。 我有这个来清除它们 txtData.setText("
这个问题不太可能帮助任何 future 的访问者;它只与一个小的地理区域、一个特定的时间点或一个非常狭窄的情况有关,这些情况并不普遍适用于互联网的全局受众。为了帮助使这个问题更广泛地适用,visit
<input type="text" name="textfield" onKeyPress="javascript:alert(event.
我正在构建的网站有一个登录表单,作为所有其他模板扩展的 base.html 模板的一部分;因此,我需要以某种方式处理每个页面上的登录/注销逻辑。 目前每个页面都在单独的 View 中加载,那么实现它的
我有一个表单类,看起来像.. #forms.py class ExampleForm(forms.Form): color = forms.CharField(max_length=25)
有没有办法在表单定义中给表单一个特殊的错误渲染函数?在 customizing-the-error-list-format 下的文档中它展示了如何为表单提供特殊的错误呈现函数,但似乎您必须在实例化表单
我正在处理由多个页面组成的表单,我想解决验证问题。 当我点击提交按钮时,当前页面上的所有字段都会在下方显示错误消息,但是如果我更改页面,那么我需要再次点击提交,因为这些字段未设置为已触摸。 如果我可以
是否可以附加到继承表单的 exclude 或 widgets 变量? 到目前为止,我有以下设置。 class AddPropertyForm(forms.ModelForm): num_mon
我是一名优秀的程序员,十分优秀!