Prevent Invalid Form Submission

Suppose I have a basic form like this:




<?php if($model->expiry_date < date('Y-m-d H:i:s') { ?>


<div class="form">


<?php $form=$this->beginWidget('CActiveForm', array(

	'id'=>'quote-form',

	'enableAjaxValidation'=>false,

)); ?>


<div class="row">

	<?php echo $form->labelEx($model, 'quote_price'); ?>

	<?php echo $form->textField($model, 'quote_price', array('size'=>25)); ?>

</div>


<div class="buttons">

	<?php echo CHtml::submitButton($model->isNewRecord ? 'Submit' : 'Save'); ?>

</div>


<?php $this->endWidget(); ?>	


</div><!-- form -->


<?php } else { ?>


<p>Sorry the last date for submitting quotes has passed.</p>


<?php } ?>




The form is only displayed if $model->expiry date is before today’s date. That’s all good, however this won’t stop someone from producing their own form and submitting it to this URL.

The obvious thing to do in that case would be to repeat the check in the controller. But is that the best way of doing this whole thing? Can the check be done just in the controller so that it displays the correct output to the user and prevents bogus form submissions?

Yes you can add this validation directly in the model Rules, so the model will be validated only if it’s not expired :)

Also, you can define the scenarios for this validation. Maybe you want to check the expire date only when creating and not when updating.

This is the best thing to do. Also you can use the ajax validation, in this way you will check automatically if are the some kind of error.

Anyway, the best way is to check everything always in the model controller or with model rules ( validator ).

If you need an example please tell me :) Anyway, you can check the documentation: http://www.yiiframework.com/doc/api/1.1/CValidator/

The best is to do the check only with a validator.

The user will simply got the form with an additional error about expiration, and no malicious sumission are possible. I always put my security check on beforeSave and AfterFind. Validation is the same of BeforeSave.

If you want to display a different view, you can create a function in the model for check the expiration, instead of writing the code in the controller (or, worst, in a view) and then use the controller for change the view, instead of this great if in the view.

It’s not so much about ‘displaying a different view’. Ideally I want to have one view file in which I can display different content depending on conditions. How about something like this:

Controller:




public function actionCreate()

{

	$model=$this->loadModel();

	

	if($model->expiry_date < date('Y-m-d H:i:s'))

	{

		$expired=false;

	}

	else

	{

		$expired=true;

	}

	

	if($expired==false && isset($_POST['Quote']))

	{

		// process the form submission

	}

	

	$this->render('create', array(

		'model'=>$model,

		'expired'=>$expired,

	));

}

View:


<?php if($expired==false) { ?>


<!-- DISPLAY THE FORM -->


<?php } else { ?>


<!-- DISPLAY THE NOTICE -->


<?php } ?>

So this way, we perform the date check in the controller and only have one variable $expired which is used in both controller and view file.

You can throw an exception




if ($expired == true ) { throw new CHttpException(404,'Time expired!'); }



You are right.

This code is nicer, but why not to create a property in the model for check if is expired? For encapsulate all logic about the model in the model itself. Maybe you will use this info on other parts too.

In the model:




public function getIsExpired()

{

   return ($this->expiry_date < date('Y-m-d H:i:s'))


}




In the controller you can:




public function actionCreate()

{

        $model=$this->loadModel();

        if(!$model->isExpiried && isset($_POST['Quote']))

        {

                // process the form submission

        }

        

        $this->render('create', array(

                'model'=>$model,

        ));

}




In the view:




<?php if($model->isExpiried) { ?>


<!-- DISPLAY THE NOTICE -->


<?php } else { ?>


<!-- DISPLAY THE FORM-->


<?php } ?>




Or with 2 views, as you wish. This looks much more MVC