Here's some elaboration on zombat's solution with code examples.
I usually have the form post to the same controller/method. Then I let $this->form_validation->run() handle all the dirty work. If $_POST data is present, the validator checks the rules. If it passes I redirect them to a success page, otherwise the same page is presented with validation errors displayed in the repopulated form.
class Contact extends CI_Controller {
function __construct() {
parent::__construct();
}
function index() {
/*
the foreach() line makes each field visible
to form_validation so we can reliably
repopulate (using set_value, set_checkbox,
etc) fields that have no validation rules
example: since 'phone' has no rules, we would
not be able to repopulate that field if
validation failed
*/
foreach ($_POST as $key => $value) $this->form_validation->set_rules($key, '', '');
$this->form_validation->set_rules('first_name', 'First Name', 'required|min_length[2]');
$this->form_validation->set_rules('last_name', 'Last Name', 'required|min_length[2]');
$this->form_validation->set_rules('email', 'Email Address', 'required|strtolower|valid_email');
if ($this->form_validation->run() == FALSE) {
$this->load->view('contact_form');
} else {
/*
save form data, email it, etc
then redirect the user so they
cannot re-submit the same data
*/
redirect('contact/success');
}
}
function success() {
$this->load->view('contact_success');
}
}
Example HTML for application/views/contact_form.php
<form method="post" action="<?php echo current_url(); ?>">
<table>
<tr>
<td>First Name</td>
<td><?php echo form_input('first_name', set_value('first_name')); ?>
<?php echo form_error('first_name'); ?></td>
</tr>
<tr>
<td>Last Name</td>
<td><?php echo form_input('last_name', set_value('last_name')); ?>
<?php echo form_error('last_name'); ?></td>
</tr>
<tr>
<td>Email Address</td>
<td><?php echo form_input('email', set_value('email')); ?>
<?php echo form_error('email'); ?></td>
</tr>
<tr>
<td>Phone Number</td>
<td><?php echo form_input('phone', set_value('phone')); ?>
<?php echo form_error('phone'); ?></td>
</tr>
<tr>
<td> </td>
<td><button type="submit">Send Message</button></td>
</tr>
</table>
</form>
I have absolutely no worries about CSFR or XSS doing it this way.
Note: As with any publicly accessible form, there are always going to be junk submissions (from bots AND real people trying to solicit business). If you encounter a lot of them, fine-tune your validation rules accordingly.
/submit.cgi.