A reconfiguração do Apache causa recursão infinita se o subdiretório for solicitado

1

Eu tenho uma regra de reescrita que funciona na maioria das vezes. No entanto, se eu solicitar uma página com um subdiretório que não existe e o subdiretório corresponder a um arquivo existente, ele causará uma recursão infinita.

    Options +FollowSymLinks
    AllowOverride None
    Require all granted

    RewriteEngine on

    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME}\.php -f
    RewriteRule ^(.*)$ $1.php [L]

Isso funciona se eu solicitar:

  • test.php
  • test (serve test.php)
  • badname.php ou badname (fornece 404 corretamente)
  • directory/file_that_exists ou directory/file_that_exists.php

Todo o trabalho. Mas se test.php existir e eu solicitar test/test , isso causará recursão infinita. O log de erros é assim:

[Wed May 23 08:16:28.176564 2018] [core:debug] [pid 27054] core.c(3620): [client 0.0.0.0:57764] AH00122: redirected from r->uri = /test/test.php.php.php
[Wed May 23 08:16:28.176566 2018] [core:debug] [pid 27054] core.c(3620): [client 0.0.0.0:57764] AH00122: redirected from r->uri = /test/test.php.php
[Wed May 23 08:16:28.176568 2018] [core:debug] [pid 27054] core.c(3620): [client 0.0.0.0:57764] AH00122: redirected from r->uri = /test/test.php
[Wed May 23 08:16:28.176570 2018] [core:debug] [pid 27054] core.c(3620): [client 0.0.0.0:57764] AH00122: redirected from r->uri = /test/test

O que estou fazendo de errado? Não deveria falhar quando vir que test/test.php não existe? ( RewriteCond %{REQUEST_FILENAME}\.php -f ) Eu recebo o mesmo resultado se eu simplesmente acrescentar uma barra, como test/ .

    
por felwithe 23.05.2018 / 17:09

2 respostas

2

Shouldn't it fail when it sees that test/test.php doesn't exist? (RewriteCond %{REQUEST_FILENAME}\.php -f) I get the same result if I simply append a slash, like test/

Ele falharia se essa fosse a verificação sendo executada, mas não é.

A variável do servidor REQUEST_FILENAME contém o caminho do sistema de arquivos após a URL foi mapeada para o sistema de arquivos. Isso não é necessariamente o mesmo que o caminho da URL com o qual o padrão RewriteRule corresponde.

Por exemplo, no seu caso, ao solicitar /test/test.php quando não houver um subdiretório físico chamado /test , a variável de servidor REQUEST_FILENAME conterá uma string com o formato /absolute/filesystem/path/to/test (ou seja, a URL solicitada até o último diretório conhecido + o primeiro segmento de caminho /test ). E o caminho da URL correspondido pelo padrão RewriteRule será /test/test.php (ao qual você adicionará repetidamente .php porque /test.php existe, conforme verificado pela diretiva RewriteCond anterior. ).

Você pode resolver isso verificando o caminho do URL (construindo um caminho absoluto do sistema de arquivos para verificar), da mesma forma que o @shanew sugere. Por exemplo:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/$1\.php -f
RewriteRule ^(.*)$ $1.php [L]

Uma otimização, para evitar todas as verificações de sistema de arquivos para cada solicitação, seria incluir uma verificação da extensão .php (e .css , .js , etc.) primeiro, antes de verificar se os arquivos existem :

RewriteCond %{REQUEST_URI} !\.(php|css|js|jpg|png)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/$1\.php -f
RewriteRule ^(.*)$ $1.php [L]

Isso evita verificações desnecessárias quando o URL solicitado já termina com .php , .css , etc.

    
por 23.05.2018 / 18:14
1

Se você estiver fazendo isso em uma seção Diretório ou arquivo .htaccess, você deve ser capaz de parar a recursão infinita adicionando a opção END ao seu RewriteRule, para que fique parecido com isto

RewriteRule ^(.*)$ $1.php [L,END]

Isso impede que o mecanismo de reescrita execute qualquer processamento de reconfiguração subsequente (enquanto L apenas interrompe a atual rodada de processamento de reconfiguração). A documentação do Apache 2.4 Rewrite Flags explica com mais detalhes.

Dito isso, não tenho certeza se isso te dá o comportamento que você realmente quer, já que ele ainda mudará / test / test para /test/test.php apesar do fato de não existir. Para resolver isso, acho que você precisa testar todo o caminho do arquivo, em vez de apenas o nome do arquivo. Para fazer isso, mude:

%{REQUEST_FILENAME}

em

%{DOCUMENT_ROOT}%{REQUEST_URI}

Além disso, por segurança, eu adicionaria outro RewriteCond no topo para que a regra nunca fosse acionada se o nome do arquivo já terminasse em .php (colocando primeiro significa que as outras condições podem ser puladas se retornar true):

%{REQUEST_FILENAME} "!\.php$"

    
por 23.05.2018 / 17:59