Ich versuche, Apache-Umgebungsvariablen (zur Verwendung in PHP) mit dem [E=VAR:VAL]
Flag für RewriteRule-Regeln in einer .htaccess-Datei festzulegen.
Ich habe bereits festgestellt, dass auf die Variablen in PHP $_SERVER
eher als Servervariablen als $_ENV
(was einen gewissen Sinn macht) zugegriffen wird . Mein Problem ist jedoch, dass bei einigen Regeln das [E=VAR:VAL]
Flag wie erwartet funktioniert und ich eine Variable erhalte $_SERVER['VAR']
, bei anderen Regeln jedoch eine Variable $_SERVER['REDIRECT_VAR']
oder $_SERVER['REDIRECT_REDIRECT_VAR']
usw.
A. Was bewirkt, dass eine in Apache mithilfe des [E=VAR:VAL]
Flags festgelegte Umgebungsvariable umbenannt wird, indem dem Variablennamen "REDIRECT_" vorangestellt wird?
B. Was kann ich tun, um sicherzustellen, dass ich eine Umgebungsvariable mit einem unveränderten Namen $_SERVER['VAR']
erhalte, damit ich in PHP darauf zugreifen kann, ohne nach Variationen des Variablennamens suchen zu müssen, denen eine oder mehrere Instanzen von "REDIRECT_" vorangestellt sind dazu?
Teillösung gefunden . Wenn Sie am Anfang der Umschreiberegeln Folgendes hinzufügen, wird die ursprüngliche ENV neu erstellt: VAR bei jeder Umleitung (und die REDIRECT_VAR-Versionen dort belassen), falls erforderlich:
RewriteCond %{ENV:REDIRECT_VAR} !^$
RewriteRule .* - [E=VAR:%{ENV:REDIRECT_VAR}]
Antworten:
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 festgelegtWenn Apache die Verarbeitung der
RewriteRule
Anweisungen beendet (aufgrund einesL
Flags oder des Endes des Regelsatzes) und die URL durch a geändert wurdeRewriteRule
, startet Apache die Anforderungsverarbeitung neu.Wenn Sie mit diesem Teil nicht vertraut sind, lesen Sie die
L
Flag-Dokumentation :Soweit ich beobachten kann, glaube ich, dass, wenn # 4 passiert, # 1 wiederholt wird, die Umgebungsvariablen, die in
RewriteRule
Direktiven festgelegt wurden, vorangestelltREDIRECT_
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 voranstellenREDIRECT_
(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 beideRewriteRule
s verarbeitet wurden, startet Apache die Prozedur neu und verarbeitet sie.htaccess
erneut. Beim zweiten Mal wird das ersteRewriteRule
aufgrund derRewriteCond
Direktive übersprungen , aber das zweiteRewriteRule
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 beideREDIRECT_EFFECTIVE_DOCUMENT_ROOT
undEFFECTIVE_DOCUMENT_ROOT
. Wenn ichL
beim ersten Mal eine Flagge benutzenRewriteRule
würde, hätte ich nurEFFECTIVE_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:
Und so
docroot/.htaccess
ähnlich:Sie fordern also
/A.php
an und es wird umgeschriebensub/B.php
. Sie haben noch IhreMAJOR
Variable.Wenn Sie jedoch Anweisungen zum Umschreiben in
docroot/sub/.htaccess
(auch nurRewriteEngine Off
oderRewriteEngine On
) haben,MAJOR
verschwindet Ihre Variable. Dies liegt daran, dass, sobald die URL neu geschriebensub/B.php
unddocroot/sub/.htaccess
verarbeitet wurde und wenn sie Anweisungen zum Umschreiben enthält, Anweisungen zum Umschreiben indocroot/.htaccess
nicht mehr verarbeitet werden. Wenn einREDIRECT_MAJOR
Afterdocroot/.htaccess
verarbeitet wurde (z. B. wenn Sie dasL
Flag vom ersten weglassenRewriteRule
), 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 (wiedocroot/.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 schreibenEine 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 einesRewriteRule
E
Flags (z. B.[E=VAR:%{ENV:REDIRECT_VAR}]
) nicht dokumentiert zu sein :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
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.
quelle
RewriteRule ^A\.php sub/B.php [L]
undRewriteRule .* - [E=MAJOR:flaw]
wenn die erste Regel übereinstimmt,MAJOR
wird sie nicht festgelegt, da die erste Regel übereinstimmt und die letzte ist (L-Flag). Die URL wird neu geschrieben und Apache wiederholt sich über diemod_rewrite
innere Schleife des Benutzers. Diesmal stimmt sie übereinRewriteRule .* - [E=MAJOR:flaw]
, legt die Umgebungsvariable fest und geht erst dann nach dem nächsten nach.htaccess
innen/sub
. Ist es richtig?RewriteRule
schreibt der URL zuerst die URL umsub/B.php
und dann ist das Spiel vorbei fürdocroot/.htaccess
: Die env-Variable wird nie wirklich gesetzt. (Das zu beschreiben, da die env-Variable "verschwindet" möglicherweise nicht der beste Weg ist, es auszudrücken.) Auch dies ist der Fall, wenn es eine gibt, die einesub/.htaccess
Anweisung zum Umschreiben enthält.: **If the URI changed L will re-inject into the the next round (the outer loop)** So I guess that if a URL is rewritten with [L] flag set, mod_rewrite will pass to the next round, but this time taking into consideration the most inner
.htaccess` Datei innerhalb des neu geschriebenen Pfads (in diesem Fallsub/.htaccess
). Zumindest verstehe ich das aus Ihrer Antwort und der Antwort, die ich verlinkt habe.Ich habe dies überhaupt nicht getestet und weiß, dass es die Punkte A oder B nicht behandelt, aber es gibt eine Beschreibung dieses Problems in den Kommentaren in der PHP-Dokumentation und einige mögliche Lösungen für den Zugriff auf diese Variablen mit
$_SERVER['VAR']
:http://www.php.net/manual/en/reserved.variables.php#79811
EDIT - einige weitere Antworten auf die angebotene Frage:
A: Die Umgebungsvariablen werden von Apache umbenannt, wenn sie an einer Umleitung beteiligt sind. Zum Beispiel, wenn Sie die folgende Regel haben:
RewriteRule ^index.php - [E=VAR1:'hello',E=VAR2:'world']
Dann können Sie mit
$_SERVER['VAR1']
und auf VAR1 und VAR2 zugreifen$_SERVER['VAR2']
. Wenn Sie die Seite jedoch wie folgt umleiten:RewriteRule ^index.php index2.php [E=VAR1:'hello',E=VAR2:'world']
Dann müssen Sie
$_SERVER['REDIRECT_VAR1']
usw. verwenden.B: Der beste Weg, um dieses Problem zu lösen, besteht darin, die Variablen zu verarbeiten, die Sie mit PHP interessieren. Erstellen Sie eine Funktion, die das
$_SERVER
Array durchläuft und die benötigten Elemente findet. Sie könnten sogar eine Funktion wie diese verwenden:function myGetEnv($key) { $prefix = "REDIRECT_"; if(array_key_exists($key, $_SERVER)) return $_SERVER[$key]; foreach($_SERVER as $k=>$v) { if(substr($k, 0, strlen($prefix)) == $prefix) { if(substr($k, -(strlen($key))) == $key) return $v; } } return null; }
quelle
Da ich keinen meiner Codes ändern möchte (und auch nicht den Code der verwendeten Bibliotheken ändern kann) , habe ich den folgenden Ansatz gewählt: Beim Bootstrapping meiner Anwendung - z. B. in meiner
index.php
- überarbeite ich die$_ENV
Superglobale so, dass Variablen mit dem PräfixREDIRECT_
are sind umgeschrieben auf ihren normalen beabsichtigten Namen:// Fix ENV vars getting prepended with `REDIRECT_` by Apache foreach ($_ENV as $key => $value) { if (substr($key, 0, 9) === 'REDIRECT_') { $_ENV[str_replace('REDIRECT_', '', $key)] = $value; putenv(str_replace('REDIRECT_', '', $key) . '=' . $value); } }
Wir setzen es nicht nur direkt ein
$_ENV
, sondern speichern es auch mitputenv()
. Auf diese Weise können vorhandener Code und Bibliotheken - die möglicherweise verwendet werdengetenv()
- einwandfrei funktionieren.Nebenbei bemerkt: Wenn Sie Header wie
HTTP_AUTHORIZATION
in Ihrem Code extrahieren , müssen Sie die gleiche Art von Manipulation durchführen an$_SERVER
:foreach ($_SERVER as $key => $value) { if (substr($key, 0, 9) === 'REDIRECT_') { $_SERVER[str_replace('REDIRECT_', '', $key)] = $value; } }
quelle