Blame | Last modification | View Log | RSS feed
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');/*** CodeIgniter** An open source application development framework for PHP 4.3.2 or newer** @package CodeIgniter* @author ExpressionEngine Dev Team* @copyright Copyright (c) 2008, EllisLab, Inc.* @license http://codeigniter.com/user_guide/license.html* @link http://codeigniter.com* @since Version 1.0* @filesource*/// ------------------------------------------------------------------------/*** Form Validation Class** @package CodeIgniter* @subpackage Libraries* @category Validation* @author ExpressionEngine Dev Team* @link http://codeigniter.com/user_guide/libraries/form_validation.html*/class CI_Form_validation {var $CI;var $_field_data = array();var $_config_rules = array();var $_error_array = array();var $_error_messages = array();var $_error_prefix = '<p>';var $_error_suffix = '</p>';var $error_string = '';var $_safe_form_data = FALSE;/*** Constructor**/function CI_Form_validation($rules = array()){$this->CI =& get_instance();// Validation rules can be stored in a config file.$this->_config_rules = $rules;// Automatically load the form helper$this->CI->load->helper('form');// Set the character encoding in MB.if (function_exists('mb_internal_encoding')){mb_internal_encoding($this->CI->config->item('charset'));}log_message('debug', "Validation Class Initialized");}// --------------------------------------------------------------------/*** Set Rules** This function takes an array of field names and validation* rules as input, validates the info, and stores it** @access public* @param mixed* @param string* @return void*/function set_rules($field, $label = '', $rules = ''){// No reason to set rules if we have no POST dataif (count($_POST) == 0){return;}// If an array was passed via the first parameter instead of indidual string// values we cycle through it and recursively call this function.if (is_array($field)){foreach ($field as $row){// Houston, we have a problem...if ( ! isset($row['field']) OR ! isset($row['rules'])){continue;}// If the field label wasn't passed we use the field name$label = ( ! isset($row['label'])) ? $row['field'] : $row['label'];// Here we go!$this->set_rules($row['field'], $label, $row['rules']);}return;}// No fields? Nothing to do...if ( ! is_string($field) OR ! is_string($rules) OR $field == ''){return;}// If the field label wasn't passed we use the field name$label = ($label == '') ? $field : $label;// Is the field name an array? We test for the existence of a bracket "[" in// the field name to determine this. If it is an array, we break it apart// into its components so that we can fetch the corresponding POST data laterif (strpos($field, '[') !== FALSE AND preg_match_all('/\[(.*?)\]/', $field, $matches)){// Note: Due to a bug in current() that affects some versions// of PHP we can not pass function call directly into it$x = explode('[', $field);$indexes[] = current($x);for ($i = 0; $i < count($matches['0']); $i++){if ($matches['1'][$i] != ''){$indexes[] = $matches['1'][$i];}}$is_array = TRUE;}else{$indexes = array();$is_array = FALSE;}// Build our master array$this->_field_data[$field] = array('field' => $field,'label' => $label,'rules' => $rules,'is_array' => $is_array,'keys' => $indexes,'postdata' => NULL,'error' => '');}// --------------------------------------------------------------------/*** Set Error Message** Lets users set their own error messages on the fly. Note: The key* name has to match the function name that it corresponds to.** @access public* @param string* @param string* @return string*/function set_message($lang, $val = ''){if ( ! is_array($lang)){$lang = array($lang => $val);}$this->_error_messages = array_merge($this->_error_messages, $lang);}// --------------------------------------------------------------------/*** Set The Error Delimiter** Permits a prefix/suffix to be added to each error message** @access public* @param string* @param string* @return void*/function set_error_delimiters($prefix = '<p>', $suffix = '</p>'){$this->_error_prefix = $prefix;$this->_error_suffix = $suffix;}// --------------------------------------------------------------------/*** Get Error Message** Gets the error message associated with a particular field** @access public* @param string the field name* @return void*/function error($field = '', $prefix = '', $suffix = ''){if ( ! isset($this->_field_data[$field]['error']) OR $this->_field_data[$field]['error'] == ''){return '';}if ($prefix == ''){$prefix = $this->_error_prefix;}if ($suffix == ''){$suffix = $this->_error_suffix;}return $prefix.$this->_field_data[$field]['error'].$suffix;}// --------------------------------------------------------------------/*** Error String** Returns the error messages as a string, wrapped in the error delimiters** @access public* @param string* @param string* @return str*/function error_string($prefix = '', $suffix = ''){// No errrors, validation passes!if (count($this->_error_array) === 0){return '';}if ($prefix == ''){$prefix = $this->_error_prefix;}if ($suffix == ''){$suffix = $this->_error_suffix;}// Generate the error string$str = '';foreach ($this->_error_array as $val){if ($val != ''){$str .= $prefix.$val.$suffix."\n";}}return $str;}// --------------------------------------------------------------------/*** Run the Validator** This function does all the work.** @access public* @return bool*/function run($group = ''){// Do we even have any data to process? Mm?if (count($_POST) == 0){return FALSE;}// Does the _field_data array containing the validation rules exist?// If not, we look to see if they were assigned via a config fileif (count($this->_field_data) == 0){// No validation rules? We're done...if (count($this->_config_rules) == 0){return FALSE;}// Is there a validation rule for the particular URI being accessed?$uri = ($group == '') ? trim($this->CI->uri->ruri_string(), '/') : $group;if ($uri != '' AND isset($this->_config_rules[$uri])){$this->set_rules($this->_config_rules[$uri]);}else{$this->set_rules($this->_config_rules);}// We're we able to set the rules correctly?if (count($this->_field_data) == 0){log_message('debug', "Unable to find validation rules");return FALSE;}}// Load the language file containing error messages$this->CI->lang->load('form_validation');// Cycle through the rules for each field, match the// corresponding $_POST item and test for errorsforeach ($this->_field_data as $field => $row){// Fetch the data from the corresponding $_POST array and cache it in the _field_data array.// Depending on whether the field name is an array or a string will determine where we get it from.if ($row['is_array'] == TRUE){$this->_field_data[$field]['postdata'] = $this->_reduce_array($_POST, $row['keys']);}else{if (isset($_POST[$field]) AND $_POST[$field] != ""){$this->_field_data[$field]['postdata'] = $_POST[$field];}}$this->_execute($row, explode('|', $row['rules']), $this->_field_data[$field]['postdata']);}// Did we end up with any errors?$total_errors = count($this->_error_array);if ($total_errors > 0){$this->_safe_form_data = TRUE;}// Now we need to re-set the POST data with the new, processed data$this->_reset_post_array();// No errors, validation passes!if ($total_errors == 0){return TRUE;}// Validation failsreturn FALSE;}// --------------------------------------------------------------------/*** Traverse a multidimensional $_POST array index until the data is found** @access private* @param array* @param array* @param integer* @return mixed*/function _reduce_array($array, $keys, $i = 0){if (is_array($array)){if (isset($keys[$i])){if (isset($array[$keys[$i]])){$array = $this->_reduce_array($array[$keys[$i]], $keys, ($i+1));}else{return NULL;}}else{return $array;}}return $array;}// --------------------------------------------------------------------/*** Re-populate the _POST array with our finalized and processed data** @access private* @return null*/function _reset_post_array(){foreach ($this->_field_data as $field => $row){if ( ! is_null($row['postdata'])){if ($row['is_array'] == FALSE){if (isset($_POST[$row['field']])){$_POST[$row['field']] = $this->prep_for_form($row['postdata']);}}else{$post = '$_POST["';if (count($row['keys']) == 1){$post .= current($row['keys']);$post .= '"]';}else{$i = 0;foreach ($row['keys'] as $val){if ($i == 0){$post .= $val.'"]';$i++;continue;}$post .= '["'.$val.'"]';}}if (is_array($row['postdata'])){$array = array();foreach ($row['postdata'] as $k => $v){$array[$k] = $this->prep_for_form($v);}$post .= ' = $array;';}else{$post .= ' = "'.$this->prep_for_form($row['postdata']).'";';}eval($post);}}}}// --------------------------------------------------------------------/*** Executes the Validation routines** @access private* @param array* @param array* @param mixed* @param integer* @return mixed*/function _execute($row, $rules, $postdata = NULL, $cycles = 0){// If the $_POST data is an array we will run a recursive callif (is_array($postdata)){foreach ($postdata as $key => $val){$this->_execute($row, $rules, $val, $cycles);$cycles++;}return;}// --------------------------------------------------------------------// If the field is blank, but NOT required, no further tests are necessary$callback = FALSE;if ( ! in_array('required', $rules) AND is_null($postdata)){// Before we bail out, does the rule contain a callback?if (preg_match("/(callback_\w+)/", implode(' ', $rules), $match)){$callback = TRUE;$rules = (array('1' => $match[1]));}else{return;}}// --------------------------------------------------------------------// Isset Test. Typically this rule will only apply to checkboxes.if (is_null($postdata) AND $callback == FALSE){if (in_array('isset', $rules, TRUE) OR in_array('required', $rules)){// Set the message type$type = (in_array('required', $rules)) ? 'required' : 'isset';if ( ! isset($this->_error_messages[$type])){if (FALSE === ($line = $this->CI->lang->line($type))){$line = 'The field was not set';}}else{$line = $this->_error_messages[$type];}// Build the error message$message = sprintf($line, $this->_translate_fieldname($row['label']));// Save the error message$this->_field_data[$row['field']]['error'] = $message;if ( ! isset($this->_error_array[$row['field']])){$this->_error_array[$row['field']] = $message;}}return;}// --------------------------------------------------------------------// Cycle through each rule and run itforeach ($rules As $rule){$_in_array = FALSE;// We set the $postdata variable with the current data in our master array so that// each cycle of the loop is dealing with the processed data from the last cycleif ($row['is_array'] == TRUE AND is_array($this->_field_data[$row['field']]['postdata'])){// We shouldn't need this safety, but just in case there isn't an array index// associated with this cycle we'll bail outif ( ! isset($this->_field_data[$row['field']]['postdata'][$cycles])){continue;}$postdata = $this->_field_data[$row['field']]['postdata'][$cycles];$_in_array = TRUE;}else{$postdata = $this->_field_data[$row['field']]['postdata'];}// --------------------------------------------------------------------// Is the rule a callback?$callback = FALSE;if (substr($rule, 0, 9) == 'callback_'){$rule = substr($rule, 9);$callback = TRUE;}// Strip the parameter (if exists) from the rule// Rules can contain a parameter: max_length[5]$param = FALSE;if (preg_match("/(.*?)\[(.*?)\]/", $rule, $match)){$rule = $match[1];$param = $match[2];}// Call the function that corresponds to the ruleif ($callback === TRUE){if ( ! method_exists($this->CI, $rule)){continue;}// Run the function and grab the result$result = $this->CI->$rule($postdata, $param);// Re-assign the result to the master data arrayif ($_in_array == TRUE){$this->_field_data[$row['field']]['postdata'][$cycles] = (is_bool($result)) ? $postdata : $result;}else{$this->_field_data[$row['field']]['postdata'] = (is_bool($result)) ? $postdata : $result;}// If the field isn't required and we just processed a callback we'll move on...if ( ! in_array('required', $rules, TRUE) AND $result !== FALSE){return;}}else{if ( ! method_exists($this, $rule)){// If our own wrapper function doesn't exist we see if a native PHP function does.// Users can use any native PHP function call that has one param.if (function_exists($rule)){$result = $rule($postdata);if ($_in_array == TRUE){$this->_field_data[$row['field']]['postdata'][$cycles] = (is_bool($result)) ? $postdata : $result;}else{$this->_field_data[$row['field']]['postdata'] = (is_bool($result)) ? $postdata : $result;}}continue;}$result = $this->$rule($postdata, $param);if ($_in_array == TRUE){$this->_field_data[$row['field']]['postdata'][$cycles] = (is_bool($result)) ? $postdata : $result;}else{$this->_field_data[$row['field']]['postdata'] = (is_bool($result)) ? $postdata : $result;}}// Did the rule test negatively? If so, grab the error.if ($result === FALSE){if ( ! isset($this->_error_messages[$rule])){if (FALSE === ($line = $this->CI->lang->line($rule))){$line = 'Unable to access an error message corresponding to your field name.';}}else{$line = $this->_error_messages[$rule];}// Build the error message$message = sprintf($line, $this->_translate_fieldname($row['label']), $param);// Save the error message$this->_field_data[$row['field']]['error'] = $message;if ( ! isset($this->_error_array[$row['field']])){$this->_error_array[$row['field']] = $message;}return;}}}// --------------------------------------------------------------------/*** Translate a field name** @access private* @param string the field name* @return string*/function _translate_fieldname($fieldname){// Do we need to translate the field name?// We look for the prefix lang: to determine thisif (substr($fieldname, 0, 5) == 'lang:'){// Grab the variable$line = substr($fieldname, 5);// Were we able to translate the field name? If not we use $lineif (FALSE === ($fieldname = $this->CI->lang->line($line))){return $line;}}return $fieldname;}// --------------------------------------------------------------------/*** Get the value from a form** Permits you to repopulate a form field with the value it was submitted* with, or, if that value doesn't exist, with the default** @access public* @param string the field name* @param string* @return void*/function set_value($field = '', $default = ''){if ( ! isset($this->_field_data[$field])){return $default;}return $this->_field_data[$field]['postdata'];}// --------------------------------------------------------------------/*** Set Select** Enables pull-down lists to be set to the value the user* selected in the event of an error** @access public* @param string* @param string* @return string*/function set_select($field = '', $value = '', $default = FALSE){if ( ! isset($this->_field_data[$field]) OR ! isset($this->_field_data[$field]['postdata'])){if ($default === TRUE AND count($this->_field_data) === 0){return ' selected="selected"';}return '';}$field = $this->_field_data[$field]['postdata'];if (is_array($field)){if ( ! in_array($value, $field)){return '';}}else{if (($field == '' OR $value == '') OR ($field != $value)){return '';}}return ' selected="selected"';}// --------------------------------------------------------------------/*** Set Radio** Enables radio buttons to be set to the value the user* selected in the event of an error** @access public* @param string* @param string* @return string*/function set_radio($field = '', $value = '', $default = FALSE){if ( ! isset($this->_field_data[$field]) OR ! isset($this->_field_data[$field]['postdata'])){if ($default === TRUE AND count($this->_field_data) === 0){return ' checked="checked"';}return '';}$field = $this->_field_data[$field]['postdata'];if (is_array($field)){if ( ! in_array($value, $field)){return '';}}else{if (($field == '' OR $value == '') OR ($field != $value)){return '';}}return ' checked="checked"';}// --------------------------------------------------------------------/*** Set Checkbox** Enables checkboxes to be set to the value the user* selected in the event of an error** @access public* @param string* @param string* @return string*/function set_checkbox($field = '', $value = '', $default = FALSE){if ( ! isset($this->_field_data[$field]) OR ! isset($this->_field_data[$field]['postdata'])){if ($default === TRUE AND count($this->_field_data) === 0){return ' checked="checked"';}return '';}$field = $this->_field_data[$field]['postdata'];if (is_array($field)){if ( ! in_array($value, $field)){return '';}}else{if (($field == '' OR $value == '') OR ($field != $value)){return '';}}return ' checked="checked"';}// --------------------------------------------------------------------/*** Required** @access public* @param string* @return bool*/function required($str){if ( ! is_array($str)){return (trim($str) == '') ? FALSE : TRUE;}else{return ( ! empty($str));}}// --------------------------------------------------------------------/*** Match one field to another** @access public* @param string* @param field* @return bool*/function matches($str, $field){if ( ! isset($_POST[$field])){return FALSE;}$field = $_POST[$field];return ($str !== $field) ? FALSE : TRUE;}// --------------------------------------------------------------------/*** Minimum Length** @access public* @param string* @param value* @return bool*/function min_length($str, $val){if (preg_match("/[^0-9]/", $val)){return FALSE;}if (function_exists('mb_strlen')){return (mb_strlen($str) < $val) ? FALSE : TRUE;}return (strlen($str) < $val) ? FALSE : TRUE;}// --------------------------------------------------------------------/*** Max Length** @access public* @param string* @param value* @return bool*/function max_length($str, $val){if (preg_match("/[^0-9]/", $val)){return FALSE;}if (function_exists('mb_strlen')){return (mb_strlen($str) > $val) ? FALSE : TRUE;}return (strlen($str) > $val) ? FALSE : TRUE;}// --------------------------------------------------------------------/*** Exact Length** @access public* @param string* @param value* @return bool*/function exact_length($str, $val){if (preg_match("/[^0-9]/", $val)){return FALSE;}if (function_exists('mb_strlen')){return (mb_strlen($str) != $val) ? FALSE : TRUE;}return (strlen($str) != $val) ? FALSE : TRUE;}// --------------------------------------------------------------------/*** Valid Email** @access public* @param string* @return bool*/function valid_email($str){return ( ! preg_match("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix", $str)) ? FALSE : TRUE;}// --------------------------------------------------------------------/*** Valid Emails** @access public* @param string* @return bool*/function valid_emails($str){if (strpos($str, ',') === FALSE){return $this->valid_email(trim($str));}foreach(explode(',', $str) as $email){if (trim($email) != '' && $this->valid_email(trim($email)) === FALSE){return FALSE;}}return TRUE;}// --------------------------------------------------------------------/*** Validate IP Address** @access public* @param string* @return string*/function valid_ip($ip){return $this->CI->input->valid_ip($ip);}// --------------------------------------------------------------------/*** Alpha** @access public* @param string* @return bool*/function alpha($str){return ( ! preg_match("/^([a-z])+$/i", $str)) ? FALSE : TRUE;}// --------------------------------------------------------------------/*** Alpha-numeric** @access public* @param string* @return bool*/function alpha_numeric($str){return ( ! preg_match("/^([a-z0-9])+$/i", $str)) ? FALSE : TRUE;}// --------------------------------------------------------------------/*** Alpha-numeric with underscores and dashes** @access public* @param string* @return bool*/function alpha_dash($str){return ( ! preg_match("/^([-a-z0-9_-])+$/i", $str)) ? FALSE : TRUE;}// --------------------------------------------------------------------/*** Numeric** @access public* @param string* @return bool*/function numeric($str){return (bool)preg_match( '/^[\-+]?[0-9]*\.?[0-9]+$/', $str);}// --------------------------------------------------------------------/*** Is Numeric** @access public* @param string* @return bool*/function is_numeric($str){return ( ! is_numeric($str)) ? FALSE : TRUE;}// --------------------------------------------------------------------/*** Integer** @access public* @param string* @return bool*/function integer($str){return (bool)preg_match( '/^[\-+]?[0-9]+$/', $str);}// --------------------------------------------------------------------/*** Is a Natural number (0,1,2,3, etc.)** @access public* @param string* @return bool*/function is_natural($str){return (bool)preg_match( '/^[0-9]+$/', $str);}// --------------------------------------------------------------------/*** Is a Natural number, but not a zero (1,2,3, etc.)** @access public* @param string* @return bool*/function is_natural_no_zero($str){if ( ! preg_match( '/^[0-9]+$/', $str)){return FALSE;}if ($str == 0){return FALSE;}return TRUE;}// --------------------------------------------------------------------/*** Valid Base64** Tests a string for characters outside of the Base64 alphabet* as defined by RFC 2045 http://www.faqs.org/rfcs/rfc2045** @access public* @param string* @return bool*/function valid_base64($str){return (bool) ! preg_match('/[^a-zA-Z0-9\/\+=]/', $str);}// --------------------------------------------------------------------/*** Prep data for form** This function allows HTML to be safely shown in a form.* Special characters are converted.** @access public* @param string* @return string*/function prep_for_form($data = ''){if (is_array($data)){foreach ($data as $key => $val){$data[$key] = $this->prep_for_form($val);}return $data;}if ($this->_safe_form_data == FALSE OR $data === ''){return $data;}return str_replace(array("'", '"', '<', '>'), array("'", """, '<', '>'), stripslashes($data));}// --------------------------------------------------------------------/*** Prep URL** @access public* @param string* @return string*/function prep_url($str = ''){if ($str == 'http://' OR $str == ''){return '';}if (substr($str, 0, 7) != 'http://' && substr($str, 0, 8) != 'https://'){$str = 'http://'.$str;}return $str;}// --------------------------------------------------------------------/*** Strip Image Tags** @access public* @param string* @return string*/function strip_image_tags($str){return $this->CI->input->strip_image_tags($str);}// --------------------------------------------------------------------/*** XSS Clean** @access public* @param string* @return string*/function xss_clean($str){return $this->CI->input->xss_clean($str);}// --------------------------------------------------------------------/*** Convert PHP tags to entities** @access public* @param string* @return string*/function encode_php_tags($str){return str_replace(array('<?php', '<?PHP', '<?', '?>'), array('<?php', '<?PHP', '<?', '?>'), $str);}}// END Form Validation Class/* End of file Form_validation.php *//* Location: ./system/libraries/Form_validation.php */