commit ef40f0e1874a86978f03348915e7ac932a6e3b0b Author: Vance Lucas Date: Sat Jan 26 21:30:55 2013 -0600 Working basic validations with tests diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..24f146c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.DS_Store +composer.phar +vendor diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..a59c5bf --- /dev/null +++ b/.travis.yml @@ -0,0 +1,13 @@ +# see http://about.travis-ci.org/docs/user/languages/php/ for more hints +language: php + +# list any PHP version you want to test against +php: + - 5.3 + - 5.4 + +before_script: + - composer install + +# Script to run tests +script: phpunit diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..70ee47e --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,32 @@ +The BSD 3-Clause License +http://opensource.org/licenses/BSD-3-Clause + +Copyright (c) 2013, Vance Lucas +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, +this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + * Neither the name of the Vance Lucas nor the names of its contributors +may be used to endorse or promote products derived from this software +without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..9b6f47c --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +## Valitron: Easy Validation That Doesn't Suck + +Valitron is a simple, minimal and elegant stand-alone validation library +with NO dependencies. Valitron uses simple, straightforward validation +methods with a focus on readable and concise syntax. Valitron is the +simple and pragmatic validation library you've been loking for. + +[![Build +Status](https://secure.travis-ci.org/vlucas/valitron.png)](http://travis-ci.org/vlucas/valitron) + + +Contributing +------------ + +1. Fork it +2. Create your feature branch (`git checkout -b my-new-feature`) +3. Make your changes +4. Run the tests, adding new ones for your own code if necessary (`phpunit`) +5. Commit your changes (`git commit -am 'Added some feature'`) +6. Push to the branch (`git push origin my-new-feature`) +7. Create new Pull Request + diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..eaa4c6e --- /dev/null +++ b/composer.json @@ -0,0 +1,24 @@ +{ + "name": "vlucas/valitron", + "version": "1.0.0", + "type": "library", + "description": "Simple, elegant, stand-alone validation library with NO dependencies", + "keywords": ["validation", "validator", "valid"], + "homepage": "http://github.com/vlucas/valitron", + "license" : "BSD", + "authors" : [ + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "http://www.vancelucas.com" + } + ], + "require": { + "php": ">=5.3.2" + }, + "autoload": { + "psr-0": { + "Valitron": "src/" + } + } +} diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..8e425f9 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,18 @@ + + + + + tests/Valitron + + + diff --git a/src/Valitron/Validator.php b/src/Valitron/Validator.php new file mode 100644 index 0000000..8460b22 --- /dev/null +++ b/src/Valitron/Validator.php @@ -0,0 +1,298 @@ + + * @link http://www.vancelucas.com/ + */ +class Validator +{ + protected $_fields = array(); + protected $_errors = array(); + protected $_validations = array(); + protected static $_rules = array(); + + + /** + * Setup validation + */ + public function __construct($data, $fields = array()) + { + // Allows filtering of used input fields against optional second array of field names allowed + // This is useful for limiting raw $_POST or $_GET data to only known fields + foreach($data as $field => $value) { + if(empty($fields) || (!empty($fields) && in_array($field, $fields))) { + $this->_fields[$field] = $value; + } + } + } + + + /** + * Register new validation rule callback + */ + public static function addRule($name, $callback) + { + if(!is_callable($callback)) { + throw new \InvalidArgumentException("Second argument must be a valid callback. Given argument was not callable."); + } + + static::$_rules[$name] = $callback; + } + + + /** + * Convenience method to add validation rules + */ + public function rule($rule, $fields, $message = null) + { + if(!isset(static::$_rules[$rule])) { + throw new \InvalidArgumentException("Rule '" . $rule . "' has not been registered with " . __CLASS__ . "::addRule()."); + } + + $this->_validations[] = array( + 'rule' => $rule, + 'fields' => (array) $fields, + 'message' => $message + ); + return $this; + } + + + /** + * Convenience method to add validation rules + */ + public function __call($rule, array $args) + { + if(!isset(static::$_rules[$rule])) { + throw new \InvalidArgumentException("Method '" . $rule . "' does not exist, or rule '" . $rule . "' has not been registered with " . __CLASS__ . "::addRule()."); + } + + array_unshift($args, $rule); + call_user_func_array(array($this, 'rule'), $args); + return $this; + } + + /** + * Required field validator + */ + public function validateRequired($field, $value, array $params = array()) + { + if(is_null($value)) { + return false; + } elseif(is_string($value) and trim($value) === '') { + return false; + } + return true; + } + + /** + * Validate that an attribute is a valid IP address + * + * @param string $field + * @param mixed $value + * @return bool + */ + public static function validateIp($field, $value) + { + return filter_var($value, FILTER_VALIDATE_IP) !== false; + } + + /** + * Validate that an attribute is a valid e-mail address + * + * @param string $field + * @param mixed $value + * @return bool + */ + public static function validateEmail($field, $value) + { + return filter_var($value, FILTER_VALIDATE_EMAIL) !== false; + } + + /** + * Validate that an attribute is a valid URL by syntax + * + * @param string $field + * @param mixed $value + * @return bool + */ + public static function validateUrl($field, $value) + { + return filter_var($value, FILTER_VALIDATE_URL) !== false; + } + + /** + * Validate that an attribute is an active URL by verifying DNS record + * + * @param string $field + * @param mixed $value + * @return bool + */ + public static function validateActiveUrl($field, $value) + { + $url = str_replace(array('http://', 'https://', 'ftp://'), '', strtolower($value)); + + return checkdnsrr($url); + } + + /** + * Validate that an attribute contains only alphabetic characters + * + * @param string $field + * @param mixed $value + * @return bool + */ + public static function validateAlpha($field, $value) + { + return preg_match('/^([a-z])+$/i', $value); + } + + /** + * Validate that an attribute contains only alpha-numeric characters. + * + * @param string $field + * @param mixed $value + * @return bool + */ + public static function validateAlphaNum($field, $value) + { + return preg_match('/^([a-z0-9])+$/i', $value); + } + + /** + * Validate that an attribute contains only alpha-numeric characters, dashes, and underscores. + * + * @param string $field + * @param mixed $value + * @return bool + */ + public static function validateAlphaDash($field, $value) + { + return preg_match('/^([-a-z0-9_-])+$/i', $value); + } + + /** + * Validate that an attribute passes a regular expression check. + * + * @param string $field + * @param mixed $value + * @return bool + */ + public static function validateRegex($field, $value, $params) + { + return preg_match($params[0], $value); + } + + /** + * Validate that an attribute is a valid date. + * + * @param string $field + * @param mixed $value + * @return bool + */ + public static function validateDate($field, $value) + { + return strtotime($value) !== false; + } + + /** + * Validate that an attribute matches a date format. + * + * @param string $field + * @param mixed $value + * @param array $params + * @return bool + */ + public static function validateDateFormat($field, $value, $params) + { + $parsed = date_parse_from_format($params[0], $value); + + return $parsed['error_count'] === 0; + } + + /** + * Validate the date is before a given date. + * + * @param string $field + * @param mixed $value + * @param array $params + * @return bool + */ + public static function validateBefore($field, $value, $params) + { + return strtotime($value) < strtotime($params[0]); + } + + /** + * Validate the date is after a given date. + * + * @param string $field + * @param mixed $value + * @param array $params + * @return bool + */ + public static function validateAfter($field, $value, $params) + { + return strtotime($value) > strtotime($params[0]); + } + + /** + * Get array of fields and data + */ + public function data($field = null) + { + return $this->_fields; + } + + /** + * Get array of error messages + */ + public function errors($field = null) + { + if($field !== null) { + return isset($this->_errors[$field]) ? $this->_errors[$field] : false; + } + return $this->_errors; + } + + /** + * Add an error to error messages array + */ + public function error($field, $msg) + { + // Add to error array + $this->_errors[$field][] = sprintf($msg, $field); + } + + /** + * Run validations and return boolean result + * + * @return boolean + */ + public function validate() + { + foreach($this->_validations as $v) { + foreach($v['fields'] as $field) { + $value = isset($this->_fields[$field]) ? $this->_fields[$field] : null; + $result = call_user_func(static::$_rules[$v['rule']], $field, $value); + if(!$result) { + $this->error($field, $v['message']); + } + } + } + return count($this->errors()) === 0; + } +} + +// Register default validations here so they can be overridden by user after include +$class = __NAMESPACE__ . '\Validator'; +$class::addRule('required', array($class, 'validateRequired')); +$class::addRule('email', array($class, 'validateEmail')); +$class::addRule('url', array($class, 'validateUrl')); + diff --git a/tests/Valitron/Validate.php b/tests/Valitron/Validate.php new file mode 100644 index 0000000..3c19e8a --- /dev/null +++ b/tests/Valitron/Validate.php @@ -0,0 +1,61 @@ + 'Chester Tester')); + $this->assertTrue($v->validate()); + } + + public function testOptionalFieldFilter() + { + $v = new Validator(array('foo' => 'bar', 'bar' => 'baz'), array('foo')); + $this->assertEquals($v->data(), array('foo' => 'bar')); + } + + public function testRequired() + { + $v = new Validator(array('name' => 'Chester Tester')); + $v->required('name'); + $this->assertTrue($v->validate()); + $this->assertSame(1, count($v->errors('name'))); + } + + public function testRequiredNonExistentField() + { + $v = new Validator(array('name' => 'Chester Tester')); + $v->required('nonexistent_field'); + $this->assertFalse($v->validate()); + } + + public function testEmailValid() + { + $v = new Validator(array('name' => 'Chester Tester', 'email' => 'chester@tester.com')); + $v->email('email'); + $this->assertTrue($v->validate()); + } + + public function testEmailInvalid() + { + $v = new Validator(array('name' => 'Chester Tester', 'email' => 'chestertesterman')); + $v->rule('email', 'email'); + $this->assertFalse($v->validate()); + } + + public function testUrlValid() + { + $v = new Validator(array('website' => 'http://google.com')); + $v->rule('url', 'website'); + $this->assertTrue($v->validate()); + } + + public function testUrlInvalid() + { + $v = new Validator(array('website' => 'shoobedobop')); + $v->rule('url', 'website'); + $this->assertFalse($v->validate()); + } +} + diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 0000000..d134f38 --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,18 @@ +