PageRenderTime 44ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/ci_crud/system/libraries/Form_validation.php

https://gitlab.com/bruno_felix/CRUD_CodeIgniter
PHP | 1596 lines | 769 code | 207 blank | 620 comment | 107 complexity | 4e5aec56a933702ad1ccc1ee695213a9 MD5 | raw file
  1. <?php
  2. /**
  3. * CodeIgniter
  4. *
  5. * An open source application development framework for PHP
  6. *
  7. * This content is released under the MIT License (MIT)
  8. *
  9. * Copyright (c) 2014 - 2015, British Columbia Institute of Technology
  10. *
  11. * Permission is hereby granted, free of charge, to any person obtaining a copy
  12. * of this software and associated documentation files (the "Software"), to deal
  13. * in the Software without restriction, including without limitation the rights
  14. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15. * copies of the Software, and to permit persons to whom the Software is
  16. * furnished to do so, subject to the following conditions:
  17. *
  18. * The above copyright notice and this permission notice shall be included in
  19. * all copies or substantial portions of the Software.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  27. * THE SOFTWARE.
  28. *
  29. * @package CodeIgniter
  30. * @author EllisLab Dev Team
  31. * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/)
  32. * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
  33. * @license http://opensource.org/licenses/MIT MIT License
  34. * @link http://codeigniter.com
  35. * @since Version 1.0.0
  36. * @filesource
  37. */
  38. defined('BASEPATH') OR exit('No direct script access allowed');
  39. /**
  40. * Form Validation Class
  41. *
  42. * @package CodeIgniter
  43. * @subpackage Libraries
  44. * @category Validation
  45. * @author EllisLab Dev Team
  46. * @link http://codeigniter.com/user_guide/libraries/form_validation.html
  47. */
  48. class CI_Form_validation {
  49. /**
  50. * Reference to the CodeIgniter instance
  51. *
  52. * @var object
  53. */
  54. protected $CI;
  55. /**
  56. * Validation data for the current form submission
  57. *
  58. * @var array
  59. */
  60. protected $_field_data = array();
  61. /**
  62. * Validation rules for the current form
  63. *
  64. * @var array
  65. */
  66. protected $_config_rules = array();
  67. /**
  68. * Array of validation errors
  69. *
  70. * @var array
  71. */
  72. protected $_error_array = array();
  73. /**
  74. * Array of custom error messages
  75. *
  76. * @var array
  77. */
  78. protected $_error_messages = array();
  79. /**
  80. * Start tag for error wrapping
  81. *
  82. * @var string
  83. */
  84. protected $_error_prefix = '<p>';
  85. /**
  86. * End tag for error wrapping
  87. *
  88. * @var string
  89. */
  90. protected $_error_suffix = '</p>';
  91. /**
  92. * Custom error message
  93. *
  94. * @var string
  95. */
  96. protected $error_string = '';
  97. /**
  98. * Whether the form data has been validated as safe
  99. *
  100. * @var bool
  101. */
  102. protected $_safe_form_data = FALSE;
  103. /**
  104. * Custom data to validate
  105. *
  106. * @var array
  107. */
  108. public $validation_data = array();
  109. /**
  110. * Initialize Form_Validation class
  111. *
  112. * @param array $rules
  113. * @return void
  114. */
  115. public function __construct($rules = array())
  116. {
  117. $this->CI =& get_instance();
  118. // applies delimiters set in config file.
  119. if (isset($rules['error_prefix']))
  120. {
  121. $this->_error_prefix = $rules['error_prefix'];
  122. unset($rules['error_prefix']);
  123. }
  124. if (isset($rules['error_suffix']))
  125. {
  126. $this->_error_suffix = $rules['error_suffix'];
  127. unset($rules['error_suffix']);
  128. }
  129. // Validation rules can be stored in a config file.
  130. $this->_config_rules = $rules;
  131. // Automatically load the form helper
  132. $this->CI->load->helper('form');
  133. log_message('info', 'Form Validation Class Initialized');
  134. }
  135. // --------------------------------------------------------------------
  136. /**
  137. * Set Rules
  138. *
  139. * This function takes an array of field names and validation
  140. * rules as input, any custom error messages, validates the info,
  141. * and stores it
  142. *
  143. * @param mixed $field
  144. * @param string $label
  145. * @param mixed $rules
  146. * @param array $errors
  147. * @return CI_Form_validation
  148. */
  149. public function set_rules($field, $label = '', $rules = array(), $errors = array())
  150. {
  151. // No reason to set rules if we have no POST data
  152. // or a validation array has not been specified
  153. if ($this->CI->input->method() !== 'post' && empty($this->validation_data))
  154. {
  155. return $this;
  156. }
  157. // If an array was passed via the first parameter instead of individual string
  158. // values we cycle through it and recursively call this function.
  159. if (is_array($field))
  160. {
  161. foreach ($field as $row)
  162. {
  163. // Houston, we have a problem...
  164. if ( ! isset($row['field'], $row['rules']))
  165. {
  166. continue;
  167. }
  168. // If the field label wasn't passed we use the field name
  169. $label = isset($row['label']) ? $row['label'] : $row['field'];
  170. // Add the custom error message array
  171. $errors = (isset($row['errors']) && is_array($row['errors'])) ? $row['errors'] : array();
  172. // Here we go!
  173. $this->set_rules($row['field'], $label, $row['rules'], $errors);
  174. }
  175. return $this;
  176. }
  177. // No fields or no rules? Nothing to do...
  178. if ( ! is_string($field) OR $field === '' OR empty($rules))
  179. {
  180. return $this;
  181. }
  182. elseif ( ! is_array($rules))
  183. {
  184. // BC: Convert pipe-separated rules string to an array
  185. if ( ! is_string($rules))
  186. {
  187. return $this;
  188. }
  189. $rules = explode('|', $rules);
  190. }
  191. // If the field label wasn't passed we use the field name
  192. $label = ($label === '') ? $field : $label;
  193. $indexes = array();
  194. // Is the field name an array? If it is an array, we break it apart
  195. // into its components so that we can fetch the corresponding POST data later
  196. if (($is_array = (bool) preg_match_all('/\[(.*?)\]/', $field, $matches)) === TRUE)
  197. {
  198. sscanf($field, '%[^[][', $indexes[0]);
  199. for ($i = 0, $c = count($matches[0]); $i < $c; $i++)
  200. {
  201. if ($matches[1][$i] !== '')
  202. {
  203. $indexes[] = $matches[1][$i];
  204. }
  205. }
  206. }
  207. // Build our master array
  208. $this->_field_data[$field] = array(
  209. 'field' => $field,
  210. 'label' => $label,
  211. 'rules' => $rules,
  212. 'errors' => $errors,
  213. 'is_array' => $is_array,
  214. 'keys' => $indexes,
  215. 'postdata' => NULL,
  216. 'error' => ''
  217. );
  218. return $this;
  219. }
  220. // --------------------------------------------------------------------
  221. /**
  222. * By default, form validation uses the $_POST array to validate
  223. *
  224. * If an array is set through this method, then this array will
  225. * be used instead of the $_POST array
  226. *
  227. * Note that if you are validating multiple arrays, then the
  228. * reset_validation() function should be called after validating
  229. * each array due to the limitations of CI's singleton
  230. *
  231. * @param array $data
  232. * @return CI_Form_validation
  233. */
  234. public function set_data(array $data)
  235. {
  236. if ( ! empty($data))
  237. {
  238. $this->validation_data = $data;
  239. }
  240. return $this;
  241. }
  242. // --------------------------------------------------------------------
  243. /**
  244. * Set Error Message
  245. *
  246. * Lets users set their own error messages on the fly. Note:
  247. * The key name has to match the function name that it corresponds to.
  248. *
  249. * @param array
  250. * @param string
  251. * @return CI_Form_validation
  252. */
  253. public function set_message($lang, $val = '')
  254. {
  255. if ( ! is_array($lang))
  256. {
  257. $lang = array($lang => $val);
  258. }
  259. $this->_error_messages = array_merge($this->_error_messages, $lang);
  260. return $this;
  261. }
  262. // --------------------------------------------------------------------
  263. /**
  264. * Set The Error Delimiter
  265. *
  266. * Permits a prefix/suffix to be added to each error message
  267. *
  268. * @param string
  269. * @param string
  270. * @return CI_Form_validation
  271. */
  272. public function set_error_delimiters($prefix = '<p>', $suffix = '</p>')
  273. {
  274. $this->_error_prefix = $prefix;
  275. $this->_error_suffix = $suffix;
  276. return $this;
  277. }
  278. // --------------------------------------------------------------------
  279. /**
  280. * Get Error Message
  281. *
  282. * Gets the error message associated with a particular field
  283. *
  284. * @param string $field Field name
  285. * @param string $prefix HTML start tag
  286. * @param string $suffix HTML end tag
  287. * @return string
  288. */
  289. public function error($field, $prefix = '', $suffix = '')
  290. {
  291. if (empty($this->_field_data[$field]['error']))
  292. {
  293. return '';
  294. }
  295. if ($prefix === '')
  296. {
  297. $prefix = $this->_error_prefix;
  298. }
  299. if ($suffix === '')
  300. {
  301. $suffix = $this->_error_suffix;
  302. }
  303. return $prefix.$this->_field_data[$field]['error'].$suffix;
  304. }
  305. // --------------------------------------------------------------------
  306. /**
  307. * Get Array of Error Messages
  308. *
  309. * Returns the error messages as an array
  310. *
  311. * @return array
  312. */
  313. public function error_array()
  314. {
  315. return $this->_error_array;
  316. }
  317. // --------------------------------------------------------------------
  318. /**
  319. * Error String
  320. *
  321. * Returns the error messages as a string, wrapped in the error delimiters
  322. *
  323. * @param string
  324. * @param string
  325. * @return string
  326. */
  327. public function error_string($prefix = '', $suffix = '')
  328. {
  329. // No errors, validation passes!
  330. if (count($this->_error_array) === 0)
  331. {
  332. return '';
  333. }
  334. if ($prefix === '')
  335. {
  336. $prefix = $this->_error_prefix;
  337. }
  338. if ($suffix === '')
  339. {
  340. $suffix = $this->_error_suffix;
  341. }
  342. // Generate the error string
  343. $str = '';
  344. foreach ($this->_error_array as $val)
  345. {
  346. if ($val !== '')
  347. {
  348. $str .= $prefix.$val.$suffix."\n";
  349. }
  350. }
  351. return $str;
  352. }
  353. // --------------------------------------------------------------------
  354. /**
  355. * Run the Validator
  356. *
  357. * This function does all the work.
  358. *
  359. * @param string $group
  360. * @return bool
  361. */
  362. public function run($group = '')
  363. {
  364. // Do we even have any data to process? Mm?
  365. $validation_array = empty($this->validation_data) ? $_POST : $this->validation_data;
  366. if (count($validation_array) === 0)
  367. {
  368. return FALSE;
  369. }
  370. // Does the _field_data array containing the validation rules exist?
  371. // If not, we look to see if they were assigned via a config file
  372. if (count($this->_field_data) === 0)
  373. {
  374. // No validation rules? We're done...
  375. if (count($this->_config_rules) === 0)
  376. {
  377. return FALSE;
  378. }
  379. if (empty($group))
  380. {
  381. // Is there a validation rule for the particular URI being accessed?
  382. $group = trim($this->CI->uri->ruri_string(), '/');
  383. isset($this->_config_rules[$group]) OR $group = $this->CI->router->class.'/'.$this->CI->router->method;
  384. }
  385. $this->set_rules(isset($this->_config_rules[$group]) ? $this->_config_rules[$group] : $this->_config_rules);
  386. // Were we able to set the rules correctly?
  387. if (count($this->_field_data) === 0)
  388. {
  389. log_message('debug', 'Unable to find validation rules');
  390. return FALSE;
  391. }
  392. }
  393. // Load the language file containing error messages
  394. $this->CI->lang->load('form_validation');
  395. // Cycle through the rules for each field and match the corresponding $validation_data item
  396. foreach ($this->_field_data as $field => $row)
  397. {
  398. // Fetch the data from the validation_data array item and cache it in the _field_data array.
  399. // Depending on whether the field name is an array or a string will determine where we get it from.
  400. if ($row['is_array'] === TRUE)
  401. {
  402. $this->_field_data[$field]['postdata'] = $this->_reduce_array($validation_array, $row['keys']);
  403. }
  404. elseif (isset($validation_array[$field]))
  405. {
  406. $this->_field_data[$field]['postdata'] = $validation_array[$field];
  407. }
  408. }
  409. // Execute validation rules
  410. // Note: A second foreach (for now) is required in order to avoid false-positives
  411. // for rules like 'matches', which correlate to other validation fields.
  412. foreach ($this->_field_data as $field => $row)
  413. {
  414. // Don't try to validate if we have no rules set
  415. if (empty($row['rules']))
  416. {
  417. continue;
  418. }
  419. $this->_execute($row, $row['rules'], $this->_field_data[$field]['postdata']);
  420. }
  421. // Did we end up with any errors?
  422. $total_errors = count($this->_error_array);
  423. if ($total_errors > 0)
  424. {
  425. $this->_safe_form_data = TRUE;
  426. }
  427. // Now we need to re-set the POST data with the new, processed data
  428. $this->_reset_post_array();
  429. return ($total_errors === 0);
  430. }
  431. // --------------------------------------------------------------------
  432. /**
  433. * Traverse a multidimensional $_POST array index until the data is found
  434. *
  435. * @param array
  436. * @param array
  437. * @param int
  438. * @return mixed
  439. */
  440. protected function _reduce_array($array, $keys, $i = 0)
  441. {
  442. if (is_array($array) && isset($keys[$i]))
  443. {
  444. return isset($array[$keys[$i]]) ? $this->_reduce_array($array[$keys[$i]], $keys, ($i+1)) : NULL;
  445. }
  446. // NULL must be returned for empty fields
  447. return ($array === '') ? NULL : $array;
  448. }
  449. // --------------------------------------------------------------------
  450. /**
  451. * Re-populate the _POST array with our finalized and processed data
  452. *
  453. * @return void
  454. */
  455. protected function _reset_post_array()
  456. {
  457. foreach ($this->_field_data as $field => $row)
  458. {
  459. if ($row['postdata'] !== NULL)
  460. {
  461. if ($row['is_array'] === FALSE)
  462. {
  463. if (isset($_POST[$row['field']]))
  464. {
  465. $_POST[$row['field']] = $row['postdata'];
  466. }
  467. }
  468. else
  469. {
  470. // start with a reference
  471. $post_ref =& $_POST;
  472. // before we assign values, make a reference to the right POST key
  473. if (count($row['keys']) === 1)
  474. {
  475. $post_ref =& $post_ref[current($row['keys'])];
  476. }
  477. else
  478. {
  479. foreach ($row['keys'] as $val)
  480. {
  481. $post_ref =& $post_ref[$val];
  482. }
  483. }
  484. if (is_array($row['postdata']))
  485. {
  486. $array = array();
  487. foreach ($row['postdata'] as $k => $v)
  488. {
  489. $array[$k] = $v;
  490. }
  491. $post_ref = $array;
  492. }
  493. else
  494. {
  495. $post_ref = $row['postdata'];
  496. }
  497. }
  498. }
  499. }
  500. }
  501. // --------------------------------------------------------------------
  502. /**
  503. * Executes the Validation routines
  504. *
  505. * @param array
  506. * @param array
  507. * @param mixed
  508. * @param int
  509. * @return mixed
  510. */
  511. protected function _execute($row, $rules, $postdata = NULL, $cycles = 0)
  512. {
  513. // If the $_POST data is an array we will run a recursive call
  514. if (is_array($postdata))
  515. {
  516. foreach ($postdata as $key => $val)
  517. {
  518. $this->_execute($row, $rules, $val, $key);
  519. }
  520. return;
  521. }
  522. // If the field is blank, but NOT required, no further tests are necessary
  523. $callback = FALSE;
  524. if ( ! in_array('required', $rules) && ($postdata === NULL OR $postdata === ''))
  525. {
  526. // Before we bail out, does the rule contain a callback?
  527. foreach ($rules as &$rule)
  528. {
  529. if (is_string($rule))
  530. {
  531. if (strncmp($rule, 'callback_', 9) === 0)
  532. {
  533. $callback = TRUE;
  534. $rules = array(1 => $rule);
  535. break;
  536. }
  537. }
  538. elseif (is_callable($rule))
  539. {
  540. $callback = TRUE;
  541. $rules = array(1 => $rule);
  542. break;
  543. }
  544. elseif (is_array($rule) && isset($rule[0], $rule[1]) && is_callable($rule[1]))
  545. {
  546. $callback = TRUE;
  547. $rules = array(array($rule[0], $rule[1]));
  548. break;
  549. }
  550. }
  551. if ( ! $callback)
  552. {
  553. return;
  554. }
  555. }
  556. // Isset Test. Typically this rule will only apply to checkboxes.
  557. if (($postdata === NULL OR $postdata === '') && ! $callback)
  558. {
  559. if (in_array('isset', $rules, TRUE) OR in_array('required', $rules))
  560. {
  561. // Set the message type
  562. $type = in_array('required', $rules) ? 'required' : 'isset';
  563. // Check if a custom message is defined
  564. if (isset($this->_field_data[$row['field']]['errors'][$type]))
  565. {
  566. $line = $this->_field_data[$row['field']]['errors'][$type];
  567. }
  568. elseif (isset($this->_error_messages[$type]))
  569. {
  570. $line = $this->_error_messages[$type];
  571. }
  572. elseif (FALSE === ($line = $this->CI->lang->line('form_validation_'.$type))
  573. // DEPRECATED support for non-prefixed keys
  574. && FALSE === ($line = $this->CI->lang->line($type, FALSE)))
  575. {
  576. $line = 'The field was not set';
  577. }
  578. // Build the error message
  579. $message = $this->_build_error_msg($line, $this->_translate_fieldname($row['label']));
  580. // Save the error message
  581. $this->_field_data[$row['field']]['error'] = $message;
  582. if ( ! isset($this->_error_array[$row['field']]))
  583. {
  584. $this->_error_array[$row['field']] = $message;
  585. }
  586. }
  587. return;
  588. }
  589. // --------------------------------------------------------------------
  590. // Cycle through each rule and run it
  591. foreach ($rules as $rule)
  592. {
  593. $_in_array = FALSE;
  594. // We set the $postdata variable with the current data in our master array so that
  595. // each cycle of the loop is dealing with the processed data from the last cycle
  596. if ($row['is_array'] === TRUE && is_array($this->_field_data[$row['field']]['postdata']))
  597. {
  598. // We shouldn't need this safety, but just in case there isn't an array index
  599. // associated with this cycle we'll bail out
  600. if ( ! isset($this->_field_data[$row['field']]['postdata'][$cycles]))
  601. {
  602. continue;
  603. }
  604. $postdata = $this->_field_data[$row['field']]['postdata'][$cycles];
  605. $_in_array = TRUE;
  606. }
  607. else
  608. {
  609. // If we get an array field, but it's not expected - then it is most likely
  610. // somebody messing with the form on the client side, so we'll just consider
  611. // it an empty field
  612. $postdata = is_array($this->_field_data[$row['field']]['postdata'])
  613. ? NULL
  614. : $this->_field_data[$row['field']]['postdata'];
  615. }
  616. // Is the rule a callback?
  617. $callback = $callable = FALSE;
  618. if (is_string($rule))
  619. {
  620. if (strpos($rule, 'callback_') === 0)
  621. {
  622. $rule = substr($rule, 9);
  623. $callback = TRUE;
  624. }
  625. }
  626. elseif (is_callable($rule))
  627. {
  628. $callable = TRUE;
  629. }
  630. elseif (is_array($rule) && isset($rule[0], $rule[1]) && is_callable($rule[1]))
  631. {
  632. // We have a "named" callable, so save the name
  633. $callable = $rule[0];
  634. $rule = $rule[1];
  635. }
  636. // Strip the parameter (if exists) from the rule
  637. // Rules can contain a parameter: max_length[5]
  638. $param = FALSE;
  639. if ( ! $callable && preg_match('/(.*?)\[(.*)\]/', $rule, $match))
  640. {
  641. $rule = $match[1];
  642. $param = $match[2];
  643. }
  644. // Call the function that corresponds to the rule
  645. if ($callback OR $callable !== FALSE)
  646. {
  647. if ($callback)
  648. {
  649. if ( ! method_exists($this->CI, $rule))
  650. {
  651. log_message('debug', 'Unable to find callback validation rule: '.$rule);
  652. $result = FALSE;
  653. }
  654. else
  655. {
  656. // Run the function and grab the result
  657. $result = $this->CI->$rule($postdata, $param);
  658. }
  659. }
  660. else
  661. {
  662. $result = is_array($rule)
  663. ? $rule[0]->{$rule[1]}($postdata)
  664. : $rule($postdata);
  665. // Is $callable set to a rule name?
  666. if ($callable !== FALSE)
  667. {
  668. $rule = $callable;
  669. }
  670. }
  671. // Re-assign the result to the master data array
  672. if ($_in_array === TRUE)
  673. {
  674. $this->_field_data[$row['field']]['postdata'][$cycles] = is_bool($result) ? $postdata : $result;
  675. }
  676. else
  677. {
  678. $this->_field_data[$row['field']]['postdata'] = is_bool($result) ? $postdata : $result;
  679. }
  680. // If the field isn't required and we just processed a callback we'll move on...
  681. if ( ! in_array('required', $rules, TRUE) && $result !== FALSE)
  682. {
  683. continue;
  684. }
  685. }
  686. elseif ( ! method_exists($this, $rule))
  687. {
  688. // If our own wrapper function doesn't exist we see if a native PHP function does.
  689. // Users can use any native PHP function call that has one param.
  690. if (function_exists($rule))
  691. {
  692. // Native PHP functions issue warnings if you pass them more parameters than they use
  693. $result = ($param !== FALSE) ? $rule($postdata, $param) : $rule($postdata);
  694. if ($_in_array === TRUE)
  695. {
  696. $this->_field_data[$row['field']]['postdata'][$cycles] = is_bool($result) ? $postdata : $result;
  697. }
  698. else
  699. {
  700. $this->_field_data[$row['field']]['postdata'] = is_bool($result) ? $postdata : $result;
  701. }
  702. }
  703. else
  704. {
  705. log_message('debug', 'Unable to find validation rule: '.$rule);
  706. $result = FALSE;
  707. }
  708. }
  709. else
  710. {
  711. $result = $this->$rule($postdata, $param);
  712. if ($_in_array === TRUE)
  713. {
  714. $this->_field_data[$row['field']]['postdata'][$cycles] = is_bool($result) ? $postdata : $result;
  715. }
  716. else
  717. {
  718. $this->_field_data[$row['field']]['postdata'] = is_bool($result) ? $postdata : $result;
  719. }
  720. }
  721. // Did the rule test negatively? If so, grab the error.
  722. if ($result === FALSE)
  723. {
  724. // Callable rules might not have named error messages
  725. if ( ! is_string($rule))
  726. {
  727. $line = $this->CI->lang->line('form_validation_error_message_not_set').'(Anonymous function)';
  728. }
  729. // Check if a custom message is defined
  730. elseif (isset($this->_field_data[$row['field']]['errors'][$rule]))
  731. {
  732. $line = $this->_field_data[$row['field']]['errors'][$rule];
  733. }
  734. elseif ( ! isset($this->_error_messages[$rule]))
  735. {
  736. if (FALSE === ($line = $this->CI->lang->line('form_validation_'.$rule))
  737. // DEPRECATED support for non-prefixed keys
  738. && FALSE === ($line = $this->CI->lang->line($rule, FALSE)))
  739. {
  740. $line = $this->CI->lang->line('form_validation_error_message_not_set').'('.$rule.')';
  741. }
  742. }
  743. else
  744. {
  745. $line = $this->_error_messages[$rule];
  746. }
  747. // Is the parameter we are inserting into the error message the name
  748. // of another field? If so we need to grab its "field label"
  749. if (isset($this->_field_data[$param], $this->_field_data[$param]['label']))
  750. {
  751. $param = $this->_translate_fieldname($this->_field_data[$param]['label']);
  752. }
  753. // Build the error message
  754. $message = $this->_build_error_msg($line, $this->_translate_fieldname($row['label']), $param);
  755. // Save the error message
  756. $this->_field_data[$row['field']]['error'] = $message;
  757. if ( ! isset($this->_error_array[$row['field']]))
  758. {
  759. $this->_error_array[$row['field']] = $message;
  760. }
  761. return;
  762. }
  763. }
  764. }
  765. // --------------------------------------------------------------------
  766. /**
  767. * Translate a field name
  768. *
  769. * @param string the field name
  770. * @return string
  771. */
  772. protected function _translate_fieldname($fieldname)
  773. {
  774. // Do we need to translate the field name? We look for the prefix 'lang:' to determine this
  775. // If we find one, but there's no translation for the string - just return it
  776. if (sscanf($fieldname, 'lang:%s', $line) === 1 && FALSE === ($fieldname = $this->CI->lang->line($line, FALSE)))
  777. {
  778. return $line;
  779. }
  780. return $fieldname;
  781. }
  782. // --------------------------------------------------------------------
  783. /**
  784. * Build an error message using the field and param.
  785. *
  786. * @param string The error message line
  787. * @param string A field's human name
  788. * @param mixed A rule's optional parameter
  789. * @return string
  790. */
  791. protected function _build_error_msg($line, $field = '', $param = '')
  792. {
  793. // Check for %s in the string for legacy support.
  794. if (strpos($line, '%s') !== FALSE)
  795. {
  796. return sprintf($line, $field, $param);
  797. }
  798. return str_replace(array('{field}', '{param}'), array($field, $param), $line);
  799. }
  800. // --------------------------------------------------------------------
  801. /**
  802. * Checks if the rule is present within the validator
  803. *
  804. * Permits you to check if a rule is present within the validator
  805. *
  806. * @param string the field name
  807. * @return bool
  808. */
  809. public function has_rule($field)
  810. {
  811. return isset($this->_field_data[$field]);
  812. }
  813. // --------------------------------------------------------------------
  814. /**
  815. * Get the value from a form
  816. *
  817. * Permits you to repopulate a form field with the value it was submitted
  818. * with, or, if that value doesn't exist, with the default
  819. *
  820. * @param string the field name
  821. * @param string
  822. * @return string
  823. */
  824. public function set_value($field = '', $default = '')
  825. {
  826. if ( ! isset($this->_field_data[$field], $this->_field_data[$field]['postdata']))
  827. {
  828. return $default;
  829. }
  830. // If the data is an array output them one at a time.
  831. // E.g: form_input('name[]', set_value('name[]');
  832. if (is_array($this->_field_data[$field]['postdata']))
  833. {
  834. return array_shift($this->_field_data[$field]['postdata']);
  835. }
  836. return $this->_field_data[$field]['postdata'];
  837. }
  838. // --------------------------------------------------------------------
  839. /**
  840. * Set Select
  841. *
  842. * Enables pull-down lists to be set to the value the user
  843. * selected in the event of an error
  844. *
  845. * @param string
  846. * @param string
  847. * @param bool
  848. * @return string
  849. */
  850. public function set_select($field = '', $value = '', $default = FALSE)
  851. {
  852. if ( ! isset($this->_field_data[$field], $this->_field_data[$field]['postdata']))
  853. {
  854. return ($default === TRUE && count($this->_field_data) === 0) ? ' selected="selected"' : '';
  855. }
  856. $field = $this->_field_data[$field]['postdata'];
  857. $value = (string) $value;
  858. if (is_array($field))
  859. {
  860. // Note: in_array('', array(0)) returns TRUE, do not use it
  861. foreach ($field as &$v)
  862. {
  863. if ($value === $v)
  864. {
  865. return ' selected="selected"';
  866. }
  867. }
  868. return '';
  869. }
  870. elseif (($field === '' OR $value === '') OR ($field !== $value))
  871. {
  872. return '';
  873. }
  874. return ' selected="selected"';
  875. }
  876. // --------------------------------------------------------------------
  877. /**
  878. * Set Radio
  879. *
  880. * Enables radio buttons to be set to the value the user
  881. * selected in the event of an error
  882. *
  883. * @param string
  884. * @param string
  885. * @param bool
  886. * @return string
  887. */
  888. public function set_radio($field = '', $value = '', $default = FALSE)
  889. {
  890. if ( ! isset($this->_field_data[$field], $this->_field_data[$field]['postdata']))
  891. {
  892. return ($default === TRUE && count($this->_field_data) === 0) ? ' checked="checked"' : '';
  893. }
  894. $field = $this->_field_data[$field]['postdata'];
  895. $value = (string) $value;
  896. if (is_array($field))
  897. {
  898. // Note: in_array('', array(0)) returns TRUE, do not use it
  899. foreach ($field as &$v)
  900. {
  901. if ($value === $v)
  902. {
  903. return ' checked="checked"';
  904. }
  905. }
  906. return '';
  907. }
  908. elseif (($field === '' OR $value === '') OR ($field !== $value))
  909. {
  910. return '';
  911. }
  912. return ' checked="checked"';
  913. }
  914. // --------------------------------------------------------------------
  915. /**
  916. * Set Checkbox
  917. *
  918. * Enables checkboxes to be set to the value the user
  919. * selected in the event of an error
  920. *
  921. * @param string
  922. * @param string
  923. * @param bool
  924. * @return string
  925. */
  926. public function set_checkbox($field = '', $value = '', $default = FALSE)
  927. {
  928. // Logic is exactly the same as for radio fields
  929. return $this->set_radio($field, $value, $default);
  930. }
  931. // --------------------------------------------------------------------
  932. /**
  933. * Required
  934. *
  935. * @param string
  936. * @return bool
  937. */
  938. public function required($str)
  939. {
  940. return is_array($str) ? (bool) count($str) : (trim($str) !== '');
  941. }
  942. // --------------------------------------------------------------------
  943. /**
  944. * Performs a Regular Expression match test.
  945. *
  946. * @param string
  947. * @param string regex
  948. * @return bool
  949. */
  950. public function regex_match($str, $regex)
  951. {
  952. return (bool) preg_match($regex, $str);
  953. }
  954. // --------------------------------------------------------------------
  955. /**
  956. * Match one field to another
  957. *
  958. * @param string $str string to compare against
  959. * @param string $field
  960. * @return bool
  961. */
  962. public function matches($str, $field)
  963. {
  964. return isset($this->_field_data[$field], $this->_field_data[$field]['postdata'])
  965. ? ($str === $this->_field_data[$field]['postdata'])
  966. : FALSE;
  967. }
  968. // --------------------------------------------------------------------
  969. /**
  970. * Differs from another field
  971. *
  972. * @param string
  973. * @param string field
  974. * @return bool
  975. */
  976. public function differs($str, $field)
  977. {
  978. return ! (isset($this->_field_data[$field]) && $this->_field_data[$field]['postdata'] === $str);
  979. }
  980. // --------------------------------------------------------------------
  981. /**
  982. * Is Unique
  983. *
  984. * Check if the input value doesn't already exist
  985. * in the specified database field.
  986. *
  987. * @param string $str
  988. * @param string $field
  989. * @return bool
  990. */
  991. public function is_unique($str, $field)
  992. {
  993. sscanf($field, '%[^.].%[^.]', $table, $field);
  994. return isset($this->CI->db)
  995. ? ($this->CI->db->limit(1)->get_where($table, array($field => $str))->num_rows() === 0)
  996. : FALSE;
  997. }
  998. // --------------------------------------------------------------------
  999. /**
  1000. * Minimum Length
  1001. *
  1002. * @param string
  1003. * @param string
  1004. * @return bool
  1005. */
  1006. public function min_length($str, $val)
  1007. {
  1008. if ( ! is_numeric($val))
  1009. {
  1010. return FALSE;
  1011. }
  1012. return ($val <= mb_strlen($str));
  1013. }
  1014. // --------------------------------------------------------------------
  1015. /**
  1016. * Max Length
  1017. *
  1018. * @param string
  1019. * @param string
  1020. * @return bool
  1021. */
  1022. public function max_length($str, $val)
  1023. {
  1024. if ( ! is_numeric($val))
  1025. {
  1026. return FALSE;
  1027. }
  1028. return ($val >= mb_strlen($str));
  1029. }
  1030. // --------------------------------------------------------------------
  1031. /**
  1032. * Exact Length
  1033. *
  1034. * @param string
  1035. * @param string
  1036. * @return bool
  1037. */
  1038. public function exact_length($str, $val)
  1039. {
  1040. if ( ! is_numeric($val))
  1041. {
  1042. return FALSE;
  1043. }
  1044. return (mb_strlen($str) === (int) $val);
  1045. }
  1046. // --------------------------------------------------------------------
  1047. /**
  1048. * Valid URL
  1049. *
  1050. * @param string $str
  1051. * @return bool
  1052. */
  1053. public function valid_url($str)
  1054. {
  1055. if (empty($str))
  1056. {
  1057. return FALSE;
  1058. }
  1059. elseif (preg_match('/^(?:([^:]*)\:)?\/\/(.+)$/', $str, $matches))
  1060. {
  1061. if (empty($matches[2]))
  1062. {
  1063. return FALSE;
  1064. }
  1065. elseif ( ! in_array($matches[1], array('http', 'https'), TRUE))
  1066. {
  1067. return FALSE;
  1068. }
  1069. $str = $matches[2];
  1070. }
  1071. $str = 'http://'.$str;
  1072. // There's a bug affecting PHP 5.2.13, 5.3.2 that considers the
  1073. // underscore to be a valid hostname character instead of a dash.
  1074. // Reference: https://bugs.php.net/bug.php?id=51192
  1075. if (version_compare(PHP_VERSION, '5.2.13', '==') OR version_compare(PHP_VERSION, '5.3.2', '=='))
  1076. {
  1077. sscanf($str, 'http://%[^/]', $host);
  1078. $str = substr_replace($str, strtr($host, array('_' => '-', '-' => '_')), 7, strlen($host));
  1079. }
  1080. return (filter_var($str, FILTER_VALIDATE_URL) !== FALSE);
  1081. }
  1082. // --------------------------------------------------------------------
  1083. /**
  1084. * Valid Email
  1085. *
  1086. * @param string
  1087. * @return bool
  1088. */
  1089. public function valid_email($str)
  1090. {
  1091. if (function_exists('idn_to_ascii') && $atpos = strpos($str, '@'))
  1092. {
  1093. $str = substr($str, 0, ++$atpos).idn_to_ascii(substr($str, $atpos));
  1094. }
  1095. return (bool) filter_var($str, FILTER_VALIDATE_EMAIL);
  1096. }
  1097. // --------------------------------------------------------------------
  1098. /**
  1099. * Valid Emails
  1100. *
  1101. * @param string
  1102. * @return bool
  1103. */
  1104. public function valid_emails($str)
  1105. {
  1106. if (strpos($str, ',') === FALSE)
  1107. {
  1108. return $this->valid_email(trim($str));
  1109. }
  1110. foreach (explode(',', $str) as $email)
  1111. {
  1112. if (trim($email) !== '' && $this->valid_email(trim($email)) === FALSE)
  1113. {
  1114. return FALSE;
  1115. }
  1116. }
  1117. return TRUE;
  1118. }
  1119. // --------------------------------------------------------------------
  1120. /**
  1121. * Validate IP Address
  1122. *
  1123. * @param string
  1124. * @param string 'ipv4' or 'ipv6' to validate a specific IP format
  1125. * @return bool
  1126. */
  1127. public function valid_ip($ip, $which = '')
  1128. {
  1129. return $this->CI->input->valid_ip($ip, $which);
  1130. }
  1131. // --------------------------------------------------------------------
  1132. /**
  1133. * Alpha
  1134. *
  1135. * @param string
  1136. * @return bool
  1137. */
  1138. public function alpha($str)
  1139. {
  1140. return ctype_alpha($str);
  1141. }
  1142. // --------------------------------------------------------------------
  1143. /**
  1144. * Alpha-numeric
  1145. *
  1146. * @param string
  1147. * @return bool
  1148. */
  1149. public function alpha_numeric($str)
  1150. {
  1151. return ctype_alnum((string) $str);
  1152. }
  1153. // --------------------------------------------------------------------
  1154. /**
  1155. * Alpha-numeric w/ spaces
  1156. *
  1157. * @param string
  1158. * @return bool
  1159. */
  1160. public function alpha_numeric_spaces($str)
  1161. {
  1162. return (bool) preg_match('/^[A-Z0-9 ]+$/i', $str);
  1163. }
  1164. // --------------------------------------------------------------------
  1165. /**
  1166. * Alpha-numeric with underscores and dashes
  1167. *
  1168. * @param string
  1169. * @return bool
  1170. */
  1171. public function alpha_dash($str)
  1172. {
  1173. return (bool) preg_match('/^[a-z0-9_-]+$/i', $str);
  1174. }
  1175. // --------------------------------------------------------------------
  1176. /**
  1177. * Numeric
  1178. *
  1179. * @param string
  1180. * @return bool
  1181. */
  1182. public function numeric($str)
  1183. {
  1184. return (bool) preg_match('/^[\-+]?[0-9]*\.?[0-9]+$/', $str);
  1185. }
  1186. // --------------------------------------------------------------------
  1187. /**
  1188. * Integer
  1189. *
  1190. * @param string
  1191. * @return bool
  1192. */
  1193. public function integer($str)
  1194. {
  1195. return (bool) preg_match('/^[\-+]?[0-9]+$/', $str);
  1196. }
  1197. // --------------------------------------------------------------------
  1198. /**
  1199. * Decimal number
  1200. *
  1201. * @param string
  1202. * @return bool
  1203. */
  1204. public function decimal($str)
  1205. {
  1206. return (bool) preg_match('/^[\-+]?[0-9]+\.[0-9]+$/', $str);
  1207. }
  1208. // --------------------------------------------------------------------
  1209. /**
  1210. * Greater than
  1211. *
  1212. * @param string
  1213. * @param int
  1214. * @return bool
  1215. */
  1216. public function greater_than($str, $min)
  1217. {
  1218. return is_numeric($str) ? ($str > $min) : FALSE;
  1219. }
  1220. // --------------------------------------------------------------------
  1221. /**
  1222. * Equal to or Greater than
  1223. *
  1224. * @param string
  1225. * @param int
  1226. * @return bool
  1227. */
  1228. public function greater_than_equal_to($str, $min)
  1229. {
  1230. return is_numeric($str) ? ($str >= $min) : FALSE;
  1231. }
  1232. // --------------------------------------------------------------------
  1233. /**
  1234. * Less than
  1235. *
  1236. * @param string
  1237. * @param int
  1238. * @return bool
  1239. */
  1240. public function less_than($str, $max)
  1241. {
  1242. return is_numeric($str) ? ($str < $max) : FALSE;
  1243. }
  1244. // --------------------------------------------------------------------
  1245. /**
  1246. * Equal to or Less than
  1247. *
  1248. * @param string
  1249. * @param int
  1250. * @return bool
  1251. */
  1252. public function less_than_equal_to($str, $max)
  1253. {
  1254. return is_numeric($str) ? ($str <= $max) : FALSE;
  1255. }
  1256. // --------------------------------------------------------------------
  1257. /**
  1258. * Value should be within an array of values
  1259. *
  1260. * @param string
  1261. * @param string
  1262. * @return bool
  1263. */
  1264. public function in_list($value, $list)
  1265. {
  1266. return in_array($value, explode(',', $list), TRUE);
  1267. }
  1268. // --------------------------------------------------------------------
  1269. /**
  1270. * Is a Natural number (0,1,2,3, etc.)
  1271. *
  1272. * @param string
  1273. * @return bool
  1274. */
  1275. public function is_natural($str)
  1276. {
  1277. return ctype_digit((string) $str);
  1278. }
  1279. // --------------------------------------------------------------------
  1280. /**
  1281. * Is a Natural number, but not a zero (1,2,3, etc.)
  1282. *
  1283. * @param string
  1284. * @return bool
  1285. */
  1286. public function is_natural_no_zero($str)
  1287. {
  1288. return ($str != 0 && ctype_digit((string) $str));
  1289. }
  1290. // --------------------------------------------------------------------
  1291. /**
  1292. * Valid Base64
  1293. *
  1294. * Tests a string for characters outside of the Base64 alphabet
  1295. * as defined by RFC 2045 http://www.faqs.org/rfcs/rfc2045
  1296. *
  1297. * @param string
  1298. * @return bool
  1299. */
  1300. public function valid_base64($str)
  1301. {
  1302. return (base64_encode(base64_decode($str)) === $str);
  1303. }
  1304. // --------------------------------------------------------------------
  1305. /**
  1306. * Prep data for form
  1307. *
  1308. * This function allows HTML to be safely shown in a form.
  1309. * Special characters are converted.
  1310. *
  1311. * @param string
  1312. * @return string
  1313. */
  1314. public function prep_for_form($data = '')
  1315. {
  1316. if ($this->_safe_form_data === FALSE OR empty($data))
  1317. {
  1318. return $data;
  1319. }
  1320. if (is_array($data))
  1321. {
  1322. foreach ($data as $key => $val)
  1323. {
  1324. $data[$key] = $this->prep_for_form($val);
  1325. }
  1326. return $data;
  1327. }
  1328. return str_replace(array("'", '"', '<', '>'), array('&#39;', '&quot;', '&lt;', '&gt;'), stripslashes($data));
  1329. }
  1330. // --------------------------------------------------------------------
  1331. /**
  1332. * Prep URL
  1333. *
  1334. * @param string
  1335. * @return string
  1336. */
  1337. public function prep_url($str = '')
  1338. {
  1339. if ($str === 'http://' OR $str === '')
  1340. {
  1341. return '';
  1342. }
  1343. if (strpos($str, 'http://') !== 0 && strpos($str, 'https://') !== 0)
  1344. {
  1345. return 'http://'.$str;
  1346. }
  1347. return $str;
  1348. }
  1349. // --------------------------------------------------------------------
  1350. /**
  1351. * Strip Image Tags
  1352. *
  1353. * @param string
  1354. * @return string
  1355. */
  1356. public function strip_image_tags($str)
  1357. {
  1358. return $this->CI->security->strip_image_tags($str);
  1359. }
  1360. // --------------------------------------------------------------------
  1361. /**
  1362. * Convert PHP tags to entities
  1363. *
  1364. * @param string
  1365. * @return string
  1366. */
  1367. public function encode_php_tags($str)
  1368. {
  1369. return str_replace(array('<?', '?>'), array('&lt;?', '?&gt;'), $str);
  1370. }
  1371. // --------------------------------------------------------------------
  1372. /**
  1373. * Reset validation vars
  1374. *
  1375. * Prevents subsequent validation routines from being affected by the
  1376. * results of any previous validation routine due to the CI singleton.
  1377. *
  1378. * @return CI_Form_validation
  1379. */
  1380. public function reset_validation()
  1381. {
  1382. $this->_field_data = array();
  1383. $this->_config_rules = array();
  1384. $this->_error_array = array();
  1385. $this->_error_messages = array();
  1386. $this->error_string = '';
  1387. return $this;
  1388. }
  1389. }