Dieses Verhalten ist unglücklich und scheint nicht einmal dokumentiert zu sein.
.htaccess Per-Dir-Kontext
Folgendes scheint im .htaccess
Kontext pro Verzeichnis (pro Verzeichnis) zu passieren :
Angenommen, Apache verarbeitet eine .htaccess
Datei, die Anweisungen zum Umschreiben enthält.
-
Apache füllt seine Umgebungsvariablenzuordnung mit allen Standard-CGI / Apache-Variablen
-
Das Umschreiben beginnt
-
Umgebungsvariablen werden in RewriteRule
Direktiven festgelegt
-
Wenn Apache die Verarbeitung der RewriteRule
Anweisungen beendet (aufgrund eines L
Flags oder des Endes des Regelsatzes) und die URL durch a geändert wurde RewriteRule
, startet Apache die Anforderungsverarbeitung neu.
Wenn Sie mit diesem Teil nicht vertraut sind, lesen Sie die L
Flag-Dokumentation :
Somit kann der Regelsatz von Anfang an erneut ausgeführt werden. Am häufigsten geschieht dies, wenn eine der Regeln eine interne oder externe Umleitung verursacht und der Anforderungsprozess von vorne beginnt.
-
Soweit ich beobachten kann, glaube ich, dass, wenn # 4 passiert, # 1 wiederholt wird, die Umgebungsvariablen, die in RewriteRule
Direktiven festgelegt wurden, vorangestellt REDIRECT_
und der Umgebungsvariablenzuordnung hinzugefügt werden (nicht unbedingt in dieser Reihenfolge, aber das Endergebnis besteht aus dieser Kombination).
In diesem Schritt werden die ausgewählten Variablennamen gelöscht, und ich werde gleich erklären, warum dies so wichtig und unpraktisch ist.
Variablennamen wiederherstellen
Als ich ursprünglich auf dieses Problem gestoßen bin, habe ich in .htaccess
(vereinfacht) Folgendes getan :
RewriteCond %{HTTP_HOST} (.+)\.projects\.
RewriteRule (.*) subdomains/%1/docroot/$1
RewriteRule (.+/docroot)/ - [L,E=EFFECTIVE_DOCUMENT_ROOT:$1]
Wenn ich die Umgebungsvariable in der ersten festlegen RewriteRule
würde, würde Apache den Umschreibungsprozess neu starten und der Variablen voranstellen REDIRECT_
(Schritte 4 und 5 oben), sodass ich den Zugriff über den von mir zugewiesenen Namen verlieren würde.
In diesem Fall RewriteRule
ändert der erste die URL. Nachdem beide RewriteRule
s verarbeitet wurden, startet Apache die Prozedur neu und verarbeitet sie .htaccess
erneut. Beim zweiten Mal wird das erste RewriteRule
aufgrund der RewriteCond
Direktive übersprungen , aber das zweite RewriteRule
stimmt überein, legt die Umgebungsvariable (erneut) fest und ändert vor allem die URL nicht . Der Anforderungs- / Umschreibungsprozess beginnt also nicht von vorne, und der von mir gewählte Variablenname bleibt erhalten. In diesem Fall habe ich tatsächlich beide REDIRECT_EFFECTIVE_DOCUMENT_ROOT
und EFFECTIVE_DOCUMENT_ROOT
. Wenn ich L
beim ersten Mal eine Flagge benutzen RewriteRule
würde, hätte ich nur EFFECTIVE_DOCUMENT_ROOT
.
Die Teillösung von @ trowel funktioniert ähnlich: Die Anweisungen zum Umschreiben werden erneut verarbeitet, die umbenannte Variable wird erneut dem ursprünglichen Namen zugewiesen, und wenn sich die URL nicht ändert, ist der Prozess beendet und der zugewiesene Variablenname bleibt erhalten.
Warum diese Techniken unzureichend sind
Beide Techniken weisen einen großen Fehler auf: Wenn die Umschreiberegeln in der .htaccess
Datei, in der Sie Umgebungsvariablen festlegen, die URL in ein tiefer verschachteltes Verzeichnis .htaccess
umschreiben, in dem sich eine Datei befindet, die neu geschrieben werden kann, wird der zugewiesene Variablenname erneut gelöscht.
Angenommen, Sie haben ein Verzeichnislayout wie das folgende:
docroot/
.htaccess
A.php
B.php
sub/
.htaccess
A.php
B.php
Und so docroot/.htaccess
ähnlich:
RewriteRule ^A\.php sub/B.php [L]
RewriteRule .* - [E=MAJOR:flaw]
Sie fordern also /A.php
an und es wird umgeschrieben sub/B.php
. Sie haben noch Ihre MAJOR
Variable.
Wenn Sie jedoch Anweisungen zum Umschreiben in docroot/sub/.htaccess
(auch nur RewriteEngine Off
oder RewriteEngine On
) haben, MAJOR
verschwindet Ihre Variable. Dies liegt daran, dass, sobald die URL neu geschrieben sub/B.php
und docroot/sub/.htaccess
verarbeitet wurde und wenn sie Anweisungen zum Umschreiben enthält, Anweisungen zum Umschreiben in docroot/.htaccess
nicht mehr verarbeitet werden. Wenn ein REDIRECT_MAJOR
After docroot/.htaccess
verarbeitet wurde (z. B. wenn Sie das L
Flag vom ersten weglassen RewriteRule
), haben Sie es immer noch, aber diese Anweisungen werden nicht erneut ausgeführt, um den von Ihnen gewählten Variablennamen festzulegen.
Erbe
Sagen Sie also, Sie möchten:
-
Umgebungsvariablen in RewriteRule
Direktiven auf einer bestimmten Ebene des Verzeichnisbaums festlegen (wie docroot/.htaccess
)
-
haben sie in Skripten auf tieferen Ebenen verfügbar
-
Halten Sie sie mit den zugewiesenen Namen bereit
-
in der Lage sein, Anweisungen in tiefer verschachtelten .htaccess
Dateien
neu zu schreiben
Eine mögliche Lösung besteht darin, RewriteOptions inherit
Anweisungen in den tiefer verschachtelten .htaccess
Dateien zu verwenden. Auf diese Weise können Sie die Anweisungen zum Umschreiben in weniger tief verschachtelten Dateien erneut ausführen und die oben beschriebenen Techniken verwenden, um die Variablen mit den ausgewählten Namen festzulegen. Beachten Sie jedoch, dass dies die Komplexität erhöht, da Sie die Anweisungen zum Umschreiben in den weniger tief verschachtelten Dateien sorgfältiger gestalten müssen, damit sie keine Probleme verursachen, wenn sie erneut aus den tiefer verschachtelten Verzeichnissen ausgeführt werden. Ich glaube, Apache entfernt das Per-Dir-Präfix für das tiefer verschachtelte Verzeichnis und führt die Rewrite-Anweisungen in den weniger tief verschachtelten Dateien für diesen Wert aus.
@ Kelle Technik
Soweit ich sehen kann, scheint die Unterstützung für die Verwendung eines Konstrukts wie %{ENV:REDIRECT_VAR}
in der Wertekomponente eines RewriteRule
E
Flags (z. B. [E=VAR:%{ENV:REDIRECT_VAR}]
) nicht dokumentiert zu sein :
VAL kann Rückreferenzen ($ N oder% N) enthalten, die erweitert werden.
Es scheint zu funktionieren, aber wenn Sie vermeiden möchten, sich auf etwas Undokumentiertes zu verlassen (bitte korrigieren Sie mich, wenn ich mich irre), können Sie dies einfach auf folgende Weise tun:
RewriteCond %{ENV:REDIRECT_VAR} (.+)
RewriteRule .* - [E=VAR:%1]
SetEnvIf
Ich empfehle nicht, sich darauf zu verlassen, da es nicht mit dem dokumentierten Verhalten (siehe unten) docroot/.htaccess
übereinzustimmen scheint , aber dies (in , mit Apache 2.2.20) funktioniert für mich:
SetEnvIf REDIRECT_VAR (.+) VAR=$1
Auf diese Weise stehen nur die Umgebungsvariablen zum Testen zur Verfügung, die durch frühere SetEnvIf [NoCase] -Anweisungen definiert wurden.
Warum?
Ich weiß nicht, warum diese Namen vorangestellt werden sollen REDIRECT_
- nicht überraschend, da sie in den Apache-Dokumentationsabschnitten für mod_rewrite-Direktiven , RewriteRule
Flags oder Umgebungsvariablen anscheinend nicht erwähnt werden .
Im Moment scheint es mir ein großes Ärgernis zu sein, da es keine Erklärung dafür gibt, warum es besser ist, als die zugewiesenen Namen in Ruhe zu lassen. Der Mangel an Dokumentation trägt nur zu meiner Skepsis bei.
Die Möglichkeit, Umgebungsvariablen in Umschreiberegeln zuzuweisen, ist nützlich oder zumindest nützlich. Die Nützlichkeit wird jedoch durch dieses namenändernde Verhalten stark beeinträchtigt. Die Komplexität dieses Beitrags zeigt, wie verrückt dieses Verhalten ist und welche Reifen durchgesprungen werden müssen, um es zu überwinden.