Picotando e maquiando URLs

Seu site funciona na base do index.php?idpag=23&idproduto=343 ?
Cada vez que você vai passar um URL você tem que explicar o que é a “?” e esses id* da vida?

Acabe com isso, facilite a vida do seu usuário e aumente até o acesso ao seu site com uma simples solução, mod_rewrite. Veja como implementar este módulo do Apache em seu servidor, neste post.

Esta semana foram lançados os Blogs do site ComuniWEB, e com eles um desafio do passado voltou a tona. Como o site é base para um jornal impresso com alguma frequencia procuramos fazer uma ligação chamando a atenção do leitor para o site. No passado isso era feito passando um longo URL “index.php?idpaginas=20&idmaterias=123456”, mas isso é um grande problema pra que lida no dia a dia com usuários leigos que nao entendem o que esta informação significa.

Mesma coisa com os blogs, acessar um endereço do tipo “blog.php?id=fulanosilva” não é nada intuitivo, imaginem acessar os posts antigos deste blog sem usar os conhecidos “permalinks”. A navegação se torna muito mais intuitiva, gerando mais acessos e melhorando o entendimento de logs de acesso.

O processo é simples (agora que consegui enteder :D) você habilita o mod_rewrite, determina as condições e por fim determina como deve ser re-escrito o URL. Claro que na teoria tudo é lindo e fácil, na prática o trabalho sempre é maior.

Primeiro verifique se seu servidor possui o mod_rewrite habilitado no Apache: use um phpinfo(); e verifique a linha “Loaded Modules” da configuração Apache. Caso esteja habilitado podemos seguir em frente, como ilustração vamos desenvolver o exemplo citado abaixo:

URL Original: http://www.domain.com/fulanodetal
URL Final: http://www.domain.com/blog.php?id=fulanodetal

Desta forma o usuário terá uma forma mais rápida de acessar o blog de Fulanodetal.

O servidor deve estar configurado para aceitar arquivos do tipo .htaccess em diretórios, este arquivo permite setarmos configurações extras ou diferenciadas no Apache para esta pasta em específico. É neste arquivo que vamos carregar as configurações. Vou mostrar a estrutura final do arquivo e depois explicar cada pedaço.

RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

RewriteRule ^([^/]*)$ blog.php?id=$1 [L]

Na linha 1 indicamos que nesta pasta devemos ativar o mod-rewrite.
Nas linhas 3 e 4 setamos as condições onde a regra da linha 6 deve ser usada.
Na linha 6 finalmente, falamos o que deve ser feito com a url.

Condições:
Estas condições devem ser respeitadas para que a URL seja re-escrita, neste caso temos duas condições baseadas em flags do CondPattern. Nestas diretivas usamos uma syntaxe Perl de expressões regulares com algumas adições.
O flag !-f se trata da negação do flag -f que indica se o “alvo” é um arquivo válido no servidor
O flag !-d se trata da negação do flag -d que indica se o “alvo” é um diretório válido no servidor
Com isso estabelecemos que se o URL aponta para algo que não seja um arquivo válido ou diretório, ou seja, algo que não existe no servidor, devemos usar a regra em seguida para re-escrever a URL.

Regras de re-escrita:
O comando RewriteRule é o mais importante do grupo, é ele que efetua a re-escrita jogando os elementos nos seus lugares
Neste caso usamos primeiro uma expressão regular para definir os trechos do nosso URL importantes. Quem já sou expressão sabe que cada texto compatível com uma expressão entre ( ) irá retornar como um item $1, $2 após aplicada a expressão. Sabendo isso podemos verificar que a expressão captura tudo que vai além do nosso url, pois o arquivo .htaccess esta na raiz de nossa estrutura de arquivos do servidor.

