O mod_rewrite do Apache e a variável REQUEST_URI do PHP

3

Eu tenho um problema com o Apache passando para a variável PHP $_SERVER['REQUEST_URI'] a URL depois que ela foi reescrita, em vez da original solicitada.

Estou fazendo isso reescrevendo porque eu tinha um site WordPress e queria movê-lo para um subdiretório em vez de tê-lo em um caminho raiz, mas ainda queria manter sua URL para ser o URL raiz.

Isso não acontece de forma consistente. Se eu pedir www.xyz.com/wp-admin ele preenche a variável PHP REQUEST_URI com www.xyz.com/wordpress/wp-admin (que é a URL depois de ter sido reescrita), mas se eu solicitar www.xyz.com/wp-admin/ (com uma barra final) ela realmente preencherá o PHP REQUEST_URI variável com www.xyz.com/wp-admin/ (o URL original, antes da reescrita). O que eu quero é que o REQUEST_URI seja preenchido com o URL antes que ele seja reescrito.

Meu arquivo .htaccess está abaixo:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(www.)?xyz.com$
RewriteCond %{REQUEST_URI} !^/wordpress/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /wordpress/$1
RewriteCond %{HTTP_HOST} ^(www.)?xyz.com$
RewriteRule ^(/)?$ wordpress/index.php [L]
</IfModule>'

A versão do PHP é 5.3. A versão do Apache é 2.4 (Win32).

UPDATE : examinei mais e quando digito o URL www.xyz.com/wp-admin , há um redirecionamento 301 primeiro para www.xyz.com/wordpress/wp-admin/ , mas isso não acontece para www.xyz.com/wp-admin/ (com um barra final). Para aquele com a barra final existe apenas a reescrita, como esperado. Então, a questão agora é por que o redirecionamento 301 acontece em primeiro lugar para o URL sem a barra final.

Para esclarecer, não há uma pasta real /wp-admin/ , mas existe uma pasta /wordpress/wp-admin/ .

    
por Mg512 21.02.2017 / 01:31

1 resposta

1

O "problema" está relacionado a mod_dir (embora mod_dir não seja estritamente "o" problema - ele está fazendo a coisa certa e "corrigindo" a URL).

Como wp-admin é um diretório físico, mod_dir "corrige" o URL anexando uma barra final (necessária para servir corretamente o índice do diretório, por exemplo, index.php ). Isso é feito com um redirecionamento 301. O problema é que isso está ocorrendo após sua reescrita interna, o que resulta na reescrita sendo transformada em um redirecionamento, expondo assim o seu subdiretório /wordpress .

Portanto, o URL correto é estritamente /wp-admin/ (com uma barra à direita). Se você não tivesse o subdiretório /wordpress e tudo estivesse na raiz do documento, mod_dir simplesmente redirecionaria /wp-admin para /wp-admin/ , o que resultaria em /wp-admin/index.php sendo servido (como uma sub-requisição interna).

O que você precisa fazer é anexar a barra final manualmente. Se o URL solicitado não terminar em uma barra, mas, caso contrário, seria mapeado para um diretório físico no subdiretório /wordpress , em seguida, anexe a barra final (por meio de um redirecionamento externo). Esse redirecionamento deve ocorrer antes das suas reescritas internas.

Então, tente o seguinte antes de suas diretivas existentes:

# Append a slash if it is omitted and would map to a directory
RewriteCond %{REQUEST_URI} !^/wordpress/
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{DOCUMENT_ROOT}/wordpress/$1 -d
RewriteRule (.*) /$1/ [R=302,L]

O que isso significa é que, para qualquer solicitação que ainda não tenha iniciado /wordpress/ e não termina em uma barra, mas mapeia para um diretório físico no subdiretório /wordpress , em seguida, redireciona e anexa uma barra. Assim, uma solicitação para /wp-admin é redirecionada /wp-admin/ , fornecendo /wordpress/wp-admin como um diretório. (Suas reescritas internas encaminham o URL como antes).

Você precisará verificar se o cache do seu navegador está desmarcado (ou testar com o inspetor de objetos do navegador aberto e desabilitar o cache), já que os redirecionamentos 301 anteriores (por mod_dir) terão sido armazenados em cache.

Quando tiver certeza de que está funcionando OK, altere o redirecionamento 302 (temporário) para 301 (permanente) - se for essa a intenção. 302s são armazenados em cache pelo navegador, portanto, torna o teste um pouco mais fácil.

Além de:

...Apache passing to the PHP $_SERVER['REQUEST_URI'] variable the URL after it has been rewritten rather than the original one requested.

O Apache na verdade não passa a variável REQUEST_URI do mod_rewrite para o PHP diretamente. Embora essas duas variáveis tenham o mesmo nome, até onde eu sei, o próprio PHP preenche essa variável a partir da requisição.

A variável do servidor Apache REQUEST_URI e $_SERVER['REQUEST_URI'] superglobal do PHP na verdade contêm informações diferentes:

  • O $_SERVER['REQUEST_URI'] do PHP contém a string de consulta, a variável de servidor REQUEST_URI do Apache não.
  • O $_SERVER['REQUEST_URI'] do PHP contém o caminho de URL original da solicitação, não o URL reescrito. Enquanto que a variável de servidor REQUEST_URI do Apache é atualizada (em todo o pedido) para conter o URL reescrito.
por 21.02.2017 / 10:24