Apache .htaccess RewriteRule e ErrorDocument

2

Eu tenho um arquivo .htaccess :

RewriteEngine On
DirectorySlash Off

RewriteCond %{REQUEST_URI}  !(\.css|\.js|\.png|\.jpg|\.mp4|\.ttf|\.eot|\.woff)$
RewriteRule ^(.*)$ ?page=$1 [NC,L,QSA]

ErrorDocument 404 /e404
ErrorDocument 403 /e404
ErrorDocument 500 /e500

E uma função PHP que verifica se o URI solicitado existe. Se o URI existir no banco de dados, ele obterá o conteúdo e renderizará a página. Caso contrário, obterá o conteúdo da página de erro 404 e renderizará a página. (Tudo está OK aqui)

O problema é quando eu uso um URI com extensões que estão dentro da parte RewriteCond do arquivo .htaccess , algo como example.com/file.css . Nesse caso, a página é redirecionada para example.com/e404 (é o que eu quero) . O problema aqui é:

Eu não sei como obter o "URI errado" usado antes de redirecionar para example.com/e404 , porque quando a página de erro é carregada, eu tenho uma função dentro da página para inserir o "URI errado" no banco de dados.

    
por Soheyl 08.11.2018 / 14:58

1 resposta

3

> Aparte: As diretivas que você postou criariam um loop de reescrita em qualquer instalação padrão do Apache, então talvez você tenha outras diretivas ou uma configuração diferente que você não esteja revelando na sua pergunta? De qualquer forma, ignorando isso por enquanto, já que você não parece estar tendo um problema como esse.

I don't know how to get the wrong URI used before redirecting to example.com/e404 ...

Mas você precisa obter essas informações antes "redirecionando"? No PHP você pode simplesmente verificar o $_SERVER['REQUEST_URI'] superglobal para obter esta informação (o URL que resultou no 404). No entanto, observe que isso contém o prefixo da barra e a string de consulta (se houver), que o parâmetro page URL não conteria de outra forma.

Além disso, apenas para esclarecer a terminologia, isso não é estritamente um "redirecionamento" para example.com/e404 . Um "redirecionamento" implica um redirecionamento HTTP externo. O Apache emite uma subrequest interna para o documento de erro (que é semelhante a uma reescrita de URL, mas não exatamente).

Um dos possíveis problemas com o seu código é que a resposta 404 é veiculada de uma forma bastante aproximada:

  1. Se file.css não existir, o Apache acionará uma subrequição interna para /e404
    (isso desencadeia outra rodada de processamento ...)
  2. Como /e404 não termina em uma das extensões de arquivo declaradas, ela é novamente reescrita em ?page=e404 (presumivelmente index.php ?).

Devido à (desnecessária) segunda reescrita, outras variáveis de servidor, como REDIRECT_URL e REDIRECT_QUERY_STRING (que também são passadas para o PHP $_SERVER superglobal) não são definidas como esperado. Normalmente, eles seriam definidos como "URI errado" (ou seja, a URL solicitada que acionou o 404), mas, em vez disso, contêm detalhes do próprio documento de erro.

Você deve fazer o acima em uma etapa e evitar a segunda reescrita. Por exemplo (assumindo que index.php é o arquivo que manipula o pedido), o documento de erro deve ser definido para o resultado final desejado:

ErrorDocument 404 /index.php?page=e404

Incidentalmente, você não precisa necessariamente passar explicitamente o "status de erro" HTTP (ou seja, e404 ) na URL, pois isso está disponível em $_SERVER['REDIRECT_STATUS'] superglobal do PHP.

RewriteRule ^(.*)$ ?page=$1 [NC,L,QSA]

Eu assumi que você está reescrevendo para index.php (o DirectoryIndex registrado)? Em vez de voltar atrás para deixar o mod_dir emitir uma sub-requisição adicional para o DirectoryIndex, você deve ser explícito e incluir o arquivo para o qual você está reescrevendo na substituição . Por exemplo:

RewriteRule ^(.*)$ index.php?page=$1 [QSA,L]

(A NC bandeira é supérflua aqui.)

I don't know how to get the wrong URI used before redirecting to example.com/e404 ...

Recuando para abordar sua consulta inicial novamente (como um exercício acadêmico ). Você pode fazer isso no Apache 2.4.13+ (embora eu não ache que você precise ). No Apache 2.4.13+ você pode criar um ErrorDocument dinâmico usando expressões do Apache.

Por exemplo, para passar explicitamente o URL-path que causou o erro 404 na URL do próprio documento de erro, você pode fazer algo como o seguinte:

ErrorDocument 404 /index.php?page=%{escape:%{REQUEST_URI}}&error=404

O parâmetro de URL page , em seguida, contém o caminho da URL (que inclui o prefixo da barra, ao contrário da sua reescrita que o exclui). Um parâmetro adicional de error URL envia o status HTTP (embora, como mencionado acima, isso não seja estritamente necessário).

    
por 11.11.2018 / 01:48