Pegando tudo que vai além do / em nosso exemplo pegamos fulanodetal e em seguida a expressão mostra onde isso será usado concatenando “blog.php?id=” com $1 (o primeiro match da expressão, fulanodetal). e finalmente após a expressão temos FLAGS especiais, sempre entre [ ] que indicam várias regas, neste caso L significa que está é a última regras a ser aplicada, pulando com isso qualquer outra coisa que estiver no arquivo.

De uma forma geral esta é a estrutura do mod_rewrite, os comandos possuem ainda uma vasta gama de flags e condições que podemos usar, verifique abaixo alguns links que podem ajudar:

Cheatsheet:
http://www.ilovejackdaniels.com/apache/mod_rewrite-cheat-sheet/
Documentação oficial:
http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html
Ferramenta para escrever regras de re-escrita (Wizard)
http://www.mod-rewrite-wizard.com/

32 comentários sobre “Picotando e maquiando URLs

  1. Interessante!
    Gostaria de saber se existe maneira de fazer isso não somente com o index.php. Como funcionaria caso tivesse uma página com index.php, noticia.php, help.php, etc?
    Pesquisei e vi que o index funcionaria como um redirecionador de conteúdo, e essa idéia não me agrada…

    Parabéns pelo artigo!
    []s

  2. Alan,

    No caso você pode alterar facilmente as funções de acordo com a sua necessidade, por exemplo, se você que usar multiplos pontos de entrada como retratou poderia fazer tipo:

    http://www.dominio.com.br/noticias
    apontar para
    http://www.dominio.com.br/noticias.php

    Nesse caso use:
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d

    RewriteRule ^([^/]*)$ $1.php [L]

    Com um pouco mais de alterações voce pode adicionar um código a isso: /noticias/12121 –> noticias.php?id=12121

    Verifique o material que recomendei que conseguirá rapidamente resolver isto.

    Abraços e obrigado pelo feedback.

  3. Olá Rafael

    Tenho q criar apenas um arquivo para todo o site, ou posso criar um para cada diretório?

    Como fazer isso no Windows, já que faço toda a programação utilizando o SO WinXP.

    Parabéns pelo artigo.

  4. Fábio,

    Você pode criar da forma que desejar, tendo apenas que mudar a expressão regular, como mostrei acima para o alan.
    No windows o arquivo é o mesmo e com o mesmo formato, só depende de você utilizar o Apache, seja qual for a plataforma.

    Origado!

  5. Olá Rafael!

    Parabéns (de novo) pelo artigo, me ajudou muito!
    Só tenho uma única dúvida: como se faz quando os parâmetros passados pra urls forem facultativos?
    Assim, podendo ser:
    página.php?id=1
    ou
    página.php?id=&var=foo

    Parabéns pelo artigo!

    Abraços!

  6. Alan,

    Primeiramente obrigado.
    Bem, tudo depende das suas expressões regulares, você tem duas possibilidade de fazer isso:
    – No RewriteRule cada trecho que “combine” com sua expressão é retornada como $1, $2, $3.. então voce pode alterar desta forma.
    – No RewriteCond voce pode usar alguma expressão que defina se você tem 1, 2 ou X variaveis, e aplicar uma regra diferente para cada situação

    Desta forma você pode transformar /materias/234242/2 em materias.php?id=234242&page=2

    Espero ter ajudado.
    Abraço

  7. Mauricio,

    Sim, você poderia usar a solução.
    No caso você poderia fazer uma condição específica para o caso do usuário procurar /webmail, ou até algo mais genérico. Vou tentar te orientar aqui por cima, se tiver algum bug você me avisa.

    RewriteEngine On
    RewriteRule ^webmail$ http://outrodominio.com.br/webmail [L]

    Com isso se seu URL for dominio.com.br/webmail ele fara o redirecionamento de forma estática como mostrei acima, para o endereço novo. Talvez precise botar a “/” no começo, tipo “/webmail” mas acredito que não.

    Verifique se consegue, de qualquer forma, visite o link da “cheatsheet” acima que nela você vai ver alguns exemplos de redirecionamentos de domínio.

    Me avise como ficou! abraço!

  8. Prezado Rafael,

    tenho uma um portal em http://meusite.com.br

    todo em PHP ao entrar no portal vc já vê assim: http://meusite.com.br/login.php

    navegando chegamos a casos extremos como:

    https://meusite.com.br/index.php?menuaction=wiki.uiwiki.view&page=Page

    Gostaria de manter e URL sempre como http://meusite.com.br/ estáticamente, não mudando nunca, sempre emitindo o conteúdo após o root do site.

    Tens alguma idéia de como fazer essa tarefa?

    Fiz alguns testes aqui e fiquei um pouco confuso.

    Parabéns pela iniciativa do artigo 🙂

  9. Rafael , por favo me tira uma pequena dúvida … Eu posso colocar vários regras de rewrites dentro do mesmo htaccess ?

    por exemplo … eu quero colocar um para o index.php e outro para o redir.php … tem como eu colocar no mesmo arquivo de regras ?

    ainda nao vi nada falando sobre isso !

    algo assim :

    RewriteEngine On
    RewriteRule ^formula1/([^/]*)/([^/]*)/$ /index.php?palavra=$1&formula1=$2 [L]

    RewriteRule ^formula1/([^/]*)/([^/]*)/$ /redir.php?codigo noticia=$1&titulo=$2 [L]

    entendeu mais ou menos ?

    []s
    Leo

  10. Leo,

    Sem problemas, voce so precisa mudar algumas coisas, por exemplo, a flag [L] faz com que o mod não execute mais nada, com isso vc deve ter cuidado com a formula senão nunca vai chegar na segunda regra.
    Outra opção, muito saudadevel por sinal é usar o RewriteCond com isso voce pode definir o que executar dependendo de certas condições, como o redir ou index.

    Espero ter respondido, ou dado uma luz, qualquer coisa pode me mandar um email.

    Abraço

  11. Guilherme,

    Acredito que com o mod_rewirte nao seja possivel fazer da forma como esta descrevendo, sim voce pode re-escrever o URL, mas voce perderia todos os dados ao fazer isso, com isso nao teria navegação. Com o mod o mais perto que voce chegaria seria meusite.com.br/wiki.iki/Page, mais amigavel mais não exatamente o que voce descreveu.

    Outra solução é o uso de frames que tb nao recomendo. Posso estar errado, vou até der uma lida por ai, mas acho que nao é possivel.

    Abraço

  12. Rafael,

    resolvi ,,, mas não fiquei totalmente satisfeito … hehehe

    vc poderia me dar um exemplo da utilização desse RewriteCond … Como eu posso testar se uso o redir ou o index …

    Eu fiz de uma forma meia porca ,,, mas funcional … criei um diretorio e coloquei um novo htaccess para o redir … mas creio que isso não seja o mais elegante a ser feito, certo ?

    Poderia me dar um exemplo básico ?

    Tentei procurar nos sites que vc mencionoi acima .. mas não consegui pescar nada que faça isso …

    []s e obrigado,

  13. Rafael , procurando um pouco mais … achei um forum que fala que eu posso diferenciar qual regra que será utilizada ,,, simplesmente colocando prefix diferentes … tem lógica isso … amanhã vou fazer uns testes ….

    []s

  14. Leo,

    No caso voce usaria uma expressao regular que procura-se redir ou index na URL e dependendo faria a ou b, tipo:

    RewriteCond (procura redir)
    RewriteRule (regra do redir)

    RewriteCond (procura index)
    RewriteRule (regra do index)

    sacou? só preciso ver a expressão regular direito, não é meu forte.

    abraço

  15. root@torio [/home/compreja/www/novo]# more .htaccess
    RewriteEngine On

    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d

    RewriteRule ^([^/]*)/$ index.php?palavra=$1&categoria=99999 [L]
    RewriteRule ^mercadolivre/categorias/([^/]*)/([^/]*)\.php$ /novo/index.php?categoria=$1&extra=$2&controle=1 [L]
    RewriteRule ^mercadolivre/compras/([^/]*)/([^/]*)/([^/]*)\.php$ /novo/redir.php?categoria=$1&extra=$2&extra1=$3 [L]

    Rafael ,,, como eu disse anteriormente ,,, se usar prefix diferentes , o rewrite trata as regras diferentes … veja como usei o mesmo index.php em regras diferentes e qtd de paramêtros diferentes … e usei o redir.php com outros paramêtros ….

    http://www.compreja.net/novo/

    acesse e veja como ficou …

    a primeira regra eu uso para fazer a busca diretamente na url … por exemplo :

    http://www.compreja.net/novo/mp4/

    a segunda regra é para listar o produtos das categorias que ficam no menu a esquerda.

    http://www.compreja.net/novo/mercadolivre/categorias/1144/games.php

    e a terceira é para redirecionar para o produto final :

    http://www.compreja.net/novo/mercadolivre/compras/47400551/nomedacategoria/sony-ericsson-w810i-w810-20mp-512mb-mp3-novo-desbloqueado.php

    Valeu por todas as dicas … foram super importantes

    []s
    Leo

    PS: Use resolução 1024 … pois 800×600 vai bagunçar um pouco …

  16. Leo,

    Bacana, eu imaginei que o RewriteRule tb fosse capaz de fazer a seleção, o Cond é só um pouco mais organizado na minha opinião. Obrigado pelas visitas, que bom que o artigo foi útil para você.

    Abraços

  17. Ok! Valeu …

    Comprei um livro legal sobre o tema ,,, DEFINITIVE GUIDE TO APACHE MOD_REWRITE … Mas gastei dinheiro atoa … pois encontrei a versão do mesmo em pdf … hahaha

    Mas faz parte do aprendizado …

    []s
    Leo

  18. Estou com uma dúvida em PHP, qual seja: tenho um site que redireciona para um outro site. Depois que ele chegasse no 2o. site, fizesse o que tinha que fazer e retornasse para o primeiro. Acontece que o primeiro site é meu e tenho total domínio e o segundo é de um particular. O que está acontecendo… eu redireciono e quando chega no 2o. site fica lá… queria que depois de um determinado tempo, ele retornasse para o primeiro, no caso o meu. Pode me ajudar nisso?

    Obrigado.

  19. Hello!, I’m with a very big problem, hehe.
    the thing is I have to make a download manager with members, and i already tryed everything that i found out ther, like using the header(), etc…
    But the problem is with the F****** IE, he have’s tath rule of security and, when its going to download the file, it stops all the precess and, ir try to download again, and then it comes the same thing on and an other.
    So, i’m trying to doing something with the RewriteRule, to hidde the really path of the file, and only show a “alias” of the pass, and then I will have to remove the line of RewriteRule, becouse the user will have the path anyway…

    Thanks for read all these, hehe.
    Really thanks.

    Bye.
    Sebas.

  20. Caro Rafael,

    Eu uso mod_rewrite no meu site com o seguinte contudo do .htaccess :

    RewriteEngine on
    RewriteRule ^([a-z,0-9,A-Z,_-] )$ /index.php?page=$1

    Até o momento usei dessa forma … hoje sinto a necessidade de acrecentar mais um “parametro” na minha url (/index.php?page=$1&sub=$2).

    Porem gostaria de continuar utilizando a regra anterior, o mod-rewrite consegue gerenciar as duas solicitações independentes?

    Fico grato por vossa atenção !

    []´s
    Lyon

  21. Amigo, você sabe me dizer como esse mod_rewrite se comporta com muitas regras? digamos…. em torno de 10000 regras….

  22. Μου αρέσει το διάβασμα και έχω συλλάβει αυτή την ιστοσελίδα πήρε κάποια πραγματικά χρήσιμα πράγματα σε αυτό!

Os comentários estão desativados.