Link to home
Start Free TrialLog in
Avatar of macgruder
macgruder

asked on

Generate an absolute link from a URL plus a link

Given a URL like

http://foo.com/bar
or
http://foo.com/bar.html
or
http://foo.com/bar/

plus a link like

index.html
or
././
or
./

etc.

I want to generate the absolute

get_absolute('http://foo.com/bar/', '../pics/my.gif')

would return

http://foo.com/pics/my.gif

etc.

Needs to be robust for slash issues.

ASKER CERTIFIED SOLUTION
Avatar of pallosp
pallosp

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
It sounds like you want something like realpath()
http://us2.php.net/realpath

something like (assuming your variable is in $var)

<?php
//change these to match your server
$base_path = '/absolute/path/to/www/dir';
$base_url = 'http://www.yoursite.com';

$var_real = str_replace($base_url, $base_path, $var);
$var_real = realpath($var_real);
$var_real = str_replace($base_path, $base_url, $var_real);

echo $var_real;
?>

This is untested, but should be the right idea.
It probably also makes sense to check if someone has put in so man ../../.. that it makes it traverse back below your web directory, and to make sure realpath is not false...putting that all together in a function,

function get_real_path($var){
  //change these to match your server  
  $base_path = '/absolute/path/to/www/dir';
  $base_url = 'http://www.yoursite.com';

  $var_real = str_replace($base_url, $base_path, $var);
  $var_real = realpath($var_real);

  if ($var_real === false || strpos($var_real, $base_path) !== 0) return false;

  return  str_replace($base_path, $base_url, $var_real);
}
<?php
function get_absolute($baseUrl, $relativeLink)
{
    // Getting base scheme, host and path. If base url is not correct
    // return false
    if (!($base = @parse_url(trim($baseUrl)))) return false;
   
    // Checking relativeLink
    if (1 === preg_match("/\/[^.]+\/\.+/", $relativeLink)) return false;
   
    // Parsing relativeLink
    $rel    = explode("/", trim($relativeLink));
   
    // Now we have to know how deep is relative
    $level_up   = 0;
    $level_root = false;
    foreach ($rel as $k => $v)
    {
        if ("" == $v)
        {
            unset($rel[$k]);
        }
        if ("." == $v)
        {
            $level_root = true;
            unset($rel[$k]);
        }
        if (".." == $v)
        {
            $level_up++;
            unset($rel[$k]);
        }
    }
   
    $path = "";
    if ($level_root)
    {
        $path = "/" . implode("/", $rel);
    }
    else
    {
        $base['path'] = preg_replace("/^\/+/", "", $base['path']);
        $base['path'] = preg_replace("/\/+$/", "", $base['path']);
        $base['path'] = explode("/", $base['path']);
        if ($level_up >= count($base['path']))
        {
            $path = "/" . implode("/", $rel);
        }
        else
        {
            while($level_up != 0)
            {
                $i = count($base['path']) - 1;
                unset($base['path'][$i]);
                $level_up--;
            }
            $path = "/" . implode("/", $base['path']) . "/" . implode("/", $rel);
        }
    }
   
    return $base['scheme'] . "://" . $base['host'] . $path;
}

echo get_absolute('http://foo.com/bar/', '../pics/my.gif');
?>
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of macgruder
macgruder

ASKER

Thanks guys. I'm splitting the points. The first led to me generating a solution(before ixti posted) and the second is also a useful solution which I'm going to look at more carefully.