Welcome Guest, Not a member yet? Register   Sign In
Form Validation
#1

(This post was last modified: 08-04-2015, 11:15 AM by ignitedcms.)

I kinda already know the answer to my question but I'll ask it anyway.

I've been using javascript to validate my forms and as a result I've been a bit lazy on server side validation. I thought if I make the field mandatory in the javascript I don't have to check it server side, which is probably a bad idea. But I'll ask the question anyway, should you always be validating form data server side?

But my other question was on repopulating the form with old data that was incorrect.

How best to do this efficiently?

At the moment my form is validated and if it is bad data instead of loading all the views again I just do

Quote:redirect("my_controller/my_method", "refresh");

I would like to use the above method as it save having to type out all the view files which the redirect method calls anyway. For example:

Code:
$this->load->view('header');
$this->load->view('body');
$this->load->view('content');
$this->load->view('footer');


But how to I pass the bad data as 'flash data' back into the view? I've never been able to do this correctly. And what happens on first load, would you need to use an isset() in the view?

An example would be great.
Practical guide to IgnitedCMS - Book coming soon, www.ignitedcms.com
Reply
#2

First: you should always validate form data on the server side. JavaScript validation is nice, but the user has full control over JavaScript, including being able to disable it completely. At the minimum, you should do enough validation on the server to make sure you don't insert something malicious into your database. You should behave as if the JavaScript validation is at best suspect, and at worst compromised or disabled.

I usually submit my form back to the method which originally displayed it, which reduces the need to duplicate code or pass data between methods in my controller just to handle a single form. The view itself just uses set_value() (or the other form_helper set_*() functions, as appropriate) to populate the values, and I usually default the record variable to an empty object if I'm loading an empty form and use isset() to avoid bad property references.

Example from view (excuse the mish-mash of bootstrap v2 classes):
PHP Code:
<?php if (validation_errors()) : ?>
<div class='alert-error'>
    <h4 class='alert-heading'><?php echo lang('example_validation_heading'); ?></h4>
    <?php echo validation_errors(); ?>
</div>
<?php endif; ?>
<?php 
echo form_open($this->uri->uri_string(), 'class="form-horizontal"'); ?>
    <fieldset>
        <div class="control-group<?php echo form_error('field_name') ? ' error' ''?>">
            <label class='form-label' for='field_name'><?php echo lang('field_name'); ?></label>
            <div class='controls'>
                <input id='field_name' name='field_name' type='text' maxlength='255' value="<?php echo set_value('field_name', isset($record->field_name) ? $record->field_name ''); ?>" />
                <span class='help-inline'><?php echo form_error('field_name'); ?></span>
            </div>
        </div>
    </fieldset>
    <fieldset class="form-actions">
        <input type='submit' name='submit' value="<?php echo lang('example_form_submit'); ?>" />
    </fieldset>
<?php 
echo form_close(); 

I probably went overboard with the following controller example. This assumes a few methods are added to the model, so I tried to add comments to vaguely describe what the model might be doing in those cases (to avoid adding an even more detailed example_model to this post).
PHP Code:
<?php 

class Example extends MY_Controller
{
 
   public function __construct()
 
   {
 
       parent::__construct();

 
       // If it's not loaded already by your base controller.
 
       $this->load->library('form_validation');
 
       $this->load->model('example_model');
 
   }

 
   public function create()
 
   {
 
       // If you have some method of access control, this might be a good time
 
       // to make sure the user is authorized to do this.
 
       if (! $this->isAuthorizedUser($this->permissionCreate)) {
 
           redirect();
 
       }

 
       // The vars for use in the view.
 
       $data = array();

 
       // Did the user submit the form? You might want to take this a step further
 
       // and ensure the value is the same as was displayed on the form.
 
       if ($this->input->post('submit')) {
 
           // Validate and save the data input into the form.
 
           if ($insertId $this->saveExample()) {
 
               // indicate success
 
               // ...
 
               redirect('example');
 
           }

 
           // Insert failed, check for errors and send any additional messages
 
           // to the view by adding them to $data. Validation messages should be 
 
           // handled by use of validation_errors() and form_error() in the view.
 
           // ...
 
           $data['error'] = $this->example_model->getErrorMessage();
 
       }

 
       // Populate the vars for use in the view.

 
       // An edit method would call the model to retrieve the record to be edited.
 
       $data['record'] = new stdClass();

 
       $this->load->view('create'$data);
 
   }

 
   protected function saveExample($type 'insert'$id 0)
 
