• 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
What's the best way to validate data in both controllers and models, before creating/reading/updating/deleting this data

#1
[eluser]skcin7[/eluser]
I have been thinking about this for several months and can't seem to think mentally about the best way to do it. Usually when a problem is in my head for a while, a solution will eventually come to me, which doesn't seem to be the case with this one. My current implementation sucks and greatly needs to be improved.

One thing I love about MVC web frameworks is that it allows for multiple layers of security before your database is allowed to be accessed. You can validate information in the controller, and if it passes validation, you can also validate it in the model, and if it passes both of these layers of security, then it is allowed to make changes to the database. If you accidentally have an error or exploit in the controller or model, chances are the other will not have the same exploits, so the likelihood of undesired or potentially malicious data being sent to the database is very low. Hooray.

My current implementation sucks. A function in one of my controllers looks something like this:

Code:
function add()
{
if($_POST) //If a form is being submitted, ensure all data is accurate. If so, write to database.
{
  if(preg_match('/^[0-9]{9}$/', $_POST['fein']) &&  //It must be a 9 character long string containing digits only
   strlen($_POST['effective_date']) > 0 &&    //String length must be more than 0
   strlen($_POST['name']) > 0       //String length must be more than 0
  ){ //All validations passed! Yippee! Write to DB!
   //If this syntax looks weird to you, I use PHPActiveRecord. More info: http://www.phpactiverecord.org/
   $dealership = new Dealership(); //An instance of the Database Model object is called.
   $dealership->user_id = $this->LOGGED_IN_USER->id; //ID is logged in user.
   $dealership->effective_date = $_POST['effective_date'];
   $dealership->name = $_POST['name'];
   $dealership->save(); //Item is now written to database.
  
   $this->session->set_flashdata('message', 'Item has been successfully created! Yippee.'); //Tell the user. They will be so happy!
   redirect('some_controller/add_success'); //Redirect to the success page.
  }
}
}

I currently only validate in the controller. The model doesn't have an extra added layer of security whatsoever. If all the validations pass in the controller, the data gets added to the database.

In addition, this way provides no way to compile a list of the errors. Inside my view, I have something like this:

Code:
<form action="<?=site_url('some_controller/add')?>" method="POST">
&lt;input type="text" name="fein" /&gt; &lt;?=$_POST && ! preg_match('/^[0-9]{9}$/', $_POST['fein']) ? '<span class="error">This must be 9 characters long and contain only digits</span>' : ''?&gt;<br />
&lt;input type="text" name="effective_date" /&gt; &lt;?=$_POST && strlen($_POST['effective_date']) == 0 ? '<span class="error">You must type something here.</span>' : ''?&gt;<br />
&lt;input type="text" name="name" /&gt; &lt;?=$_POST && strlen($_POST['name']) == 0 ? '<span class="error">You must type something here.</span>' : ''?&gt;<br />
&lt;/form&gt;

In other words, I have PHP to completely re-check every possible type of error that can happen in the view, and output an error message accordingly. Not only is this messy and unorganized, but a lot of the code is duplicated now too. I'm positive there is a better way to do this. What is it? I feel like it would be much better to store something like an array that keeps track of the amount of errors that there are, let's call it $errors[], and appends data to it if it does contain errors. However, I can't seem to figure out a way that controllers and models would both be able to work with each other to write to the $errors[] array, and have the errors (if any) sent to the view to properly be displayed.

Any help or insight would be greatly appreciated. I know that this implementation sucks and I would like to make it better.

#2
[eluser]@robertotra[/eluser]
[quote author="skcin7" date="1329815327"] ...I can't seem to figure out a way that controllers and models would both be able to work with each other to write to the $errors[] array, and have the errors (if any) sent to the view to properly be displayed...[/quote]

Maybe with a multidimensional session array:
Code:
session_start();

$_SESSION['errors']['controller'][] = 'error caught in the controller';

$_SESSION['errors']['model'][] = 'error caught in the model';

R.

#3
[eluser]InsiteFX[/eluser]
Code:
$dealership->name = $this->input->post('name', TRUE);  // TRUE use CI xss_clean security!

Or you can turn it on for global use in ./application/config/config.php

#4
[eluser]porquero[/eluser]
You shoul use CI validation way, so you can validate in controller and model:


http://ellislab.com/codeigniter/user-gui...ation.html

#5
[eluser]Mauricio de Abreu Antunes[/eluser]
Don't use global validation.
Validate your data in your controllers even it needs copy and paste.
Sometimes, you need to validate a user name or purchase date in different ways.

#6
[eluser]jellysandwich[/eluser]
[quote author="porquero" date="1329827144"]You shoul use CI validation way, so you can validate in controller and model:


http://ellislab.com/codeigniter/user-gui...ation.html[/quote]

^Agreed, you should be using CI's validation library.

If you want to keep it simple, you can put all the validation in the model.

For callback validations, you can use this:

http://ellislab.com/forums/viewthread/205469/


Digg   Delicious   Reddit   Facebook   Twitter   StumbleUpon  


  Theme © 2014 iAndrew  
Powered By MyBB, © 2002-2019 MyBB Group.