Turn URLs into Links Without Affecting Existing Links (and a gripe about collective stupidity)

This is one of those problems that has been solved, but, it's been solved in incomplete ways so many times that these not-too-useful answers outnumber the useful answers, totally messing up web searches. This consequently seeds the idea that this is an intractable problem! Even at stackoverflow, they say it's really tough.

In fact, this problem is not that tough. The code below will work in most situations. The technique is to guard the existing links by encoding them as base64. Then, find the bare URLs and turn them into links. Then, unguard the existing links by decoding them.

<?php
function add_url_links($data)
{
        $data = preg_replace_callback('/(<a href=.+?<\/a>)/','guard_url',$data);

        $data = preg_replace_callback('/(http:\/\/.+?)([ \\n\\r])/','link_url',$data);
        $data = preg_replace_callback('/^(http:\/\/.+?)/','link_url',$data);
        $data = preg_replace_callback('/(http:\/\/.+?)$/','link_url',$data);

        $data = preg_replace_callback('/{{([a-zA-Z0-9+=]+?)}}/','unguard_url',$data);

        return $data;
}

function guard_url($arr) { return '{{'.base64_encode($arr[1]).'}}'; }
function unguard_url($arr) { return base64_decode($arr[1]); }
function link_url($arr) { return guard_url(array('','<a href="'.$arr[1].'">'.$arr[1].'</a>')).$arr[2]; }
You may need to alter the regex in the second preg_replace_callback for your application. An odd thing is that link_url has to use guard_url to prevent the link from being mangled -- perhaps part of the preg_replace_callback is done in-place.