Seções iMasters
PHP

Função para criar URL amigável com PHP

Na realidade a URL tem a função de endereçar um determinado recurso na internet, um site, FTP etc. Mas como oportunidade de marketing e vendas, tornou-se importante a usabilidade, SEO (Otimização dos motores de busca) e a acessibilidade, assim gerando a melhora da experiência do o usuário.

Nesse artigo pretendo ensinar uma forma fácil de construir uma função que fique responsável por formatar a URL, tornando-a dinâmica e amigável.

Diferente das demais formas de construção de URL´s Amigáveis, essa forma trabalha com um método de “Alias” (apelidos) para determinado arquivo ou pasta e possibilita a o envio de variáveis via GET.

Obs.: Esse método está sendo aplicado da forma mais simples possível, justamente para melhor entendimento do processo.

Requerimento:

  • Conhecimentos intermediários nas diretivas do Apache;
  • Conhecimentos Intermediários em expressão Regular;
  • Conhecimentos Intermediários em PHP;
  • Apache com o mod_rewrite habilitado.

Primeiramente, criaremos um diretório onde ficará o projeto, vamos chamá-lo de projeto_1.

Dentro desse diretório criaremos três arquivos e um diretório:

  • O arquivo .htaccess, onde criaremos a regra de reescrita da url;
  • O arquivo main.php, que será responsável dela indexação do site;
  • O arquivo url_response.php, onde será codificada a função para o tratamento da url;
  • O diretório applications, onde serão guardados nossos aplicativos ex.: noticias.php, índex.php etc

No arquivo .htaccess vamos criar regras de url usando o mod_rewrite(módulo responsável por reescritas de url) do apache.

# Habilitamos o modo Rewrite

RewriteEngine on

#Aqui, criamos as regras de redirecionamento.

RewriteRule !\.(js|ico|txt|gif|jpg|png|css)$ main.php

Detalhando o arquivo .htaccess

Na diretriz RewriteEngine é possível habilitar(On) ou desabilitar(off) o modo de reescrita do apache. Em RewriteRule configuramos a regra de reescrita das urls, neste caso redirecionamos para main.php.

Feito isso vamos criar e codificar a função responsável por tratar a URL, abra o arquivo url_response.php:

<?php

	//diretório do projeto
	if(!defined(´PROJECT_DIR´))
		define(´PROJECT_DIR´, ´projeto_1´);
		
	// diretório da aplicacao
             if(!defined(´APPLICATION_DIR´))	
		define(´APPLICATION_DIR´, ´applications´);

	// URL enviado
            if(!defined(´REQUEST_URI´))	
		define(´REQUEST_URI´	,str_replace(´/´.PROJECT_DIR,´´,$_SERVER[´REQUEST_URI´]));

	 /**
               * Função Resposável pelo tratamento da URL
               *
               * @author Camilo Teixeira de Melo
               * @link http://www.camilotx.com.br
               * @param string $urlpatterns array com os modelos de url
               * @return void
              **/
	function url_response($urlpatterns){
			foreach($urlpatterns as $pcre=>$app){
				if(preg_match("@^{$pcre}$@",REQUEST_URI,$_GET)){
						include(APPLICATION_DIR.´/´.$app);
						exit();
				}else{
					$msg = ´<h1>404 Página não existe</h1>´;
				}
			}
			echo $msg;
		return;		
	}

?>

Neste trecho:

//diretório do projeto

if(!defined(´PROJECT_DIR´))

define(´PROJECT_DIR´, ´projeto_1´);

Definimos a constante PROJECT_DIR onde conterá o diretório do projeto. No trecho a seguir definimos o diretório da aplicação e a url enviada pelo browser.

// diretório da aplicacao

if(!defined(´APPLICATION_DIR´))

define(´APPLICATION_DIR´, ´applications´);

// URL enviado

if(!defined(´REQUEST_URI´))