   {
 
       if ($type == 'update') {
 
           // Get the name of the primary key.
 
           $exampleKey $this->example_model->get_key();
 
           // Validate the $id before assigning it here...
 
           $_POST[$exampleKey] = $id;
 
       }

 
       // Get the validation rules from the model.
 
       $this->form_validation->set_rules($this->example_model->get_validation_rules());
 
       if ($this->form_validation->run() === false) {
 
           return false;
 
       }

 
       // Extract only the permitted fields from the post data.
 
       $data $this->example_model->prep_data($this->input->post());

 
       if ($type == 'insert') {
 
           $id $this->example_model->insert($data);
 
           return is_numeric($id);
 
           // To return the inserted ID, it could look something like this:
 
           // return is_numeric($id) ? $id : false;
 
       } elseif ($type == 'update') {
 
           // If prep_data() method doesn't include the key, add it as needed.
 
           // $data[$exampleKey] = $id;
 
           return $this->example_model->update($id$data);
 
       }

 
       return false;
 
   }

Reply
#3

I always view server-side validation as a must to prevent my system to be filled with with unwanted, unexpected and/or possible harmfull data. Client side validation is just a tool to make thing prettier and more user friendly for your audiance.

You need to look at the form validation class documentation, especialy to the set_value, set_radio etc methodes. They can set the desired value to an input element. If you edit some data set the default value to the stored data and if there's a post variable ci will use that posted value instead of the stored value.
Reply
#4

OK is there anyway to repopulate the view using redirect install of load->view(). Redirect seems to loose the data, but it makes the code more readable(only one line)

It justs seems a ballache to load all the views files, and db queries again to pass into the view that failed.
Practical guide to IgnitedCMS - Book coming soon, www.ignitedcms.com
Reply
#5

I dont see how a redirect saves you resources, perhaps i dont quite understand you. After your controller decides a form is not valid you can:
A) load the original form view file and populate it with the posted data and show an error why it was not valid
B) redirect to another url, another controller has to be loaded and some other view file.

I dont see how B would be more efficient.

But if you feel that performace is effected by A you could use both server-side and client-side validation. Then you can asume most users input is being validated on the client side and the server side is just a formality wich should pass straigt away for all regular nice userrs which use javascript or html5 validation.

I prefer to first make things work nicely with server-side validation and if thats done I implement javascript for better user experience since js can validate alot faster.

But the main point is to never trust user input, just like you read in every book about securing a php application.
Reply
#6

(This post was last modified: 08-05-2015, 12:09 AM by ignitedcms.)

Thanks. The reason why I would like to use redirect is NOT because of resource efficiency.

Purely because it makes the code more readable. It would only be one line to maintain.

So any examples using redirect would be greatly appreciated. Or would you have to use flash data?
Practical guide to IgnitedCMS - Book coming soon, www.ignitedcms.com
Reply
#7

If the posted data a user provides is valid I first insert/update/delete the database. After that I store a success message in a session and redirect to the main page. There the message is being shown (and removed from the session).

Flashdata could be used but I feel it is somewhat unreliable as it is cleared during the next load. In some cases the flash data is cleared before it is shown to the user (for example if there is another redirect in place or some error occurred). I created my own messages library which stores these succes and error messages and only removes them when it is presented to the user. My library was inspired by Jens Segers but I recently found another one which does about the same.

https://github.com/jenssegers/codeignite...ge-library
https://github.com/avenirer/CodeIgniter-Rat
Reply
#8

Flashdata is not intended for repopulating a form that doesn't meet the form validation rules.
A better method is using the form_validation library.

Basically, your method (in the controller) can look look like this:
PHP Code:
public function show_form()
{
  $this->load->library('form_validation');
  $this->form_validation->set_rules('name','name','required');
  if ($this->form_validation->run() == FALSE) {
    $this->load->helper('form');
    //code to load the form view here.
  }
  else {
    //code to process $this->input->post().
    redirect('page_you_want_to_show_after_saving_post_data');
  }

In your view:
PHP Code:
echo form_open();
echo 
form_label('Your name:');
echo 
form_input('name',set_value('name'NULL));
echo 
form_submit('submit','Submit form');
echo 
form_close(); 

form_open() without any parameters will just submit your form to the controller where it came from.
Reply
#9

(This post was last modified: 08-05-2015, 07:20 AM by CroNiX.)

If you want to repopulate the form, you shouldn't redirect. PHP's $_POST superglobal vars only exists for one request. If you redirect you lose the contents of $_POST.

My controllers usually look something like this:

PHP Code:
// Was form submitted?
if ($this->input->server('REQUEST_METHOD') == 'POST')
{
  
// validate form fields here using validation library.
  // If success, redirect to success page
}

//If we made it this far in the code, either the form was submitted and failed validation, OR the person just came to the page for the first time. In either case, just display the form. The view will handle showing field errors using the validation library if any exist.
$this->load->view('your_form_view'); 
Reply
#10

(08-05-2015, 12:08 AM)iamthwee Wrote: Thanks. The reason why I would like to use redirect is NOT because of resource efficiency.

Purely because it makes the code more readable. It would only be one line to maintain.

So any examples using redirect would be greatly appreciated. Or would you have to use flash data?

In theory, you could probably do this by setting session data, but not only would you be misusing redirect and wasting resources, the scaffolding you would be rebuilding to support the redirect (instead of using the form_validation library and related helper functions) would be significantly more difficult to maintain and read than the alternative. In other words, a redirect is more readable and maintainable only because you haven't done what would be necessary to make it work properly. It's also a waste of the end user's resources, not just your server's resources, because the redirect forces the browser to make another request.
Reply




Theme © iAndrew 2016 - Forum software by © MyBB