views:

337

answers:

4

I noticed that there're some similar questions about this problem when I typed the title,but they seem not be in PHP.So what's the solution to it with a PHP function?

To be specified.

$a="/home/apache/a/a.php";
$b="/home/root/b/b.php";
$relpath = getRelativePath($a,$b);//needed function,should return '../../root/b/b.php'

Any good ideas?Thanks.

+5  A: 

Relative path? This seems more like a travel path. You seem to want to know the path one travels to get from path A to path B. If that's the case, you can explode $a and $b on '/' then inversely loop through the $aParts, comparing them to $bParts of the same index until the "common denominator" directory is found (recording the number of loops along the way). Then create an empty string and add '../' to it $numLoops-1 times then add to that $b minus the common denominator directory.

webbiedave
+6  A: 

Try this one:

function getRelativePath($from, $to)
{
    $from     = explode('/', $from);
    $to       = explode('/', $to);
    $relPath  = $to;

    foreach($from as $depth => $dir) {
        // find first non-matching dir
        if($dir === $to[$depth]) {
            // ignore this directory
            array_shift($relPath);
        } else {
            // get number of remaining dirs to $from
            $remaining = count($from) - $depth;
            if($remaining > 1) {
                // add traversals up to first matching dir
                $padLength = (count($relPath) + $remaining - 1) * -1;
                $relPath = array_pad($relPath, $padLength, '..');
                break;
            } else {
                $relPath[0] = './' . $relPath[0];
            }
        }
    }
    return implode('/', $relPath);
}

This will give

$a="/home/a.php";
$b="/home/root/b/b.php";
echo getRelativePath($a,$b), PHP_EOL;  // ./root/b/b.php

and

$a="/home/apache/a/a.php";
$b="/home/root/b/b.php";
echo getRelativePath($a,$b), PHP_EOL; // ../../root/b/b.php

and

$a="/home/root/a/a.php";
$b="/home/apache/htdocs/b/en/b.php";
echo getRelativePath($a,$b), PHP_EOL; // ../../apache/htdocs/b/en/b.php

and

$a="/home/apache/htdocs/b/en/b.php";
$b="/home/root/a/a.php";
echo getRelativePath($a,$b), PHP_EOL; // ../../../../root/a/a.php
Gordon
Looks like we came up with almost the exact same algorithm, mine in english, yours in PHP (me being too lazy too code it, you not being).
webbiedave
@webbiedave SO told me about it 8 minutes after you wrote it. Otherwise I had been too lazy to come up with the code either ;) Upvoted yours though.
Gordon
ha. thanks!....
webbiedave
That's nice.Thanks guys.
SpawnCxy
it seems the function doesn't work well when the depths of the two argument paths are not equal.
SpawnCxy
@SpawnCxy updated code. try new version please.
Gordon
How about `$a` is deeper than `$b`?:)
SpawnCxy
@SpawnCxy that will teach me to come up with code when I actually am too lazy to think about it :) updated again. Good now?
Gordon
yeah good now.Sorry for the bothering stuff.U r a nice guy.
SpawnCxy
@SpawnCxy you're welcome and actually thanks for bothering. gave me the opportunity to fix the code.
Gordon
A: 

Based on Gordon's function,my solution is as follows:

function getRelativePath($from, $to)
{
   $from = explode('/', $from);
   $to = explode('/', $to);
   foreach($from as $depth => $dir)
   {

        if(isset($to[$depth]))
        {
            if($dir === $to[$depth])
            {
               unset($to[$depth]);
               unset($from[$depth]);
            }
            else
            {
               break;
            }
        }
    }
    //$rawresult = implode('/', $to);
    for($i=0;$i<count($from)-1;$i++)
    {
        array_unshift($to,'..');
    }
    $result = implode('/', $to);
    return $result;
}
SpawnCxy
A: 

I would need modified code, with would have only the $from as parameter. After typing, please send a notification to: mcgiwer-at-yahoo-dot-com

Mcgiwer