Index: includes/common.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/common.inc,v retrieving revision 1.840 diff -u -p -r1.840 common.inc --- includes/common.inc 26 Dec 2008 21:01:57 -0000 1.840 +++ includes/common.inc 29 Dec 2008 20:51:01 -0000 @@ -1173,7 +1173,7 @@ function valid_email_address($mail) { * * This function should only be used on actual URLs. It should not be used for * Drupal menu paths, which can contain arbitrary characters. - * + * Valid values per RFC 3986. * @param $url * The URL to verify. * @param $absolute @@ -1182,12 +1182,21 @@ function valid_email_address($mail) { * TRUE if the URL is in a valid format. */ function valid_url($url, $absolute = FALSE) { - $allowed_characters = '[a-z0-9\/:_\-_\.\?\$,;~=#&%\+]'; if ($absolute) { - return (bool)preg_match("/^(http|https|ftp):\/\/" . $allowed_characters . "+$/i", $url); + return (bool)preg_match(" + /^ # Start at the beginning of the text + (?:ftp|https?):\/\/ # Look for ftp, http, or https + (?: # Userinfo (optional) + (?:[\w\.\-\+%!$&'\(\)*\+,;=]+:)* + [\w\.\-\+%!$&'\(\)*\+,;=]+@ + )? + (?:[a-z0-9\-\.%]+) # The domain + (?::[0-9]+)? # Server port number (optional) + (?:[\/|\?][\w#!:\.\?\+=&%@!$'~*,;\/\(\)\[\]\-]*)? # The path (optional) + $/xi", $url); } else { - return (bool)preg_match("/^" . $allowed_characters . "+$/i", $url); + return (bool)preg_match("/^[\w#!:\.\?\+=&%@!$'~*,;\/\(\)\[\]\-]+$/i", $url); } } Index: modules/profile/profile.test =================================================================== RCS file: /cvs/drupal/drupal/modules/profile/profile.test,v retrieving revision 1.10 diff -u -p -r1.10 profile.test --- modules/profile/profile.test 16 Dec 2008 23:57:33 -0000 1.10 +++ modules/profile/profile.test 29 Dec 2008 20:51:02 -0000 @@ -134,7 +134,8 @@ class ProfileTestFields extends ProfileT 'textarea' => $this->randomName(), 'list' => $this->randomName(), 'checkbox' => 1, - 'url' => 'http://www.' . $this->randomName(10). '.org', + // _ is an invalid character for domain names. + 'url' => 'http://www.' . str_replace('_', '', $this->randomName(10)). '.org', ); // For each field type, create a field, give it a value and delete the field. Index: modules/simpletest/tests/common.test =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/tests/common.test,v retrieving revision 1.19 diff -u -p -r1.19 common.test --- modules/simpletest/tests/common.test 26 Dec 2008 21:01:57 -0000 1.19 +++ modules/simpletest/tests/common.test 29 Dec 2008 20:51:02 -0000 @@ -523,6 +523,82 @@ class DrupalErrorHandlerUnitTest extends } /** + * Test for valid_url(). + */ +class ValidUrlTestCase extends DrupalWebTestCase { + /** + * Implementation of getInfo(). + */ + function getInfo() { + return array( + 'name' => t('Valid Url'), + 'description' => t("Performs tests on Drupal's valid url function."), + 'group' => t('System') + ); + } + + function testValidUrl() { + $url_schemes = array('http', 'https', 'ftp'); + $valid_absolute_urls = array( + 'example.com', + 'www.example.com', + 'ex-ample.com', + '3xampl3.com', + 'example.com/paren(the)sis', + 'example.com/index.html#pagetop', + 'example.com:8080', + 'subdomain.example.com', + 'example.com/index.php?q=node', + 'example.com/index.php?q=node¶m=false', + 'user@www.example.com', + 'user:pass@www.example.com:8080/login.php?do=login&style=%23#pagetop', + '127.0.0.1', + 'example.org?', + 'john%20doe:secret:foo@example.org/', + 'example.org/~,$\'*;', + 'caf%C3%A9.example.org', + ); + + foreach ($url_schemes as $scheme) { + foreach ($valid_absolute_urls as $url) { + $test_url = $scheme . '://' . $url; + $valid_url = valid_url($test_url, TRUE); + $this->assertTrue($valid_url, $test_url .t(' is a valid url.')); + } + } + + $invalid_ablosule_urls = array( + '', + 'ex!ample.com', + ); + + foreach ($url_schemes as $scheme) { + foreach ($invalid_ablosule_urls as $url) { + $test_url = $scheme . '://' . $url; + $valid_url = valid_url($test_url, TRUE); + $this->assertFalse($valid_url, $test_url .t(' is NOT a valid url.')); + } + } + + $valid_relative_urls = array( + 'paren(the)sis', + 'index.html#pagetop', + 'index.php?q=node', + 'index.php?q=node¶m=false', + 'login.php?do=login&style=%23#pagetop', + ); + + foreach (array('', '/') as $front) { + foreach ($valid_relative_urls as $url) { + $test_url = $front . $url; + $valid_url = valid_url($test_url); + $this->assertTrue($valid_url, $test_url .t(' is a valid url.')); + } + } + } +} + +/** * Tests Simpletest error and exception collecter. */ class DrupalErrorCollectionUnitTest extends DrupalWebTestCase {