Pfade in der Webentwicklung
Der Umgang mit absoluten und relativen Dateipfaden gehört wie allgemein in der Programmierung auch in der Webentwicklung zum täglichen Brot. Dennoch gilt es, dabei ein paar Details zu beachten, um die Möglichkeiten voll auszuschöpfen bzw. keine unerwarteten Ergebnisse zu produzieren.
HTML
Pfadangaben in HTML – wie beispielsweise im Attribut href der Elemente <a> und <link> oder im Attribut src der Elemente <img> und <script> – folgen den üblichen Konventionen:
Absolute Pfade zu externen Ressourcen sind vollwertige URLs und beginnen immer mit der Bezeichnung für das jeweilige Internetprotokoll (meist http:// oder https://) gefolgt von dem Hostnamen (z. B. www.decocode.de). Darauf folgt der eigentliche Dateipfad, beginnend mit einem / für das Wurzelverzeichnis („Host-Root“).
Absolute Pfade zu lokalen Ressourcen auf dem Hostsystem beginnen immer mit einem / für das Wurzelverzeichnis, ggf. gefolgt von weiteren Unterverzeichnissen.
Relative Pfade auf eine lokale Ressource werden in der Regel ab dem Verzeichnis des aufrufenden Dokuments gerechnet. Dies kann explizit durch die Zeichen ./ am Beginn des Pfades angegeben werden. Werden diese Zeichen weggelassen, wird das aktuelle Verzeichnis implizit angenommen.
Um einen relativen Pfad zu einem Ort in der Verzeichnishierarchie oberhalb des aufrufenden Dokuments anzugeben, werden dem Pfad die Zeichen ../ für die nächsthöhere Verzeichnisebene vorangestellt. Befindet sich der Ort zwei Ebenen höher, werden diese Zeichen verdoppelt (../../) usw.
Beispiele:
<a href='https://www.decocode.de/scripts/'>Absoluter Pfad auf eine externe Ressource</a>
<a href='/scripts/inc/face-smile.svg'>Absoluter Pfad auf eine lokale Ressource</a>
<a href='scripts/inc/face-smile.svg'>Relativer Pfad auf eine lokale Ressource (implizit)</a>
<a href='./scripts/inc/face-smile.svg'>Relativer Pfad auf eine lokale Ressource (explizit)</a>
<a href='../../scripts/inc/face-smile.svg'>Relativer Pfad auf eine lokale Ressource (zwei Ebenen höher)</a>
Sollen relative Pfade von einem anderen Verzeichnis aus gerechnet werden, so kann das im <head>-Abschnitt des HTML-Quelltextes im <base>-Element festgelegt werden (s. MDN):
<head>
<base href='/scripts/inc/default.php'>
</head>
CSS
Pfade werden in Cascading Style Sheets (CSS) mit url() angegeben (s. MDN). Für sie gelten praktisch die gleichen Konventionen wie oben beschrieben.
<style>
/* relative Pfade: */
@font-face { font-family:Salsa; font-weight:bold; font-style:normal; src:url(inc/Salsa-Regular.ttf); }
.smile { background-image:url(inc/bg.png); }
/* absoluter Pfad: */
.smile::before { content:url(/scripts/inc/face-smile.svg); }
</style>
<link href='/scripts/inc/styles.css' rel='stylesheet'>
Mit der @import-Regel können CSS-Dateien, die sich an anderen Orten befinden, in ein Stylesheet eingebunden werden (s. MDN). Relative Pfade in diesen Dateien beziehen sich immer auf den Ort, an dem diese Datei gespeichert ist (hier beispielsweise: inc/styles.css), nicht auf den Ort der einbindenden Datei (hier beispielsweise: /scripts/index.php), weshalb diese CSS-Dateien von den unterschiedlichsten Orten aus eingebunden werden können, ohne dass sich dies auf die relativen Pfade in ihnen auswirkt.
@import url(inc/extra.css);
PHP
Mit den Funktionen include() und require() können PHP-Dateien in andere PHP-Dateien eingebunden werden (s. PHP.net).
Absolute Pfade beziehen sich hier auf das Wurzelverzeichnis des Webservers, das nicht mit dem Wurzelverzeichnis des Hosts identisch ist. Das Wurzelverzeichnis des Webservers („Server-Root“) ist wie bei jedem anderen Rechner auch das oberste Verzeichnis der Verzeichnishierarchie des Dateisystems, also /. In der Regel sind auf diesem Server eine Vielzahl von Hosts in ihren eigenen Verzeichnissen installiert. Die eigene Domain zeigt nun auf das Wurzelverzeichnis eines dieser Hosts („Host-Root“). Der Pfad zu diesem Host ist in der PHP-Variable $_SERVER['DOCUMENT_ROOT'] gespeichert (s. PHP.net).
Beispielsweise lautet die URL einer Ressource:
https://www.decocode.de/scripts/inc/extra.php
Und der Wert von $_SERVER['DOCUMENT_ROOT'] für diese Domain ist:
/var/www/vhosts/web007.server42/httpdocs
Dann ist der vollständige Pfad zu dieser Ressource auf dem Server:
/var/www/vhosts/web007.server42/httpdocs/scripts/inc/extra.php
Bei relativen Pfaden sucht PHP zuerst relativ zu dem aktuellen Dokument (die erste einbindende Datei). Wird hier keine Ressource gefunden, wird danach relativ zu der einbindenden Datei gesucht (falls diese nicht mit dem aktuellen Dokument identisch ist).
Angenommen, es existieren beispielsweise folgende Dateien:
1. /scripts/index.php
2. /scripts/inc/extra.php
3. /scripts/inc/extra2.php
4 ./scripts/inc/inc/extra2.php
Datei 1 bindet Datei 2 mit require("inc/extra.php") ein. Datei 2 bindet Datei 3 mit require("inc/extra2.php") ein. PHP sucht nun zuerst /scripts/inc/extra2.php und bindet diese Datei ein. Wäre diese Datei nicht vorhanden, würde weiter nach /scripts/inc/inc/extra2.php gesucht werden. In diesem Fall würde also Datei 4 eingebunden werden.
Die eingebundenen Dateien werden „räumlich“ so behandelt, als sei ihr gesamter Code schon immer Teil der einbindenen Datei gewesen. Für die in ihnen enthaltenen relativen Pfade gilt also, dass sie sich somit auf den Ort des ersten einbindenden Dokuments beziehen.
Dies gilt insbesondere für die Dateisystem-Funktionen von PHP, aber auch beispielsweise für getimagesize(), exif_read_data() usw.
<?php
# absoluter Pfad:
$file = $_SERVER['DOCUMENT_ROOT']."/scripts/inc/extra.php";
if (file_exists($file)) require($file);
# relativer Pfad:
$file = "inc/extra2.php";
if (file_exists($file)) require($file);
?>
Pfade ab Server-Root:
Den vollständigen Pfad zum aktuellen Dokument findet man in der Variable $_SERVER['SCRIPT_FILENAME'], während man den Pfad zu einer eingebundenen Datei in der Variable __FILE__ findet.
Hier die Ausgabe von /scripts/inc/extra.php:
echo $_SERVER['SCRIPT_FILENAME'];
# Ausgabe: /var/www/vhosts/web007.server42/httpdocs/scripts/index.php
echo __FILE__;
# Ausgabe: /var/www/vhosts/web007.server42/httpdocs/scripts/inc/extra.php
Die Funktion realpath() wandelt einen relativen in einen absoluten Pfad ab Server-Root um (s. PHP.net).
$path = "/scripts/inc/extra.php";
echo realpath($path);
# Ausgabe: /var/www/vhosts/web007.server42/httpdocs/scripts/inc/extra.php
Pfade ab Host-Root:
Den Pfad zum aktuellen Dokument findet man in der Variable $_SERVER['PHP_SELF']. Den Pfad zu einer eingebundenen Datei kann man mit mb_substr(__FILE__, mb_strlen($_SERVER['DOCUMENT_ROOT'])) ermitteln.
Hier die Ausgabe von /scripts/inc/extra.php:
echo $_SERVER['PHP_SELF'];
# Ausgabe: /scripts/index.php
echo mb_substr(__FILE__, mb_strlen($_SERVER['DOCUMENT_ROOT']));
# Ausgabe: /scripts/inc/extra.php
Query-String:
Eine eventuell vorhandene Kette mit Variablen, die an eine URL angehängt wurde, kann mit $_SERVER['QUERY_STRING'] ermittelt werden.
$_SERVER['REQUEST_URI'] enthält den gesamten Pfad ab Host-Root einschließlich Query-String.
# URL = https://www.decocode.de/scripts/index.php?a=100&b=Hallo
echo $_SERVER['QUERY_STRING'];
# Ausgabe: a=100&b=Hallo
echo $_SERVER['REQUEST_URI'];
# Ausgabe: /scripts/index.php?a=100&b=Hallo
Die einzelnen Variablen des Query-Strings befinden sich in dem Array $_GET:
$_GET['a'] == 100
$_GET['b'] == "Hallo"
Pfad zerlegen:
Mit der Funktion dirname() kann ein Pfad vom Dateinamen bereinigt werden (s. PHP.net). Als zusätzliches Argument kann die Anzahl der Ebenen oberhalb der Datei angegeben werden, bis zu der der Pfad beschnitten werden soll.
Mit der Funktion basename() kann der Dateiname aus einem Pfad extrahiert werden (s. PHP.net). Als zusätzliches Argument kann die Dateiendung angegeben werden, die dann abgetrennt wird.
$path = "/scripts/inc/extra.php";
echo dirname($path);
# Ausgabe: /scripts/inc
echo dirname($path, 2);
# Ausgabe: /scripts
echo basename($path);
# Ausgabe: extra.php
echo basename($path, ".php");
# Ausgabe: extra
Mit der Funktion pathinfo() kann ein Pfad in seine Bestandteile zerlegt werden (s. PHP.net). Zurückgegeben wird ein assoziatives Array mit den Bestandteilen.
$path = "/scripts/inc/extra2.php";
$parts = pathinfo($path);
/*
Ausgabe:
$parts['dirname'] == "/scripts/inc"
$parts['basename'] == "extra2.php"
$parts['filename'] == "extra2"
$parts['extension'] == "php"
*/
Mit der Funktion parse_url() kann eine URL in ihre Bestandteile zerlegt werden (s. PHP.net). Zurückgegeben wird ein assoziatives Array mit den Bestandteilen.
$url = "https://www.decocode.de/scripts/index.php?a=100&b=Hallo#details";
$parts = parse_url($url);
/*
Ausgabe:
$parts['scheme'] == "https"
$parts['host'] == "www.decocode.de"
$parts['path'] == "/scripts/index.php"
$parts['query'] == "a=100&b=Hallo"
$parts['fragment'] == "details"
*/