define(´REQUEST_URI´ ,str_replace(´/´.PROJECT_DIR,´´,$_SERVER[´REQUEST_URI´]));

Por último a constituição da função url_response responsável pelo tratamento da url.

foreach($urlpatterns as $pcre=>$app){

if(preg_match(“@^{$pcre}$@”,REQUEST_URI,$_GET)){

include(APPLICATION_DIR.´/´.$app);

exit();

}else{

$msg = ´<h1>404 Página não existe</h1>´;

}

}

Aqui é criado um laço responsável por percorrer o array com as URLs padrões e procurar o arquivo na pasta de aplicações, caso exista é feito sua inclusão. Caso não exista o arquivo apresento uma mensagem de página inexistente, ou 404.

Usando a função no arquivo main.php:

<?php
           include(´url_response.php´); 
          $urlpatterns = array(
		´/´=>´index.php´,
		´/noticias´=>´noticias.php´,
		´/noticia/(?P<id_noticia>\d+)´=>´noticias.php´,
           );
          url_response($urlpatterns);
?>

O include não tem segredo. Na array $urlpatterns como o próprio nome diz refere-se aos padrões de url. O índice do array é a url e o valor é o arquivo que deve ser executado.

Exemplo:

´/´=>´index.php´

´/´ refere-se a raiz por exemplo www.dominio.com.br/ que será redirecionado ao índex.php

´/noticias´=>´noticias.php´

´/noticias´ refere-se a www.dominio.com.br/noticias onde executa o arquivo noticias.php

´/noticia/(?P<id_noticia>\d+)´=>´noticias.php´

Aqui eu usufruo da expressão regular para enviar um parâmetro com valor decimal

Via GET. A url ´/noticias/(?P<id_noticia>\d+)´ refere-se a www.dominio.com.br/noticias/12. O valor é acessado via GET para o arquivo notícias.php

Por último criamos os arquivos índex.php e noticias.php na pasta applications.

Abaixo deixo um exemplo simples dos arquivos para melhor entendimento do processo de cada arquivo.

index.php

<?php
        echo ´você está na index´;
?>

noticias.php

<?php
             i f(isSet($_GET[´id_noticia´]))
	         echo ´Exibindo a notícia de id ´ .$_GET[´id_noticia´];
            else
	          echo (´Notícias´);

?>
Mensagem do anunciante:

Em apoio à evangelização do WordPress, os cursos da Apiki são gratuitos para que você possa se especializar na plataforma que mais cresce no mundo. Vagas limitadas, Inscreva-se agora.

Comente também

60 Comentários

Douglas Miranda

Mas só me enrolei um pouco para passar mais parâmetros do array
Se eu quisesse passar mais parametros tipo:

‘/noticia/(?P\d+)’=>’noticias.php’ ,

tipo naum é assim mas achu que você entendeu neh.. tentei de várias formas .. estou errando algum detalhe e não sei qual é?

Camilo Teixeira de Melo

Oi Douglas, tudo bem ?
desculpa responder como comentário é que eu não consegui enviar um email particular para você.
Bom o que aconteceu foi um pequeno detalhe esta parte
o que você me passou é:
‘/noticia/(?P\d+)’=>’noticias.php’ ,
e o correto é:
‘/noticia/(?P\d+)´=>´noticias.php’
foi só um errinho na expressão regular.
qualquer dúvida me add no msn dark_khan@hotmail.com.
Abraços.

    Olá Camilo,
    sobre a pergunta do amigo acima também possuo esta dúvida ….. como passar mais de 1 parametro no mesmo caminho sem dar erro ? no caso seria além de passar o ID_NOTICIA por exemplo passar também o NOME_NOTICIA …. ex: /noticia/1/titulonotica1 ….. tentei fazer adicionando /(?P\S+) …… mas não funciona …
    Obrigado

Lourival Gomes

Ola Camilo, tudo bem?
tentei executar o procedimento acima, mas não obtive sucesso, tem alguma dica que poderia me ajudar.. desde ja eu agradeço.. um abraço

