PageRenderTime 45ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/guide/kohana/security/validation.md

http://github.com/kohana/core
Markdown | 267 lines | 190 code | 77 blank | 0 comment | 0 complexity | 3c94971d5b2816f76c91212d5b235345 MD5 | raw file
  1. # Validation
  2. *This page needs to be reviewed for accuracy by the development team. Better examples would be helpful.*
  3. Validation can be performed on any array using the [Validation] class. Labels and rules can be attached to a Validation object by the array key, called a "field name".
  4. labels
  5. : A label is a human-readable version of the field name.
  6. rules
  7. : A rule is a callback or closure used to decide whether or not to add an error to a field
  8. [!!] Note that any valid [PHP callback](http://php.net/manual/language.pseudo-types.php#language.types.callback) can be used as a rule.
  9. Using `TRUE` as the field name when adding a rule will be applied to all named fields.
  10. Creating a validation object is done using the [Validation::factory] method:
  11. $object = Validation::factory($array);
  12. [!!] The `$object` object will be used for the rest of this tutorial. This tutorial will show you how to validate the registration of a new user.
  13. ## Provided Rules
  14. Kohana provides a set of useful rules in the [Valid] class:
  15. Rule name | Function
  16. ------------------------- |-------------------------------------------------
  17. [Valid::not_empty] | Value must be a non-empty value
  18. [Valid::regex] | Match the value against a regular expression
  19. [Valid::min_length] | Minimum number of characters for value
  20. [Valid::max_length] | Maximum number of characters for value
  21. [Valid::exact_length] | Value must be an exact number of characters
  22. [Valid::email] | An email address is required
  23. [Valid::email_domain] | Check that the domain of the email exists
  24. [Valid::url] | Value must be a URL
  25. [Valid::ip] | Value must be an IP address
  26. [Valid::phone] | Value must be a phone number
  27. [Valid::credit_card] | Require a credit card number
  28. [Valid::date] | Value must be a date (and time)
  29. [Valid::alpha] | Only alpha characters allowed
  30. [Valid::alpha_dash] | Only alpha and hyphens allowed
  31. [Valid::alpha_numeric] | Only alpha and numbers allowed
  32. [Valid::digit] | Value must be an integer digit
  33. [Valid::decimal] | Value must be a decimal or float value
  34. [Valid::numeric] | Only numeric characters allowed
  35. [Valid::range] | Value must be within a range
  36. [Valid::color] | Value must be a valid HEX color
  37. [Valid::matches] | Value matches another field value
  38. ## Adding Rules
  39. All validation rules are defined as a field name, a method, a function (using the [PHP callback](http://php.net/callback) syntax) or [closure](http://php.net/manual/functions.anonymous.php), and an array of parameters:
  40. $object->rule($field, $callback, array($parameter1, $parameter2));
  41. If no parameters are specified, the field value will be passed to the callback. The following two rules are equivalent:
  42. $object->rule($field, 'not_empty');
  43. $object->rule($field, 'not_empty', array(':value'));
  44. Rules defined in the [Valid] class can be added by using the method name alone. The following three rules are equivalent:
  45. $object->rule('number', 'phone');
  46. $object->rule('number', array('Valid', 'phone'));
  47. $object->rule('number', 'Valid::phone');
  48. ### Adding Rules for multiple fields together
  49. To validate multiple fields together, you can do something like this:
  50. $object->rule('one', 'only_one', array(':validation', array('one', 'two')));
  51. $object->rule('two', 'only_one', array(':validation', array('one', 'two')));
  52. public function only_one($validation, $fields)
  53. {
  54. // If more than 1 field is set, bail.
  55. $matched = 0;
  56. foreach ($fields as $field)
  57. {
  58. if (isset($validation[$field]))
  59. {
  60. $matched++;
  61. }
  62. }
  63. if ($matched > 0)
  64. {
  65. // Add the error to all concerned fields
  66. foreach ($fields as $field)
  67. {
  68. $validation->error($field, 'only_one');
  69. }
  70. }
  71. }
  72. ## Binding Variables
  73. The [Validation] class allows you to bind variables to certain strings so that they can be used when defining rules. Variables are bound by calling the [Validation::bind] method.
  74. $object->bind(':model', $user_model);
  75. // Future code will be able to use :model to reference the object
  76. $object->rule('username', 'some_rule', array(':model'));
  77. By default, the validation object will automatically bind the following values for you to use as rule parameters:
  78. - `:validation` - references the validation object
  79. - `:field` - references the field name the rule is for
  80. - `:value` - references the value of the field the rule is for
  81. ## Adding Errors
  82. The [Validation] class will add an error for a field if any of the rules associated to it return `FALSE`. This allows many built in PHP functions to be used as rules, like `in_array`.
  83. $object->rule('color', 'in_array', array(':value', array('red', 'green', 'blue')));
  84. Rules added to empty fields will run, but returning `FALSE` will not automatically add an error for the field. In order for a rule to affect empty fields, you must add the error manually by calling the [Validation::error] method. In order to do this, you must pass the validation object to the rule.
  85. $object->rule($field, 'the_rule', array(':validation', ':field'));
  86. public function the_rule($validation, $field)
  87. {
  88. if (something went wrong)
  89. {
  90. $validation->error($field, 'the_rule');
  91. }
  92. }
  93. [!!] `not_empty` and `matches` are the only rules that will run on empty fields and add errors by returning `FALSE`.
  94. ## Example
  95. To start our example, we will perform validation on the HTTP POST data of the current request that contains user registration information:
  96. [!!] In Kohana controllers, we access `$this->request->post()` instead of `$_POST` for better request isolation.
  97. $object = Validation::factory($this->request->post());
  98. Next we need to process the POST'ed information using [Validation]. To start, we need to add some rules:
  99. $object
  100. ->rule('username', 'not_empty')
  101. ->rule('username', 'regex', array(':value', '/^[a-z_.]++$/iD'))
  102. ->rule('password', 'not_empty')
  103. ->rule('password', 'min_length', array(':value', '6'))
  104. ->rule('confirm', 'matches', array(':validation', 'confirm', 'password'))
  105. ->rule('use_ssl', 'not_empty');
  106. Any existing PHP function can also be used a rule. For instance, if we want to check if the user entered a proper value for the SSL question:
  107. $object->rule('use_ssl', 'in_array', array(':value', array('yes', 'no')));
  108. Note that all array parameters must still be wrapped in an array! Without the wrapping array, `in_array` would be called as `in_array($value, 'yes', 'no')`, which would result in a PHP error.
  109. Any custom rules can be added using a [PHP callback](http://php.net/manual/language.pseudo-types.php#language.types.callback]:
  110. $object->rule('username', 'User_Model::unique_username');
  111. The method `User_Model::unique_username()` would be defined similar to:
  112. public static function unique_username($username)
  113. {
  114. // Check if the username already exists in the database
  115. return ! DB::select(array(DB::expr('COUNT(username)'), 'total'))
  116. ->from('users')
  117. ->where('username', '=', $username)
  118. ->execute()
  119. ->get('total');
  120. }
  121. [!!] Custom rules allow many additional checks to be reused for multiple purposes. These methods will almost always exist in a model, but may be defined in any class.
  122. # A Complete Example
  123. First, we need a [View] that contains the HTML form, which will be placed in `application/views/user/register.php`:
  124. <?php echo Form::open() ?>
  125. <?php if ($errors): ?>
  126. <p class="message">Some errors were encountered, please check the details you entered.</p>
  127. <ul class="errors">
  128. <?php foreach ($errors as $message): ?>
  129. <li><?php echo $message ?></li>
  130. <?php endforeach ?>
  131. </ul>
  132. <?php endif ?>
  133. <dl>
  134. <dt><?php echo Form::label('username', 'Username') ?></dt>
  135. <dd><?php echo Form::input('username', $post['username']) ?></dd>
  136. <dt><?php echo Form::label('password', 'Password') ?></dt>
  137. <dd><?php echo Form::password('password') ?></dd>
  138. <dd class="help">Passwords must be at least 6 characters long.</dd>
  139. <dt><?php echo Form::label('confirm', 'Confirm Password') ?></dt>
  140. <dd><?php echo Form::password('confirm') ?></dd>
  141. <dt><?php echo Form::label('use_ssl', 'Use extra security?') ?></dt>
  142. <dd><?php echo Form::select('use_ssl', array('yes' => 'Always', 'no' => 'Only when necessary'), $post['use_ssl']) ?></dd>
  143. <dd class="help">For security, SSL is always used when making payments.</dd>
  144. </dl>
  145. <?php echo Form::submit(NULL, 'Sign Up') ?>
  146. <?php echo Form::close() ?>
  147. [!!] This example uses the [Form] helper extensively. Using [Form] instead of writing HTML ensures that all of the form inputs will properly handle input that includes HTML characters. If you prefer to write the HTML yourself, be sure to use [HTML::chars] to escape user input.
  148. Next, we need a controller and action to process the registration, which will be placed in `application/classes/Controller/User.php`:
  149. class Controller_User extends Controller {
  150. public function action_register()
  151. {
  152. $user = Model::factory('user');
  153. $validation = Validation::factory($this->request->post())
  154. ->rule('username', 'not_empty')
  155. ->rule('username', 'regex', array(':value', '/^[a-z_.]++$/iD'))
  156. ->rule('username', array($user, 'unique_username'))
  157. ->rule('password', 'not_empty')
  158. ->rule('password', 'min_length', array(':value', 6))
  159. ->rule('confirm', 'matches', array(':validation', ':field', 'password'))
  160. ->rule('use_ssl', 'not_empty')
  161. ->rule('use_ssl', 'in_array', array(':value', array('yes', 'no')));
  162. if ($validation->check())
  163. {
  164. // Data has been validated, register the user
  165. $user->register($this->request->post());
  166. // Always redirect after a successful POST to prevent refresh warnings
  167. $this->redirect('user/profile', 303);
  168. }
  169. // Validation failed, collect the errors
  170. $errors = $validation->errors('user');
  171. // Display the registration form
  172. $this->response->body(View::factory('user/register'))
  173. ->bind('post', $this->request->post())
  174. ->bind('errors', $errors);
  175. }
  176. }
  177. We will also need a user model, which will be placed in `application/classes/Model/User.php`:
  178. class Model_User extends Model {
  179. public function register($array)
  180. {
  181. // Create a new user record in the database
  182. $id = DB::insert(array_keys($array))
  183. ->values($array)
  184. ->execute();
  185. // Save the new user id to a cookie
  186. cookie::set('user', $id);
  187. return $id;
  188. }
  189. }
  190. That is it, we have a complete user registration example that properly checks user input!