A verificação de existência de arquivo RewriteCond falha em arquivos existentes

7

Eu tenho um cenário estranho com essa regra de reescrita:

RewriteCond img/$2/$3/$4/$1 -f
RewriteRule ^img/(([a-z0-9]{4})([a-z0-9]{4})([a-z0-9]{4})[a-z0-9]{28}\.\w+)$ img/$2/$3/$4/$1 [L]

A estrutura de diretórios para isso é (simplificada):

var/
  images/
    ..
  www/
    .htaccess
    img -> /var/images

Em outras palavras, as imagens são armazenadas fora da webroot em uma área geral de armazenamento de dados e são vinculadas ao diretório img do webroot por meio de um link simbólico. Nomes de imagem são hashes. Para eficiência, eles são armazenados em uma hierarquia de diretórios profunda de três níveis. Por exemplo:

0a808e34edaaeeffd973e4138789a4957d6b6a26.jpg

é armazenado em

images/0a80/8e34/edaa/0a808e34edaaeeffd973e4138789a4957d6b6a26.jpg

A regra de reescrita simplesmente reescreve o nome do arquivo na estrutura de diretórios aninhada.

Agora, o mais estranho é que o RewriteCond funciona bem em meus sistemas locais, mas falha em um servidor de teste. O log de depuração do Apache diz explicitamente que "o padrão -f não corresponde" para essa condição. Se eu simplesmente remover essa condição, a regra de reescrita funcionará bem e a imagem será exibida.

O que poderia fazer com que -f falhasse nos arquivos que existem claramente?

FollowSymLinks é permitido. Apache versão 2.2.22-6ubuntu2 instalado via apt e dificilmente modificado. Funciona em uma instalação local do Apache 2.2.23 (via homebrew). Não foi possível ver alterações significativas entre as duas versões que devem causar isso

Alguns detalhes possivelmente mais significativos sobre a estrutura real do diretório:

$ ls -l /var/www/myapp/current
[snip] /var/www/myapp/current -> /var/www/myapp/releases/20130418090750

$ ls -la /var/www/myapp/current/webroot
[snip]
[snip] .htaccess
[snip] img -> /usr/local/var/myapp/images

A webroot do Apache está configurada como:

DocumentRoot /var/www/myapp/current/webroot

Se eu escrever o RewriteCond como:

RewriteCond /usr/local/var/myapp/images/$2/$3/$4/$1 -f

funciona. Eu preferiria não codificar caminhos absolutos, embora de alguma forma evitáveis.

O Apache pode ficar confuso com os vários níveis de links simbólicos?

    
por deceze 12.04.2013 / 15:14

3 respostas

1

Na verdade, eu nunca vi um artigo que tenha um tutorial sobre RewriteCond para obter uma variável do RewriteRule abaixo dela. No entanto, você ainda pode tentar adicionar uma diretiva RewriteBase no topo do seu arquivo .htaccess :

RewriteBase /www/

Ou apenas experimente:

RewriteBase /var/www/

Ou você pode tentar um desses conjuntos de diretivas abaixo, mas EXCLUINDO qualquer diretiva RewriteBase listada acima:

RewriteCond /www/img/$2/$3/$4/$1 -f
RewriteRule ^www/img/(([a-z0-9]{4})([a-z0-9]{4})([a-z0-9]{4})[a-z0-9]{28}\.\w+)$ /www/img/$2/$3/$4/$1 [L]

Ou você pode até tentar:

RewriteCond /var/www/img/$2/$3/$4/$1 -f
RewriteRule ^var/www/img/(([a-z0-9]{4})([a-z0-9]{4})([a-z0-9]{4})[a-z0-9]{28}\.\w+)$ /var/www/img/$2/$3/$4/$1 [L]

Sinto muito por copiar o formato da sua condição de reescrita e regra, porque você disse que "funciona no seu sistema de desenvolvimento local." Mas esta é a regra que eu recomendo a você se você quiser apenas reescrever / $ var1. $ var2 em /images/0a80/8e34/edaa/$var1.$var2 , você pode até adicionar os outros estaticamente, um por um:

RewriteRule ^([a-zA-Z0-9_-]+).([a-zA-Z]{3})$ /images/0a80/8e34/edaa/$var1.$var2

