Como usar URL amigáveis no servidor apache

Com certeza você que desenvolve sites, blogs, portais ou sistemas voltados para ambiente web alguma vez já trabalhou, já pensou em trabalhar ou pelo menos ouviu falar das famosas URL Amigáveis.

URL amigáveis são na verdade o nome “amigável” que damos ao processo de reescrita(rewrite) de URLs afim de padronizar, organizar, otimizar e tornar mais atraente os links de um site. Além é claro de facilitar aos mecanismos de busca uma boa indexação.

Essa reescrita é a capacidade do servidor de aplicações  converter uma URL antes de executá-la. Isso permite a manipulação de barras(/) sem a preocupação de ferir os níveis de diretórios. Por exemplo, imagine o endereço:

www.site.com/index.php?p=noticias&categoria=esportes&id=1055

Confuso né? Difícil de lembrar e “feio” também. Mas usando a reescrita poderíamos tranformar essa URL em algo parecido com:

www.site.com/noticias/esportes/1055

Muito mais elegante, padronizado e fácil de ser encontrada pelo Google, Bing, Yahoo Search e etc.

Bom. Depois de uma breve e informal descrição do que são as URL amigáveis e do que ela pode nos proporcionar, vamos agora ao que realmente interessa. Como configurar, construir e utilizar essas URLs?

Esse é o foco desse post. Só ressaltando que as explicações são voltadas para o servidor apache, pois é gratuito, famoso e mais utilizado no mundo para aplicações php. Em um post futuro falarei sobre o mesmo assunto focando nos servidores IIS.

Então vamos lá.

1º – Como habilitar o módulo de reescrita(mod_rewrite) no Apache?

Se você estiver utilizando uma hospedagem web com apache não se preocupe pois 99% delas já vem com o módulo rewrite habilitado. Se não estiver e você não tiver acesso aos arquivos de configuração(como o httpd.conf) solicite ao seu provedor a habilitação do mesmo. Se estás em um ambiente local, saiba que por padrão no processo de instalação do apache o mod_rewrite vem desabilitado. Para habilitá-lo é só abrir o arquivo de configuração httpd.conf e procurar pelas linhas.

#LoadModule rewrite_module modules/mod_rewrite.so
#AddModule mod_rewrite.c

