Rá! Hoje quero falar sobre mod_rewrite. Um módulo para o apache que permite reescrever URL’s. Ele é muito útil em vários sentidos: aumenta a o page rank em buscadores, torna URL’s limpas e inteligíveis, fazendo com que o usuário consiga lembrá-las muito mais rápida e facilmente.
Porém, como todos os outros artefatos que estão por aí, pode complicar ainda mais a vida de um programador, caso não seja usado adequadamente.
Introdução
Como visto no post anterior, onde está descrito algumas vantagens e desvantages de se usar o mod_rewrite, neste post vamos concluir o assunto. Assumindo que você esteja usando Apache com o mod_rewrite habilitado. Também é necessário o uso de arquivos .htaccess: Arquivos ocultos que contém diretivas interpretadas pelo Apache. Para que seu .htaccess funcione, deve se certificar de que a diretiva AllowOverride All esteja nos arquivos de configuração do apache. Ela deve ficar dentro de <Directory />, mais ou menos assim:
AllowOverride All
Basta adicionar ao seus arquivos de configuração do apache ou requisitar seu servidor que o faça.
Conhecendo as diretivas
Antes de mais nada, vamos entender o que o mod_rewrite faz e é capaz de fazer, conhecendo seus parâmetros de configurações.
RewriteEngine on|off
Habilita(on) ou desabilita(off) o uso do módulo mod_rewrite.
RewriteOptions [inherit] [MaxRedirects=X]
Adiciona uma ou as duas opções.
inherit
Herda os parâmetros dos diretórios pai.
MaxRedirects=X
Ao invés de permitir o ‘loop infinito’ de redirecionamento, limita para X vezes. Caso, X seja alcançado, é disparado erro 500 (Internal Error).
RewriteLog /caminho/para/arquivo.log
Escreve o log dos eventos ocorridos no arquivo especificado.
RewriteLogLevel Level
Level inicia em 0 (desabilitado) e vai até 9 (números superiores podem ser utilizados, mas terão o mesmo efeito: irão logar quase tudo! Use somente para debug, pois vai diminuir a performance do apache. Bom para testes/debug, não para produção.)
RewriteBase /dir
Especifica /dir como a base para a procura do arquivo pelo Apache. (Mais explicações adiante)
RewriteCond
Responsável pela condições (a.k.a. IF’s). Pode-se utilizar inúmeros testes antes de especificar uma regra, sendo que a mesma só será executada ao passar por todos os testes com sucesso. Exemplos:
# Se o host for 123.45.67.89 RewriteCond %{REMOTE_ADDR} ^123.45.67.89$ [OR] # ou for 98.76.54.32 RewriteCond %{REMOTE_ADDR} ^98.76.54.32 # A regra será a seguinte...
Podem ser usadas uma série de variáveis, entre elas:
- %{HTTP_USER_AGENT}
- %{HTTP_REFERER}
- %{REMOTE_ADDR}
- %{SCRIPT_FILENAME}
- %{QUERY_STRING}
- %{HTTP_HOST}
- mais informações aqui
É aqui que realmente acontece a reestruturação da URL. Aqui é onde é dito o que deve ser entrepretado como o quê. Se o Padrão casar, o apache interpreta como se fosse o Caminho.
Por exemplo:
RewriteRule ^/(about|aboutme|sobre|sobremim|eu|minhavida)$ eu.html [L,NC]
Referências interessantes:
Exemplos de uso
Agora, com alguma noção sobre o mod_rewrite, vamos utilizá-los. Com alguns exemplos do que é possível. A idéia é que você descubra um jeito próprio e que funcione PARA VOCÊ. Esta é o tipo da coisa que não adianta fazer porque alguém disse que funciona, deve seguir os seus padrões e cobrir suas necessidades.
Exemplo 1: Organizando seu site no .htaccess
Convenhamos: uma notícia sobre um acidente não irá mudar. Depois de submetida para um site de notícias, dificilmente ela irá ser modificada. Ao menos que tenha passado desapercebido um erro de português ou uma estatística imprecisa, uma notícia não será modificada. Portando, é possível manter um cache da notícia em um arquivo .html, evitando consultas desnecessárias a bancos de dados ou outras fontes. Mas só porque ela está em cache, não significa que ela deva aparecer com o .html no fim ou .htm ou seja lá o que for.
RewriteEngine On RewriteBase / # Se não foi requerido um arquivo vazio (-s) RewriteCond %{REQUEST_FILENAME} !-s [OR] # Se não foi requerido um link simbólico (-l) RewriteCond %{REQUEST_FILENAME} !-l [OR] # ou um arquivo (-f) RewriteCond %{REQUEST_FILENAME} !-f [OR] # ou um diretório (-d) RewriteCond %{REQUEST_FILENAME} !-d # Aplique a seguinte regra: # Se for notícia cacheada, chama o cache RewriteRule ^ler/([A-Za-z0-9_-]+)$ /noticias/cache/$1.html [L] # Se for para buscar por noticias RewriteRule ^buscar/([A-Za-z0-9_-]+) /noticias/busca.php?termo=$1&area=noticias [L] # Feeds RewriteRule ^feeds$ feeds.php?area=noticias # Feeds para a categoria X RewriteRule ^feeds/(.*)$ feeds.php?area=noticias&categoria=$1
e assim por diante. Podemos estabelecer regras, inclusive, para subdomínios.
RewriteCond %{HTTP_HOST} ^en\.example\.com$ RewriteRule ^(.*)$ /news/english/index.php?q=$1 [L] RewriteCond %{HTTP_HOST} ^br\.example\.com$ RewriteRule ^(.*)$ /news/brazilian/index.php?q=$1 [L]
uma outra sugestão:
RewriteCond %{HTTP_HOST} ^en\.example\.com$ RewriteRule ^(.*)$ /news/index.php?lang=en&q=$1 [L] RewriteCond %{HTTP_HOST} ^br\.example\.com$ RewriteRule ^(.*)$ /news/index.php?lang=pt-br&q=$1 [L]
Exemplo 2: Listas de traduções
A questão de usar uma única variável que receberá o valor da url, funciona melhor para este segundo caso:
RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f [OR] RewriteCond %{REQUEST_FILENAME} !-s [OR] RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php/$1 [L,NC]
Imagine que seu cliente queira criar páginas novas, de ‘política de privacidade’, ’sobre a empresa’, seja lá qual for o assunto da página. Ele vai querer acessá-la de forma rápida e acessível. Para tanto, index.php?area=view_page&page=4354 não parece agradar muita gente. Não seria interessante deixar que o próprio cliente crie seu padrão de URL? Talvez /politicas ou /empresa.
Existe uma forma interessante de se fazer isso: usando uma lista de expressões regulares e seus arquivos originais, os quais serão usados caso as expressões regulares casarem. Por exemplo, nos casos acima, apenas com o código abaixo no .htaccess, já poderíamos fazer algo:
A idéia é usar a REQUEST_URI (no php $_SERVER['REQUEST_URI']). Ela retornará, por exemplo, /ler/minha_noticia_bombastica que casará com ^/ler/([a-z0-9_-])$ e por consequência, irá chamar a noticias.php. Agora, como pegar o ‘minha_noticia_bombastica’ ? Fácil! Basta apenas utilizarmos os grupos das expressões regulares de forma apropriada. Usando o exemplo do php, com preg_match podemos resolver isso!
$urlPatterns = Array( '/^ler\/([a-z0-9_-]+)$/i' => 'noticias.php' ); foreach ($urlPatterns as $pattern => $fileName) if (preg_match($pattern, $_SERVER['REQUEST_URI'], $vars)) { $_GET = $vars; include $fileName; break; } }
Pronto! Alguns usuários podem ter notado, mas $vars irá ser uma sequência numérica dos grupos casados:
0 => /ler/minha_noticia_bombastica, 1 => ‘minha_noticia_bombastica’
Para resolver isso, podemos dar nomes aos grupos, o que seria extremamente normal para o programador (que utilizaria a variável $_GET normalmente) e bonito aos olhos do cliente. Para tanto, modificamos a nossa $urlPatterns:
$urlPatterns = Array( '/ler\/(?<news -slug>[a-z0-9_-]+)$/i' => 'noticias.php' );</news>
Assim, poderemos acessar $_GET['news-slug']. Como fica mais difícil do usuário modificar nomes de variáveis vindos da URL, se torna uma solução segura. Podemos ter certeza de que $_GET['news-slug'] não conterá aspas, caracateres hexadecimais ou qualquer outro tipo de código malicioso. Pois se tivesse, não passaria no teste da expressão regular. E também nos certificamos de que aquele arquivo (noticias.php) só esteja sendo acessado, caso nossa index.php o esteja incluindo. Porque o usuário não conseguirá acessar de fora.
Neste caso, nós estipulamos os valores na $urlPatterns, mas ainda se pode pegar esses valores do banco de dados, por exemplo. Uma lista de ‘tradução’ para a url. Funciona muito bem, principalmente com páginas estáticas ou fixas. Ao invés do cidadão digitar index.php?area=pages&page_id=4232, ele estará acessando /sobre-a-empresa. Para usuários provenientes de sites de busca, isto é muito importante. Lhe dá muito mais segurança e você garante o seu clique. Ele vai direto ao ponto.
55 comentários
Enviar um comentárioAjuda URL Amigavel
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule ^([^/]*)$ $1.php
RewriteRule noticia_detalhes/(.*)/(.*)/$ /site/noticia_detalhes.php?$1=$2 Olhem os testes: 1) localhost/site/pesquisa_academia.php => localhost/site/pesquisa_academia (Funciona Beleza). Como faço para inserir a barra no final?
2) localhost/site/noticia_detalhes.php?registro=1 => localhost/site/noticia_detalhes/registro/1/ Mostra a página, mas as imagens não aparecem e links não funcionam.
Possível solução
RewriteRule ^([^/]*)$ $1.php
para
RewriteRule ^([^/]*)/?$ $1.php O segundo caso acontece pois a url localhost/site/noticia_detalhes/registro/1/ passa a ser a principal, logo é procurada em /site/noticias_detalhes/registro/1/img/logo.png. Para resolver isso você pode usar a tag (x)html . Procure sobre ela e resolverá o problema. Ou, podes passar o caminho completo
Parabéns
2 parâmetros utilizando urlpatterns
'/(?Pw+\/?Pw+)'=>'index.php', Ou seja, pegando 2 parâmetros, mas não sei como... O.O
Mysql