Skip to content

Instantly share code, notes, and snippets.

@NaszvadiG
Created September 6, 2013 23:01
Show Gist options
  • Save NaszvadiG/6471144 to your computer and use it in GitHub Desktop.
Save NaszvadiG/6471144 to your computer and use it in GitHub Desktop.
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
* CodeIgniter Better Form Validation
*
* @package CodeIgniter
* @author Sepehr Lajevardi <me@sepehr.ws>
* @copyright Copyright (c) 2012 Sepehr Lajevardi.
* @license http://codeigniter.com/user_guide/license.html
* @link https://github.com/sepehr/ci-form-validation
* @version Version 1.0
* @filesource
*/
// ------------------------------------------------------------------------
/**
* CI Form Validation Extension.
*
* @package CodeIgniter
* @subpackage Libraries
* @category Forms
* @author Sepehr Lajevardi <me@sepehr.ws>
* @link https://github.com/sepehr/ci-form-validation
* @todo - Document.
*/
class MY_Form_validation extends CI_Form_validation {
/**
* Stores CI superglobal.
*/
public $CI;
// ------------------------------------------------------------------------
/**
* Class constructor
*/
function __construct($params = array())
{
// Merge $_FILES and $_POST arrays and let lazies cheer!
if (isset($_FILES) AND is_array($_FILES) AND ! empty($_FILES))
{
$_POST = array_merge($_POST, $_FILES);
}
parent::__construct($params);
}
// ------------------------------------------------------------------------
/**
* Provides easy-lazy access to CI's superobject.
*/
function __get($var)
{
return $this->CI->$var;
}
// --------------------------------------------------------------------
// Parent Extensions
// --------------------------------------------------------------------
/**
* Executes form validation.
*
* Extends default run() regarding HMVC compatibility.
*/
public function run($module = '', $group = '')
{
is_object($module) AND $this->CI =& $module;
return parent::run($group);
}
// ------------------------------------------------------------------------
// Authentication Validation Callbacks (Requires IonAuth)
// ------------------------------------------------------------------------
/**
* Custom validation callback to validate password length.
*
* Note: It's only usable for "password" fields.
*/
public function check_pass($pass)
{
if ( ! empty($pass))
{
$pass = strlen($pass);
// Get password length configs
$min = $this->config->item('min_password_length', 'ion_auth');
$max = $this->config->item('max_password_length', 'ion_auth');
// Set callback's custom error message
$this->set_message('check_pass', "Incorrect password length. Minimum: $min, maximum: $max");
return $pass >= $min AND $pass <= $max;
}
return TRUE;
}
// ------------------------------------------------------------------------
/**
* Custom validation callback to verify user credentials.
*
* Note: It's only usable for "password" fields.
*/
public function check_login($pass, $email)
{
// Set callback's custom error message
$this->set_message('check_login', 'Invalid username/password combination.');
return $this->auth->login($this->input->post($email), $pass, TRUE);
}
// ------------------------------------------------------------------------
/**
* Custom validation callback to verify user group.
*
* NOTE: The user should be already logged in and its only usable for "password" fields.
*/
public function check_group($pass, $group)
{
if ( ! $this->auth->in_group($group))
{
// Set callback's custom error message
$this->set_message('check_group', "Your account is not registered as a $group.");
// Make sure that user is already logged out
$this->auth->logout();
$this->user = array();
return FALSE;
}
return TRUE;
}
// ------------------------------------------------------------------------
/**
* Custom validation callback to check existing email.
*
* Note: It's only usable for "email" fields.
*/
public function check_email_existing($email)
{
// Set callback's custom error message
$this->set_message('check_email_existing', 'E-mail address not found.');
return $this->auth->email_check($email);
}
// ------------------------------------------------------------------------
/**
* Custom validation callback to check if an email is free.
*
* Note: It's only usable for "email" fields.
*/
public function check_email_free($email)
{
// Set callback's custom error message
$this->set_message('check_email_free', 'E-mail address already exists.');
return ! $this->auth->email_check($email);
}
// ------------------------------------------------------------------------
/**
* Custom validation callback to check existing username.
*
* Note: It's only usable for "username" fields.
*/
public function check_username($username)
{
// Set callback's custom error message
$this->set_message('check_username', 'Username is not available to register.');
return $this->auth->username_check($username);
}
// ------------------------------------------------------------------------
// UK Address Validators (Application Specific)
// ------------------------------------------------------------------------
/**
* Custom validation callback to validate Country field.
*
* It's identical to "required" rule but with just one exception,
* if the "county" field is set to "Channel Islands" which has
* no "country" associated with.
*
* Note: It's only usable for "country" fields.
*/
public function check_country($country, $county)
{
// Set callback's custom error message
$this->set_message('check_country', 'The Country field is required.');
// Get county value from $_POST array
$county = $this->input->post($county);
return $county === 'Channel Islands' ? TRUE : (bool) $country;
}
// ------------------------------------------------------------------------
/**
* Custom validation callback to validate County field.
*
* Checks if the conty is located in the specified country.
*/
public function check_county($county, $country)
{
// This kid got no parent, skip
if ($county === 'Channel Islands')
{
return TRUE;
}
// Set callback's custom error message
$this->set_message('check_county', 'Please provide a valid county/country combination.');
// Get country value
$country = $this->input->post($country);
if (! $country)
{
return FALSE;
}
// Load town model, if not yet loaded
class_exists('Town_model') OR $this->load->model('system/town_model');
// Prepare country value. Weired widget, you know!
$criteria = in_array($country, array(
// List of non-england countries:
'N. Ireland', 'Scotland', 'Wales',
)) ? 'country' : 'region';
// Count documents matching both county and country/region
return (bool) $this->town_model->count_by(array(
'county' => $county,
$criteria => $country,
));
}
// ------------------------------------------------------------------------
/**
* Custom validation callback to validate Town field.
*
* Checks if the town is located in the specified county.
*/
public function check_town($town, $county = FALSE)
{
if ( ! $town)
{
return TRUE;
}
// Set callback's custom error message
$this->set_message('check_town', $county
? 'Please provide a valid town/county combination.'
: 'Please provide a valid town.');
// Get county value if set
$county AND $county = $this->input->post($county);
// Load town model, if not yet loaded
class_exists('Town_model') OR $this->load->model('system/town_model');
// Buildup conditions array
$wheres = array('town' => $town);
$county AND $wheres['county'] = $county;
// Count documents matching town, and county if set
return (bool) $this->town_model->count_by($wheres);
}
// ------------------------------------------------------------------------
/**
* Custom validation callback to validate UK postcodes.
*
* It also tries to format provided postcode in correct format.
*
* Note: It's only usable for "postcode" fields.
*/
public function check_postcode_uk($original_postcode)
{
// Set callback's custom error message
$this->set_message('check_postcode_uk', 'Invalid UK postcode format.');
// Permitted letters depend upon their position in the postcode.
// Character 1
$alpha1 = "[abcdefghijklmnoprstuwyz]";
// Character 2
$alpha2 = "[abcdefghklmnopqrstuvwxy]";
// Character 3
$alpha3 = "[abcdefghjkpmnrstuvwxy]";
// Character 4
$alpha4 = "[abehmnprvwxy]";
// Character 5
$alpha5 = "[abdefghjlnpqrstuwxyz]";
// Expression for postcodes: AN NAA, ANN NAA, AAN NAA, and AANN NAA with a space
$pcexp[0] = '/^('.$alpha1.'{1}'.$alpha2.'{0,1}[0-9]{1,2})([[:space:]]{0,})([0-9]{1}'.$alpha5.'{2})$/';
// Expression for postcodes: ANA NAA
$pcexp[1] = '/^('.$alpha1.'{1}[0-9]{1}'.$alpha3.'{1})([[:space:]]{0,})([0-9]{1}'.$alpha5.'{2})$/';
// Expression for postcodes: AANA NAA
$pcexp[2] = '/^('.$alpha1.'{1}'.$alpha2.'{1}[0-9]{1}'.$alpha4.')([[:space:]]{0,})([0-9]{1}'.$alpha5.'{2})$/';
// Exception for the special postcode GIR 0AA
$pcexp[3] = '/^(gir)([[:space:]]{0,})(0aa)$/';
// Standard BFPO numbers
$pcexp[4] = '/^(bfpo)([[:space:]]{0,})([0-9]{1,4})$/';
// c/o BFPO numbers
$pcexp[5] = '/^(bfpo)([[:space:]]{0,})(c\/o([[:space:]]{0,})[0-9]{1,3})$/';
// Overseas Territories
$pcexp[6] = '/^([a-z]{4})([[:space:]]{0,})(1zz)$/';
// Anquilla
$pcexp[7] = '/^ai-2640$/';
// Load up the string to check, converting into lowercase
$postcode = strtolower($original_postcode);
// Assume we are not going to find a valid postcode
$valid = FALSE;
// Check the string against the six types of postcodes
foreach ($pcexp as $regexp)
{
if (preg_match($regexp, $postcode, $matches))
{
// Load new postcode back into the form element
$postcode = strtoupper ($matches[1] . ' ' . $matches [3]);
// Take account of the special BFPO c/o format
$postcode = preg_replace ('/C\/O([[:space:]]{0,})/', 'c/o ', $postcode);
// Take acount of special Anquilla postcode format (a pain, but that's the way it is)
preg_match($pcexp[7], strtolower($original_postcode), $matches) AND $postcode = 'AI-2640';
// Remember that we have found that the code is valid and break from loop
$valid = TRUE;
break;
}
}
// Return with the reformatted valid postcode in uppercase if the postcode was
return $valid ? $postcode : FALSE;
}
// ------------------------------------------------------------------------
/**
* Custom validation callback to validate UK phone format.
*
* Note: It's only usable for "phone" fields.
*/
public function check_phone_uk($phone)
{
// Setting custom validation error
// There are more specific error messages commented out in the function
$this->set_message('check_phone_uk', 'Please provide a valid phone number, e.g. 07777 222222');
// Copy the parameter and strip out the spaces
$phone_copy = str_replace(' ', '', $phone);
// Convert into a string and check that we were provided with something
if (empty($phone_copy))
{
// $this->set_message('check_phone_uk', 'Telephone number not provided.');
return FALSE;
}
// Don't allow country codes to be included (assumes a leading "+")
if (preg_match('/^(\+)[\s]*(.*)$/',$phone_copy))
{
// $this->set_message('check_phone_uk', 'UK number without country code, please.');
return FALSE;
}
// Remove hyphens - they are not part of a telephone number
$phone_copy = str_replace('-', '', $phone_copy);
// Now check that all the characters are digits
if ( ! preg_match('/^[0-9]{10,11}$/',$phone_copy))
{
// $this->set_message('check_phone_uk', 'UK numbers should contain 10 or 11 digits.');
return FALSE;
}
// Now check that the first digit is 0
if ( ! preg_match('/^0[0-9]{9,10}$/',$phone_copy))
{
// $this->set_message('check_phone_uk', 'The number should start with a 0.');
return FALSE;
}
// Check the string against the numbers allocated for dramas
// Expression for numbers allocated to dramas
$tnexp[0] = '/^(0113|0114|0115|0116|0117|0118|0121|0131|0141|0151|0161)(4960)[0-9]{3}$/';
$tnexp[1] = '/^02079460[0-9]{3}$/';
$tnexp[2] = '/^01914980[0-9]{3}$/';
$tnexp[3] = '/^02890180[0-9]{3}$/';
$tnexp[4] = '/^02920180[0-9]{3}$/';
$tnexp[5] = '/^01632960[0-9]{3}$/';
$tnexp[6] = '/^07700900[0-9]{3}$/';
$tnexp[7] = '/^08081570[0-9]{3}$/';
$tnexp[8] = '/^09098790[0-9]{3}$/';
$tnexp[9] = '/^03069990[0-9]{3}$/';
foreach ($tnexp as $regexp)
{
if (preg_match($regexp, $phone_copy, $matches))
{
// $this->set_message('check_phone_uk', 'The number is either invalid or inappropriate.');
return FALSE;
}
}
// Finally, check that the telephone number is appropriate.
if ( ! preg_match('/^(01|02|03|05|070|071|072|073|074|075|07624|077|078|079)[0-9]+$/', $phone_copy))
{
// $this->set_message('check_phone_uk', 'The number is either invalid or inappropriate.');
return FALSE;
}
// Seems to be valid, return the stripped telephone number
return $phone_copy;
}
// --------------------------------------------------------------------
// Misc. Custom Validation Callbacks
// --------------------------------------------------------------------
/**
* Improved version of CI matches rule.
*/
public function matches($string, $args)
{
// Extract args and get field name and label
list($field, $label) = array_map('trim', explode(',', $args));
// Set label if not provided
$label OR $label = $field;
// Set callback's custom error message
$this->set_message('matches', "The %s field does not match the $label.");
if ( ! isset($_POST[$field]))
{
return FALSE;
}
// Fetch password value
$field = $_POST[$field];
return $string === $field;
}
// ------------------------------------------------------------------------
/**
* Checks that a string only contains alphanum chars plus:
* - Spaces
* - Periods
* - Underscores
* - Dashes
*/
function alpha_extra($string)
{
// Set callback's custom error message
$this->set_message('alpha_extra', 'The %s field may only contain alpha-numeric characters, spaces, periods, underscores, and dashes.');
return (bool) preg_match("/^([\.\s-a-z0-9_-])+$/i", $string);
}
// --------------------------------------------------------------------
/**
* Checks that the string matches the passed regex pattern.
*/
function regex($string, $pattern)
{
// Set callback's custom error message
$this->set_message('regex', 'The %s field does not match the required pattern.');
return (bool) preg_match('/^' . $pattern . '$/', $string);
}
// --------------------------------------------------------------------
/**
* Checks that the passed string is one of the values entered as the second parameter.
*
* Usage: 'required|one_of[option1,option2,option3]'
*/
public function one_of($string, $options = NULL)
{
if ($options)
{
// Set callback's custom error message
$this->set_message('one_of', "%s must contain one of the allowed options: $options");
return in_array($string, explode(',', $options));
}
return TRUE;
}
// --------------------------------------------------------------------
// General File Validation Callbacks
// --------------------------------------------------------------------
/**
* Checks file extension against passed allowed types.
*
* Usage: 'required|file_types[doc,pdf,rtf,odt]'
*/
public function file_types($file, $types = NULL)
{
if ($types)
{
// Set callback's custom error message
$this->set_message('allowed_types', "%s has an invalid type. Allowed types are: $types");
// Get types
$types = explode(',', $types);
$file_type = pathinfo($file['name'], PATHINFO_EXTENSION);
return in_array($file_type, $types);
}
return TRUE;
}
// --------------------------------------------------------------------
/**
* Checks filesize against passed maximum size.
*
* Usage: 'required|file_max_size[1024]'
*/
public function file_max_size($file, $size = 0)
{
if ($size)
{
// Set callback's custom error message
$this->set_message('one_of', "Invalid size for %s. Maximum size is: $size");
return (bool) $file['size'] <= $size;
}
return TRUE;
}
// --------------------------------------------------------------------
}
// End of MY_Form_validation class
/* End of file MY_Form_validation.php */
/* Location: ./application/libraries/MY_Form_validation.php */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment