Well these regexes here are all nice and so, however, they grow over time and in the end, things might look like a little bit different. It's not all my credit nor is it all ideal, this one is with code from a community project having a some years on it's back and I don't want to say it's ideal, however it suits some needs. Compiled it up into a single function:
echo make_clickable('test http://www.google.com/');
/**
* make_clickable
*
* make a text clickable
*
* @param string $text to make clickable
* @param callback $url callback to process URLs
* @return string clickable text
* @author hakre and contributors
* @license GPL
*/
function make_clickable($text, $url = null) {
if (null === $url)
$callback_url = function($url) {return $url;};
else
$callback_url = $url;
$ret = ' ' . $text;
// urls
$save = ini_set('pcre.recursion_limit', 10000);
$retval = preg_replace_callback('#(?<!=[\'"])(?<=[*\')+.,;:!&$\s>])(\()?([\w]+?://(?:[\w\\x80-\\xff\#%~/?@\[\]-]{1,2000}|[\'*(+.,;:!=&$](?![\b\)]|(\))?([\s]|$))|(?(1)\)(?![\s<.,;:]|$)|\)))+)#is', function($matches) use ($callback_url)
{
$url = $matches[2];
$suffix = '';
/** Include parentheses in the URL only if paired **/
while ( substr_count( $url, '(' ) < substr_count( $url, ')' ) ) {
$suffix = strrchr( $url, ')' ) . $suffix;
$url = substr( $url, 0, strrpos( $url, ')' ) );
}
$url = $callback_url($url);
if ( empty($url) )
return $matches[0];
return $matches[1] . "<a href=\"$url\">$url</a>" . $suffix;
}, $ret);
if (null !== $retval )
$ret = $retval;
ini_set('pcre.recursion_limit', $save);
// web ftp
$ret = preg_replace_callback('#([\s>])((www|ftp)\.[\w\\x80-\\xff\#$%&~/.\-;:=,?@\[\]+]+)#is', function ($matches) use ($callback_url)
{
$ret = '';
$dest = $matches[2];
$dest = 'http://' . $dest;
$dest = $callback_url($dest);
if ( empty($dest) )
return $matches[0];
// removed trailing [.,;:)] from URL
if ( in_array( substr($dest, -1), array('.', ',', ';', ':', ')') ) === true ) {
$ret = substr($dest, -1);
$dest = substr($dest, 0, strlen($dest)-1);
}
return $matches[1] . "<a href=\"$dest\">$dest</a>$ret";
}, $ret);
// email
$ret = preg_replace_callback('#([\s>])([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})#i', function($matches)
{
$email = $matches[2] . '@' . $matches[3];
return $matches[1] . "<a href=\"mailto:$email\">$email</a>";
}, $ret);
$ret = preg_replace("#(<a( [^>]+?>|>))<a [^>]+?>([^>]+?)</a></a>#i", "$1$3</a>", $ret);
$ret = trim($ret);
return $ret;
}