Ou você pode até tentar isso se quiser reescrever /img/0a808e34edaaeeffd973e4138789a4957d6b6a26.jpg dinamicamente em /img/0a80/8e34/edaa/0a808e34edaaeeffd973e4138789a4957d6b6a26.jpg com condição se o URL dinâmico em que o remapeamento é um arquivo:

RewriteCond /img/$2/$3/$4/$1\.$5 -f
RewriteRule ^img/(([a-z0-9]{4})([a-z0-9]{4})([a-z0-9]{4})[a-z0-9]{28})\.([a-z]{3})$ /img/$2/$3/$4/$1.$5

Lembre-se de que os caracteres em "0a80" , "8e34" e "edaa" devem ser exatos como 4 e os caracteres. em "eeffd973e4138789a4957d6b6a26" deve ser como 28 e em "jpg" deve ser como 3. Espero que isso funcione, mas duvido ..

    
por 16.04.2013 / 13:13
1

Se funcionar em localhost, mas não em test.com, eu diria que é um problema no sistema de arquivos ou está relacionado a uma configuração de site mais geral que você pode estar tomando como garantida. Você instalou os dois sistemas operacionais e instalou os mesmos pacotes usando o mesmo procedimento em ambas as máquinas? O que cada uma das configurações padrão é semelhante àquela fornecida com cada Apache? E quanto aos pacotes que modificaram a configuração padrão antes mesmo de você dar uma olhada?

Talvez suas versões do Apache sejam quase semelhantes, mas se fossem de origens diferentes, a configuração padrão pode ter sido diferente e ter sido modificada de maneira diferente. Verifique sua configuração a partir do topo. O que está diferente? Tentando fazê-los parecer exatamente iguais (não apenas em seus reescritos, mas em contextos de Host Virtual ou Servidor).

O contexto de suas diretivas Rewrite provavelmente ajudaria (já que vejo isso como uma questão de escopo). As reescritas estão no contexto VirtualHost, Document-Root, Directory?

A maior diferença que vejo nos seus posts entre sucesso e fracasso é:

Relativo

RewriteCond img/$2/$3/$4/$1 -f

Absoluto

RewriteCond /usr/local/var/myapp/images/$2/$3/$4/$1 -f

O Apache é capaz de encontrar o arquivo, portanto, ele não deve ter permissões ou algo assim. Você está usando alguma diretiva Alias (localhost vs test.com)? Se não, talvez você deva tentar usar o Alias especificamente:

/var/www/myapp/current -> /var/www/myapp/releases/20130418090750

Coloque pelo menos um caminho físico na configuração raiz que não exija um link simbólico. Você pode finalizar suas reescritas em um contexto do Diretório ...

<Directory /var/www/myapp/current/webroot>
    rewrite statements...
</Directory>

O que acontece se você mantiver sua configuração quebrada no test.com, mas onde você tem atualmente links simbólicos, tente copiar diretórios reais (temporariamente) começando na raiz. Apenas verifique se não há alguma configuração do Symlink flutuante. Livre-se de tantos links simbólicos quanto possível e coloque-os de volta em 1 por 1.

    
por 21.04.2013 / 07:32
-1

As backreferences são "up" (rewriteCond) para "down" (RewriteRule). No exemplo que você publica é como "para baixo" para "para cima". E as referências anteriores estão com% não com $.

RewriteCond backreferences: These are backreferences of the form %N (0 <= N <= 9). %1 to %9 provide access to the grouped parts (again, in parentheses) of the pattern, from the last matched RewriteCond in the current set of conditions. %0 provides access to the whole string matched by that pattern.

Você pode tentar isso:

RewriteBase /
RewriteCond %{REQUEST_URI} /img/([a-z0-9]{4})([a-z0-9]{4})([a-z0-9]{4})([a-z0-9]{28}\.\w+)$
RewriteCond %{DOCUMENT_ROOT}/test/%1/%2/%3/%4 -f
RewriteRule .* img/%1/%2/%3/%4 [L]

Primeiro, a expressão regular para encontrar as variáveis. O caminho para o arquivo contendo as variáveis é construído e verificado se o arquivo existe

Eu uso o % {DOCUMENT_ROOT} para teste no meu servidor local. Se você não tem este arquivo de imagem no mesmo DocumentRoot você precisa do PATH COMPLETO como:

RewriteCond /var/www/cache_images/test/%1/%2/%3/%4 -f
    
por 01.02.2014 / 20:44