1、YII中控制器中actionDelete方法
以前的方案,对于“删除”功能来说,我是通过<form>中的隐藏域包含id,部门名称(name)等信息,然后通过jquery的post来提交。在用YII时,对控制器中的actionDelete($id)方法有了更进一步了解。
一般YII中自动生成的actionDelete()方法如下
/**
* Deletes a particular model.
* If deletion is successful, the browser will be redirected to the 'admin' page.
* @param integer $id the ID of the model to be deleted
*/
public function actionDelete($id)
{
$this->loadModel($id)->delete();
// if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser
if(!isset($_GET['ajax']))
$this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('admin'));
}
一开始一直以为,actionDelete方法的参数$id,是通过get方式传递的。似乎CI框架中就是这样,在YII的示例中,提交的URL都是通过类似下面语句生成的
$this->createUrl('controller/action',array('id'=>$id));
所以,我在做项目中关于“部门分类”删除功能,就在想,如果这样的话(通过GET方式提交),那只要在浏览器提交相应的URL,更改id值,这样数据的安全性如何保证呢?
后来,在js中,我特意将post提交,改为get提交,代码如下:
$(".del").bind("click",function(event){
var id=$("input[name='id']",$(this).parents("form:first")).attr("value");
var name=$("input[name='name']",$(this).parents('form:first')).val();
var url=$(this).attr('href');//例如:index.php?r=controller/action&id=1
art.dialog.confirm('你确认删除['+name+']该分类吗?',function(){
$.post(url,function(tips)//<------------------这里改为get
{
alert('tips');
return false;
var json=eval("("+tips+")");
if(json.result=='success'){
art.dialog.tips(json.msg);
$(event.target).parents('ul:first').hide();
}
if(json.result=='error'){
var str='';
$.each(json,function(idx,item){
if(idx=='msg')
str+=item;
});
art.dialog.tips(str);
}
});
});
return false;
});
在actionDelete方法中,echo一个字符串,并exit();结果发现,根本不执行actionDelete方法。研究了半天,最终恍然大悟,原来控制器的上面有这样一句代码:
public function filters()
{
return array(
'accessControl', // perform access control for CRUD operations
'postOnly + delete', // we only allow deletion via POST request
);
}
就是说:delete方法只能用POST方式提交。
关于YII中删除不安全的想法一下就没有了。接下来就做了一个测试,actionDelete($id),post提交和get提交,能否能获取到。
假如我通过URL:index.php?r=controller/test&id=3
public function actionTest($id)
{
echo $id;
exit;
}
测试结果:
POST提交,$id值为3
GET提交,$id值为3
真相终于大白。
二、CActiveForm的ajax验证
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'post-form',
'enableAjaxValidation'=>true,
)); ?>
如果开启ajax验证,如上:将属性enableAjaxValidation设置为true,那么在控制器中要调用以下方法:
protected function performAjaxValidation($model)
{
if(isset($_POST['ajax']) && $_POST['ajax']==='costcategory-form')//这里的$_POST['ajax']的值默认为表单的id
{
echo CActiveForm::validate($model);
Yii::app()->end();
}
}
在实际项目开发中遇到的问题说明一下:
1、在控制器中调用performAjaxValidation,这个方法是在数据未提交(点击submit按钮)之前所执行的,即 未提交数据时的ajax验证。
2、如果有错误,CActiveForm::validate($model);返回的是json格式的数据
3、自定义表单注意,如果要使用ajax验证,针对验证字段,比如我要对name这个字段进行ajax验证,要加上
<?php echo $form->error($model,'name'); ?>
否则,无法开启ajax验证。
4、下面对我本人有用
由于上述表单中没有submit按钮,上图中的“保存”按钮,是基于artDialog插件生成。源码如下:
function btn_restore(){
api=art.dialog.open.api;
api.button({
name:'保存',
disabled:false
});
}
$(document).ready(function(){
//$(document).bind("contextmenu",function(){return false;});
setTimeout(function () {$("#name").focus()}, 240);
var parent=art.dialog.parent,
api=art.dialog.open.api;
if(!api) return;
api.button(
{
name:'保存',
callback:function(){
this.button({
name:'保存',
disabled:true
});
$.post($("#costcategory-form").attr("action"),$("#costcategory-form").serialize(),function(s){
var json=eval("("+s+")");
if(json.result=='success')
{
msg(1,"操作成功",true);
}
if(json.result=='error')
{
var str='';
$.each(json,function(idx,item){
if(idx=='msg')
str+=item;
});
//$("#error").html(str);
art.dialog.tips(str);
btn_restore();
}
});
return false;
},
focus:true
},
{
name:'放弃'
}
);
});
所以,即使我在CActiveForm中做以下配置:
<?php
CHtml::$afterRequiredLabel=':';
$form=$this->beginWidget('CActiveForm',array(
'id'=>'costcategory-form',//该值也是默认的$_POST['ajax']的值。
'enableClientValidation'=>true,
'enableAjaxValidation'=>true,
'clientOptions'=>array(
'validateOnSubmit'=>true
),
));?>
当点击“保存”按钮时,无法触发enableClientValidation(客户端验证)以及validateOnSubmit
validateOnSubmit: boolean, 当表单被提交时是否执行AJAX验证。如果存在任何验证错误,表单的提交动作将被停止。默认值是false。
ajax验证的情况在:在分类名称中输入内容,鼠标在旁边空白处单击后,可触发ajax验证。但是当点击“保存”按钮时,不会触发ajax验证。具体的可通过chrome浏览器中“审查元素”->NetWork中可查看。