Dicas para depurar .htaccess rewrite regras

Muitos pôsteres têm problemas ao depurar suas instruções RewriteRule e RewriteCond dentro de seus arquivos .htaccess . A maioria deles está usando um serviço de hospedagem compartilhada e, portanto, não tem access à configuração do servidor raiz. Eles não podem evitar o uso de arquivos .htaccess para rewrite e não podem habilitar um RewriteLogLevel “como muitos entrevistados sugerem. Também há muitas armadilhas específicas do .htaccess e as restrições não são cobertas bem. Configurando um teste local A pilha LAMP envolve muito de um curva de aprendizado para a maioria.

Então meu Q aqui é como nós recomendamos que eles depurem suas próprias regras. Eu forneço algumas sugestões abaixo. Outras sugestões seriam apreciadas.

  1. Entenda que o mecanismo mod_rewrite percorre os arquivos .htaccess . O mecanismo executa esse loop:

     do execute server and vhost rewrites (in the Apache Virtual Host Config) find the lowest "Per Dir" .htaccess file on the file path with rewrites enabled if found(.htaccess) execute .htaccess rewrites (in the user's directory) while rewrite occurred 

    Portanto, suas regras serão executadas repetidamente e, se você alterar o caminho do URI, poderá executar outros arquivos .htaccess se existirem. Portanto, certifique-se de terminar este loop, se necessário, adicionando RewriteCond extra para impedir que as regras sejam triggersdas. Exclua também qualquer nível inferior. .htaccess rewrite os conjuntos de regras, a menos que a intenção explícita de usar conjuntos de regras de vários níveis.

  2. Certifique-se de que a syntax de cada Regexp esteja correta , testando um conjunto de padrões de teste para garantir que seja uma syntax válida e faça o que você pretende com um intervalo completo de URIs de teste. Veja a resposta abaixo para mais detalhes.

  3. Construa suas regras incrementalmente em um diretório de teste. Você pode fazer uso do “executar o arquivo .htaccess mais profundo no recurso de caminho” para configurar um diretório de teste (tree) separado e definir os conjuntos de regras de debugging sem estragar suas regras principais e parar o funcionamento do seu site. Você precisa adicioná-los um a um, porque essa é a única maneira de localizar falhas em regras individuais.

  4. Use um esboço de script fictício para despejar variables ​​de servidor e ambiente . (Veja a Listagem 2 ) Se seu aplicativo usa, digamos, blog/index.php então você pode copiar isso em test/blog/index.php e usá-lo para testar suas regras de blog no subdiretório de test . Você também pode usar variables ​​de ambiente para certificar-se de que o mecanismo de reescrita na interpretação de seqüências de caracteres de substituição corretamente, por exemplo,

     RewriteRule ^(.*) - [E=TEST0:%{DOCUMENT_ROOT}/blog/html_cache/$1.html] 

    e procure por estas variables REDIRECT_ * no dump phpinfo. BTW, eu usei este e descobri no meu site que eu tive que usar %{ENV:DOCUMENT_ROOT_REAL} lugar. No caso do loop do redirecionador, as variables REDIRECT_REDIRECT_ * listam o passo anterior. Etc ..

  5. Certifique-se de não ser mordido pelo cache do seu navegador incorretamente redirecionamentos 301 . Veja a resposta abaixo . Meus agradecimentos a Ulrich Palha por isso.

  6. O mecanismo de reescrita parece sensível a regras em cascata dentro de um contexto .htaccess , (isso é onde um RewriteRule resulta em uma substituição e isso cai para outras regras), como eu encontrei bugs com sub-pedidos internos (1) e processamento PATH_INFO incorreto que muitas vezes pode ser evitado pelo uso dos sinalizadores [NS], [L] e [PT].

Mais algum comentário ou sugestão?

Listagem 1 – phpinfo

 <?php phpinfo(INFO_ENVIRONMENT|INFO_VARIABLES); 

Aqui estão algumas dicas adicionais sobre regras de teste que podem facilitar a debugging de usuários em hospedagem compartilhada

1. Use um agente de usuário falso

Ao testar uma nova regra, adicione uma condição para executá-la apenas com um agente de usuário fake que você usará para suas solicitações. Dessa forma, isso não afetará mais ninguém em seu site.

por exemplo

 #protect with a fake user agent RewriteCond %{HTTP_USER_AGENT} ^my-fake-user-agent$ #Here is the actual rule I am testing RewriteCond %{HTTP_HOST} !^www\.domain\.com$ [NC] RewriteRule ^ http://www.domain.com%{REQUEST_URI} [L,R=302] 

Se você estiver usando o Firefox, poderá usar o User Agent Switcher para criar a string e teste do agente do usuário falso.

2. Não use 301 até terminar os testes

Eu vi muitos posts onde as pessoas ainda estão testando suas regras e estão usando 301’s. NÃO .

Se você não estiver usando a sugestão 1 em seu site, não apenas você, mas quem visitar seu site no momento será afetado pelo 301.

Lembre-se de que eles são permanentes e agressivamente armazenados em cache pelo seu navegador. Use um 302 até ter certeza, então mude para 301.

3. Lembre-se de que os 301 são armazenados em cache agressivamente no seu navegador

Se sua regra não funcionar e parecer correta para você, e você não estiver usando as sugestões 1 e 2, faça um novo teste após limpar o cache do navegador ou enquanto estiver navegando.

4. Use uma ferramenta HTTP Capture

Use uma ferramenta de captura de HTTP, como o Fiddler, para ver o tráfego HTTP real entre o navegador e o servidor.

Enquanto outros podem dizer que seu site does not look right , você pode ver e reportar que all of the images, css and js are returning 404 errors , rapidamente reduzindo o problema.

Enquanto outros relatarão que você started at URL A and ended at URL C , poderá ver que eles começaram no URL A, were 302 redirected to URL B and 301 redirected to URL C Mesmo se a URL C fosse o objective final, você saberia que isso é ruim para o SEO e precisa ser corrigido.

Você poderá ver headers de cache que foram definidos no lado do servidor, solicitações de repetição, headers de solicitação de modificação para testar ….


Teste de reescrita .htaccess on-line

Eu encontrei esta ajuda Googling for RegEx, me poupou muito tempo de ter que fazer o upload de novos arquivos .htaccess toda vez que faço uma pequena modificação.

do site:

testador de htaccess

Para testar suas regras de reescrita do htaccess, basta preencher o URL para o qual você está aplicando as regras, colocar o conteúdo do seu htaccess na área de input maior e pressionar o botão “Verificar agora”.

Não esqueça que nos arquivos .htaccess é uma URL relativa que é correspondida.

Em um arquivo .htaccess o seguinte RewriteRule nunca corresponderá:

 RewriteRule ^/(.*) /something/$s 

Certifique-se de que a syntax de cada Regexp esteja correta

testando um conjunto de padrões de teste para garantir que seja uma syntax válida e faça o que você pretende com uma gama completa de URIs de teste.

Veja regexpCheck.php abaixo para um script simples que você pode adicionar a um diretório privado / teste em seu site para ajudá-lo a fazer isso. Eu mantive este breve em vez de bonito. Apenas após isso em um arquivo regexpCheck.php em um diretório de teste para usá-lo em seu site. Isso ajudará você a criar qualquer regexp e testá-lo em uma lista de casos de teste. Eu estou usando o mecanismo PHP PCRE aqui, mas depois de dar uma olhada na fonte do Apache, isso é basicamente idêntico ao usado no Apache. Há muitos HowTos e tutoriais que fornecem modelos e podem ajudá-lo a desenvolver suas habilidades de regexp.

Listagem 1 – regexpCheck.php

 Regexp checker < ?php $a_pattern= isset($_POST['pattern']) ? $_POST['pattern'] : ""; $a_ntests = isset($_POST['ntests']) ? $_POST['ntests'] : 1; $a_test = isset($_POST['test']) ? $_POST['test'] : array(); $res = array(); $maxM=-1; foreach($a_test as $t ){ $rtn = @preg_match('#'.$a_pattern.'#',$t,$m); if($rtn == 1){ $maxM=max($maxM,count($m)); $res[]=array_merge( array('matched'), $m ); } else { $res[]=array(($rtn === FALSE ? 'invalid' : 'non-matched')); } } ?> 

 

" />

 

< ?php for ( $i=0; $i<$maxM; $i++ ) echo "\n"; for( $i=0; $i< $a_ntests; $i++ ){ echo ''; foreach ($res[$i] as $v) { echo '';} echo "\n"; } ?>
Test Vector    Result    \$$i"; echo "
     ',htmlentities($v, ENT_QUOTES,"UTF-8"),'   

Definir variables ​​de ambiente e usar headers para recebê-los:

Você pode criar novas variables ​​de ambiente com linhas RewriteRule, conforme mencionado pelo OP:

 RewriteRule ^(.*) - [E=TEST0:%{DOCUMENT_ROOT}/blog/html_cache/$1.html] 

Mas se você não conseguir que um script do lado do servidor funcione, como você pode ler essa variável de ambiente? Uma solução é definir um header:

 Header set TEST_FOOBAR "%{REDIRECT_TEST0}e" 

O valor aceita especificadores de formato , incluindo o especificador %{NAME}e especificador para variables ​​de ambiente (não esqueça o e minúsculo). Às vezes, você precisa adicionar o prefixo REDIRECT_ , mas eu não trabalhei quando o prefixo foi adicionado e quando não.

Uma de algumas horas que perdi:

Se você aplicou todas essas dicas e está ocorrendo apenas 500 erros porque você não tem access ao log de erros do servidor, talvez o problema não esteja no .htaccess, mas nos arquivos para os quais ele redireciona.

Depois de consertar o problema do .htaccess, passei mais duas horas tentando consertá-lo um pouco mais, embora eu simplesmente tivesse esquecido algumas permissions.

Certifique-se de usar o sinal de porcentagem na frente das variables, não do cifrão.

É %{HTTP_HOST} , não ${HTTP_HOST} . Não haverá nada no error_log, não haverá Erros Internos do Servidor, o seu regexp ainda está correto, a regra simplesmente não corresponderá. Isso é muito horrível se você trabalha muito com modelos de django / genshi e tem ${} para substituição de variables ​​na memory muscular.

Se você estiver criando redirecionamentos, teste com o curl para evitar problemas de cache do navegador. Use -I para buscar apenas headers http. Use -L para seguir todos os redirecionamentos.

Eu encontrei esta pergunta ao tentar depurar meus problemas de mod_rewrite, e definitivamente tem algum conselho útil. Mas no final, o mais importante é certificar-se de que sua syntax de regex está correta. Devido a problemas com minha própria syntax RE, instalar o script regexpCheck.php não era uma opção viável.

Mas como o Apache usa PCRE (Perl-Compatible Regular Expressions), qualquer ferramenta que ajude a escrever PCREs deve ajudar. Eu usei a ferramenta do RegexPlanet com Java e Javascript REs no passado, e fiquei feliz em descobrir que eles suportam o Perl também.

Basta digitar sua expressão regular e um ou mais URLs de exemplo, e ele informará se a regex corresponde (um “1” na coluna “~ =”) e, se aplicável, quaisquer grupos correspondentes (os números na divisão) A coluna corresponderá aos números que o Apache espera, por exemplo, $ 1, $ 2, etc.) para cada URL. Eles alegam que o suporte PCRE está “em beta”, mas foi exatamente o que eu precisava para resolver meus problemas de syntax.

