Frank Opper

Relativer Pfad zu einem Verzeichnis

Es gibt meines Wissens keine vordefinierte Funktion in PHP, die - ausgehend von einem absoluten Verzeichnispfad - den relativen Pfad zu einem anderen Verzeichnis liefert. Ich bin z.B. im Verzeichnis /wwwroot/123456/78/9/htdocs/kontakt und möchte den relativen Pfad zu /wwwroot/123456/78/9/htdocs/blog/images wissen.

Wie sieht eine Funktion aus, die die Lösung ../blog/images liefert? Ich muss ein Verzeichnis nach oben zu /wwwroot/123456/78/9 und dann runter zu blog/images. Dieses Resultat kann ich z.B. in Links zur Navigation zwischen HTML-Seiten verwenden. Die Funktion muss also

  1. ermitteln, wie viele Verzeichnisebenen der Quellpfad hat,
  2. feststellen, welche Verzeichnisebene als erste unterschiedlich ist und
  3. anhand dieser Ergebnisse den relativen Pfad zusammenbauen.

Verzeichnisebene ermitteln

Die Verzeichnisebene kann ermittelt werden, indem z.B. das Zeichen "/" im Pfad gezählt wird. Vorher muss ggf. der Pfad um Substrings wie "///" oder "../../" bereinigt werden.

  $from = "/wwwroot/123456/78/9/htdocs/kontakt";
  $fromLevel = substr_count($from, "/");
  

Die letzte Ebene ist auf dem Level 6.

Wo ist der erste unterschiedliche Name?

Das erste unterschiedliche Verzeichnis wird ermittelt, indem beide Pfade mit explode() gesplittet und beide resultierende Arrays verglichen werden. Identische Namensbestandteile am Anfang werden gestrichen.
/wwwroot/123456/78/9/htdocs/kontakt
/wwwroot/123456/78/9/htdocs/blog/images

  $fromParts = explode("/", $from);
  $toParts = explode("/", $to);

  for ($i = 0; $i < min(count($fromParts), count($toParts)); $i++) {
    if ($fromParts[$i] != $toParts[$i]) {
      break;
    }
  }
  // $i contains the first level on which the folder names are different
  

Relativen Pfad zusammenbauen

Jetzt muss nur noch der relative Pfad zusammengebaut werden. Das erfolgt mit

  $relpath = str_repeat("../", $fromLevel - $i + 1) . implode("/", array_slice($toParts, $i));
  

Die vollständige Funktion

Die vollständige Funktion sieht damit so aus:

  function getRelpath($from, $to)
  {
    $fromLevel = substr_count($from, "/");
    $toLevel = substr_count($to, "/");

    $fromParts = explode("/", $from);
    $toParts = explode("/", $to);

    for ($i = 0; $i < min(count($fromParts), count($toParts)); $i++) {
      if ($fromParts[$i] != $toParts[$i]) {
        break;
      }
    }
    // $i contains the first level on which the folder names are different

    return str_repeat("../", $fromLevel - $i + 1) . implode("/", array_slice($toParts, $i));
  } // getRelpath