Commit 1c65f4fc authored by Nathan Haug's avatar Nathan Haug
Browse files

Cleaned up validation code and added support for mailto: format links. Issue #128225.

parent 2462ca67
......@@ -6,6 +6,11 @@
* Defines simple link field types.
*/
define('LINK_EXTERNAL', 'external');
define('LINK_INTERNAL', 'internal');
define('LINK_FRONT', 'front');
define('LINK_EMAIL', 'email');
/**
* Implementation of hook_help().
*/
......@@ -313,12 +318,15 @@ function link_field_formatter($field, $item, $formatter, $node) {
}
}
$type = link_validate_url($item['url']);
$url = link_cleanup_url($item['url']);
// Seperate out the anchor if any
if (strpos($url, '#') !== FALSE) {
$fragment = substr($url, strpos($url, '#') + 1);
$url = substr($url, 0, strpos($url, '#'));
}
// Seperate out the query string if any
if (strpos($url, '?') !== FALSE) {
$query = substr($url, strpos($url, '?') + 1);
$url = substr($url, 0, strpos($url, '?'));
......@@ -332,10 +340,11 @@ function link_field_formatter($field, $item, $formatter, $node) {
elseif (strlen(trim($item['title']))) {
$output = l($item['title'], $url, $attributes, $query, $fragment);
}
// Build the link with the URL as the title (max 80 characters)
// Build the link with the URL or email address as the title (max 80 characters)
else {
$display_url = url($url, $query, $fragment, TRUE);
$output = l(strlen($display_url) > 80 ? substr($display_url,0,80)."..." : $display_url, $url, $attributes, $query, $fragment);
$display_url = $type == LINK_EMAIL ? str_replace('mailto:', '', $url) : url($url, $query, $fragment, TRUE);
$display_url = strlen($display_url) > 80 ? substr($display_url, 0, 80) . "..." : $display_url;
$output = l($display_url, $url, $attributes, $query, $fragment);
}
return $output;
}
......@@ -350,12 +359,12 @@ function link_field_formatter($field, $item, $formatter, $node) {
function link_cleanup_url($url, $protocol = "http") {
$url = trim($url);
$type = link_validate_url($url);
if ($type == 1) {
if ($type == LINK_EXTERNAL) {
// Check if there is no protocol specified
$protocol_match = preg_match("/^([a-z0-9][a-z0-9\.\-_]*:\/\/)/i",$url);
if (empty($protocol_match)) {
// But should it be? Add an automatic http:// if it starts with a domain name
$domain_match = preg_match('/^(([a-z0-9]([a-z0-9\-_]*\.)+)(aero|arpa|biz|com|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel|[a-z]{2}))/i',$url);
// But should there be? Add an automatic http:// if it starts with a domain name
$domain_match = preg_match('/^(([a-z0-9]([a-z0-9\-_]*\.)+)(aero|arpa|biz|com|cat|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel|mobi|[a-z]{2}))/i',$url);
if (!empty($domain_match)) {
$url = $protocol."://".$url;
}
......@@ -373,43 +382,39 @@ function link_cleanup_url($url, $protocol = "http") {
* the following attributes: protocol, hostname, ip, and port.
*/
function link_validate_url($text) {
static $allowed_protocols;
if (!isset($allowed_protocols)) {
$allowed_protocols = implode("|",variable_get('filter_allowed_protocols', array('http', 'https', 'ftp', 'news', 'nntp', 'telnet', 'mailto', 'irc', 'ssh', 'sftp', 'webcal')));
}
$external_pattern =
// protocol
'/^((' . $allowed_protocols . '):\/\/)?'.
'('.
// domains
'(([a-z0-9]([a-z0-9\-_]*\.)+)(aero|arpa|biz|com|cat|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel|mobi|[a-z]{2}))'.
// OR ip addresses
'|(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'.
')'.
// port number
'(:([0-9]{1,4}))?';
$allowed_protocols = variable_get('filter_allowed_protocols', array('http', 'https', 'ftp', 'news', 'nntp', 'telnet', 'mailto', 'irc', 'ssh', 'sftp', 'webcal'));
$protocol = '((' . implode("|", $allowed_protocols) . '):\/\/)';
$domain = '(([a-z0-9]([a-z0-9\-_]*\.)+)(aero|arpa|biz|com|cat|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel|mobi|[a-z]{2}))';
$ipv4 = '([0-9]{1,3}(\.[0-9]{1,3}){3})';
$ipv6 = '([0-9a-fA-F]{1,4}(\:[0-9a-fA-F]{1,4}){7})';
$port = '(:([0-9]{1,4}))';
// Starting path
// Pattern specific to eternal links
$external_pattern = '/^' . $protocol . '?'. '(' . $domain . '|' . $ipv4 . '|' . $ipv6 . ')' . $port . '?';
// Pattern specific to internal links
$internal_pattern = "/^([a-z0-9_\-+]+)";
// the rest of the path
$end = "(\/[a-z0-9_\-\.~+%=&,$'():;*@]*)*".
// query string
"(\/?\?[a-z0-9+_\-\.\/%=&,$'():;*@]*)?".
// anchors
"(#[a-z0-9_\-\.~+%=&,$'():;*@]*)?".
// end of the expression, case insensitive
'$/i';
$directories = "(\/[a-z0-9_\-\.~+%=&,$'():;*@]*)*";
$query = "(\/?\?[a-z0-9+_\-\.\/%=&,$'():;*@]*)";
$anchor = "(#[a-z0-9_\-\.~+%=&,$'():;*@]*)";
// the rest of the path for a standard URL
$end = $directories . '?' . $query . '?' . $anchor . '?' . '$/i';
if (preg_match($external_pattern . $end, $text, $m)) {
return 1;
if (preg_match($external_pattern . $end, $text)) {
return LINK_EXTERNAL;
}
elseif (preg_match($internal_pattern . $end, $text)) {
return LINK_INTERNAL;
}
elseif (preg_match($internal_pattern . $end, $text, $m)) {
return 2;
elseif (in_array('mailto', $allowed_protocols) && ($address = preg_replace('/^mailto:/', '', $text)) && valid_email_address($address)) {
return LINK_EMAIL;
}
elseif (strpos($text, '<front>') === 0) {
return 3;
return LINK_FRONT;
}
return FALSE;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment