RewriteMap dentro de RewriteCond não funciona (Apache)

Sep 29 2020

Eu tenho um RewriteCondque verifica se {QUERY_STRING}contém o número da versão correta; se não, redireciona os usuários para a versão correta.

Por exemplo, se a versão 0.7 for a mais recente, os usuários que acessam http://localhost/?v=0.5devem ser redirecionados para, http://localhost/?v=0.7mas por algum motivo, se estou usando RewriteMapas condições, não funciona ...

Isso funciona

RewriteMap versions txt:/var/www/html/version.txt
RewriteCond "%{QUERY_STRING}" !^v=0.7
RewriteRule "^/$" "/?v=${versions:version}" [R,L]

Isso não

RewriteMap versions txt:/var/www/html/version.txt
RewriteCond "%{QUERY_STRING}" !^v=${versions:version} RewriteRule "^/$" "/?v=${versions:version}" [R,L]

Conteúdo da versão.txt

##
##  version.txt -- rewriting map
##  The version number written here will be mapped to the URL
##
##
version 0.7

Respostas

2 MrWhite Sep 29 2020 at 18:37
RewriteCond "%{QUERY_STRING}" !^v=${versions:version}

Isso não funciona porque o CondPattern (segundo argumento da RewriteConddiretiva) é uma regex e, conseqüentemente, não oferece suporte à expansão de variável. (Assim como você não pode usar referências anteriores do formulário $nou das %nvariáveis ​​do servidor %(SERVER_VAR}ou env vars %{ENV:MY_ENV_VAR}etc.) Caso contrário, isso entraria em conflito com a sintaxe regex PCRE. Apenas o TestString (primeiro argumento da RewriteConddiretiva) e os argumentos de RewriteRule substituição suportam a expansão de variável, uma vez que esses argumentos são strings "regulares", não regex.

No entanto, você ainda pode fazer o que precisa e verificar se o número da versão correto, conforme retornado do RewriteMap, está presente no início da string de consulta. Em vez disso, expanda o resultado de RewriteMapem TestString (que oferece suporte à expansão de variável, pois é uma string "comum", não uma regex) e compare isso usando uma referência anterior interna.

Por exemplo, altere o RewriteCondpara ler:

RewriteCond %{QUERY_STRING}@${versions:version} !^v=([\d.]+)(?:&[^@]*)?@\1

Após a expansão da variável, acabamos combinando uma string do formulário [email protected]com a regex ^v=([\d.]+)(?:&.*)?@\1. \1é uma referência anterior interna ao primeiro subpadrão capturado (ou seja, o valor do vparâmetro de URL). Portanto, isso corresponde efetivamente ao valor do parâmetro do URL com o valor retornado do RewriteMap. Essa expressão inteira é então negada ( !prefixo), então é bem-sucedida quando a condição não corresponde, ou seja o número da versão é diferente.

([\d.]+)- Corresponde ao número da versão na string de consulta, que consiste em 1 ou mais dígitos ou pontos literais. por exemplo.0.5

(?:&.*)? - Corresponde ao restante da string de consulta (se houver).

@ é apenas uma string arbitrária que não ocorre de outra forma na string de consulta ou na string de "versão".

Você não precisa colocar os argumentos entre aspas duplas, a menos que eles contenham espaços (mesmo assim, você pode usar a barra invertida para escapar dos espaços). Portanto, as aspas duplas são totalmente opcionais neste exemplo. O mesmo se aplica à RewriteRulediretiva.