Search code examples
phpurlrelative-pathresolve

Resolve a relative path in a URL with PHP


Example 1: domain.com/dir_1/dir_2/dir_3/./../../../
Should resolve naturally in the browser into = domain.com/

Example 2: domain.com/dir_1/dir_2/dir_3/./../../../test/././../new_dir/
Should resolve into domain.com/new_dir/

Example 3: domain.com/dir_1/dir_2/dir_3/./../../../test/dir4/../final
Should resolve into domain.com/test/final

How can I iterate through the string to do this? I feel like the for() loop would get confused at this point.

The answers provided in Transform relative path into absolute URL using PHP and PHP: How to resolve a relative url don't work for me in this case. I shouldn't need a reference point (base), since the objective to clean up what I already have.

This is not a duplicate of PHP - Failed to open stream : No such file or directory


Solution

  • This is a more simple problem then you are thinking about it. All you need to do is explode() on the / character, and parse out all of the individual segments using a stack. As you traverse the array from left to right, if you see ., do nothing. If you see .., pop an element from the stack. Otherwise, push an element onto the stack.

    $str = 'domain.com/dir_1/dir_2/dir_3/./../../../';
    $array = explode( '/', $str);
    $domain = array_shift( $array);
    
    $parents = array();
    foreach( $array as $dir) {
        switch( $dir) {
            case '.':
            // Don't need to do anything here
            break;
            case '..':
                array_pop( $parents);
            break;
            default:
                $parents[] = $dir;
            break;
        }
    }
    
    echo $domain . '/' . implode( '/', $parents);
    

    This will properly resolve the URLs in all of your test cases.

    Note that error checking is left as an exercise to the user (i.e. when the $parents stack is empty and you try to pop something off of it).