RewriteCond per abbinare i parametri della stringa di query in qualsiasi ordine
Ho un URL che può contenere tre parametri:
- ? categoria = computer
- & sottocategoria = laptop
- & prodotto = dell-inspiron-15
Ho bisogno di 301 reindirizzare questo URL alla sua versione amichevole:
http://store.example.com/computers/laptops/dell-inspiron-15/
Ho questo ma non riesco a farlo funzionare se i parametri della stringa di query sono in qualsiasi altro ordine:
RewriteCond %{QUERY_STRING} ^category=(\w+)&subcategory=(\w+)&product=(\w+) [NC]
RewriteRule ^index\.php$ http://store.example.com/%1/%2/%3/? [R,L]
Risposte
Puoi ottenere ciò con più passaggi, rilevando un parametro e quindi inoltrando al passaggio successivo e quindi reindirizzando alla destinazione finale
RewriteEngine On
RewriteCond %{QUERY_STRING} ^category=([^&]+) [NC,OR]
RewriteCond %{QUERY_STRING} &category=([^&]+) [NC]
RewriteRule ^index\.php$ $0/%1
RewriteCond %{QUERY_STRING} ^subcategory=([^&]+) [NC,OR]
RewriteCond %{QUERY_STRING} &subcategory=([^&]+) [NC]
RewriteRule ^index\.php/[^/]+$ $0/%1
RewriteCond %{QUERY_STRING} ^product=([^&]+) [NC,OR]
RewriteCond %{QUERY_STRING} &product=([^&]+) [NC]
RewriteRule ^index\.php/([^/]+/[^/]+)$ http://store.example.com/$1/%1/? [R,L]
Per evitare la ORe doppia condizione, puoi usare
RewriteCond %{QUERY_STRING} (?:^|&)category=([^&]+) [NC]
come suggerito da @TrueBlue.
Un altro approccio consiste nel anteporre a TestString QUERY_STRING una e commerciale &e controllare sempre
RewriteCond &%{QUERY_STRING} &category=([^&]+) [NC]
Questa tecnica (anteponendo TestString ) può essere utilizzata anche per portare avanti i parametri già trovati al successivo RewriteCond. Questo ci consente di semplificare le tre regole a una sola
RewriteCond &%{QUERY_STRING} &category=([^&]+) [NC]
RewriteCond %1!&%{QUERY_STRING} (.+)!.*&subcategory=([^&]+) [NC]
RewriteCond %1/%2!&%{QUERY_STRING} (.+)!.*&product=([^&]+) [NC]
RewriteRule ^index\.php$ http://store.example.com/%1/%2/? [R,L]
L' !viene utilizzato solo per separare i parametri già presenti e riordinati dal QUERY_STRING.
Adotto un approccio leggermente diverso per questo genere di cose, sfruttando i VAR ENV impostati e letti da mod_rewrite . Trovo più leggibile / gestibile fare riferimento ai riferimenti a ritroso con un nome come questo, e questi VAR ENV possono essere riutilizzati in seguito anche nell'elaborazione delle richieste. Nel complesso penso che sia un approccio più potente e flessibile rispetto alla risposta accettata qui. In ogni caso, funziona bene per me. Ho copiato interamente la mia sintesi:
A partire dal https://gist.github.com/cweekly/5ee064ddd551e1997d4c
# Mod_rewrite is great at manipulating HTTP requests.
# Using it to set and read temp env vars is a helpful technique.
#
# This example walks through fixing a query string:
# Extract good query params, discard unwanted ones, reorder good ones, append one new one.
#
# Before: /before?badparam=here&baz=w00t&foo=1&bar=good&mood=bad
# After: /after?foo=1&bar=good&baz=w00t&mood=happy
#
# Storing parts of the request (or anything you want to insert into it) in ENV VARs is convenient.
# Note the special RewriteRule target of "-" which means "no redirect; simply apply side effects"
# This lets you manipulate the request at will over multiple steps.
#
# In a RewriteRule, set custom temp ENV VARs via [E=NAME:value]
# Note it's also possible to set multiple env vars
# like [E=VAR_ONE:hi,E=VAR_TWO:bye]
#
# You can read these values using %{ENV:VAR_NAME}e <- little "e" is not a typo
#
# Tangent:
# Note you can also read these env vars the same way, if you set them via SetEnvIf[NoCase]
# (It won't work to use SetEnv, which runs too early for mod_rewrite to pair with it.)
#
# Regex details:
# (?:) syntax means "match but don't store group in %1 backreference"
# so (?:^|&) is simply the ^ beginning or an & delimiter
# (the only 2 possibilities for the start of a qs param)
# ([^&]+) means 1 or more chars that are not an & delimiter
RewriteCond %{QUERY_STRING} (?:^|&)foo=([^&]+)
RewriteRule ^/before - [E=FOO_VAL:%1]
RewriteCond %{QUERY_STRING} (?:^|&)bar=([^&]+)
RewriteRule ^/before - [E=BAR_VAL:%1]
RewriteCond %{QUERY_STRING} (?:^|&)baz=([^&]+)
RewriteRule ^/before - [E=BAZ_VAL:%1]
RewriteRule ^/before /after?foo=%{FOO_VAL}e&bar=%{BAR_VAL}e&baz=%{BAZ_VAL}e&mood=happy [R=301,L]
PS Questa non è una soluzione copia / incollabile alla tua domanda, ma piuttosto mostra esattamente come gestire questo tipo di problema. Armato di questa comprensione, sfruttarla per il tuo esempio sarà completamente banale. :)
1) Nel caso in cui devi solo controllare che tutti i parametri siano nell'URL:
RewriteCond %{QUERY_STRING} (^|&)category\=computers($|&) RewriteCond %{QUERY_STRING} (^|&)subcategory\=laptops($|&)
RewriteCond %{QUERY_STRING} (^|&)product\=dell\-inspiron\-15($|&) RewriteRule ^$ http://store.example.com/computers/laptops/dell-inspiron-15/? [R=301,L]
2) Nel caso in cui sia necessario un set esatto di parametri:
RewriteCond %{QUERY_STRING} ^&*(?:category\=computers|subcategory\=laptops|product\=dell\-inspiron\-15)(?!.*&\1(?:&|$))(?:&+(category\=computers|subcategory\=laptops|product\=dell\-inspiron\-15)(?!.*&\1(?:&|$))){2}&*$ RewriteRule ^$ http://store.example.com/computers/laptops/dell-inspiron-15/? [R=301,L]
Questa regola è generata dal generatore di reindirizzamenti 301