34

I have the following string:

"Look on http://www.google.com".

I need to convert it to:

"Look on http://www.google.com"

The original string can have more than 1 URL string.

How do I do this in php?

Thanks

Alex
  • 897
  • 1
  • 11
  • 21
  • You need to indent it 4 spaces so it doesn't process it. I did it for you. – Paolo Bergantino Feb 03 '09 at 15:06
  • possible duplicate of [How to convert a link in a textarea into a link-element using php?](http://stackoverflow.com/questions/6204590/how-to-convert-a-link-in-a-textarea-into-a-link-element-using-php) – kapa Sep 25 '14 at 11:26

11 Answers11

63

You can use the following:

$string = "Look on http://www.google.com";
$string = preg_replace(
              "~[[:alpha:]]+://[^<>[:space:]]+[[:alnum:]/]~",
              "<a href=\"\\0\">\\0</a>", 
              $string);

PHP versions < 5.3 (ereg_replace) otherwise (preg_replace)

Krasimir
  • 1,806
  • 2
  • 18
  • 31
Ben
  • 66,838
  • 37
  • 84
  • 108
  • Thanks Ben I've found this too, but haven't got a chance to test it yet. – Alex Feb 03 '09 at 15:10
  • No worries! I started to try to write my own regular expression to do it, but then realised it was trickier than I originally thought, so I was glad I found something online! :-) – Ben Feb 03 '09 at 17:00
  • 2
    It didn't work when just replacing ereg with pred ( Unknown modifier '+' ). Should I change something else? – Nathan H Dec 02 '12 at 17:44
  • @Ben any news about what @nathanhazout said? about the `Unknown modifier '+'`. the error pops up if you change from `ereg_replace` to `preg_replace`. Thanks! – Jo E. Feb 01 '14 at 08:13
  • 1
    To fix the Unknown modifier '+' error - use this : `$new_string = preg_replace("~[[:alpha:]]+://[^<>[:space:]]+[[:alnum:]/]~","\\0", $string);` – Kiran Aghor Feb 17 '14 at 18:07
21

lib_autolink does a pretty good job, avoiding pitfalls like extra punctuation after the link and links inside HTML tags:

https://github.com/iamcal/lib_autolink

Jan Derk
  • 2,552
  • 27
  • 22
Cal
  • 7,067
  • 25
  • 28
  • 4
    I've never used it, and barely even looked at it, but this seems like a much better solution than trying to roll your own. +1 – rmeador Feb 03 '09 at 16:13
  • Is there a way to make `http://` (the protocol) stay? I think it looks weird when `http://` is removed automatically. – Nathan Jun 26 '12 at 00:40
  • 1
    @Nathan - yes, at the top of the lib autolink file is an autolink_options field in the globals array. Set the 'strip_protocols' value to false and the protocol prefixes will be displayed. – Andrey Butov Dec 26 '13 at 14:55
7

Have a look at regular expressions. You would then do something like:

$text = preg_replace('@(https?://([-\w\.]+)+(:\d+)?(/([\w/_\.]*(\?\S+)?)?)?)@', '<a href="$1">$1</a>', $text);
Bouke
  • 11,768
  • 7
  • 68
  • 102
  • 1
    You're missing a - in the path part it should be `@(https?://([-\w\.]+)+(:\d+)?(/([-\w/_\.]*(\?\S+)?)?)?)@` – ianbarker Sep 13 '13 at 09:49
3

Small update from nowadays. Just a regex won't be enough. Urls could contain unicode characters, brackets, punctuation etc.

There is a Url highlight library that cover lots of edge cases.

Example:

<?php

use VStelmakh\UrlHighlight\UrlHighlight;

$urlHighlight = new UrlHighlight();
$urlHighlight->highlightUrls('Look on http://www.google.com or even google.com.');
// return: 'Look on <a href="http://www.google.com">http://www.google.com</a> or even <a href="http://google.com">google.com</a>.'
vstelmakh
  • 742
  • 1
  • 11
  • 19
2

