/** * Validate by processing pre-filters, rules, callbacks, and post-filters. * All fields that have filters, rules, or callbacks will be initialized if * they are undefined. Validation will only be run if there is data already * in the array. * * @return bool */ public function validate() { // All the fields that are being validated $all_fields = array_unique(array_merge(array_keys($this->pre_filters), array_keys($this->rules), array_keys($this->callbacks), array_keys($this->post_filters))); // Copy the array from the object, to optimize multiple sets $object_array = $this->getArrayCopy(); foreach ($all_fields as $i => $field) { if ($field === $this->any_field) { // Remove "any field" from the list of fields unset($all_fields[$i]); continue; } if (substr($field, -2) === '.*') { // Set the key to be an array Kohana::key_string_set($object_array, substr($field, 0, -2), array()); } else { // Set the key to be NULL Kohana::key_string_set($object_array, $field, NULL); } } // Swap the array back into the object $this->exchangeArray($object_array); // Reset all fields to ALL defined fields $all_fields = array_keys($this->getArrayCopy()); foreach ($this->pre_filters as $field => $calls) { foreach ($calls as $func) { if ($field === $this->any_field) { foreach ($all_fields as $f) { // Process each filter $this[$f] = is_array($this[$f]) ? arr::map_recursive($func, $this[$f]) : call_user_func($func, $this[$f]); } } else { // Process each filter $this[$field] = is_array($this[$field]) ? arr::map_recursive($func, $this[$field]) : call_user_func($func, $this[$field]); } } } if ($this->submitted === FALSE) { return FALSE; } foreach ($this->rules as $field => $calls) { foreach ($calls as $call) { // Split the rule into function and args list($func, $args) = $call; if ($field === $this->any_field) { foreach ($all_fields as $f) { if (isset($this->array_fields[$f])) { // Use the field key $f_key = $this->array_fields[$f]; // Prevent other rules from running when this field already has errors if (!empty($this->errors[$f_key])) { break; } // Don't process rules on empty fields if (!in_array($func[1], $this->empty_rules, TRUE) and $this[$f_key] == NULL) { continue; } foreach ($this[$f_key] as $k => $v) { if (!call_user_func($func, $this[$f_key][$k], $args)) { // Run each rule $this->errors[$f_key] = is_array($func) ? $func[1] : $func; } } } else { // Prevent other rules from running when this field already has errors if (!empty($this->errors[$f])) { break; } // Don't process rules on empty fields if (!in_array($func[1], $this->empty_rules, TRUE) and $this[$f] == NULL) { continue; } if (!call_user_func($func, $this[$f], $args)) { // Run each rule $this->errors[$f] = is_array($func) ? $func[1] : $func; } } } } else { if (isset($this->array_fields[$field])) { // Use the field key $field_key = $this->array_fields[$field]; // Prevent other rules from running when this field already has errors if (!empty($this->errors[$field_key])) { break; } // Don't process rules on empty fields if (!in_array($func[1], $this->empty_rules, TRUE) and $this[$field_key] == NULL) { continue; } foreach ($this[$field_key] as $k => $val) { if (!call_user_func($func, $this[$field_key][$k], $args)) { // Run each rule $this->errors[$field_key] = is_array($func) ? $func[1] : $func; // Stop after an error is found break 2; } } } else { // Prevent other rules from running when this field already has errors if (!empty($this->errors[$field])) { break; } // Don't process rules on empty fields if (!in_array($func[1], $this->empty_rules, TRUE) and $this[$field] == NULL) { continue; } if (!call_user_func($func, $this[$field], $args)) { // Run each rule $this->errors[$field] = is_array($func) ? $func[1] : $func; // Stop after an error is found break; } } } } } foreach ($this->callbacks as $field => $calls) { foreach ($calls as $func) { if ($field === $this->any_field) { foreach ($all_fields as $f) { // Execute the callback call_user_func($func, $this, $f); // Stop after an error is found if (!empty($errors[$f])) { break 2; } } } else { // Execute the callback call_user_func($func, $this, $field); // Stop after an error is found if (!empty($errors[$field])) { break; } } } } foreach ($this->post_filters as $field => $calls) { foreach ($calls as $func) { if ($field === $this->any_field) { foreach ($all_fields as $f) { if (isset($this->array_fields[$f])) { // Use the field key $f = $this->array_fields[$f]; } // Process each filter $this[$f] = is_array($this[$f]) ? array_map($func, $this[$f]) : call_user_func($func, $this[$f]); } } else { if (isset($this->array_fields[$field])) { // Use the field key $field = $this->array_fields[$field]; } // Process each filter $this[$field] = is_array($this[$field]) ? array_map($func, $this[$field]) : call_user_func($func, $this[$field]); } } } // Return TRUE if there are no errors return count($this->errors) === 0; }
/** * Validate by processing pre-filters, rules, callbacks, and post-filters. * All fields that have filters, rules, or callbacks will be initialized if * they are undefined. Validation will only be run if there is data already * in the array. * * @param bool $validate_csrf When TRUE, performs CSRF token validation * @return bool */ public function validate($validate_csrf = TRUE) { // CSRF token field $csrf_token_key = 'form_auth_token'; if (array_key_exists($csrf_token_key, $this)) { unset($this[$csrf_token_key]); } // Delete the CSRF token field if it's in the validation // rules if (array_key_exists($csrf_token_key, $this->callbacks)) { unset($this->callbacks[$csrf_token_key]); } elseif (array_key_exists($csrf_token_key, $this->rules)) { unset($this->rules[$csrf_token_key]); } // Disable CSRF for XHR // Same method as django CSRF protection: // http://michael-coates.blogspot.co.nz/2010/12/djangos-built-in-csrf-defense-for-ajax.html if (request::is_ajax()) { $validate_csrf = FALSE; } // Perform CSRF validation for all HTTP POST requests // where CSRF validation is enabled and the request // was not submitted via the API if ($_POST and $validate_csrf and !Validation::$is_api_request) { // Check if CSRF module is loaded if (in_array(MODPATH . 'csrf', Kohana::config('config.modules'))) { // Check for presence of CSRF token in HTTP POST payload $form_auth_token = isset($_POST[$csrf_token_key]) ? $_POST[$csrf_token_key] : text::random('alnum', 10); // Validate the token if (!csrf::valid($form_auth_token)) { Kohana::log('debug', 'Invalid CSRF token: ' . $form_auth_token); Kohana::log('debug', 'Actual CSRF token: ' . csrf::token()); // Flag CSRF validation as having failed $this->csrf_validation_failed = TRUE; // Set the error message $this->errors[$csrf_token_key] = Kohana::lang('csrf.form_auth_token.error'); return FALSE; } } } // All the fields that are being validated $all_fields = array_unique(array_merge(array_keys($this->pre_filters), array_keys($this->rules), array_keys($this->callbacks), array_keys($this->post_filters))); // Copy the array from the object, to optimize multiple sets $object_array = $this->getArrayCopy(); foreach ($all_fields as $i => $field) { if ($field === $this->any_field) { // Remove "any field" from the list of fields unset($all_fields[$i]); continue; } if (substr($field, -2) === '.*') { // Set the key to be an array Kohana::key_string_set($object_array, substr($field, 0, -2), array()); } else { // Set the key to be NULL Kohana::key_string_set($object_array, $field, NULL); } } // Swap the array back into the object $this->exchangeArray($object_array); // Reset all fields to ALL defined fields $all_fields = array_keys($this->getArrayCopy()); foreach ($this->pre_filters as $field => $calls) { foreach ($calls as $func) { if ($field === $this->any_field) { foreach ($all_fields as $f) { // Process each filter $this[$f] = is_array($this[$f]) ? arr::map_recursive($func, $this[$f]) : call_user_func($func, $this[$f]); } } else { // Process each filter $this[$field] = is_array($this[$field]) ? arr::map_recursive($func, $this[$field]) : call_user_func($func, $this[$field]); } } } if ($this->submitted === FALSE) { return FALSE; } foreach ($this->rules as $field => $calls) { foreach ($calls as $call) { // Split the rule into function and args list($func, $args) = $call; if ($field === $this->any_field) { foreach ($all_fields as $f) { if (isset($this->array_fields[$f])) { // Use the field key $f_key = $this->array_fields[$f]; // Prevent other rules from running when this field already has errors if (!empty($this->errors[$f_key])) { break; } // Don't process rules on empty fields if (!in_array($func[1], $this->empty_rules, TRUE) and $this[$f_key] == NULL) { continue; } foreach ($this[$f_key] as $k => $v) { if (!call_user_func($func, $this[$f_key][$k], $args)) { // Run each rule $this->errors[$f_key] = is_array($func) ? $func[1] : $func; } } } else { // Prevent other rules from running when this field already has errors if (!empty($this->errors[$f])) { break; } // Don't process rules on empty fields if (!in_array($func[1], $this->empty_rules, TRUE) and $this[$f] == NULL) { continue; } if (!call_user_func($func, $this[$f], $args)) { // Run each rule $this->errors[$f] = is_array($func) ? $func[1] : $func; } } } } else { if (isset($this->array_fields[$field])) { // Use the field key $field_key = $this->array_fields[$field]; // Prevent other rules from running when this field already has errors if (!empty($this->errors[$field_key])) { break; } // Don't process rules on empty fields if (!in_array($func[1], $this->empty_rules, TRUE) and $this[$field_key] == NULL) { continue; } foreach ($this[$field_key] as $k => $val) { if (!call_user_func($func, $this[$field_key][$k], $args)) { // Run each rule $this->errors[$field_key] = is_array($func) ? $func[1] : $func; // Stop after an error is found break 2; } } } else { // Prevent other rules from running when this field already has errors if (!empty($this->errors[$field])) { break; } // Don't process rules on empty fields if (!in_array($func[1], $this->empty_rules, TRUE) and $this[$field] == NULL) { continue; } if (!call_user_func($func, $this[$field], $args)) { // Run each rule $this->errors[$field] = is_array($func) ? $func[1] : $func; // Stop after an error is found break; } } } } } foreach ($this->callbacks as $field => $calls) { foreach ($calls as $func) { if ($field === $this->any_field) { foreach ($all_fields as $f) { // Execute the callback call_user_func($func, $this, $f); // Stop after an error is found if (!empty($errors[$f])) { break 2; } } } else { // Execute the callback call_user_func($func, $this, $field); // Stop after an error is found if (!empty($errors[$field])) { break; } } } } foreach ($this->post_filters as $field => $calls) { foreach ($calls as $func) { if ($field === $this->any_field) { foreach ($all_fields as $f) { if (isset($this->array_fields[$f])) { // Use the field key $f = $this->array_fields[$f]; } // Process each filter $this[$f] = is_array($this[$f]) ? array_map($func, $this[$f]) : call_user_func($func, $this[$f]); } } else { if (isset($this->array_fields[$field])) { // Use the field key $field = $this->array_fields[$field]; } // Process each filter $this[$field] = is_array($this[$field]) ? array_map($func, $this[$field]) : call_user_func($func, $this[$field]); } } } // Return TRUE if there are no errors return count($this->errors) === 0; }
/** * Because PHP does not have this function, and array_walk_recursive creates * references in arrays and is not truly recursive. * * @param mixed callback to apply to each member of the array * @param array array to map to * @return array */ public static function map_recursive($callback, array $array) { foreach ($array as $key => $val) { // Map the callback to the key $array[$key] = is_array($val) ? arr::map_recursive($callback, $val) : call_user_func($callback, $val); } return $array; }
/** * Tests the arr::map_recursive() function. * @dataProvider map_recursive_provider * @group core.helpers.arr.map_recursive * @test */ public function map_recursive($input_callback, $input_array, $expected_result) { $result = arr::map_recursive($input_callback, $input_array); $this->assertEquals($expected_result, $result); }