Cel: Ustawić mod-rewrite tak, żeby żądanie postaci post/foo/123
trafiało na stronę
post.php?user=foo&val=123
.
Rozwiązanie
Struktura:
www
├── .htaccess
└── post.php
.htaccess
RewriteEngine On
RewriteBase /
RewriteRule post/([0-9]+)/(\w+) "/post.php?category=$1&item=$2"
RewriteRule post/([0-9]+) "/post.php?category=$1"
RewriteRule post2/([0-9]+)/(\w+)$ "/post.php?category=$1&item=$2"
post.php
post.php, args: <?php print_r($_GET); ?>
RewriteEngine On
włącza obsługę przekierowań (w rewrite’ach na poziomie.htaccess
nie należy polegać na ustawieniach domyślnych)- Reguły są stosowane iteracyjnie. Żeby uniknąć zastąpienia bardziej
szczegółowej reguły dla
post/
trzeba ją umieścić przed ogólniejszą - inaczej pierwsze przepisanie zmieni adres i kolejna reguła nie będzie pasowała - Reguła dla
post/
: pierwszy element ścieżki musi być liczbą ([0-9]+
), drugi- opcjonalny - ciągiem znaków (
\w
)
- opcjonalny - ciągiem znaków (
- Reguła dla
post2/
wymusza dokładny format URLa:post/
może zastąpić tylko część URLa, np,/post/1/2/3 -> /post.php?category=1&item=$2/3
(czy takie przekierowanie ma sens, to już inna sprawa).
Skrypt do testowania:
#!/usr/bin/env bash
shopt -s expand_aliases
alias quietcurl="curl -so /dev/null -w '%{http_code}\n'"
set -x
# prawidłowe przekierowania
curl localhost:8111/post/123
curl localhost:8111/post/1/2
curl localhost:8111/post/1/asd
# nieprawidłowe
quietcurl localhost:8111/bad # nie ma takiego zasobu/przekierowania
quietcurl localhost:8111/post/asd # Not Found (pierwszy argument nie jest liczbą)
# post2 wymusza odp. zakończenie URLa
quietcurl localhost:8111/post/1/asd/123 # post/ akceptuje dalszą część ścieżki
quietcurl localhost:8111/post2/1/asd/123 # Not Found (wymuszone przez post2/)
quietcurl localhost:8111/post2/1/asd # to oczywiście działa
Wyniki:
$ ./curls.sh
+ curl localhost:8111/post/123
post.php, args: Array
(
[category] => 123
)
+ curl localhost:8111/post/1/2
post.php, args: Array
(
[category] => 1
[item] => 2
)
+ curl localhost:8111/post/1/asd
post.php, args: Array
(
[category] => 1
[item] => asd
)
+ curl -so /dev/null -w '%{http_code}\n' localhost:8111/bad
404
+ curl -so /dev/null -w '%{http_code}\n' localhost:8111/post/asd
404
+ curl -so /dev/null -w '%{http_code}\n' localhost:8111/post/1/asd/123
200
+ curl -so /dev/null -w '%{http_code}\n' localhost:8111/post2/1/asd/123
404
+ curl -so /dev/null -w '%{http_code}\n' localhost:8111/post2/1/asd
200
Środowisko
rewrite_url_args
├── 000-default.conf
├── docker-compose.yml
├── Dockerfile
└── www
├── .htaccess
└── post.php
Dockerfile
FROM php:apache
RUN a2enmod rewrite
CMD /usr/sbin/apache2ctl -D FOREGROUND
docker-compose.yml
version: '3'
services:
004_php:
build: .
ports:
- 8111:80
volumes:
- ./000-default.conf:/etc/apache2/sites-available/000-default.conf
- ./www:/var/www/html
000-default.conf
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
LogLevel info rewrite:trace3
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
<Directory />
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
Rozmaitości
- Apache musi mieć włączony
mod_rewrite
, najprościej zrobić toa2enmod
ema2enmod rewrite
- mod_rewrite nie wie nic o unikodzie. Żądanie
/post2/ąę
będzie najpierw zdekodowane do/post2/%C4%85%C4%99
, a dopiero potem będą na to nakładane reguły. Oczywiście - Przy pisaniu reguł bardzo, bardzo, bardzo przydaje się ustawienie
odpowiedniego poziomu logowania. W Apache można to zrobić dla pojedynczego
modułu:
LogLevel info rewrite:trace3
; więcej w dokumentacji Apache - Domyślnie aliasy są wyłączone w skryptach shellowych (ściślej - w sesjach nieinteraktywnych):
(man bash)
Aliases are not expanded when the shell is not interactive, unless the
expand_aliases shell option is set using shopt.
(jak włączyć?)
shopt -s expand_aliases