NaszvadiG
9/6/2013 - 11:01 PM

MY_Form_validation.php

<?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 */