This article has moved to:
http://bsd-noobz.com/blog/php-script-for-converting-relative-to-absolute-url

PHP Script for Converting Relative to Absolute URL

Jun 5, 2009 | Tags: PHP, Regex | del.icio.us del.icio.us | digg Digg

This is a very simple PHP script to convert relative URL to its absolute path, given a base URL. e.g: converting lena.jpg to http://www.example.com/a/b/lena.jpg.

When I searched Google for scripts to convert relative to absolute URL, I came accross a site that has done that, only in Perl. It is a very simple script compared to the others, so I tried to port the code into PHP.

Note what the Perl geek said about this:

"I wrote this mainly because someone asked how to do this in PHP. Turns out there is nothing in like the venerable URI module in all of PHP-dom (how pathetic is that for a language as web-centric as it?)" lol

Btw, here's the script:

Listing 1: rel2abs.php

  1. <?php
  2. function rel2abs($rel, $base)
  3. {
  4.     /* return if already absolute URL */
  5.     if (parse_url($rel, PHP_URL_SCHEME) != '') return $rel;
  6.    
  7.     /* queries and anchors */
  8.     if ($rel[0]=='#' || $rel[0]=='?') return $base.$rel;
  9.    
  10.     /* parse base URL and convert to local variables:
  11.        $scheme, $host, $path */
  12.     extract(parse_url($base));
  13.  
  14.     /* remove non-directory element from path */
  15.     $path = preg_replace('#/[^/]*$#', '', $path);
  16.  
  17.     /* destroy path if relative url points to root */
  18.     if ($rel[0] == '/') $path = '';
  19.    
  20.     /* dirty absolute URL */
  21.     $abs = "$host$path/$rel";
  22.  
  23.     /* replace '//' or '/./' or '/foo/../' with '/' */
  24.     $re = array('#(/\.?/)#', '#/(?!\.\.)[^/]+/\.\./#');
  25.     for($n=1; $n>0; $abs=preg_replace($re, '/', $abs, -1, $n)) {}
  26.    
  27.     /* absolute URL is ready! */
  28.     return $scheme.'://'.$abs;
  29. }

The results is shown in the table below, given base URL is http://www.example.com/a/b/c

Table 1. Conversion Results

Relative URL Absolute URL
lena.jpg http://www.example.com/a/b/lena.jpg
./lena.jpg http://www.example.com/a/b/lena.jpg
../lena.jpg http://www.example.com/a/lena.jpg
../../lena.jpg http://www.example.com/lena.jpg
/lena.jpg http://www.example.com/lena.jpg
../x/lena.jpg http://www.example.com/a/x/lena.jpg
../../x/y/lena.jpg http://www.example.com/x/y/lena.jpg
http://google.com http://google.com
../../x/y/lena.jpg http://www.example.com/x/y/lena.jpg
?w=90&h=60&f=lena.jpg http://www.example.com/a/b/c?w=90&h=60&f=lena.jpg
#lena http://www.example.com/a/b/c#lena

Related Articles

Recommended Book

14 Comments

dr.emi on Jun 27, 2009:

Hi! Nashruddin..
Remember me ?

Nice tutorial friend !

Salman on Jun 29, 2009:

Complicated but complete example. You might want to add additional details about how to calculate $base instead of hard-coding it. Something that goes along these lines:

$base = 'http://' . $_SERVER['HTTP_HOST'] . dirname($_SERVER['PHP_SELF']);

Nash on Jun 29, 2009:

I got your point. but the script is intended to determine the absolute URL of a _remote_ resource, not local resources in our server. It goes like this: say you are writing a bulk downloader to download the images in http://example.com/nature/photos.html. If the links are in relative URLs:

<a href="img/beach.jpg">The Beach</a>
<a href="img/lake.jpg">The Lake</a>
<a href="img/river.jpg">The River</a>


You can use the script above to obtain the absolute URLs:

http://example.com/nature/img/beach.jpg
http://example.com/nature/img/lake.jpg
http://example.com/nature/img/river.jpg

Alex Vincent on Nov 11, 2009:

Bug in the script: ../../../x/y/lena.jpg leads to http://www.example.com/../x/y/lena.jpg

Nash on Jan 29, 2010:

I won't call it a bug. If the directory depth is 2, why would you go up to level 3?

Ben on Jan 31, 2010:

I thing this is excellent! Thanks for saving me a headache. Now if I could just get back the last hour or so looking for this. *sigh* Such is the life of the coder. Thanks! Ben

chesser on Feb 8, 2010:

> I won't call it a bug. If the directory depth is 2, why would you go up to level 3?

I think it is a bug, look at the following link:
http://www.w3.org/2004/04/uri-rel-test.html - there are some tests for your function

Asri on May 5, 2010:

If I might suggest these instead of the last line of that function:

...
...
$result = $scheme.'://'.$abs;
return str_ireplace("../", "", $result);
}

S* on Aug 2, 2010:

Good work; it's the fourth script I tried and the first that works, and the shorter.
When I was starting to think that I would have lost less time doing it by myself I found it. Thanks.
S*

Paul on Feb 27, 2011:

Hi! I want to correct a little for Your code, because there are relative links as "/../../x/y/z/somefile.ext":

function rel_2_abs ($rel, $base)
{
  if (parse_url ($rel, PHP_URL_SCHEME) != "")
  {
    return $rel;
  }
  if (substr($rel, 0, strlen("/..")) == "/..")
  {
    $rel = substr($rel, 1);
  }
  elseif ($rel[0] == "#" || $rel[0] == "?")
  {
    return $base.$rel;
  }
  extract(parse_url($base));
  $path = preg_replace("#/[^/]*$#", "", $path);
  if ($rel[0] == "/")
  {
    $path = "";
  }
  $abs = "".$host.$path."/".$rel."";
  $re = array("#(/.?/)#", "#/(?!..)[^/]+/../#");
  for ($n = 1; $n &gt; 0; $abs = preg_replace($re, "/", $abs, -1, $n)) ;
  $result = $scheme."://".$abs;
  return str_ireplace("../", "", $result);
}
this code is working for me very well.

Jeff on Apr 8, 2011:

I noticed a slight problem with the script (which is excellent BTW). The first example should return http://www.example.com/a/b/c/lena.jpg not http://www.example.com/a/b/lena.jpg.

The function is dropping one level. This can be solved by post-fixing $base with a "/" or adding the line $base .= "/"; (at line 9 of the code).

If $base already post-fixed with a "/" then no harm is done.

Roger Olsson on Apr 8, 2011:

The script fails on relative addresses that end in '..' or '.' (most likely when the whole address is just one or two dots). The $re regexps could end in '(?:/|$)' instead of a slash to fix this.

Some more notes on using this function:
1) The base address can't contain the elements 'port', 'user' and 'pass' because they'll be ignored. See the parse_url function in PHP documentation.
2) The base address must end in a slash, otherwise the last directory will be erased.

- You might want to check whether rel begins with a slash, and if it doesn't, THEN remove the non-path element from path.
- Host doesn't need to be in $abs yet when you remove the dots - you can and it in the last return statement.
- You can end the for statement in ';' instead of ' {}'.

Hope this helps.

Affinity on Apr 29, 2011:

Thanks alot - your answer solved all my problems after several days struggling

Nash on Jul 25, 2011:

@all: Thanks for your feedbacks.

I've rewrite the script to fix the bugs. The new version is available at http://bsd-noobz.com/blog/php-script-for-converting-relative-to-absolute-url

Comment is closed.