Verständnisproblem RewriteRule/relativer Pfad
- programmiertechnik
Hallo zusammen,
ich versuche in meinem Projekt die "sprechenden" URLs /produkte und /produkte/produkt1 per htaccess folgendermaßen aufzulösen:
RewriteEngine On
RewriteRule ^produkte/?$ index.php?section=produkte&produkte_section=home [L,QSA]
RewriteRule ^produkte/([a-zA-Z0-9_-]+)/?$ index.php?section=produkte&produkte_section=$1 [L,QSA]
Für den ersten Fall, also den Aufruf https://localhost/projekt/produkte, funktioniert das auch.
Beim zweiten Aufruf https://localhost/projekt/produkte/produkt1 wird auch das korrekte Script eingebunden, allerdings stimmen die relativen Pfade nicht mehr. Mich hat das komplett überrascht, weil ich dachte, die geänderte Anzeige im Browser wäre rein kosmetischer Natur. Aber offenbar denkt der ja, er befindet sich im Ordner /produkte.
Ich hatte solche Probleme sonst nie, weil ich immer mit index.php?section=produkte... arbeite.
Das hier ist die Antwort von Claude zu meinem Problem:
Ist dort die richtige Lösung dabei? Ich misstraue dem Burschen ja mittlerweile etwas. Zumal das in Lösung 2 doch kein absoluter Pfad ist, oder?
Schöne Grüße
Nico
Hallo Nico R.,
was Du da hast, ist eine URL-Route. Die muss vom Apache abgefangen werden. In einfachen Fällen reicht mod_rewrite-Logik, in schwereren Fällen liest Du die Route aus $_SERVER['REQUEST_URI'] und verwendest einen PHP-Router, um sie zu interpretieren und ggf. auch gleich aus dem ersten Teil der Route eine passende Controller-Klasse zu erzeugen (aber NIE NIE NIE ungeprüft, ob das ein gültiger Controllername ist).
Wie auch immer, der Browser bekommt den Rewrite nicht mit und löst relative Adressen in Bezug zur Routen-URL auf. Wenn Du variabel lange Routen hast, wie bei Dir mit produkte und produkte/produkt1, ist eine Adressierung von Ressourcen relativ zur URL nicht mehr handhabbar[1].
Lösung 3 ist für die Lösung "absolute URLs" die richtige.
$base = dirname($_SERVER['SCRIPT_NAME']) liefert Dir in der index.php das logische Root deines Webauftritts und wenn Du dieses logische Root mit Ressourcenpfaden verkettest, die relativ dazu sind, bist Du auf der sicheren Seite. Auch dann, wenn die URL auf dem produktiven Server den Pfadteil /projekt nicht mehr enthält.
Du kannst aber auch Lösung 1 anstreben, <base href> auf den $base Wert setzen, und dann im HTML alle Ressourcen relativ dazu abrufen. Das würde ich dann aber explizit machen. Also "./css/style.css" und nicht "css/style.css".
Denke dabei auch immer daran, dass der Rewrite vielleicht gar nicht stattfindet. Vielleicht rufst Du index.php auch mal direkt auf. Ob das geschieht, kannst Du an $_SERVER['REDIRECT_URL'] erkennen. Beim Direktaufruf fehlt der Wert.
Beides geht. Lösung 1 braucht keine PHP-Action bei jeder Ressourcenreferenz, aber gerade das könnte zu Unaufmerksamkeit führen. Lösung 3 braucht kein <base>, aber dafür eben explizites Ausgeben von $base bei jedem Ressourcenzugriff.
Von Lösung 2 würde ich abraten, weil sie nur funktioniert, wenn die absoluten Pfade auf Dev- und Prod-Servern identisch sind.
Bei Ressourcen mit relativem Pfad, die aus CSS-Dateien heraus geholt werden, denke daran, dass die nicht relativ zum HTML Dokument oder zum base-href sind, sondern relativ zur CSS Datei in der sie stehen.
Rolf
ich sage bewusst handhabbar, denn MACHBAR ist das schon. Wenn man das Rewrite-Plugin für den Microsoft IIS benutzt, dann flöht es tatsächlich jede Web-Response auf relative URLs und passt sie an, damit man im index.php relative URLs so verwenden kann, als ob man index.php direkt aufgerufen hätte ↩︎
Hallo Rolf,
danke für deine Erklärung. Ich hatte wohl mal wieder einen Aussetzer. Vielleicht war ich ja zu verwirrt darüber, dass der Browser den Ursprungsaufruf nicht kennt. Aber klar, er kriegt ja vom Server nur die reine Anzeige geliefert.
Mit einem absoluten Pfad klappts jetzt. Allerdings nutze ich nicht dirname($_SERVER['SCRIPT_NAME'])[1] , das hat nur einen Teil dessen gebracht, was ich brauchte. Ich nutze das hier:
$HOST = $_SERVER['HTTP_HOST'];
$URI = dirname($_SERVER['PHP_SELF']);
if(strlen($URI) === 1) $URI = "";
$URL = "https://".$HOST.$URI;
Und in der Anwendung dann: href="<?=$URL?>/style.css"
So läufts jetzt zumindest.
Schöne Grüße
Nico
edit: dirname($_SERVER['SCRIPT_NAME']) liefert am Ende allerdings das gleiche wie dirname($_SERVER['PHP_SELF']) ↩︎
Hallo Nico R.,
nein, so nicht.
PHP_SELF kann mehr enthalten, man kann Apache so einstellen, dass er bei /foo.php/bar/baz das foo.php aufruft. /bar/baz ist dann in PHP_SELF noch drin. In SCRIPT_NAME nicht. Nimm SCRIPT_NAME.
Und wenn du https://example.com/projekt/produkte aufrufst und aus diesem HTML die relative URL /projekt/css/styles ansprichst, dann setzt der Browser den Origin https://example.com automatisch davor. Den musst du nicht ermitteln.
Es gibt
Dir reicht Typ 2.
Rolf
Hallo Rolf,
Und wenn du https://example.com/projekt/produkte aufrufst und aus diesem HTML die relative URL /projekt/css/styles ansprichst, dann setzt der Browser den Origin https://example.com automatisch davor. Den musst du nicht ermitteln.
Ach menno. Ich hab meine Versuche immer nur mit echo angezeigt. nicht ins href gesetzt. Deswegen musste ich mir (dachte ich) den Link alleine zusammenfriemeln. So ists natürlich einfacher und sauberer.
Es gibt
- absolute URLs (https://example.com/foo/bar)
- relative URLs mit absolutem Pfad (/foo/bar)
- relative URLs mit relativem Pfad (bar oder ../bla/hui.txt)
Kapiert, denke ich. Danke für die übersichtliche Darstellung und Nachhilfe.
Schöne Grüße
Nico
Lieber Nico,
Lesehilfen aus dem hiesigen Wiki:
Liebe Grüße
Felix Riesterer