Desmistificando URLs amigáveis com php e htaccess (apache)

Boas!!
A quantidade de pessoas que perguntam como fazer URLs amigáveis no forum.imasters é enorme. Seja em WebStandars, SEO ou php, a dúvida é sempre a mesma.

É simples de fazer. Basta ir com calma e procurar entender tudo o que você está fazendo.

A reescrita é para o servidor, e não para você

As suas tags de link e a forma com que vc abrirá os seus conteúdos, você mesmo terá que alterar. Então onde você usava:

<a href="?page=contato">Contato</a>

Agora passará a escrever:

<a href="/contato">Contato</a>

E se precisar de mais parâmetros, indique-os:

<a href="/edit/user/1">Editar usuário</a>

Isso significa, que o servidor irá receber a requisição em /contato, ou /edit/user/1, e com a RewriteEngine, irá traduzir para o que vc realmente queria dizer, que era ?page=contato, ou ?action=edit&model=user&id=1.

Fica muito mais bonito depois de reescrito, mas para isso é necessário que as suas regras traduzam o amigável para a querystring.

Estude expressões regulares

O arquivo .htaccess que é uma “configuração” externa do apache, acessível da sua aplicação, desde que liberado na configuração do servidor, te possibilita a configurar diversas coisas do ambiente. E as RewriteRules fazem ainda mais sentido, e serão mais poderosas se vc souber Expressões Regulares.

Ahh página em branco, erro 500

São duas as possibilidades, ou a sua hospedagem não suporta configuração via htaccess (muito difícil), ou vc cometeu algum erro de sintaxe, e quebrou o servidor, lembra que o htaccess é um arquivo externo de configuração do apache ? pois é, faça algo errado, que vc terá um 500 na tela.

Não é necessário re-startar o servidor após escrever suas regras, mas cuidado com o cache do teu browser, pois uma regra bem escrita pode parecer ainda não estar funcionando, se o chrome cachear a requisição, e continuar te devolvendo erro.

Mãos na massa

Comece, e para isso vc precisa “ligar” a engine de reescrita:

RewriteEngine On

Lembrando que ela já deve estar instalada no apache, a linha acima, apenas “avisa” que vc irá utilizá-la. O meu arquivo para saber se está funcionando e receber a requisição será o teste.php, com o seguinte conteúdo:

<?php 
var_dump($_GET);

O que eu quero é acessar a url /edit/user/1, e receber o seguinte no GET:

array(3) {
  ["action"]=>
  string(4) "edit"
  ["model"]=>
  string(4) "user"
  ["id"]=>
  string(1) "1"
}

Ok, vamos lá.

Primeiro devo identificar as partes da minha URL. /edit/user/1 é composto por um grupo de letras, seguido por uma barra, outro grupo de letras, outra barra e um número.
Simples!

A Expressão Regular para isso é: ([a-z]+)\/([a-z]+)\/([0-9]+)
Básico não ? apenas escapei as barras com barras invertidas, para não quebrar a sintaxe da ER.

O que eu quero realmente receber na aplicação é teste.php?action=$1&model=$2&id=$3, sendo cada $n, o número do grupo em sequência ao que foi casado pela ER anterior.

Sintaxe da regra

Bem simples, é composta por 3 partes:

RewriteRule <regular expression> <url to translate> [FLAGs]

Aplicando ao caso acima, fica:

RewriteRule ^([a-z]+)\/([a-z]+)\/([0-9]+)$ teste.php?action=$1&model=$2&id=$3 [NC,L]

Adicionei ^ no início da ER, para indicar que a requisição deve começar com aquele padrão, e $ para indicar que ali a ER acaba, e não deve casar nada mais diferente disso.
Utilizei as flags [NC] para ignorar sensitive case, então se a url for: http://wbruno.com.br/EdIt/uSeR/1 a ER continua funcionando, e [L] para dizer que se a ER casar, essa é a última regra a ser testada, e deve processá-la, e não continuar procurando mais ERs e ver se outra abaixo dela também casa.

E para /contato, a minha ER fica simplesmente:

RewriteRule ^([a-z]+)\/?$ teste.php?page=$1 [NC,L]

note que os padrões não são conflitantes, então podem coexistir no mesmo htaccess.

Funcionando:
http://wbruno.com.br/scripts/edit/user/1
http://wbruno.com.br/scripts/fale-comigo

Não redirecione tudo para a index

Alguns frameworks e alguns preguiçosos têm a mania de fazer coisas parecidas com isso:

RewriteRule . /index.php [L] #retirei esse do wordpress :p

e ai parsear toda a URL do lado da aplicação.
Eu não aconselho, pois vc terá deixado tudo mais lento, uma vez que um trabalho que deveria ser feito no servidor, foi delegado a aplicação, e agora você é dependente de reescrita, e se por algum motivo ela não for suportada na hospedagem, não irá funcionar sem ela.

Dá para entender o motivo do WP utilizar, pois são tantos padrões, e tantas opções de URL amigável que vc pode configurar, que para a app é até mais simples parsear nela, mas na sua, evite usar. Eu pelo menos prefiro trabalhar assim. =)

E ai ? entendeu #comofas?

Complemento

http://moz.com/blog/htaccess-file-snippets-for-seos

