Como usar mod_rewrite de verdade
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
RewriteRule
É 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=$1e 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.
Posts Relacionados
Por favor, se você deseja opinar, criticar ou até mesmo mandar uma receita de bolo, deixe um comentário! Ou fique atento aos feeds.
Comentários
Que bom que lhe serviu! É uma satisfação saber que, de fato, alguém pôde aproveitar/tirar algo dos meus posts.
Obrigado pelo elogio!
Muito bom o post!
Encontro muita coisa sobre rewrite na internet.. mas seu artigo prova que um bom conteúdo tem que estar aliado a forma de se escrever.
só uma dúvida..
por exemplo… quero q as imagens,css,js que são chamados pelo html sejam direcionados a um certo diretório
html-> src=”/images/imagem.png”
rewrite -> /public/beck/images/imagem.png
seria possivel?
Obrigado pelo elogio!
Não sei se entendi direito. O Apache apenas consegue enxergar arquivos que estiverem dentro do teu DocumentRoot ou do DocumentRoot de outro virtualhost. O que é possÃvel fazer, é o seguinte:
RewriteRule ^/images/(.*)\.(jpg|png|jpeg|gif)$ /public/beck/images/$1.$2
Veja se funciona!
EXCELENTE!!!
Brow cada dia que passa vc c supera com a simplicidade e qualidade de seus POSTS…
F1 é nois queirois ^^
ola, Gustavo
eu por ex quero criar o subdominio: videos.meusite.com/
mas quando eu uso esse codigo abaixo:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(www\.)?videos\.meusite\.com$ [NC]
RewriteCond %{REQUEST_URI} !^/videos/
RewriteRule ^(.*) /videossexo/$1 [L,R]
aparece no navegador: videos.meusite.com/videos
como elimino esse “/videos” para somente aparecer videos.meusite.com?
email: guganet@hotmail.com
agradeço! abs!
gustavo
Muito bom post. Parabéns.
Só estou com um probleminha, fiz o Exemplo 2: Listas de traduções e quando coloco o .htaccess no servidor o site nem abre mais da erro 500 Internal server erro. O que seria isso!? Será que tem algo desabilitado no apache? Pelo phpinfo consigo ver se está tudo que preciso habilitado no servidor?
Valeu. à todos, se puder responder agradeço de verdade, pois estou precisando muito, e esse post esta espetacular.
o Erro 500, internal error, é geralmente um erro ocorrido decorrente à má configuração do .htaccess.
Antes de mais nada, eu entraria em contato com o seu servidor para verificar se ele permite mod_rewrite e se o seu domÃnio possui AllowOverride All.
Caso não resolva, então poste exatamente o .htaccess do seu servidor pra gente dar uma olhada ;P
Estou com um problema grave com um subdominio em joomla!
http://www.nomedosite.com/subdominio acessa o sub e os links perfeitamente.
subdominio.nomedosite.com acessa o sub e os links ao acessar da erro 500!
Agradeço desde já!
Antonio Bruno, você pode nos mostrar o .htaccess ?, como falei antes, erro 500 é geralmente decorrente a algum problema na configuração do .htaccess
[...] mais informações ver o blog do Gustavo Dutra que foi o cara que me ajudou nesse .htaccess [...]
Obrigado pelo excelente post.
Procurei em um monte de posts sobre esta informação e nenhum deles falava sobre a opção “AllowOverride” que a única coisa que me faltava para funcionar o que eu precisava!!





Que ótimo artigo!
Acabei de ficar ‘irritado’ rsrsrs
Enquanto posts sem sentido algum, pela web, estão cheios de comentários e agradecimentos, posts como esse estão quase que na escuridão… Uma pena.
Ótimo post! Conferindo o blog já!
Abraços!