Se elas estiverem comentadas(com o #), descomente (tirando o #). Deverá ficar assim:

LoadModule rewrite_module modules/mod_rewrite.so
AddModule mod_rewrite.c

Para surtir efeito, salve o arquivo e reinicie o seu servidor apache.

2º – Criando o arquivo .htaccess e definindo as regras de reescrita

O arquivo .htaccess (isso mesmo, arquivo sem nome, só com extensão) é um arquivo de texto para tratar as configurações do apache. Com ele é possível ativar/desativar módulos, restringir acesso a certos arquivos ou pastas, escrever expressões regulares, etc. Ele tem efeito nos arquivos de seu nível de diretório e em todos os sub-diretórios. Logo, o mais interessante é que ele seja criado na raiz do seu projeto.

É dentro do .htaccess que definimos regras de reescritas de URLs. Vamos supor que tenho um pequeno site e que ele possui as páginas Home, Sobre, Noticias e Contato. Vou criar uma regra de reescrita para ele dentro do arquivo .htaccess. Veja:

1
2
3
4
5
RewriteEngine on
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule ^([^/]*)$ index.php?pagina=$1
RewriteRule ^([^/]*)/$ index.php?pagina=$1

Na linha 1 eu “ligo” a engine (motor) de reescrita. Depois coloco 2 condições para que os diretórios e os arquivos não sejam submetidos à reescrita(Ex: Não queremos que os sub-diretórios imagens ou css seja interpretados como amigáveis quando alguem digitar www.site.com/imagens ou www.site.com/css/estilos.css).

Nas linha 4 e 5 eu defino as regras(rule) de reescrita. Coloquei 2 regras para que uma possível barra no final da URL não cause erros. Assim, tanto www.site.com/sobre e www.site.com/sobre/ irão funcionar.

^(.*)$   index.php?pagina=$1 defini que o que for informado depois da barra será atribuído ao parâmetro “pagina” no arquivo index.php

Assim, as páginas do nosso site ficarão assim:

  • www.site.com/home
  • www.site.com/sobre
  • www.site.com/noticias
  • www.site.com/contato

E para facilitar mais ainda, podemos definir dentro de um único arquivo(no caso o index.php) qual página será carregada.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
$pagina = $_GET['pagina'];
 
/* Verifica qual é a pagina a ser incluida */
if($pagina == 'home' || !$pagina) 
   include_once('home.php');
 
else if($pagina == 'sobre')
   include_once('sobre.php');
 
else if($pagina == 'noticias')
   include_once('noticias.php');
 
else if($pagina == 'contato')
   include_once('contato.php');
 
else
   die('Essa página não existe');
?>

Ele pega o parâmetro “pagina” na URL via GET e de acordo com o valor inclui a página correspondente. Se não for uma página válida ele emite um erro (poderia redirecionar para uma página de erro 404).

Agora imaginemos que dentro da parte de notícias agente filtre as mesmas por categorias. Logo precisaremos criar uma nova regra dentro do nosso .htaccess (linhas 6 e 7)

1
2
3
4
5
6
7
RewriteEngine on
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule ^([^/]*)$ index.php?pagina=$1
RewriteRule ^([^/]*)/$ index.php?pagina=$1
RewriteRule ^([^/]*)/([^/]*)$ index.php?pagina=$1&categoria=$2
RewriteRule ^([^/]*)/([^/]*)/$ index.php?pagina=$1&categoria=$2

Note que o $1 é válido para o 1º parametro informado(vem antes da 1ª barra na URL), o $2 identifica o 2º parâmetro(vem antes da 2ª barra na URL), e assim por diante. Adicionei uma nova regra onde é informado a categoria de noticias via URL no parâmetro “categoria“. Assim, poderemos ter os seguintes links de noticias(dentre outros é claro):

  • www.site.com/noticias/esportes
  • www.site.com/noticias/politica
  • www.site.com/noticias/entrenimento

Com isso, faremos uma modificação no index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
$pagina = $_GET['pagina'];
 
if($pagina == 'home' || !$pagina) 
   include_once('home.php');
 
else if($pagina == 'sobre')
   include_once('sobre.php');
 
else if($pagina == 'noticias'){
   $categoria = $_GET['categoria'];
 
   /* Verificar qual é a categoria e incluir a pagina correspondente */
   if($categoria == 'esportes')
      include_once('noticias_esportes.php');
 
   else if($categoria == 'politica')
      include_once('noticias_politica.php');
 
   else if($categoria == 'entretenimento')
      include_once('noticias_entrenimento.php');
 
   else
      include_once('noticias.php');
}
 
else if($pagina == 'contato')
   include_once('contato.php');
 
else
   die('Essa página não existe');
?>

No exemplo cada categoria inclui uma página distinta, mas como o processo de busca das notícias será feito é você quem define.

E pronto! O post de hoje teve como objetivo auxiliar o processo de configuração do apache para a reescrita e como trabalhar com URL amigáveis. Espero que possa ajudá-los.

Abs.

Siga-me no twitter: @rafaelwendel

É formado em Sistemas de Informação, pós-graduado em Sistemas de Banco de Dados e mestre em Educação com foco em Tecnologias Sociocomunitárias. Trabalha como professor de ensino técnico e tecnológico no Instituto Federal de Educação, Ciência e Tecnologia de São Paulo ministrando disciplinas nas áreas de programação, banco de dados, desenvolvimento de projetos e engenharia de software.

Posts relacionados

Comentários

  1. muito bom este tutorial, gostei muito mesmo. só acho que tem um erro ali na linha 5 do .htaccess, pelo menos eu mudei aqui e deu certo…

    RewriteRule ^([^/]*)$/ index.php?url=$1

    a barra esta depois do cifrão, e aqui não estava funcionando quando digitava localhost/urlamigavel/sobre/, então mudei para antes do cifrão e deu certo…

    1. Olá Junior,

      Primeiramente obrigado por sua visita aqui no blog.

      E realmente eu me atrapalhei com as barras. Elas estavam depois dos cifrões e estava dando erro. Mas já consertei no post e também troquei o parametro url por pagina que também estava errado.

      Obrigado pela observação.

      Abs

  2. Boa noite Rafael.
    Antes de mais nada, parabéns pelo site. Excelentes tutoriais.
    Eu sou completamente leigo no contexto de mexer com Apache, faço desenvolvimento estruturado e pra ser mais exato, tenho sistemas já operando dessa forma onde o usuário acessa o caminho absoluto. Não tem segurança alguma, eu sei, mas foi o que deu pra fazer na época e agora é complicado mudar pois o sistema já cresceu absurdamente.
    Bem, essa idéia eu gostaria de implementar, porém, gostaria de saber se é possível usar o .htaccess dessa forma:

    RewriteEngine on
    RewriteCond %{SCRIPT_FILENAME} !-f
    RewriteCond %{SCRIPT_FILENAME} !-d
    RewriteRule ^([^/]*)$ admin.php?pagina=$1
    RewriteRule ^([^/]*)/$ admin.php?pagina=$1
    RewriteRule ^([^/]*)/([^/]*)$ admin.php?pagina=$1&categoria=$2
    RewriteRule ^([^/]*)/([^/]*)/$ admin.php?pagina=$1&categoria=$2

    Ex.:
    ________________________________
    RewriteEngine on
    RewriteCond %{SCRIPT_FILENAME} !-f
    RewriteCond %{SCRIPT_FILENAME} !-d
    RewriteRule ^([^/]*)$ usuario.php?pagina=$1
    RewriteRule ^([^/]*)/$ usuario.php?pagina=$1
    RewriteRule ^([^/]*)/([^/]*)$ usuario.php?pagina=$1&categoria=$2
    RewriteRule ^([^/]*)/([^/]*)/$ usuario.php?pagina=$1&categoria=$2
    _____________________________________

    Ou seja, colocar dentro do .htaccess uma regra para cada tipo de usuário???

    Ex.:
    RewriteRule ^([^/]*)$ admin.php?pagina=$1
    RewriteRule ^([^/]*)$ usuario.php?pagina=$1

    Pois, meu index.php faz a validação do usuário e o direciona para a página inicial correto que busca num diretório todas as páginas que podem ser acessados por aquele usuário em questão

    É possível fazer dessa forma???
    Obrigado desde já..

  3. Opa…
    Ficou meio confuso, mas seria as duas regras juntas:
    Ex.:
    ________________________________
    RewriteEngine on
    RewriteCond %{SCRIPT_FILENAME} !-f
    RewriteCond %{SCRIPT_FILENAME} !-d
    RewriteRule ^([^/]*)$ admin.php?pagina=$1
    RewriteRule ^([^/]*)/$ admin.php?pagina=$1
    RewriteRule ^([^/]*)/([^/]*)$ admin.php?pagina=$1&categoria=$2
    RewriteRule ^([^/]*)/([^/]*)/$ admin.php?pagina=$1&categoria=$2

    RewriteEngine on
    RewriteCond %{SCRIPT_FILENAME} !-f
    RewriteCond %{SCRIPT_FILENAME} !-d
    RewriteRule ^([^/]*)$ usuario.php?pagina=$1
    RewriteRule ^([^/]*)/$ usuario.php?pagina=$1
    RewriteRule ^([^/]*)/([^/]*)$ usuario.php?pagina=$1&categoria=$2
    RewriteRule ^([^/]*)/([^/]*)/$ usuario.php?pagina=$1&categoria=$2

    Agora sim…

  4. Uma outra perguntinha…
    Se não for pedir demais, teria como mostrar como fariamos a passagem de parametros usando a URL amigável???

    Pergunto isso pois realizo, por exemplo, a alteração de um dado no DB, óbvio, e não sei como passaria os parametros via URL amigável…

    Obrigado.

  5. Bom, consegui resolver esse problema Rafael…
    Como o seu blog é bastante visto fica a dica pro pessoal…
    No caso eu só aumentei a quantidade de parametros…
    Desta forma:

    RewriteEngine on
    RewriteCond %{SCRIPT_FILENAME} !-f
    RewriteCond %{SCRIPT_FILENAME} !-d
    RewriteRule ^([^/]*)/$ index.php?usuario=$1
    RewriteRule ^([^/]*)/([^/]*)/$ index.php?usuario=$1
    RewriteRule ^([^/]*)/([^/]*)/([^/]*)$ index.php?usuario=$1&pagina=$2&categoria=$3&id=$4
    RewriteRule ^([^/]*)/([^/]*)/([^/]*)/([^/]*)$ index.php?usuario=$1&pagina=$2&categoria=$3&id=$4

    Dai ficaria da seguinte forma com a url amigável:

    admin/usuarios/ver/4

    Sendo “admin” o tipo de usuário, “usuarios” diretório que eu estou no momento, “ver” o arquivo php para visualizar um usuário em particular e “4” o ID de um usuário em particular que eu estou vendo…

    Obrigado pelo tutorial, ajudou muito!!!

  6. Galera, meu xampp não está funcionando isso ai corretamente naum, é como se ele abrisse a index.php a partir de uma pasta ai num carrega o meu CSS e as imgs

    no meu só funciona corretamente com apenas um paramentro:

    RewriteEngine On
    RewriteCond %{SCRIPT_FILENAME} !-f
    RewriteCond %{SCRIPT_FILENAME} !-d
    RewriteRule ^([^/]*)$ index.php?p=$1

    1. Olá Fábio,

      É porque o navegador entende como sendo um diretório.

      O ideal seria você colocar no head do seu html a url base do site ou da pasta onde voce coloca o conteudo publico do site (imagens, scripts, css e etc)

      <base href="http://urldoseusite.com/" />

      Assim, todos os links do site (inclusive os que importam os css e js) partirão dessa URL como base.

      Espero ter ajudado

      Abs

  7. Olha, mesmo assim ele num funciona com mais de um parâmetro
    estou testando online mesmo..
    Agora gostaria de saber como fazer com mais de 3 parametros… pois num funciona nl online.

    testei isso

    RewriteRule ^([^/]*)/([^/]*)/([^/]*)/([^/]*)$ index.php?pag=$1&categoria=$2&subcat=$3&subsubcat=$4

    mais nada funfa.

    1. RewriteRule ^([^/]*)/([^/]*)/([^/]*)/([^/]*)$ index.php?usuario=$1&pagina=$2&categoria=$3

      As três opções

      como eu configuro aqui para poder funcionar as três opções
      o caminho “Usuario” seria uma pasta a onde estaria o arquivo “pagina” e categoria seria os arquivos

      else if($pagina == ‘noticias’){
      $categoria = $_GET[‘categoria’];

      /* Verificar qual é a categoria e incluir a pagina correspondente */
      if($categoria == ‘esportes’)
      include_once(‘noticias_esportes.php’);

  8. RewriteRule ^([^/]*)/([^/]*)/([^/]*)/([^/]*)$ index.php?usuario=$1&pagina=$2&categoria=$3&assunto=$4

    As três opções

    como eu configuro aqui para poder funcionar as quatro opções
    o caminho “Usuario” seria uma pasta a onde estaria o arquivo “pagina”. O arquivo página vão ter três arquivos diferentes. Noticias, informações e computador

    e “categoria” seriam três pastas (Noticias, informações e computador)
    e “assunto” seriam os arquivos em cada pasta diferente

    como ficaria a configuração

    else if($pagina == ‘noticias’){
    $categoria = $_GET[‘categoria’];

    /* Verificar qual é a categoria e incluir a pagina correspondente */
    if($categoria == ‘esportes’)
    include_once(‘noticias_esportes.php’);

    Aguardo contato obrigado 🙂

  9. Gostei muito da explicaçao, funcionou legal, só que eu tive um problema.
    quando eu abro “meusite.com/fotos” ele funciona certinho, mas eu criei uma pasta chamada “adm”, que faz a postagem de fotos e videos pro site, ai quando eu tento entrar em “meusite.com/adm” ou “meusite.com/adm/index.php”, ele nao encontra e da erro 404.
    procurei bastante no google e nao achei…

    o q faço pra corrigir isso?

    obrigado

  10. Poxa! Até que enfim encontrei uma explicação clara e objetiva sobre este assunto! Foram 2 meses de muito garimpo! Obrigada por este e pelos tutoriais de CodeIgniter, Rafael! Estão me ajudando bastante, pois quero aprender um Framework e o material sobre outros que encontrei eram muito densos [Zend, Cake etc]. O seu está me ajudando bastante mesmo a entender como funciona e o por quê de algumas sintaxes. Mesmo sendo um post antigo.

    Obrigada mesmo!

Deixe um comentário

O seu endereço de e-mail não será publicado.