diff --git a/cake/libs/validation.php b/cake/libs/validation.php index dfb49cb6a..08a545bb3 100644 --- a/cake/libs/validation.php +++ b/cake/libs/validation.php @@ -825,7 +825,16 @@ class Validation extends Object { return $_this->_check(); } /** - * Checks that a value is a valid URL. + * Checks that a value is a valid URL according to http://www.w3.org/Addressing/URL/url-spec.txt + * + * The regex checks for the following component parts: + * a valid, optional, scheme + * a valid ip address OR + * a valid domain name as defined by section 2.3.1 of http://www.ietf.org/rfc/rfc1035.txt + * with an optional port number + * an optional valid path + * an optional query string (get parameters) + * an optional fragment (anchor tag) * * @param string $check Value to check * @return boolean Success @@ -834,9 +843,16 @@ class Validation extends Object { function url($check) { $_this =& Validation::getInstance(); $_this->check = $check; - $_this->regex = '/^(?:(?:https?|ftps?|file|news|gopher):\\/\\/)?(?:(?:(?:25[0-5]|2[0-4]\d|(?:(?:1\d)?|[1-9]?)\d)\.){3}(?:25[0-5]|2[0-4]\d|(?:(?:1\d)?|[1-9]?)\d)' - . '|(?:[0-9a-z]{1}[0-9a-z\\-]*\\.)*(?:[0-9a-z]{1}[0-9a-z\\-]{0,62})\\.(?:[a-z]{2,6}|[a-z]{2}\\.[a-z]{2,6})' - . '(?::[0-9]{1,4})?)(?:\\/?|\\/[\\w\\-\\.,\'@?^=%&:;\/~\\+\(\)#]*[\\w\\-\\@?^=%&\/~\\+\(\)#])$/i'; + $validChars = '([' . preg_quote('!"$&\'()*+,-.@_:;=') . '\/0-9a-z]|(%[0-9a-f]{2}))'; + $_this->regex = '/^(?:(?:https?|ftps?|file|news|gopher):\\/\\/)?' . + '(?:' . + '(?:(?:25[0-5]|2[0-4]\d|(?:(?:1\d)?|[1-9]?)\d)\.){3}(?:25[0-5]|2[0-4]\d|(?:(?:1\d)?|[1-9]?)\d)|' . + '(?:[0-9a-z]{1}[0-9a-z\\-]*\\.)*(?:[0-9a-z]{1}[0-9a-z\\-]{0,62})\\.(?:[a-z]{2,6}|[a-z]{2}\\.[a-z]{2,6})' . + '(?::[0-9]{1,4})?' . + ')' . + '(?:\/?|\/' . $validChars . '*)?' . + '(?:\?' . $validChars . '*)?' . + '(?:#' . $validChars . '*)?$/i'; return $_this->_check(); } /** diff --git a/cake/tests/cases/libs/validation.test.php b/cake/tests/cases/libs/validation.test.php index c0d954fff..b0e08ab75 100644 --- a/cake/tests/cases/libs/validation.test.php +++ b/cake/tests/cases/libs/validation.test.php @@ -1644,6 +1644,11 @@ class ValidationTestCase extends CakeTestCase { $this->assertTrue(Validation::url('http://123456789112345678921234567893123456789412345678951234567896123.com')); $this->assertFalse(Validation::url('http://this-domain-is-too-loooooong-by-icann-rules-maximum-length-is-63.com')); $this->assertTrue(Validation::url('http://www.domain.com/blogs/index.php?blog=6&tempskin=_rss2')); + $this->assertTrue(Validation::url('http://www.domain.com/blogs/parenth()eses.php')); + $this->assertTrue(Validation::url('http://www.domain.com/index.php?get=params&get2=params')); + $this->assertTrue(Validation::url('http://www.domain.com/ndex.php?get=params&get2=params#anchor')); + $this->assertFalse(Validation::url('http://www.domain.com/fakeenco%ode')); + $this->assertTrue(Validation::url('http://www.domain.com/real%20url%20encodeing')); $this->assertTrue(Validation::url('http://en.wikipedia.org/wiki/Architectural_pattern_(computer_science)')); $this->assertFalse(Validation::url('http://en.(wikipedia).org/')); } @@ -1773,28 +1778,28 @@ class ValidationTestCase extends CakeTestCase { $this->assertFalse(Validation::multiple(array())); $this->assertFalse(Validation::multiple(array(0))); $this->assertFalse(Validation::multiple(array('0'))); - + $this->assertTrue(Validation::multiple(array(0, 3, 4, 5), array('in' => range(0, 10)))); $this->assertFalse(Validation::multiple(array(0, 15, 20, 5), array('in' => range(0, 10)))); $this->assertFalse(Validation::multiple(array(0, 5, 10, 11), array('in' => range(0, 10)))); $this->assertFalse(Validation::multiple(array('boo', 'foo', 'bar'), array('in' => array('foo', 'bar', 'baz')))); - + $this->assertTrue(Validation::multiple(array(0, 5, 10, 11), array('max' => 3))); $this->assertFalse(Validation::multiple(array(0, 5, 10, 11, 55), array('max' => 3))); $this->assertTrue(Validation::multiple(array('foo', 'bar', 'baz'), array('max' => 3))); $this->assertFalse(Validation::multiple(array('foo', 'bar', 'baz', 'squirrel'), array('max' => 3))); - + $this->assertTrue(Validation::multiple(array(0, 5, 10, 11), array('min' => 3))); $this->assertTrue(Validation::multiple(array(0, 5, 10, 11, 55), array('min' => 3))); $this->assertFalse(Validation::multiple(array('foo', 'bar', 'baz'), array('min' => 5))); - $this->assertFalse(Validation::multiple(array('foo', 'bar', 'baz', 'squirrel'), array('min' => 10))); - + $this->assertFalse(Validation::multiple(array('foo', 'bar', 'baz', 'squirrel'), array('min' => 10))); + $this->assertTrue(Validation::multiple(array(0, 5, 9), array('in' => range(0, 10), 'max' => 5))); - $this->assertFalse(Validation::multiple(array(0, 5, 9, 8, 6, 2, 1), array('in' => range(0, 10), 'max' => 5))); + $this->assertFalse(Validation::multiple(array(0, 5, 9, 8, 6, 2, 1), array('in' => range(0, 10), 'max' => 5))); $this->assertFalse(Validation::multiple(array(0, 5, 9, 8, 11), array('in' => range(0, 10), 'max' => 5))); - + $this->assertFalse(Validation::multiple(array(0, 5, 9), array('in' => range(0, 10), 'max' => 5, 'min' => 3))); - $this->assertFalse(Validation::multiple(array(0, 5, 9, 8, 6, 2, 1), array('in' => range(0, 10), 'max' => 5, 'min' => 2))); + $this->assertFalse(Validation::multiple(array(0, 5, 9, 8, 6, 2, 1), array('in' => range(0, 10), 'max' => 5, 'min' => 2))); $this->assertFalse(Validation::multiple(array(0, 5, 9, 8, 11), array('in' => range(0, 10), 'max' => 5, 'min' => 2))); } /**