http://www.regexplanet.com/advanced/perl/index.html

Eu teria simplesmente adicionado um comentário a uma resposta existente, mas minha reputação ainda não está nesse nível. Espero que isso ajude alguém.

Com relação a 4., você ainda precisa garantir que seu “esboço de script fictício” seja realmente o URL de destino depois que toda a reescrita estiver concluída ou você não verá nada!

Um truque semelhante / relacionado (veja esta questão ) é inserir uma regra temporária como:

 RewriteRule (.*) /show.php?url=$1 [END] 

Onde show.php é um script muito simples que exibe seus parâmetros $_GET (você também pode exibir variables ​​de ambiente, se quiser).

Isso interromperá a reescrita no momento em que você inseri-lo no conjunto de regras, como um ponto de interrupção em um depurador.

Se você estiver usando o Apache <2.3.9, você precisará usar [L] ao invés de [END] , e você pode então precisar adicionar:

 RewriteRule ^show.php$ - [L] 

No topo do seu conjunto de regras, se a URL /show.php estiver sendo reescrita.

Alguns erros que eu observei acontecem ao escrever .htaccess

Usando ^(.*)$ Repetitivamente em várias regras, usar ^(.*)$ Faz com que outras regras sejam impotentes na maioria dos casos, porque ele corresponde a todas as URLs em um único hit.