Felipe Oliveira da Silva

É verdade que não é ideal ter hífen seguidos, hífen no começo e no final?
Exemplos:
http://www.imatsers.com.br/-teste/
http://www.imatsers.com.br/-teste-/
http://www.imatsers.com.br/te–ste/

Camilo Teixeira de Melo

Realmente não é ideal no inicio ou no fim.Na realidade o browser interpreta o hifen,%20 como espaço.
por exemplo:
uma url: http://www.camilotx.com.br/materia/funcoes-php não estaria errado pois siginifica que são duas palavras distintas, mas http://www.camilotx.com.br/materia/-funcoes-php. não seria desnecessário esse hifem pois não necessitaria de um espaço na frente da palavra.
Qualquer dúvida estou a disposição.

Douglas Miranda

Estou com dúvida quanto ao tratamento dos parâmetros de URL como nessa parte

/noticia/(?P\d+)’=>’noticia.php’

Como eu faria para passar mais outro parâmetro como: nomenoticia, ou seja passar o idnoticia, nomenoticia ou datanoticia se eu quiser.. não consegui.. e eu chamo-te no msn mas você não recebe minhas mensagens?

Max Oliveira

Ótima dica Camilo..valew

João Neto Coelho Garcias

Como eu faria para transformar > ?includepg=home&cidade=3

Michel Borges

Olá Pessoal estou a com a seguinte dúvida, coloquei o quero transformar a seguinte URL:
http://localhost/br/moveis/produto.php?cdproduto=3
Tranformar em:
http://localhost/br/moveis/produto/3

meu .htacess está dentro do diretorio localhost/br/moveis e está desta forma:

RewriteEngine On
RewriteRule ^([^/]*)/([^/]*)/([^/]*)/([^/]*)\.html$ /$1.php?cdproduto=$2

Não está funcionando, já tentei de tudo li em um monte de sites mas nada acontece. Estou desesperado já. Abraço.
Muito Obrigado.

Marcos Magalhaes

Olá, o script funciona QUASE perfeitamente, mais tem um problema, se o campo da noticia não for em formato ID e for um texto da erro, por exemplo:
‘/categorias/(?P\d+)’=>’exibe_categoria.php’,

Por favor alguem me da um help.

Marcos Magalhaes

Opa, consegui resolver o problema, segue a solução abaixo:

‘/categorias/(?P\S+)’=>’exibe_categoria.php’,

Mais surgiu um novo problema, como eu faço para o sistema de URL amigáveis funcioar apenas nas urls listadas na página “main.php” pois tenho algumas páginas em “php” que não quero passar para “url amigáveis”.

Marcos Magalhaes

Bem amigos, consegui resolver o problema assim tbm, segue a solução:

RewriteRule !\.(js|ico|txt|gif|jpg|png|css|php)$ main.php

Agora surgiu um novo problema no sistema de paginação, como fazer o seguinte?

site.com.br/noticias/1

No caso ou funciona o site.com.br/noticias ou funciona o site.com.br/noticias/1 os 2 juntos não funcionam. Segue o meu código:

‘/(?P\S+)’=>’exibe_categoria.php’,
‘/(?P\S+)/(?P\d+)’=>’exibe_categoria2.php’,

Como podem ver, ate mudei a página colocando um “2” no final, mais nem assim funcionou, espero que alguem possa me ajudar.

Abraços.

Saulo Silva

Fuciona tudo mais ele não reconhece o caminhos das minhas IMG e CSS

Matheus Rennê Balduino Vares