I found an example which allows for links that include ftp, https and others which seems to work fine for multiple URLs

how-to-detect-urls-in-text-and-convert-to-html-links-php-using-regular-expressions

<?php
// The Regular Expression filter
$pattern = "/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/";

//example text
$text="Example user text with a URL http://www.zero7web.com , second link http://www.didsburydesign.co.uk";

// convert URLs into Links
$text= preg_replace($pattern, "<a href=\"\\0\" rel=\"nofollow\">\\0</a>", $text);

echo $text;
?>

Proabably a good idea to add nofollow to the link too is it's a user submitted value.

Andrew
  • 9,967
  • 10
  • 64
  • 103
2

I found this code at http://code.seebz.net/p/autolink-php/ and tweaked it a bit to recognize www.* as links. I am not very conversant with regular expressions but I think the two str_replace lines can be modified to one regexp

<?php
$text = 'First link is: www.example.com. Second link is http://example.com. Third link is https://example.com. Fourth link is http://www.example.com. Fifth link is <a href="http://www.example.com">www.example.com</a>';

function autolink($str, $attributes=array()) {
$str = str_replace("http://www","www",$str);
$str = str_replace("https://www","www",$str);

$attrs = '';
foreach ($attributes as $attribute => $value) {
$attrs .= " {$attribute}=\"{$value}\"";
}
$str = ' ' . $str;
$str = preg_replace(
'`([^"=\'>])((http|https|ftp)://[^\s<]+[^\s<\.)])`i',
'$1<a href="$2"'.$attrs.'>$2</a>',
$str
);
$str = preg_replace(
'`([^"=\'>])((www).[^\s<]+[^\s<\.)])`i',
'$1<a href="http://$2"'.$attrs.'>$2</a>',
$str
);
$str = substr($str, 1);
return $str;
}

echo autolink($text);
?>
Sam Lee
  • 21
  • 2
2

Try this...

<?

   function link_it($text)  
   {  
        $text= preg_replace("/(^|[\n ])([\w]*?)([\w]*?:\/\/[\w]+[^ \,\"\n\r\t<]*)/is", "$1$2<a href=\"$3\" >$3</a>", $text);  
        $text= preg_replace("/(^|[\n ])([\w]*?)((www)\.[^ \,\"\t\n\r<]*)/is", "$1$2<a href=\"http://$3\" >$3</a>", $text);
                $text= preg_replace("/(^|[\n ])([\w]*?)((ftp)\.[^ \,\"\t\n\r<]*)/is", "$1$2<a href=\"ftp://$3\" >$3</a>", $text);  
        $text= preg_replace("/(^|[\n ])([a-z0-9&\-_\.]+?)@([\w\-]+\.([\w\-\.]+)+)/i", "$1<a href=\"mailto:$2@$3\">$2@$3</a>", $text);  
        return($text);  
    }


$text = "ini link gue: http://sapua.com <br>
https://sapua.com <br>
anything1://www.sss.com <br>

dua www.google.com <br>
tiga http://www.google.com <br>

ftp.sapua.com <br>

someone@sapua.com


";

print link_it($text);

?>
2

You will need to use regular expressions...

Something like this will help.

$result = preg_replace('/\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[A-Z0-9+&@#\/%=~_|]/i', '<a href="\0">\0</a>', $text);
Rik Heywood
  • 13,816
  • 9
  • 61
  • 81
1

