Hành vi này không may và thậm chí không xuất hiện trong tài liệu.
.htaccess mỗi dir bối cảnh
Đây là những gì dường như xảy ra trong .htaccess
mỗi thư mục (mỗi thư mục) ngữ cảnh:
Giả sử rằng Apache xử lý một tập tin .htaccess
bao gồm viết lại chỉ thị.
-
Apache populates môi trường đồ biến của nó với tất cả các CGI tiêu chuẩn/Apache biến
-
Viết lại bắt đầu
-
biến môi trường được thiết lập trong RewriteRule
chỉ
-
Khi Apache dừng xử lý RewriteRule
chỉ thị (vì một L
cờ hoặc cuối ruleset) và URL đã được được thay đổi bởi một RewriteRule
, Apache khởi động lại yêu cầu xử lý.
Nếu bạn không quen thuộc với phần này, xem L
flag documentation:
do đó ruleset chưa chạy lại từ đầu. Thông thường nhất điều này sẽ xảy ra nếu một trong các quy tắc gây ra chuyển hướng - bên trong hoặc bên ngoài - khiến quá trình yêu cầu bắt đầu lại.
-
Từ những gì tôi có thể quan sát, tôi tin rằng khi # 4 xảy ra, # 1 được lặp đi lặp lại, sau đó các biến môi trường đã được thiết lập trong RewriteRule
chỉ được thêm vào phía trước với REDIRECT_
và bổ sung vào môi trường bản đồ vars (không nhất thiết theo thứ tự đó, nhưng kết quả cuối cùng bao gồm kết hợp đó).
Bước này là nơi các tên biến được chọn bị xóa sổ, và trong giây lát tôi sẽ giải thích tại sao điều đó lại quan trọng và bất tiện.
Khôi phục tên biến
Khi tôi ban đầu chạy vào vấn đề này, tôi đang làm một cái gì đó như sau trong .htaccess
(giản thể):
RewriteCond %{HTTP_HOST} (.+)\.projects\.
RewriteRule (.*) subdomains/%1/docroot/$1
RewriteRule (.+/docroot)/ - [L,E=EFFECTIVE_DOCUMENT_ROOT:$1]
Nếu tôi được đặt biến môi trường trong RewriteRule
đầu tiên, Apache sẽ khởi động lại quá trình viết lại và thêm biến vào trước với REDIRECT_
(các bướC# 4 & 5 ở trên), do đó tôi sẽ mất quyền truy cập vào nó thông qua tên mà tôi đã chỉ định.
Trong trường hợp này, RewriteRule
thay đổi URL đầu tiên, vì vậy sau khi cả hai RewriteRule
được xử lý, Apache khởi động lại quy trình và xử lý lại .htaccess
. Lần thứ hai, RewriteRule
đầu tiên bị bỏ qua vì chỉ thị RewriteCond
, nhưng đối sánh thứ hai RewriteRule
, đặt biến môi trường (lại) và quan trọng là không thay đổi URL. Vì vậy, yêu cầu/viết lại quá trình không bắt đầu lại, và tên biến tôi đã chọn gậy. Trong trường hợp này, tôi thực sự có cả REDIRECT_EFFECTIVE_DOCUMENT_ROOT
và EFFECTIVE_DOCUMENT_ROOT
. Nếu tôi sử dụng cờ L
trên RewriteRule
đầu tiên, tôi chỉ có EFFECTIVE_DOCUMENT_ROOT
.
giải pháp một phần của trowel hoạt động tương tự: chỉ thị viết lại được xử lý lại, biến được đổi tên được gán lại tên gốc và nếu URL không thay đổi, quá trình kết thúc và tên biến được gán.
Tại sao những kỹ thuật là không đủ
Cả hai của những kỹ thuật bị một lỗ hổng lớn: khi viết lại quy tắc trong file .htaccess
nơi bạn thiết lập các biến môi trường viết lại URL vào một thư mục lồng nhau sâu sắc hơn rằng có một tập tin .htaccess
mà không có bất kỳ viết lại, tên biến được chỉ định của bạn sẽ bị xóa một lần nữa.
Giả sử bạn có một bố trí thư mục như thế này:
docroot/
.htaccess
A.php
B.php
sub/
.htaccess
A.php
B.php
Và một docroot/.htaccess
như thế này:
RewriteRule ^A\.php sub/B.php [L]
RewriteRule .* - [E=MAJOR:flaw]
Vì vậy, bạn yêu cầu /A.php
, và nó được viết lại để sub/B.php
. Bạn vẫn có biến số MAJOR
.
Tuy nhiên, nếu bạn có bất kỳ chỉ thị viết lại nào trong docroot/sub/.htaccess
(thậm chí chỉ RewriteEngine Off
hoặc RewriteEngine On
), biến số MAJOR
của bạn biến mất. Đó là bởi vì khi URL được viết lại thành sub/B.php
, docroot/sub/.htaccess
được xử lý và nếu nó chứa bất kỳ chỉ thị viết lại nào, thì chỉ thị viết lại trong docroot/.htaccess
sẽ không được xử lý lại. Nếu bạn đã có REDIRECT_MAJOR
sau khi docroot/.htaccess
được xử lý (ví dụ: nếu bạn bỏ qua cờ L
từ RewriteRule
đầu tiên), bạn vẫn sẽ có nó, nhưng những chỉ thị đó sẽ không chạy lại để đặt tên biến bạn đã chọn.
Inheritance
Vì vậy, nói rằng bạn muốn:
-
biến môi trường thiết lập trong RewriteRule
chỉ ở một mức độ cụ thể của cây thư mục (như docroot/.htaccess
)
-
có họ sẵn trong kịch bản ở mức sâu hơn
-
có họ sẵn với tên giao
-
có thể có chỉ thị viết lại nhiều hơn lồng sâu .htaccess
file
Một giải pháp khả thi là sử dụng RewriteOptions inherit
chỉ thị trong lồng nhau sâu sắc hơn .htaccess
tập tin. Điều đó cho phép bạn chạy lại các chỉ thị viết lại trong các tệp lồng nhau ít sâu hơn và sử dụng các kỹ thuật được nêu ở trên để đặt các biến với các tên được chọn. Tuy nhiên, lưu ý rằng điều này làm tăng sự phức tạp bởi vì bạn phải cẩn thận hơn khi viết lại các chỉ thị trong các tệp lồng nhau ít sâu hơn để chúng không gây ra vấn đề khi chạy lại từ các thư mục lồng nhau sâu hơn. Tôi tin rằng Apache dải tiền tố cho mỗi thư mục cho các thư mục lồng nhau sâu hơn và chạy các chỉ thị viết lại trong các tập tin lồng nhau ít sâu hơn về giá trị đó.
@ kỹ thuật bay của
Theo như tôi thấy, hỗ trợ cho việc sử dụng một cấu trúc giống như %{ENV:REDIRECT_VAR}
trong thành phần giá trị của một lá cờ RewriteRule
E
(ví dụ [E=VAR:%{ENV:REDIRECT_VAR}]
) không xuất hiện để được documented:
VAL có thể chứa backreferences ($ N hoặc% N) sẽ được mở rộng.
Nó xuất hiện để làm việc, nhưng nếu bạn muốn tránh dựa vào một cái gì đó không có cơ sở (hãy sửa lại cho tôi nếu tôi sai về điều đó), nó có thể dễ dàng được thực hiện theo cách này thay vì:
RewriteCond %{ENV:REDIRECT_VAR} (.+)
RewriteRule .* - [E=VAR:%1]
SetEnvIf
Tôi không khuyên bạn nên dựa vào điều này, vì nó dường như không nhất quán với số documented behavior (xem bên dưới), nhưng điều này (trong docroot/.htaccess
, với Apache 2.2.20) làm việc cho tôi:
SetEnvIf REDIRECT_VAR (.+) VAR=$1
Chỉ những biến môi trường được xác định bởi SetEnvIf [NoCase] chỉ thị trước đó có sẵn để thử nghiệm theo cách này.
Tại sao?
Tôi không biết lý do để đặt tiền tố cho những tên này với số REDIRECT_
là gì - không đáng ngạc nhiên vì nó dường như không được đề cập trong phần tài liệu Apache cho mod_rewrite directives, RewriteRule
flags hoặc environment variables.
Hiện tại nó có vẻ như là một mối phiền toái lớn đối với tôi, trong trường hợp không có lời giải thích vì sao nó tốt hơn là để lại tên được chỉ định một mình. Việc thiếu tài liệu chỉ góp phần vào sự hoài nghi của tôi về nó.
Có thể gán các biến môi trường trong quy tắc viết lại rất hữu ích, hoặc ít nhất, nó sẽ là. Nhưng tính hữu dụng bị giảm đi rất nhiều bởi hành vi thay đổi tên này. Sự phức tạp của bài viết này minh họa cách thức hoạt động của hành vi này và các vòng lặp phải vượt qua để cố gắng vượt qua nó.
Tôi luôn sử dụng getenv() - http://php.net/manual/en/function.getenv.php và chưa gặp phải bất kỳ sự cố lạ nào. – Chaoley