Camilo,
Porque usar \S+ quando a variável vai ser texto?
Não entendi da onde saiu isso.

    Camilo Teixeira de Melo

    foi uma outra pessoa que colocou \S+ na realidade em expressão regular \s é space. o correto é você colocar ou \w+ para strings sem caracteres especiais ou \d+ para decimais.

    Matheus Rennê Balduino Vares

    Certo, fiz uma pesquisa e vi que \w+ \S+ \d+ são sequências de escape do PERL que servem como atalhos para certo metacaracteres. Me corrija se eu estiver errado Camilo.

    Mas e o início da expressão, o ?P. Não achei nada falando a respeito. Poderia explicar?

    Tem algum site objetivo sobre expressões regulares pra indicar?

    E sobre a dúvida do nosso amigo que não reconhece os caminhos das IMGs e do CSS. Como resolver?

    Não quero ser chato, só não quero simplesmente dar CTRL+C CTRL+V… Quero de fato entender o código para fazer minhas adaptações.

    Camilo Teixeira de Melo

    Sim são caracteres de escape. Na realidade a expressão regular usado primeiramente no PERL, pois e uma linguagem forte para manipulação de string.
    já o serve para criar um alias para a array de retorno.

    se quiser posso te passar depois uns estudos de expressao regular. Anota meu msn dark_khan@hotmail.com ai trocamos umas idéias. Abraços.

Douglas Miranda

Para se trabalhar com urls amigáveis a melhor forma que encontrei até hoje foi com o Zend Framework que aliás fornece padrões de desenvolvimento inclusive MVC. A aplicação fica mais robusta, escalável e inteligível. eu aprendi muita coisa sobre urls amigáveis com este post, foi bem produtivo!

    olá amigo Douglas, tudo bem?
    tenho procurado na web mas não tenho tido muito exito, um how to bem específico para urls amigaveis com zend framework…
    se puder me ajudar de alguma maneira ficaria mto agradecido.

    att

Olá, muito bom o tutorial… gostaria de tirar uma dúvida…
eu queria saber como tratar a url quando a pesoa digitar uma palavra composta…

ex:
http://www.xxx.com.br/fale conosco

eu fiz aqui e funciona, mas só quando a palavra é simples, quando é composta ele dá 404.
se puder me ajudar… qualquer coisa meu email: gutoluis753@gmail.com

Agradeço.

Bom, isto é para apenas um parâmetro, como vimos, o id_noticia, e se quisermos utilizar uma sequência de parâmetros ou parâmetros diferentes em sequência para alguns tópicos?

otimo tutorial,

alguem tem ideia de criar uma paginacao com essa função?

Tylër Vortex

Bom, e se eu quiser que os submits do site sejam todos em uma página a parte, a página post.php, como devo criar estas regras no .htaccess de modo que não interfira nas demais?

quero assim: http://site.com.br/post/contact (para submeter um form de e-mail, por exemplo)

att.

Tylër Vortex

Acho que devo modificar aqui em url_response.php

“if( preg_match(“@^{$pcre}$@”,REQUEST_URI,$_GET) ) ”

mas não sei como modificar pra aceitar string como parametro na id….

Olá Camilo, excelente matéria.
Só fiquei num problema que não consigo solucionar.
Fiz tudo conforme você citou acima, sendo que tudo está resultado em “404 Página não existe”.
O que fazer?

cara,
isso é pra localhost e como faço no servidor ?
onde vejo e como ver se essa função está habilitada?
a principio é isso ai pois estou querendo criar um site e ter assinantes gratuitos
ex: http://www.site.com.br/“nome assinante”

[]’s
teh mais

Aê galera,

e se eu quiser deixar meus arquivos soltos no servidor, ou seja, fora da pasta projeto_1, o que devo mudar?

Abraços a todos!!!

Rodrigo Carvalho

Opa, pessoal estou com duas duvidas como que eu posso fazer uma pagina INDEX.PHP e jogar os conteudos das outras paginas dentro da INDEX.PHP para que eu nao precise ficar carregando mas html, segunda duvida tenho uma pagina ‘/produtos/detalhe/(?P\d+)’/(?P\d+)’ / => ‘detalhe_produtos.php’,

como que eu posso pegar esses dois dados ID e o NOME do produto mas ele nao encontra

att

Rodrigo

Émerson