Correctly linkifying a URL is non-trivial. (See: http://www.codinghorror.com/blog/2008/10/the-problem-with-urls.html for more on why this is so.) I spent quite a bit of time on this and have come up with a pretty good solution to the problem (for both PHP and/or Javascript). See: http://jmrware.com/articles/2010/linkifyurl/linkify.html

ridgerunner
  • 33,777
  • 5
  • 57
  • 69
1

Checkout my linkify function, which uses preg_replace_callback (PHP 5.3 only). It supports http, email and twitter:

http://www.jasny.net/articles/linkify-turning-urls-into-clickable-links-in-php/

/**
* Turn all URLs in clickable links.
*
* @param string $value
* @param array $protocols http/https, ftp, mail, twitter
* @param array $attributes
* @param string $mode normal or all
* @return string
*/
    function linkify($value, $protocols = array('http', 'mail'), array $attributes = array(), $mode = 'normal')
    {
        // Link attributes
        $attr = '';
        foreach ($attributes as $key => $val) {
            $attr = ' ' . $key . '="' . htmlentities($val) . '"';
        }

        $links = array();

        // Extract existing links and tags
        $value = preg_replace_callback('~(<a .*?>.*?</a>|<.*?>)~i', function ($match) use (&$links) { return '<' . array_push($links, $match[1]) . '>'; }, $value);

        // Extract text links for each protocol
        foreach ((array)$protocols as $protocol) {
            switch ($protocol) {
                case 'http':
                case 'https': $value = preg_replace_callback($mode != 'all' ? '~(?:(https?)://([^\s<]+)|(www\.[^\s<]+?\.[^\s<]+))(?<![\.,:])~i' : '~([^\s<]+\.[^\s<]+)(?<![\.,:])~i', function ($match) use ($protocol, &$links, $attr) { if ($match[1]) $protocol = $match[1]; $link = $match[2] ?: $match[3]; return '<' . array_push($links, '<a' . $attr . ' href="' . $protocol . '://' . $link . '">' . $link . '</a>') . '>'; }, $value); break;
                case 'mail': $value = preg_replace_callback('~([^\s<]+?@[^\s<]+?\.[^\s<]+)(?<![\.,:])~', function ($match) use (&$links, $attr) { return '<' . array_push($links, '<a' . $attr . ' href="mailto:' . $match[1] . '">' . $match[1] . '</a>') . '>'; }, $value); break;
                case 'twitter': $value = preg_replace_callback('~(?<!\w)[@#](\w++)~', function ($match) use (&$links, $attr) { return '<' . array_push($links, '<a' . $attr . ' href="https://twitter.com/' . ($match[0][0] == '@' ? '' : 'search/%23') . $match[1] . '">' . $match[0] . '</a>') . '>'; }, $value); break;
                default: $value = preg_replace_callback($mode != 'all' ? '~' . preg_quote($protocol, '~') . '://([^\s<]+?)(?<![\.,:])~i' : '~([^\s<]+)(?<![\.,:])~i', function ($match) use ($protocol, &$links, $attr) { return '<' . array_push($links, '<a' . $attr . ' href="' . $protocol . '://' . $match[1] . '">' . $match[1] . '</a>') . '>'; }, $value); break;
            }
        }

        // Insert all link
        return preg_replace_callback('/<(\d+)>/', function ($match) use (&$links) { return $links[$match[1] - 1]; }, $value);
    }
Arnold Daniels
  • 16,516
  • 4
  • 53
  • 82
  • Welcome to Stack Overflow! While this may theoretically answer the question, [it would be preferable](http://meta.stackexchange.com/q/8259) to include the essential parts of the answer here, and provide the link for reference. – Bill the Lizard Mar 08 '12 at 12:37
  • @BilltheLizard I don't understand your remark. This code does exactly the this what Alex is asking for. You just need to copy/paste. – Arnold Daniels Mar 26 '12 at 22:44
  • Seems to work here in my tests. Just one warning: if you're not using it in a class (OOP), remove `public` or else PHP will issue a fatal parse error. – Artem Russakovskii Jan 14 '15 at 08:16
0

Simple like that:

$text = "Atenção, isto é um link de teste";
$text = str_replace(
  [' ', ',', '&', '&', 'á', 'ã', 'à', 'é', 'ê', 'í', 'ç', 'õ', 'ô', 'ó', 'ú', "'", ")", "(", "]", "["],
  ['-', '', '', '', 'a', 'a', 'a', 'e', 'e', 'i', 'c', 'o', 'o', 'o', 'u', '', "", "", "", ""],
  $text
);

echo strtolower($text);

If you need more chars, add them in the str_replace.

vvvvv
  • 25,404
  • 19
  • 49
  • 81