Então, se estamos usando a regra para esta url sapmle/url ela também consumirá essa url sapmle/url/string .


[L] sinalizador [L] deve ser usado para garantir que nossa regra tenha processado.


Deve saber sobre:

Diferença em% n e $ n

%n é correspondido durante a parte %{RewriteCond} e $n é correspondências na parte %{RewriteRule} .

Trabalhando de RewriteBase

A diretiva RewriteBase especifica o prefixo de URL a ser usado para diretivas RewriteRule por diretório (htaccess) que substituem um caminho relativo.

Essa diretiva é necessária quando você usa um caminho relativo em um contexto de substituição por diretório (htaccess), a menos que qualquer uma das seguintes condições seja verdadeira:

A solicitação original e a substituição estão abaixo do DocumentRoot (ao contrário de serem acessadas por outros meios, como o Alias). O caminho do sistema de arquivos para o diretório que contém o RewriteRule, sufixado pela substituição relativa, também é válido como um caminho de URL no servidor (isso é raro). No Apache HTTP Server 2.4.16 e posterior, essa diretiva pode ser omitida quando a solicitação é mapeada via Alias ​​ou mod_userdir.

Se você planeja escrever mais do que apenas uma linha de regras em .htacesss,
nem pense em tentar um desses methods de correção para depurá-lo.