<?

include "config.php";

global $connection;

$query = "SELECT * FROM noticias ORDER BY pdate DESC LIMIT 0, 20";
$result = mysql_query($query) or die("Error: " . mysql_error());

while ($row = mysql_fetch_assoc($result))
{
$titulo = $row['titulo'];
$cidade = $row['cidade'];
$estado = $row['estado'];
echo "$titulo\n”;
} ?>

esse é o resultado do link
portal/perolas.php?id=22-FMI%20alerta%20sobre%20deteriora%E7%E3o%20brusca%20nas%20contas%20p%FAblicas%20do%20Brasil

como eu troco %20 por um digito ou underline…

Michel Camargo

%20 são espaços entre as palavras então faça o seguinte

str_replace(” “, “_” $frase);

A função acima subistitui os espaçõs brancos por underline

EDUARDO COSTA

galeria achei muito legal o post, alguem sabe como usar – ao inves de _ para juntar as palavras

ex: DE: minha_pagina.html PARA minha-pagina.html

tentei alterar o arquivo URL_RESPONSE mas não obtive sucesso.

WilliamF

suauhsauhusahusa, salvo minha pele eu tava buscando algumas maneiras de se trabalhar mais facilmente com URLs Amigáveis fiz uma clas Dispatcher e talz + faltava isso ainda, vlw man, mt bom e a essa URL com a saida seria algo em torno de

noticias/15

ou

noticias:15

Att.WilliamF CLGames.
PortoAlegre, 10 de Março de 2011.

Laercio da Silva

Parabéns Camilo, fez um ótimo artigo, porém que se for possível tirar umas dúvidas contigo, pois não tivi sucesso usando os códigos.

Kaio Marcellus

Camilo, enviei os codigos funcionando perfeitamente em localhost, mas no servidor nada funciona.

Mailson Leal

Olá amigo tudo bem…. sou novo na comunidade e estou com problemas com url amigaveis amigo.

meu link hoje está assim !

http://mailsonleal.com.br/detBlog.php?id=28

Gostaria de melhorar esta minha URL tinha como você me ajudar ?

Rodrigo Bacelli

Quero saber como faço para, por exemplo, transformar minha url http://www.meusite.com.br/produto.php?id=123 em http://www.meusite.com.br/produto/nome_do_produto.html ou algo parecido.

Rodrigo Cirino

estou a semanas tentando entender as URLS amigaveis, não poderia gravar em video, esta ruim de enteder, antes eu achava que era so colocar o htaccess no root, agora me dizem que tem que ter funcao!, copie e colei os arquivos acima, mas nada aconteceu.

Peterson

Olá amigos! Tentei aplicar as técnicas explicadas, mas o que penso e desejo fazer não é simples. Já queimei meus neurônios em vão várias vezes e apesar de não ter desistido confesso que ficou a dúvida: “Será que é possível?”
Tranformar:
http://www.meusite.com.br/index.php?site=vitrine&vitrine=19
Em:
http://www.meusite.com.br/nomedaloja

Bruno Campos

Olá Camilo, me tire essa pequena dúvida aqui: se eu estou na página noticia/12 e tem um link para ir para a index, a url fica assim: “noticia/index”, como fazer para ir diretamente para a index? você saberia me ajudar?! Agradeço desde já!

Daniel

<?php

$topico = $_GET['titulo'];