9 Comments

  1. Muito Boa a explicação, embora o método de url amigável que eu utilize seja outro o seu também é excelente. Mas no meu caso o cliente quer que a url apareça

    http://www.imobiliaria.com.br/detalhe_imovel/4-dormitorios-2-banheiros-1-vaga

    E sendo assim para passar N parâmetros de filtros eu preferi deixar a url da seguinte maneira:

    http://www.imobiliaria.com.br/detalhe_imovel/4-dormitorios-2-banheiros-1-vaga/Wasadaskdhauiaasjhdaksdh== onde o hash (que existe só por estética e não por segurança) eu pego com os valores necessários.

    Dá um certo trabalho, exige javascript por conta dos filtros que são acionados através do click, mas fica bom.

    Abraços.

  2. Gostei do artigo embora eu tenha de usar de maneira diferente, ajuda muito. No meu caso uso um pouco de javascript devido aos filtros utilizados na pesquisa e um hash (apenas por estética e não por segurança) para passar os valores. Fica bom também. Tipo assim detalhes_imoveis / 4-dormitorios-5banheiros-1vaga / wuhuasyuewoi==

  3. Ótimo o post. Ainda tenho algumas dúvidas. Vou passar meu problema, talvez ajude alguem

    Estava passando por um problema na qual o wordpress sempre rescrevia o htacess do wordpress (depois de um tempo).

    Isso acontecia quando mudava a Rewritebase para um diretorio (mvcsobralcupom) na própria raiz do www/ que tinha uma outra configuração htacess

    Ou seja, as configurações htacess do wordpress estavam sendo usadas no meu framework,( funcioando o.O …) e de vezes o wordpress rescrevia de volta o htacess (www/) e bugava meu mvc.

    Em uma conversa com amigo mais experiente na área (:= Marcos Brasil), ele me deu algumas conclusões do que poderia estar acontecendo, o wordpress fazia isso pois a RewriteBase estava apontada para um diretorio diferente da index.php (da www/) e a rescrevia… de volta para as configuraçoes da wp-admin

    _________________________________
    /*Htacess wordpress*/

    # BEGIN WordPress
    
    RewriteEngine On
    RewriteBase /mvcsobralcupom /*Estava fazendo isso e voltava para /  */
    RewriteRule ^index\.php$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.php [L]
    
    
    # END WordPress

    /*Essa parte era um problema quanto o dns com e sem www que tava bugando*/

    RewriteCond %{HTTP_HOST} ^www\.sobralcupom\.com\.br$
    RewriteRule ^/?$ "http\:\/\/sobralcupom\.com\.br\/" [R=301,L]

    _________________________________
    /*seque o htacess /mvcsobralcupom*/

    RewriteEngine on
    RewriteBase /
    RewriteCond %{SCRIPT_FILENAME} !-f
    RewriteCond %{SCRIPT_FILENAME} !-d
    RewriteRule ^(.*)? index.php?url=$1

    /*percebi que esta configuração estava indo para o wordpress devido a RewriteBase/ e talvez esse fosse o motivo de rescrita do wordpress dando sempre pag 404 :(*/
    _________________________________
    /*minha solução– funfando– htacess /mvcsobralcupom*/

    RewriteEngine on
    RewriteBase /mvcsobralcupom
    RewriteCond %{SCRIPT_FILENAME} !-f
    RewriteCond %{SCRIPT_FILENAME} !-d
    RewriteRule ^(.*)? index.php?url=$1

    /*Desta forma ao acessar este diretorio ele vai reconhecer para onde deve ser aplicado estas configurações 🙂 /mvcsobralcupom*/

    Eis uma solução…Desde já agradecido…

  4. Tenho um sistema que ele ta em

    /admin/verservidor

    nesse ver servidor ele possui um link para

    /admin/php/pago?i=430&s=nao

    onde i= id do servidor
    onde s= sim/nao

    queria fazer url amigavel com esse link e nao consigo
    lembrando que a pagina pago é com .php

  5. Parabéns!!! muito bom, me ajudou muito a desmitificar isso.

  6. Olá fiz um teste. Estou aprendendo ainda e me deparei com a seguinte duvida. Se eu fizer como está no tutorial dessa forma:

    RewriteRule ^([a-z]+)\/?$ teste/teste.php?page=$1 [NC,L]
    eu tenho como resultado
    array(1) { [“page”]=> string(7) “contato” }

    Mas se eu fizer dessa forma:
    RewriteRule ^contato/?$ teste/teste.php?page=$1 [NC,L]
    me tenho como resultado
    array(1) { [“page”]=> string(0) “” }

    Nas duas formas, page não deveria ser page=contato ?

  7. Tenho o php 7 instalado e como ele ja vem com o servidor embutido para rodar, as configurações que estou fazendo no meu apache nao estao surgindo efeito para que o .htaccess funcione…

  8. Vinicius Ribeiro

    agosto 23, 2016 at 21:20

    Funciona perfeitamente!
    Tive problemas em relação ao CSS e JS que não carregavam.
    Descobri que basta colocar no “head” a meta tag BASE que funciona perfeitamente.

    Se alguém enfrentar algo parecido, fica a dica.

    OU

Deixe uma resposta

Your email address will not be published.

*