Eu desperdicei dias definindo várias regras sem feedback de LOGs, apenas para finalmente desistir de um.
Peguei o Apache no meu PC, copiei todo o site para o HDD e terminei todo o conjunto de regras usando logs rapidamente.
Então eu revi minhas regras antigas que estavam funcionando, eu vi que elas não estão realmente fazendo o que era desejado. Uma bomba-relógio para um endereço diferente.

Há tantas quedas nas regras de reescrita, não é uma coisa lógica direta.
Você pode instalar o Apache em dez minutos, com 10 MB, boa licença, pronto para NIX / WIN / MAC, mesmo sem instalar.
Além disso, verifique as linhas de header do seu servidor e obtenha a mesma versão do Apache do arquivo, se for antigo. Meu OP ainda está no 2.0, muitas coisas não são suportadas.

(Similar à idéia de Doin) Para mostrar o que está sendo correspondido, eu uso este código

 $keys = array_keys($_GET); foreach($keys as $i=>$key){ echo "$i => $key 
"; }

Salve-o em r.php na raiz do servidor e faça alguns testes em .htaccess
Por exemplo, eu quero corresponder URLs que não começam com um prefixo de idioma

 RewriteRule ^(?!(en|de)/)(.*)$ /r.php?$1&$2 [L] #$1&$2&... RewriteRule ^(.*)$ /r.php?nomatch [L] #report nomatch and exit 

Vou deixar isso aqui, talvez com detalhes óbvios, mas tenho que bater a cabeça por horas: tenha cuidado com %{REQUEST_URI} porque o que o @Krist van Besien disse em sua resposta está totalmente certo, mas não com a string REQUEST_URI , porque A saída deste TestString começa com um / . Então tome cuidado:

 RewriteCond %{REQUEST_URI} ^/assets/$ ^ | check this pesky fella right here if missing