$noticias = mysql_query("SELECT
id,
thumb,
titulo,
texto,
categoria,
`data`,
autor,
valor_real,
valor_pagseguro,
visitas
FROM up_posts
WHERE titulo= '$topico'
")
or die(mysql_error());
if(@mysql_num_rows($noticias) <= '0'){
echo "$info_not“;
}else{

$numero = ‘0’;

while($res_noticias=mysql_fetch_array($noticias)){

$id = $res_noticias[0];
$thumb = $res_noticias[1];
$titulo = $res_noticias[2];
$texto = $res_noticias[3];
$categoria = $res_noticias[4];
$data = $res_noticias[5];
$autor = $res_noticias[6];
$valor_real = $res_noticias[7];
$valor_pagseguro = $res_noticias[8];
$visitas = $res_noticias[9];
$numero++;

?>

<a href="index.php?topicos=nav/single&topico=“>

esse é o resultado do link

site/index.php?inicio=single&id=GoldenEye%20007:%20Reloaded%20recebe%20as

como eu troco %20 por um digito ou underline…

Dawton Marques

Ótimo artigo, mas ainda não vi o exemplo de passagem com dois parâmetros.
Ex.: noticias/2/611
noticias.php?id=2&cc=611
Como eu faria essa transição?
Obrigado…

Rafael Butt Fernandes Farias

Galera para quem não conseguiu fazer o GET com string ta ae .

$urlpatterns = array(
‘/’=>’index.php’,
‘/pagina’=>’pagina.php’,
‘/pagina/(?P\w+)/(?P\w+)’=>’pagina.php’
);

Espero que ajude.

Abraços,
Rafael B Farias

Lucas Guimarães Felipe

Fala Camilo, beleza?
Implementei sua função e fiz algumas modificações para abranger determinadas situações.
Disponibilizei no Laboratório de Script do iMaster: http://forum.imasters.com.br/topic/470581-url-amigavel/
Abraço!

Marlon Schemberger

Olá. Cara estou tendo um problema, a página principal do site está funfando, a página produto/id está funfando, mas essa página produto/id não está carregando css ou as imgs do site, é como se ela estivesse em outro diretório das demais páginas.

Só pra vc entender estou tentando usar o padrão MVC e separei minha aplicação em

PastaProjeto: contém o arquivo main e o arquivo url responde e tbm uma pasta app
Pasta app: contém a pasta Model, Controller, View, webroot
Pasta View: contém a pasta layout e a pasta page (não vou falar dessas 2 pois vc já deve saber o que cada contém)
e a Pasta webroot (contém os css, js, imgs) não sei pq o produto/id não está carregando, tem como dar uma força ?

    Marlon Schemberger

    só uma observação, quando coloco ../ na frente do caminho de inclusão do css na página layout.php, a página produto/id reconhece ele, mas a página principal do site não..

volverinejr

Bacana o post, estou com algumas dúvidas:
– como faço pra passar mais de um campo na url
– como paço pra dar um post num formulário de cadastro?

Maria Lina

O código funcionou certinho mas quando utilizo a URL Amigável e preciso pegar o IP de quem está acessando o site com $_SERVER['REMOTE_ADDR']; ele passa a pegar o IP do provedor (no caso, UolHost)… sabe me dizer como solucionar???

    Camilo Teixeira de Melo

    Senhorita, testes esses métodos: $_SERVER['HTTP_X_FORWARDED_FOR'], ou $_SERVER['HTTP_X_FORWARDED'], ou $_SERVER['HTTP_FORWARDED_FOR'], ou $_SERVER['HTTP_FORWARDED'].

    Dá um ok se der certo.

Raphael

Fiz o script não rodava nada depois da de executar o include ai fiz a seguinte alteração:

if(preg_match(“@^{$pcre}$@”,REQUEST_URI,$_GET)){
include(“modulo/”.$app);
return; //antes era exit()
}else{

Marcos Martins

Primeiro queria agradecer pelo post, pois ajudou muito. Agora como faço para enviar 2 parametros, estou tentando da forma abaixo mas não dá certo, alguem poderia ajudar:
pra ficar /detalhes/10/descricao-do-produto estou tentando o codigo abaixo, mas sem sucesso:
‘/detalhe/(?P\d+)/(?P\w+)’=>’detalhes.php’,

    Marcos Martins

    Só pra constar, tentei invertido também, mas sem sucesso:
    ‘/detalhe/(?P\w+)/(?P\d+)’=>’detalhes.php’,

Qual a sua opinião?