Como usar mod_rewrite de verdade

Como visto no post anterior, onde está descrito algumas vantagens e desvantagens de se usar o mod_rewrite

modrewrite

Introdução

Como visto no post anterior, onde está descrito algumas vantagens e desvantagens 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 link simbólico (-s)
RewriteCond %{REQUEST_FILENAME} !-s [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.

 

vi aqui

Escrito por Portalpower

É pai de família, especialista em WordPress e na produção de conteúdo de tecnologia e otimização para conquistar as melhores posições no Google.

Full Stack na vida, Youtuber Gamer Tech, apaixonado por tecnologia, gosta de silêncio e brownie com café ou Coca-Cola.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *