Apache RewriteRule 지시문에서 환경 변수를 설정할 때 변수 이름 앞에 "REDIRECT_"가 붙는 이유는 무엇입니까?
[E=VAR:VAL]
.htaccess 파일의 RewriteRule 규칙에 플래그 를 사용하여 Apache 환경 변수 (PHP에서 사용)를 설정하려고 합니다.
난 이미 변수는 서버 변수로 PHP에 액세스 할 수 있습니다 발견 $_SERVER
보다는 $_ENV
(감각의 일정 금액을 만든다). 그러나 내 문제는 일부 규칙의 경우 [E=VAR:VAL]
플래그가 예상대로 작동하고 변수로 $_SERVER['VAR']
끝나지만 다른 규칙의 경우 변수 $_SERVER['REDIRECT_VAR']
또는 $_SERVER['REDIRECT_REDIRECT_VAR']
등으로 끝납니다.
A. [E=VAR:VAL]
변수 이름 앞에 "REDIRECT_"를 추가 하여 플래그를 사용하여 Apache에 설정된 환경 변수의 이름을 바꾸는 원인은 무엇입니까 ?
B. 이름이 변경되지 않은 환경 변수로 끝나도록 $_SERVER['VAR']
하려면 "REDIRECT_"인스턴스가 하나 이상 추가 된 변수 이름의 변형을 확인하지 않고도 PHP에서 액세스 할 수 있도록하려면 어떻게해야합니까? 그것에?
부분 솔루션을 찾았습니다 . 다시 쓰기 규칙의 시작 부분에 다음을 추가하면 필요한 경우 각 리디렉션에서 원래 ENV : VAR이 다시 생성되고 REDIRECT_VAR 버전은 그대로 유지됩니다.
RewriteCond %{ENV:REDIRECT_VAR} !^$
RewriteRule .* - [E=VAR:%{ENV:REDIRECT_VAR}]
이 동작은 불행하며 문서화되지 않은 것 같습니다.
.htaccess per-dir 컨텍스트
다음은 .htaccess
디렉토리 별 (디렉터리 별) 컨텍스트 에서 발생하는 것처럼 보입니다 .
Apache .htaccess
가 재 작성 지시문이 포함 된 파일을 처리한다고 가정합니다 .
-
Apache는 환경 변수 맵을 모든 표준 CGI / Apache 변수로 채 웁니다.
-
재 작성 시작
-
환경 변수는
RewriteRule
지시문에 설정됩니다. -
Apache가
RewriteRule
지시문 처리를 중지하고 (L
플래그 또는 규칙 세트의 끝으로 인해) URL이에 의해 변경RewriteRule
되면 Apache는 요청 처리를 다시 시작합니다.이 부분에 익숙하지 않은 경우
L
플래그 문서를 참조하십시오 .따라서 규칙 세트는 처음부터 다시 실행될 수 있습니다. 가장 일반적으로 이는 규칙 중 하나가 내부 또는 외부 리디렉션을 유발하여 요청 프로세스를 다시 시작하는 경우에 발생합니다.
-
내가 관찰 할 수있는 바에 따르면 # 4가 발생하면 # 1이 반복되고
RewriteRule
지시문 에 설정된 환경 변수가REDIRECT_
환경 변수 맵 앞에 추가 되고 추가된다고 생각합니다 (반드시 그 순서는 아니지만 최종 결과는 그 조합의).이 단계는 선택한 변수 이름이 지워지는 곳이며, 잠시 후에 이것이 왜 그렇게 중요하고 불편한지 설명하겠습니다.
변수 이름 복원
처음에이 문제가 발생했을 때 .htaccess
(간체) 에서 다음과 같은 작업을 수행했습니다 .
RewriteCond %{HTTP_HOST} (.+)\.projects\.
RewriteRule (.*) subdomains/%1/docroot/$1
RewriteRule (.+/docroot)/ - [L,E=EFFECTIVE_DOCUMENT_ROOT:$1]
처음에 환경 변수를 설정하면 RewriteRule
Apache는 재 작성 프로세스를 다시 시작하고 변수 앞에 REDIRECT_
(위의 4 단계 및 5 단계)를 추가하므로 할당 한 이름을 통해 액세스 할 수 없게됩니다.
이 경우 첫 번째 RewriteRule
는 URL을 변경하므로 두 가지가 모두 RewriteRule
처리 된 후 Apache는 프로 시저를 다시 시작하고 .htaccess
다시 처리 합니다. 두 번째 RewriteRule
는 RewriteCond
지시문으로 인해 첫 번째 는 건너 뛰지 만 두 번째는 RewriteRule
일치하고 환경 변수를 설정하며 중요한 것은 URL을 변경하지 않습니다 . 따라서 요청 / 재 작성 프로세스가 다시 시작되지 않고 내가 선택한 변수 이름이 고정됩니다. 이 경우 실제로 REDIRECT_EFFECTIVE_DOCUMENT_ROOT
및 EFFECTIVE_DOCUMENT_ROOT
. 내가 사용한다면 L
처음에 플래그를 RewriteRule
, 나는 단지이 것입니다 EFFECTIVE_DOCUMENT_ROOT
.
@trowel의 부분 솔루션은 비슷하게 작동합니다. 재 작성 지시문이 다시 처리되고 이름이 변경된 변수가 원래 이름에 다시 할당되며 URL이 변경되지 않으면 프로세스가 종료되고 할당 된 변수 이름이 유지됩니다.
이러한 기술이 부적절한 이유
두 기술 모두 중대한 결함이 있습니다. .htaccess
환경 변수를 설정 한 파일 의 재 작성 규칙 이 URL을 .htaccess
재 작성을 수행 하는 파일이 있는 더 깊게 중첩 된 디렉토리로 재 작성하면 할당 된 변수 이름이 다시 지워집니다.
다음과 같은 디렉토리 레이아웃이 있다고 가정합니다.
docroot/
.htaccess
A.php
B.php
sub/
.htaccess
A.php
B.php
그리고 다음 docroot/.htaccess
과 같이 :
RewriteRule ^A\.php sub/B.php [L]
RewriteRule .* - [E=MAJOR:flaw]
그래서 당신은을 요청 /A.php
하고 sub/B.php
. 여전히 MAJOR
변수 가 있습니다 .
그러나에 재 작성 지시문이있는 경우 docroot/sub/.htaccess
( RewriteEngine Off
또는 조차도 RewriteEngine On
) MAJOR
변수가 사라집니다. 그의 URL이에 다시 한번 있기 때문에 sub/B.php
, docroot/sub/.htaccess
처리, 그리고 어떤 재 작성 지침이 포함 된 경우에 지시 다시 docroot/.htaccess
다시 처리되지 않습니다. 당신이이 있다면 REDIRECT_MAJOR
후에는 docroot/.htaccess
(당신은 생략하면 예를 들어, 처리 된 L
첫 번째 플래그을 RewriteRule
), 당신은 여전히있을 것이다, 그러나 그 지시가 선택한 변수 이름을 설정 다시 실행되지 않습니다.
계승
따라서 다음을 원한다고 가정하십시오.
-
RewriteRule
디렉토리 트리의 특정 수준 에서 지시문에 환경 변수 설정 (예docroot/.htaccess
:) -
더 깊은 수준의 스크립트에서 사용할 수 있습니다.
-
할당 된 이름으로 사용할 수 있도록
-
be able to have rewrite directives in more deeply nested
.htaccess
files
A possible solution is to use RewriteOptions inherit
directives in the more deeply nested .htaccess
files. That allows you to re-run the rewrite directives in less deeply nested files and use the techniques outlined above to set the variables with the chosen names. However, note that this increases complexity because you have to be more careful crafting the rewrite directives in the less deeply nested files so that they don't cause problems when run again from the more deeply nested directories. I believe Apache strips the per-dir prefix for the more deeply nested directory and runs the rewrite directives in the less deeply nested files on that value.
@trowel's technique
As far as I can see, support for using a construct like %{ENV:REDIRECT_VAR}
in the value component of a RewriteRule
E
flag (e.g. [E=VAR:%{ENV:REDIRECT_VAR}]
) does not appear to be documented:
VAL may contain backreferences ($N or %N) which will be expanded.
It does appear to work, but if you want to avoid relying on something undocumented (please correct me if I'm wrong about that), it can easily be done this way instead:
RewriteCond %{ENV:REDIRECT_VAR} (.+)
RewriteRule .* - [E=VAR:%1]
SetEnvIf
I don't recommend relying on this, because it doesn't seem to be consistent with the documented behavior (see below), but this (in docroot/.htaccess
, with Apache 2.2.20) works for me:
SetEnvIf REDIRECT_VAR (.+) VAR=$1
Only those environment variables defined by earlier SetEnvIf[NoCase] directives are available for testing in this manner.
Why?
I don't know what the rationale for prefixing these names with REDIRECT_
is -- not surprising, since it doesn't appear to be mentioned in the Apache documentation sections for mod_rewrite directives, RewriteRule
flags, or environment variables.
At the moment it seems like a big nuisance to me, in the absence of an explanation for why it's better than leaving the assigned names alone. The lack of documentation only contributes to my skepticism about it.
Being able to assign environment variables in rewrite rules is useful, or at least, it would be. But the usefulness is greatly diminished by this name-changing behavior. The complexity of this post illustrates how nuts this behavior and the hoops that have to be jumped through to try to overcome it are.
I haven't tested this at all and I know it doesn't address points A or B, but there is some description of this issue in the comments in PHP documentation and some possible solutions for accessing these variables using $_SERVER['VAR']
:
http://www.php.net/manual/en/reserved.variables.php#79811
EDIT - some more responses to the question offered:
A: The environment variables are renamed by Apache if they are involved in a redirect. For example, if you have the following rule:
RewriteRule ^index.php - [E=VAR1:'hello',E=VAR2:'world']
Then you may access VAR1 and VAR2 using $_SERVER['VAR1']
and $_SERVER['VAR2']
. However, if you redirect the page like so:
RewriteRule ^index.php index2.php [E=VAR1:'hello',E=VAR2:'world']
Then you must use $_SERVER['REDIRECT_VAR1']
, etc.
B: The best way to overcome this issue is to process the variables that you're interested in using PHP. Create a function that runs through the $_SERVER
array and finds the items that you need. You might even use a function like this:
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;
}
As I don't want to change any of my code (nor can I change code of the libraries used), I went with the following approach: whilst bootstrapping my application – e.g. in my index.php
– I rework the $_ENV
superglobal so that variables prefixed with REDIRECT_
are rewritten to their normal intended name:
// 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);
}
}
Not only do we directly set it in $_ENV
, but we also store it using putenv()
. This way existing code and libraries – which might use getenv()
– can work fine.
On a sidenote: if you're extracting headers – like HTTP_AUTHORIZATION
– in your code, you need to do the same kind of manipulation on $_SERVER
:
foreach ($_SERVER as $key => $value) {
if (substr($key, 0, 9) === 'REDIRECT_') {
$_SERVER[str_replace('REDIRECT_', '', $key)] = $value;
}
}
'IT Share you' 카테고리의 다른 글
Android 에뮬레이터 : qemu-system-i386.exe : goldfish_battery_read : 잘못된 오프셋 (0) | 2020.11.08 |
---|---|
다른 가변 함수에 줄임표 전달 (0) | 2020.11.08 |
동시 JUnit 테스트 (0) | 2020.11.08 |
새 DbContext ()는 언제 만들어야합니까? (0) | 2020.11.08 |
java.net.SocketTimeoutException 가져 오기 : Android에서 연결 시간이 초과되었습니다. (0) | 2020.11.08 |