From d51be02dd2e1260294c9140651788774c1c0b9c9 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 27 Jun 2011 17:33:07 -0500 Subject: [PATCH] enhanced validation, added mimes config array. --- application/config/mimes.php | 97 ++++++++++++ application/lang/en/validation.php | 27 ++++ system/file.php | 115 ++------------ system/validation/message.php | 144 +++++++++++++++++ system/validation/nullable_rule.php | 94 +++++++++++ system/validation/rangable_rule.php | 145 +++++++++++++++++ system/validation/rule.php | 55 ++----- system/validation/rules/acceptance_of.php | 4 +- system/validation/rules/confirmation_of.php | 2 +- system/validation/rules/exclusion_of.php | 12 +- system/validation/rules/format_of.php | 12 +- system/validation/rules/inclusion_of.php | 12 +- system/validation/rules/length_of.php | 49 ++++++ system/validation/rules/numericality_of.php | 116 ++++++++++++++ system/validation/rules/presence_of.php | 61 ++----- system/validation/rules/size_of.php | 166 -------------------- system/validation/rules/uniqueness_of.php | 17 +- system/validation/rules/upload_of.php | 106 +++++++++++-- system/validation/rules/with_callback.php | 18 +-- 19 files changed, 841 insertions(+), 411 deletions(-) create mode 100644 application/config/mimes.php create mode 100644 application/lang/en/validation.php create mode 100644 system/validation/message.php create mode 100644 system/validation/nullable_rule.php create mode 100644 system/validation/rangable_rule.php create mode 100644 system/validation/rules/length_of.php create mode 100644 system/validation/rules/numericality_of.php delete mode 100644 system/validation/rules/size_of.php diff --git a/application/config/mimes.php b/application/config/mimes.php new file mode 100644 index 00000000..e2bd4fbb --- /dev/null +++ b/application/config/mimes.php @@ -0,0 +1,97 @@ + 'application/mac-binhex40', + 'cpt' => 'application/mac-compactpro', + 'csv' => array('text/x-comma-separated-values', 'text/comma-separated-values', 'application/octet-stream'), + 'bin' => 'application/macbinary', + 'dms' => 'application/octet-stream', + 'lha' => 'application/octet-stream', + 'lzh' => 'application/octet-stream', + 'exe' => array('application/octet-stream', 'application/x-msdownload'), + 'class' => 'application/octet-stream', + 'psd' => 'application/x-photoshop', + 'so' => 'application/octet-stream', + 'sea' => 'application/octet-stream', + 'dll' => 'application/octet-stream', + 'oda' => 'application/oda', + 'pdf' => array('application/pdf', 'application/x-download'), + 'ai' => 'application/postscript', + 'eps' => 'application/postscript', + 'ps' => 'application/postscript', + 'smi' => 'application/smil', + 'smil' => 'application/smil', + 'mif' => 'application/vnd.mif', + 'xls' => array('application/excel', 'application/vnd.ms-excel', 'application/msexcel'), + 'ppt' => array('application/powerpoint', 'application/vnd.ms-powerpoint'), + 'wbxml' => 'application/wbxml', + 'wmlc' => 'application/wmlc', + 'dcr' => 'application/x-director', + 'dir' => 'application/x-director', + 'dxr' => 'application/x-director', + 'dvi' => 'application/x-dvi', + 'gtar' => 'application/x-gtar', + 'gz' => 'application/x-gzip', + 'php' => array('application/x-httpd-php', 'text/x-php'), + 'php4' => 'application/x-httpd-php', + 'php3' => 'application/x-httpd-php', + 'phtml' => 'application/x-httpd-php', + 'phps' => 'application/x-httpd-php-source', + 'js' => 'application/x-javascript', + 'swf' => 'application/x-shockwave-flash', + 'sit' => 'application/x-stuffit', + 'tar' => 'application/x-tar', + 'tgz' => array('application/x-tar', 'application/x-gzip-compressed'), + 'xhtml' => 'application/xhtml+xml', + 'xht' => 'application/xhtml+xml', + 'zip' => array('application/x-zip', 'application/zip', 'application/x-zip-compressed'), + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mpga' => 'audio/mpeg', + 'mp2' => 'audio/mpeg', + 'mp3' => array('audio/mpeg', 'audio/mpg', 'audio/mpeg3', 'audio/mp3'), + 'aif' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'ram' => 'audio/x-pn-realaudio', + 'rm' => 'audio/x-pn-realaudio', + 'rpm' => 'audio/x-pn-realaudio-plugin', + 'ra' => 'audio/x-realaudio', + 'rv' => 'video/vnd.rn-realvideo', + 'wav' => 'audio/x-wav', + 'bmp' => 'image/bmp', + 'gif' => 'image/gif', + 'jpeg' => array('image/jpeg', 'image/pjpeg'), + 'jpg' => array('image/jpeg', 'image/pjpeg'), + 'jpe' => array('image/jpeg', 'image/pjpeg'), + 'png' => 'image/png', + 'tiff' => 'image/tiff', + 'tif' => 'image/tiff', + 'css' => 'text/css', + 'html' => 'text/html', + 'htm' => 'text/html', + 'shtml' => 'text/html', + 'txt' => 'text/plain', + 'text' => 'text/plain', + 'log' => array('text/plain', 'text/x-log'), + 'rtx' => 'text/richtext', + 'rtf' => 'text/rtf', + 'xml' => 'text/xml', + 'xsl' => 'text/xml', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpe' => 'video/mpeg', + 'qt' => 'video/quicktime', + 'mov' => 'video/quicktime', + 'avi' => 'video/x-msvideo', + 'movie' => 'video/x-sgi-movie', + 'doc' => 'application/msword', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'word' => array('application/msword', 'application/octet-stream'), + 'xl' => 'application/excel', + 'eml' => 'message/rfc822', + 'json' => array('application/json', 'text/json'), + +); \ No newline at end of file diff --git a/application/lang/en/validation.php b/application/lang/en/validation.php new file mode 100644 index 00000000..8f38c22f --- /dev/null +++ b/application/lang/en/validation.php @@ -0,0 +1,27 @@ + "The :attribute must be accepted.", + "confirmation_of" => "The :attribute confirmation does not match.", + "exclusion_of" => "The :attribute value is invalid.", + "format_of" => "The :attribute format is invalid.", + "inclusion_of" => "The :attribute value is invalid.", + "presence_of" => "The :attribute can't be blank.", + "uniqueness_of" => "The :attribute has already been taken.", + "with_callback" => "The :attribute is invalid.", + + "number_not_valid" => "The :attribute is not a valid number.", + "number_not_integer" => "The :attribute is not a valid integer.", + "number_wrong_size" => "The :attribute must be :size.", + "number_too_big" => "The :attribute must be less than :max.", + "number_too_small" => "The :attribute must be at least :min.", + + "string_wrong_size" => "The :attribute must be :size characters.", + "string_too_big" => "The :attribute must be less than :max characters.", + "string_too_small" => "The :attribute must be at least :min characters.", + + "file_too_big" => "The :attribute exceeded size limit of :maxkb.", + "file_wrong_type" => "The :attribute is an invalid type.", + +); \ No newline at end of file diff --git a/system/file.php b/system/file.php index 24402dc4..7156243b 100644 --- a/system/file.php +++ b/system/file.php @@ -2,105 +2,6 @@ class File { - /** - * Extensions and their matching MIME types. - * - * @var array - */ - public static $mimes = array( - 'hqx' => 'application/mac-binhex40', - 'cpt' => 'application/mac-compactpro', - 'csv' => array('text/x-comma-separated-values', 'text/comma-separated-values', 'application/octet-stream'), - 'bin' => 'application/macbinary', - 'dms' => 'application/octet-stream', - 'lha' => 'application/octet-stream', - 'lzh' => 'application/octet-stream', - 'exe' => array('application/octet-stream', 'application/x-msdownload'), - 'class' => 'application/octet-stream', - 'psd' => 'application/x-photoshop', - 'so' => 'application/octet-stream', - 'sea' => 'application/octet-stream', - 'dll' => 'application/octet-stream', - 'oda' => 'application/oda', - 'pdf' => array('application/pdf', 'application/x-download'), - 'ai' => 'application/postscript', - 'eps' => 'application/postscript', - 'ps' => 'application/postscript', - 'smi' => 'application/smil', - 'smil' => 'application/smil', - 'mif' => 'application/vnd.mif', - 'xls' => array('application/excel', 'application/vnd.ms-excel', 'application/msexcel'), - 'ppt' => array('application/powerpoint', 'application/vnd.ms-powerpoint'), - 'wbxml' => 'application/wbxml', - 'wmlc' => 'application/wmlc', - 'dcr' => 'application/x-director', - 'dir' => 'application/x-director', - 'dxr' => 'application/x-director', - 'dvi' => 'application/x-dvi', - 'gtar' => 'application/x-gtar', - 'gz' => 'application/x-gzip', - 'php' => array('application/x-httpd-php', 'text/x-php'), - 'php4' => 'application/x-httpd-php', - 'php3' => 'application/x-httpd-php', - 'phtml' => 'application/x-httpd-php', - 'phps' => 'application/x-httpd-php-source', - 'js' => 'application/x-javascript', - 'swf' => 'application/x-shockwave-flash', - 'sit' => 'application/x-stuffit', - 'tar' => 'application/x-tar', - 'tgz' => array('application/x-tar', 'application/x-gzip-compressed'), - 'xhtml' => 'application/xhtml+xml', - 'xht' => 'application/xhtml+xml', - 'zip' => array('application/x-zip', 'application/zip', 'application/x-zip-compressed'), - 'mid' => 'audio/midi', - 'midi' => 'audio/midi', - 'mpga' => 'audio/mpeg', - 'mp2' => 'audio/mpeg', - 'mp3' => array('audio/mpeg', 'audio/mpg', 'audio/mpeg3', 'audio/mp3'), - 'aif' => 'audio/x-aiff', - 'aiff' => 'audio/x-aiff', - 'aifc' => 'audio/x-aiff', - 'ram' => 'audio/x-pn-realaudio', - 'rm' => 'audio/x-pn-realaudio', - 'rpm' => 'audio/x-pn-realaudio-plugin', - 'ra' => 'audio/x-realaudio', - 'rv' => 'video/vnd.rn-realvideo', - 'wav' => 'audio/x-wav', - 'bmp' => 'image/bmp', - 'gif' => 'image/gif', - 'jpeg' => array('image/jpeg', 'image/pjpeg'), - 'jpg' => array('image/jpeg', 'image/pjpeg'), - 'jpe' => array('image/jpeg', 'image/pjpeg'), - 'png' => 'image/png', - 'tiff' => 'image/tiff', - 'tif' => 'image/tiff', - 'css' => 'text/css', - 'html' => 'text/html', - 'htm' => 'text/html', - 'shtml' => 'text/html', - 'txt' => 'text/plain', - 'text' => 'text/plain', - 'log' => array('text/plain', 'text/x-log'), - 'rtx' => 'text/richtext', - 'rtf' => 'text/rtf', - 'xml' => 'text/xml', - 'xsl' => 'text/xml', - 'mpeg' => 'video/mpeg', - 'mpg' => 'video/mpeg', - 'mpe' => 'video/mpeg', - 'qt' => 'video/quicktime', - 'mov' => 'video/quicktime', - 'avi' => 'video/x-msvideo', - 'movie' => 'video/x-sgi-movie', - 'doc' => 'application/msword', - 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', - 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', - 'word' => array('application/msword', 'application/octet-stream'), - 'xl' => 'application/excel', - 'eml' => 'message/rfc822', - 'json' => array('application/json', 'text/json'), - ); - /** * Get the contents of a file. * @@ -156,9 +57,11 @@ public static function extension($path) */ public static function mime($extension, $default = 'application/octet-stream') { - if (array_key_exists($extension, static::$mimes)) + $mimes = Config::get('mimes'); + + if (array_key_exists($extension, $mimes)) { - return (is_array(static::$mimes[$extension])) ? static::$mimes[$extension][0] : static::$mimes[$extension]; + return (is_array($mimes[$extension])) ? $mimes[$extension][0] : $mimes[$extension]; } return $default; @@ -167,20 +70,22 @@ public static function mime($extension, $default = 'application/octet-stream') /** * Determine if a file is a given type. * - * The Fileinfo PHP extension will be used to determine the MIME - * type of the file. Any extension in the File::$mimes array may + * The Fileinfo PHP extension will be used to determine the MIME type + * of the file. Any extension in the mimes configuration array may * be passed as a type. */ public static function is($extension, $path) { - if ( ! array_key_exists($extension, static::$mimes)) + $mimes = Config::get('mimes'); + + if ( ! array_key_exists($extension, $mimes)) { throw new \Exception("File extension [$extension] is unknown. Cannot determine file type."); } $mime = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $path); - return (is_array(static::$mimes[$extension])) ? in_array($mime, static::$mimes[$extension]) : $mime === static::$mimes[$extension]; + return (is_array($mimes[$extension])) ? in_array($mime, $mimes[$extension]) : $mime === $mimes[$extension]; } /** diff --git a/system/validation/message.php b/system/validation/message.php new file mode 100644 index 00000000..669656ae --- /dev/null +++ b/system/validation/message.php @@ -0,0 +1,144 @@ +error)) + { + $class = explode('\\', get_class($rule)); + + $rule->error = Str::lower(end($class)); + } + + return (is_null($rule->message)) ? Lang::line('validation.'.$rule->error)->get() : $rule->message; + } + + /** + * Get the error message for a Rangable rule. + * + * @param Rule $rule + * @return string + */ + private static function get_rangable_message($rule) + { + // --------------------------------------------------------- + // Rangable rules sometimes set a "presence_of" error. + // + // This occurs when an attribute is null and the option to + // allow null values has not been set. + // --------------------------------------------------------- + if ($rule->error == 'presence_of') + { + return static::get_message($rule); + } + + // --------------------------------------------------------- + // Slice "number_" or "string_" off of the error type. + // --------------------------------------------------------- + $error_type = substr($rule->error, 7); + + return (is_null($rule->$error_type)) ? Lang::line('validation.'.$rule->error)->get() : $rule->$error_type; + } + + /** + * Get the error message for an Upload_Of rule. + * + * @param Rule $rule + * @return string + */ + private static function get_upload_of_message($rule) + { + // --------------------------------------------------------- + // Slice "file_" off of the error type. + // --------------------------------------------------------- + $error_type = substr($rule->error, 5); + + return (is_null($rule->$error_type)) ? Lang::line('validation.'.$rule->error)->get() : $rule->$error_type; + } + + /** + * Prepare an error message for display. All place-holders will be replaced + * with their actual values. + * + * @param Rule $rule + * @param string $attribute + * @param string $message + * @return string + */ + private static function prepare($rule, $attribute, $message) + { + // --------------------------------------------------------- + // The rangable rule messages have three place-holders that + // must be replaced. + // + // :max = The maximum size of the attribute. + // :min = The minimum size of the attribute. + // :size = The exact size the attribute must be. + // --------------------------------------------------------- + if ($rule instanceof Rangable_Rule) + { + $message = str_replace(':max', $rule->maximum, $message); + $message = str_replace(':min', $rule->minimum, $message); + $message = str_replace(':size', $rule->size, $message); + } + // --------------------------------------------------------- + // The Upload_Of rule message have two place-holders taht + // must be replaced. + // + // :max = The maximum file size of the upload (kilobytes). + // :types = The allowed file types for the upload. + // --------------------------------------------------------- + elseif ($rule instanceof Rules\Upload_Of) + { + $message = str_replace(':max', $rule->maximum, $message); + + if (is_array($rule->types)) + { + $message = str_replace(':types', implode(', ', $rule->types), $message); + } + } + + return str_replace(':attribute', Lang::line('attributes.'.$attribute)->get(str_replace('_', ' ', $attribute)), $message); + } + +} \ No newline at end of file diff --git a/system/validation/nullable_rule.php b/system/validation/nullable_rule.php new file mode 100644 index 00000000..40f43f6e --- /dev/null +++ b/system/validation/nullable_rule.php @@ -0,0 +1,94 @@ +allow_null) + { + $this->error = 'presence_of'; + } + + return is_null($this->error); + } + + // ------------------------------------------------------------- + // Make sure the attribute is not an empty string. An error + // will be raised if the attribute is empty and empty strings + // are not allowed, halting the child's validation. + // ------------------------------------------------------------- + elseif (Str::length((string) $attributes[$attribute]) == 0 and ! $this->allow_empty) + { + $this->error = 'presence_of'; + + return false; + } + } + + /** + * Allow a empty and null to be considered valid. + * + * @return Nullable_Rule + */ + public function not_required() + { + return $this->allow_empty()->allow_null(); + } + + /** + * Allow empty to be considered valid. + * + * @return Nullable_Rule + */ + public function allow_empty() + { + $this->allow_empty = true; + return $this; + } + + /** + * Allow null to be considered valid. + * + * @return Nullable_Rule + */ + public function allow_null() + { + $this->allow_null = true; + return $this; + } + +} \ No newline at end of file diff --git a/system/validation/rangable_rule.php b/system/validation/rangable_rule.php new file mode 100644 index 00000000..1845ca29 --- /dev/null +++ b/system/validation/rangable_rule.php @@ -0,0 +1,145 @@ +size = $size; + return $this; + } + + /** + * Set the minimum and maximum size of the attribute. + * + * @param int $minimum + * @param int $maximum + * @return Rangable_Rule + */ + public function between($minimum, $maximum) + { + $this->minimum = $minimum; + $this->maximum = $maximum; + + return $this; + } + + /** + * Set the minimum size the attribute. + * + * @param int $minimum + * @return Rangable_Rule + */ + public function minimum($minimum) + { + $this->minimum = $minimum; + return $this; + } + + /** + * Set the maximum size the attribute. + * + * @param int $maximum + * @return Rangable_Rule + */ + public function maximum($maximum) + { + $this->maximum = $maximum; + return $this; + } + + /** + * Set the validation error message. + * + * @param string $message + * @return Rangable_Rule + */ + public function message($message) + { + return $this->wrong_size($message)->too_big($message)->too_small($message); + } + + /** + * Set the "wrong size" error message. + * + * @param string $message + * @return Rangable_Rule + */ + public function wrong_size($message) + { + $this->wrong_size = $message; + return $this; + } + + /** + * Set the "too big" error message. + * + * @param string $message + * @return Rangable_Rule + */ + public function too_big($message) + { + $this->too_big = $message; + return $this; + } + + /** + * Set the "too small" error message. + * + * @param string $message + * @return Rangable_Rule + */ + public function too_small($message) + { + $this->too_small = $message; + return $this; + } + +} \ No newline at end of file diff --git a/system/validation/rule.php b/system/validation/rule.php index fd89b5c0..2087bdf7 100644 --- a/system/validation/rule.php +++ b/system/validation/rule.php @@ -24,7 +24,7 @@ abstract class Rule { * * @var string */ - protected $error; + public $error; /** * Create a new validation Rule instance. @@ -48,50 +48,27 @@ public function validate($attributes, &$errors) { foreach ($this->attributes as $attribute) { + $this->error = null; + if ( ! $this->check($attribute, $attributes)) { - $errors[$attribute][] = $this->prepare_message($attribute); + $message = Message::get($this, $attribute); + + // ------------------------------------------------------------- + // Make sure the error message is not duplicated. + // + // For example, the Nullable rules can add a "required" message. + // If the same message has already been added we don't want to + // add it again. + // ------------------------------------------------------------- + if ( ! array_key_exists($attribute, $errors) or ! is_array($errors[$attribute]) or ! in_array($message, $errors[$attribute])) + { + $errors[$attribute][] = $message; + } } } } - /** - * Prepare the message to be added to the error collector. - * - * @param string $attribute - * @return string - */ - private function prepare_message($attribute) - { - if (is_null($this->message)) - { - throw new \Exception("An error message must be specified for every validation rule."); - } - - $message = $this->message; - - // --------------------------------------------------------- - // Replace any place-holders with their actual values. - // - // Attribute place-holders are loaded from the language - // directory. If the line doesn't exist, the attribute - // name will be used instead. - // --------------------------------------------------------- - if (strpos($message, ':attribute')) - { - $message = str_replace(':attribute', Lang::line('attributes.'.$attribute)->get($attribute), $message); - } - - if ($this instanceof Rules\Size_Of) - { - $message = str_replace(':max', $this->maximum, $message); - $message = str_replace(':min', $this->minimum, $message); - $message = str_replace(':size', $this->length, $message); - } - - return $message; - } - /** * Set the validation error message. * diff --git a/system/validation/rules/acceptance_of.php b/system/validation/rules/acceptance_of.php index 001c9a30..02b505a9 100644 --- a/system/validation/rules/acceptance_of.php +++ b/system/validation/rules/acceptance_of.php @@ -17,7 +17,7 @@ class Acceptance_Of extends Rule { * * @param string $attribute * @param array $attributes - * @return void + * @return bool */ public function check($attribute, $attributes) { @@ -27,7 +27,7 @@ public function check($attribute, $attributes) /** * Set the accepted value. * - * @param string $value + * @param string $value * @return Acceptance_Of */ public function accepts($value) diff --git a/system/validation/rules/confirmation_of.php b/system/validation/rules/confirmation_of.php index 02185cca..a6d7de0e 100644 --- a/system/validation/rules/confirmation_of.php +++ b/system/validation/rules/confirmation_of.php @@ -10,7 +10,7 @@ class Confirmation_Of extends Rule { * * @param string $attribute * @param array $attributes - * @return void + * @return bool */ public function check($attribute, $attributes) { diff --git a/system/validation/rules/exclusion_of.php b/system/validation/rules/exclusion_of.php index df0f6318..46b5a6eb 100644 --- a/system/validation/rules/exclusion_of.php +++ b/system/validation/rules/exclusion_of.php @@ -1,8 +1,8 @@ reserved); @@ -31,7 +31,7 @@ public function check($attribute, $attributes) /** * Set the reserved values for the attribute * - * @param array $reserved + * @param array $reserved * @return Exclusion_Of */ public function from($reserved) diff --git a/system/validation/rules/format_of.php b/system/validation/rules/format_of.php index 4b969dc0..dfcebb16 100644 --- a/system/validation/rules/format_of.php +++ b/system/validation/rules/format_of.php @@ -1,8 +1,8 @@ expression, $attributes[$attribute]); @@ -31,7 +31,7 @@ public function check($attribute, $attributes) /** * Set the regular expression. * - * @param string $expression + * @param string $expression * @return Format_Of */ public function using($expression) diff --git a/system/validation/rules/inclusion_of.php b/system/validation/rules/inclusion_of.php index db1e0afb..f92ace6f 100644 --- a/system/validation/rules/inclusion_of.php +++ b/system/validation/rules/inclusion_of.php @@ -1,8 +1,8 @@ accepted); @@ -31,7 +31,7 @@ public function check($attribute, $attributes) /** * Set the accepted values for the attribute. * - * @param array $accepted + * @param array $accepted * @return Inclusion_Of */ public function in($accepted) diff --git a/system/validation/rules/length_of.php b/system/validation/rules/length_of.php new file mode 100644 index 00000000..f53ff5aa --- /dev/null +++ b/system/validation/rules/length_of.php @@ -0,0 +1,49 @@ +size) and Str::length($value) !== $this->size) + { + $this->error = 'string_wrong_size'; + } + // --------------------------------------------------------- + // Validate the maximum length of the attribute. + // --------------------------------------------------------- + elseif ( ! is_null($this->maximum) and Str::length($value) > $this->maximum) + { + $this->error = 'string_too_big'; + } + // --------------------------------------------------------- + // Validate the minimum length of the attribute. + // --------------------------------------------------------- + elseif ( ! is_null($this->minimum) and Str::length($value) < $this->minimum) + { + $this->error = 'string_too_small'; + } + + return is_null($this->error); + } + +} \ No newline at end of file diff --git a/system/validation/rules/numericality_of.php b/system/validation/rules/numericality_of.php new file mode 100644 index 00000000..43813ba7 --- /dev/null +++ b/system/validation/rules/numericality_of.php @@ -0,0 +1,116 @@ +error = 'number_not_valid'; + } + // --------------------------------------------------------- + // Validate the attribute is an integer. + // --------------------------------------------------------- + elseif ($this->only_integer and filter_var($attributes[$attribute], FILTER_VALIDATE_INT) === false) + { + $this->error = 'number_not_integer'; + } + // --------------------------------------------------------- + // Validate the exact size of the attribute. + // --------------------------------------------------------- + elseif ( ! is_null($this->size) and $attributes[$attribute] != $this->size) + { + $this->error = 'number_wrong_size'; + } + // --------------------------------------------------------- + // Validate the maximum size of the attribute. + // --------------------------------------------------------- + elseif ( ! is_null($this->maximum) and $attributes[$attribute] > $this->maximum) + { + $this->error = 'number_too_big'; + } + // --------------------------------------------------------- + // Validate the minimum size of the attribute. + // --------------------------------------------------------- + elseif ( ! is_null($this->minimum) and $attributes[$attribute] < $this->minimum) + { + $this->error = 'number_too_small'; + } + + return is_null($this->error); + } + + /** + * Specify that the attribute must be an integer. + * + * @return Numericality_Of + */ + public function only_integer() + { + $this->only_integer = true; + return $this; + } + + /** + * Set the "not valid" error message. + * + * @param string $message + * @return Numericality_Of + */ + public function not_valid($message) + { + $this->not_valid = $message; + return $this; + } + + /** + * Set the "not integer" error message. + * + * @param string $message + * @return Numericality_Of + */ + public function not_integer($message) + { + $this->not_integer = $message; + return $this; + } + +} \ No newline at end of file diff --git a/system/validation/rules/presence_of.php b/system/validation/rules/presence_of.php index 093b30c0..8926e967 100644 --- a/system/validation/rules/presence_of.php +++ b/system/validation/rules/presence_of.php @@ -1,70 +1,29 @@ allow_null) - { - return false; - } - - if (trim((string) $attributes[$attribute]) === '' and ! $this->allow_empty) - { - return false; + return $nullable; } + // --------------------------------------------------------- + // The Nullable_Rule check method essentially is a check for + // the presence of an attribute, so there is no further + // checking that needs to be done. + // --------------------------------------------------------- return true; } - /** - * Allow an empty string to be considered present. - * - * @return Presence_Of - */ - public function allow_empty() - { - $this->allow_empty = true; - return $this; - } - - /** - * Allow a null to be considered present. - * - * @return Presence_Of - */ - public function allow_null() - { - $this->allow_null = true; - return $this; - } - } \ No newline at end of file diff --git a/system/validation/rules/size_of.php b/system/validation/rules/size_of.php deleted file mode 100644 index e5f02b55..00000000 --- a/system/validation/rules/size_of.php +++ /dev/null @@ -1,166 +0,0 @@ -check_number($attribute, $attributes); - } - else - { - return $this->check_string($attribute, $attributes); - } - } - - /** - * Evaluate the validity of a numeric attribute. - * - * @param string $attribute - * @param array $attributes - * @return void - */ - private function check_number($attribute, $attributes) - { - if ( ! is_null($this->length) and $attributes[$attribute] !== $this->length) - { - $this->error = 'number_wrong_size'; - return false; - } - - if ( ! is_null($this->maximum) and $attributes[$attribute] > $this->maximum) - { - $this->error = 'number_too_big'; - return false; - } - - if ( ! is_null($this->minimum and $attributes[$attribute] < $this->minimum)) - { - $this->error = 'number_too_small'; - return false; - } - - return true; - } - - /** - * Evaluate the validity of a string attribute. - * - * @param string $attribute - * @param array $attributes - * @return void - */ - public function check_string($attribute, $attributes) - { - $value = trim((string) $attributes[$attribute]); - - if ( ! is_null($this->length) and Str::length($value) !== $this->length) - { - $this->error = 'string_wrong_size'; - return false; - } - - if ( ! is_null($this->maximum) and Str::length($value) > $this->maximum) - { - $this->error = 'string_too_big'; - return false; - } - - if ( ! is_null($this->minimum) and Str::length($value) < $this->minimum) - { - $this->error = 'string_too_small'; - return false; - } - - return true; - } - - /** - * Set the exact size the attribute must be. - * - * @param int $length - * @return Size_Of - */ - public function is($length) - { - $this->length = $length; - return $this; - } - - /** - * Set the minimum and maximum size of the attribute. - * - * @param int $minimum - * @param int $maximum - * @return Size_Of - */ - public function between($minimum, $maximum) - { - $this->minimum = $minimum; - $this->maximum = $maximum; - - return $this; - } - - /** - * Set the minimum size the attribute. - * - * @param int $minimum - * @return Size_Of - */ - public function at_least($minimum) - { - $this->minimum = $minimum; - return $this; - } - - /** - * Set the maximum size the attribute. - * - * @param int $maximum - * @return Size_Of - */ - public function less_than($maximum) - { - $this->maximum = $maximum; - return $this; - } - -} \ No newline at end of file diff --git a/system/validation/rules/uniqueness_of.php b/system/validation/rules/uniqueness_of.php index a693d556..94f39d67 100644 --- a/system/validation/rules/uniqueness_of.php +++ b/system/validation/rules/uniqueness_of.php @@ -1,9 +1,9 @@ column)) @@ -44,8 +44,11 @@ public function check($attribute, $attributes) /** * Set the database table and column. * - * @param string $table - * @param string $column + * The attribute name will be used as the column name if no other + * column name is specified. + * + * @param string $table + * @param string $column * @return Uniqueness_Of */ public function on($table, $column = null) diff --git a/system/validation/rules/upload_of.php b/system/validation/rules/upload_of.php index 473b9b49..77d71bbb 100644 --- a/system/validation/rules/upload_of.php +++ b/system/validation/rules/upload_of.php @@ -2,9 +2,9 @@ use System\File; use System\Input; -use System\Validation\Rule; +use System\Validation\Nullable_Rule; -class Upload_Of extends Rule { +class Upload_Of extends Nullable_Rule { /** * The acceptable file types. @@ -20,38 +20,72 @@ class Upload_Of extends Rule { */ public $maximum; + /** + * The "wrong type" error message. + * + * @var string + */ + public $wrong_type; + + /** + * The "too big" error message. + * + * @var string + */ + public $too_big; + /** * Evaluate the validity of an attribute. * * @param string $attribute * @param array $attributes - * @return void + * @return bool */ public function check($attribute, $attributes) { + // ----------------------------------------------------- + // Check the presence of the upload. If the upload does + // not exist and the upload is required, a presence_of + // error will be raised. + // + // Otherwise no error will be raised. + // ----------------------------------------------------- if ( ! array_key_exists($attribute, Input::file())) { - return true; + if ( ! $this->allow_null) + { + $this->error = 'presence_of'; + } + + return is_null($this->error); } + // ----------------------------------------------------- + // Uploaded files are stored in the $_FILES array, so + // we use that array instead of the $attributes. + // ----------------------------------------------------- $file = Input::file($attribute); - if ( ! is_null($this->maximum) and $file['size'] > $this->maximum) + if ( ! is_null($this->maximum) and $file['size'] > $this->maximum * 1000) { $this->error = 'file_too_big'; - return false; } + // ----------------------------------------------------- + // The File::is method uses the Fileinfo PHP extension + // to determine the MIME type of the file. + // ----------------------------------------------------- foreach ($this->types as $type) { - if ( ! File::is($type, $file['tmp_name'])) + if (File::is($type, $file['tmp_name'])) { - $this->error = 'file_wrong_type'; - return false; + break; } + + $this->error = 'file_wrong_type'; } - return true; + return is_null($this->error); } /** @@ -66,15 +100,61 @@ public function is() } /** - * Set the maximum file size in bytes. + * Require that the uploaded file is an image type. * - * @param int $maximum * @return Upload_Of */ - public function less_than($maximum) + public function is_image() + { + $this->types = array_merge($this->types, array('jpg', 'gif', 'png', 'bmp')) + return $this; + } + + /** + * Set the maximum file size in kilobytes. + * + * @param int $maximum + * @return Upload_Of + */ + public function maximum($maximum) { $this->maximum = $maximum; return $this; } + /** + * Set the validation error message. + * + * @param string $message + * @return Upload_Of + */ + public function message($message) + { + return $this->wrong_type($message)->too_big($message); + } + + /** + * Set the "wrong type" error message. + * + * @param string $message + * @return Upload_Of + */ + public function wrong_type($message) + { + $this->wrong_type = $message; + return $this; + } + + /** + * Set the "too big" error message. + * + * @param string $message + * @return Upload_Of + */ + public function too_big($message) + { + $this->too_big = $message; + return $this; + } + } \ No newline at end of file diff --git a/system/validation/rules/with_callback.php b/system/validation/rules/with_callback.php index 8630b460..ed1d2ff3 100644 --- a/system/validation/rules/with_callback.php +++ b/system/validation/rules/with_callback.php @@ -1,8 +1,8 @@ callback)) { throw new \Exception("The validation callback for the [$attribute] attribute is not callable."); } + if ( ! is_null($nullable = parent::check($attribute, $attributes))) + { + return $nullable; + } + return call_user_func($this->callback, $attributes[$attribute]); } /** * Set the validation callback. * - * @param function $callback + * @param function $callback * @return With_Callback */ public function using($callback)