Teskon
Teskon

Reputation: 115

PHP preg_replace URL without http, https or www

I am not that good with regex and stuff. I know how to change http://google.com and www.google.com into links. However, I want my script to get links around the following strings:

Hello. Have you visited [link goes here]google.com[/link goes here] today?
Hello. Have you visited [link goes here]www.google.com[/link goes here] today?
Hello. Have you visited [link goes here]http://google.com[/link goes here] today?
Hello. Have you visited [link goes here]https://google.com[/link goes here] today?

Of course, I would really like the expression to allow as many characters as possible. But for the first link to work, I can only think of one explanation (I don't want people to start writing text.text and it will become a link):

<?php
$tlds = array("com", "net", "org", "info", "no", "dk", "se");
foreach($tlds as $tld){
$string = preg_replace("something", "something", $string);
}
?>

Do any of you know what to do? :P

I want it to be similar to Autolinker.js, only in PHP: https://github.com/gregjacobs/Autolinker.js

Upvotes: 1

Views: 3147

Answers (2)

Pedro Lobito
Pedro Lobito

Reputation: 98961

$template = <<< EOF
Hello. Have you visited google.com today?
Hello. Have you visited www.google.com today?
Hello. Have you visited http://google.com today?
Hello. Have you visited https://google.com today?
EOF;

$template = preg_replace_callback('/(?=(([\w\/\/:.]+)\.(?:com|net|org|info|no|dk|se)))\b(?:(?:https?|ftp|file):\/\/|(?:www\.|ftp\.)?)
      (?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[-A-Z0-9+&@#\/%=~_|$?!:,.])*
      (?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[A-Z0-9+&@#\/%=~_|$])/ix','my_callback',$template);

function my_callback($matches) {

 //check it the link has the protocol if not adds it.
if (preg_match('/https?/ix', $matches[1])) {
    $link = $matches[1];
    return "<a href=\"$link\">$link</a>";
} else {
    $link = $matches[1];
    return "<a href=\"http://$link\">http://$link</a>";
}
}

echo $template;

http://ideone.com/D1E5EK

Upvotes: 0

jonnu
jonnu

Reputation: 728

I just skimmed previous questions for a semi-decent regular expression to match domains and tweaked it a little - there are probably better out there if you keep looking.

<?php

$test = 'Hello. Have you visited google.com today?
Hello. Have you visited www.google.com today?
Hello. Have you visited http://google.com today?
Hello. Have you visited https://google.com today?';

$func = function ($match) {

    $text   = trim($match[0]);
    $pieces = parse_url($text);
    $scheme = array_key_exists('scheme', $pieces) ? $pieces['scheme'] : 'http';
    $host   = isset($pieces['host']) ? $pieces['host'] : $pieces['path'];
    $link   = sprintf('%s://%s', $scheme, $host);

    return sprintf('<a href="%s">%s</a>', $link, $text);
};

echo preg_replace_callback('/((http[s]?:\/\/)?(?>[a-z\-0-9]{2,}\.){1,}[a-z]{2,8})(?:\s|\/)/m', $func, $test);

Output for me is as follows:

Hello. Have you visited <a href="http://google.com">google.com</a>today?
Hello. Have you visited <a href="http://www.google.com">www.google.com</a>today?
Hello. Have you visited <a href="http://google.com">http://google.com</a>today?
Hello. Have you visited <a href="https://google.com">https://google.com</a>today?

I hope this was what you were after.

(I don't want people to start writing text.text and it will become a link)

Agreed, that would be annoying :-) - you should probably unit test this method, once you have settled on your solution. Use PHPUnit to write a test, and define an array of test data for it using a data provider - it'll give you confidence that your solution is sound.

Upvotes: 1

Related Questions