Gerenciamento de URLs com PHP


Estou devendo aos meus leitores um artigo sobre como criar e gerenciar um bom esquema de URLs usando PHP e freqüentemente sou cobrado por isso.

Neste texto vou tentar explicar o funcionamento e as vantagens do gerenciamento de URLs com PHP em relação ao gerenciamento de URLs usando apenas mod_rewrite.

Este artigo não é uma tradução, mas é fortemente baseado no artigo de Till Quack para o A List Apart, How to succeed with URLs.

A principal vantagem de se usar PHP ao invés de apenas o mod_rewrite é que o PHP é bem mais simples. O mod_rewrite é conhecido tanto pelo seu poder quanto pela sua complexidade, não apenas pelo fato de ser necessário um bom entendimento de expressões regulares para poder usá-lo mas também por ser um tanto obscuro e difícil de entender, principalmente para os iniciantes.

É importante que você entenda o que eu quero dizer com o termo gerenciamento de URLs antes de ler o restante deste texto. Dois textos escritos por mim podem ajudá-lo a entender melhor o que isso significa: Gerenciamento de URLs – Criando URLs amigáveis e URLs amigáveis – esclarecendo dúvidas.

O principal conceito a ser entendido sobre as URLs é que elas nem sempre se referem a um arquivo ou diretório existente no disco. Na realidade, URLs nunca devem se referir a arquivos diretamente. Isso torna suas URLs voláteis, vulneráveis a mudanças. Afinal, como diria Tim Berners-Lee, cool URIs don’t change.

Para usar as técnicas descritas neste texto você precisa do servidor web Apache com o mod_rewrite habilitado, PHP e, principalmente, um bom planejamento. Antes de qualquer coisa, planeje como você quer que suas URLs sejam. Use URLs que resumam de maneira adequada e sucinta o conteúdo do recurso que descrevem.

Bem, agora que você já tem seu esquema de URLs bem planejado, vamos ao que interessa. Mãos à obra.

Crie um script PHP. Vamos chamá-lo de urls.php. Todo tráfego do site (com algumas exceções) será direcionado para esse script. Para fazer isso, crie um arquivo .htaccess na raiz do seu site com o seguinte conteúdo:

RewriteEngine On
RewriteRule !\.(gif|jpg|png|css)$ /raiz_do_site/urls.php

A primeira linha serve para ligar o mod_rewrite e a segunda é a que direciona o tráfego para urls.php. O conteúdo entre parêntesis define as extensões de arquivo que devem ser excluídas desse processo, ou seja, devem ser tratadas da maneira padrão pelo servidor web. Você pode querer incluir mais algumas extensões nessa lista (swf, svg, xml, js, txt, por exemplo), de acordo com a sua necessidade.

Você deve substituir raiz_do_site pelo caminho completo do seu site no servidor, por exemplo, /home/httpd/dominio.com/. Porém, em algumas configurações do apache (todas que eu particularmente já usei), apenas o caminho relativo já é o suficiente, no caso /urls.php ou apenas urls.php.

Agora vamos começar a escrever o script urls.php.

O primeiro passo é verificar se a requisição refere-se a um arquivo existente.

<?php
//Código retirado do A List Apart
$DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
$REQUEST_URI = $_SERVER['REQUEST_URI'];
$SCRIPT_FILENAME = $_SERVER['SCRIPT_FILENAME'];
if(file_exists($DOCUMENT_ROOT.$REQUEST_URI)
and ($SCRIPT_FILENAME!=$DOCUMENT_ROOT.$REQUEST_URI)
and ($REQUEST_URI!="/")){
    $url=$REQUEST_URI;
    include($DOCUMENT_ROOT.$url);
    exit();
}

Simplesmente verificamos se a URL refere-se a um arquivo existente, incluimos este arquivo e encerramos o script.

O próximo passo é dividir a URL em pedaços separados por “/” e verificar se o user-agent fez uma requisição pela index do site.

$url=strip_tags($REQUEST_URI);
$url_array=explode("/",$url);
array_shift($url_array); //o primeiro índice sempre será vazio
if(empty($url_array)){
	include("site_index.php");
exit();
}

Trivial, não? Se $REQUEST_URI estiver vazia significa que o usuário está requisitando a index do site. Neste caso, incluimos o script referente à index e encerramos o script.

Bom, se o usuário não requisitou um arquivo existente nem a index do site, chegou a hora de verificar se o que ele está tentando acessar é um conteúdo dinâmico. Provavelmente algo armazenado em um banco de dados, arquivos XML ou o que quer que você use pra armazenar o conteúdo dinâmico do seu site.

Neste caso não há uma fórmula pronta. Cada caso é um caso. Como você já planejou previamente o seu esquema de URLs, com certeza você sabe o que cada URL descreve. Portanto, você deve cuidar dessa parte.

Vou usar uma função fictícia verifica_conteudo() que retorna true caso a URL requisitada corresponda a algum dado presente, por exemplo, no seu banco de dados e uma outra exibe_conteudo() que cuidará para que este conteúdo seja exibido da forma adequada.

if (verifica_conteudo()){
	exibe_conteudo();
	exit();
}

Se também não houver conteúdo dinâmico referente à URL requisitada, só nos resta enviar um erro 404, informando ao user agent que o recurso requisitado não existe.

header("HTTP/1.1 404 Not Found");
exit();

Alguns cuidados devem ser tomados em relação a usuários maliciosos que queiram tentar acessar arquivos do seu sistema que podem causar danos ou garantir acesso privilegiado. Para prevenir esse tipo de coisa, adicione no início do script algumas linhas de código verificando se o usuário está requisitando algo como “../../../algum_script” ou coisas do tipo.

Acessos a URLs longas demais também devem ser prevenidos. Para isso, inclua o seguinte no início do script:

if(strlen($REQUEST_URI)>100){
	header("HTTP/1.1 404 Not Found");
	exit();
}

E é isso. O desenvolvimento desse script vai depender exclusivamente do seu caso específico. A idéia é essa. Se você a entendeu vai ser fácil adaptá-la para a sua necessidade.

Mas, além disso, há outra coisa interessante que se pode fazer com esse script que – para mim pelo menos – não é possível fazer usando apenas regras do mod_rewrite.

Lembra quando você ainda não conhecia as vantagens de se usar URLs amigáveis e usava URLs do tipo index.php?var1=valor1&var2=valor2…? Então, agora você está usando URLs totalmente diferentes e não é legal deixar “quebrados” todos os links e bookmarks que apontam para as URLs antigas, concorda?

Desde que haja alguma correspondência (é bem provável que haja) entre as URLs antigas e as novas, é possível mantê-las funcionando, lançando mão de redirecionamentos permanentes (código HTTP 301).

Como? Bem, a o código vai variar de acordo com o esquema de URLs usado. Você pode criar um código que analise a URL e redirecione para a URL nova. Exemplo: digamos que suas URLs antigas fossem da forma index.php?s=secao&a=artigo e as novas sejam da forma /secao/artigo. Neste caso, ao dividir a URL em pedaços teríamos $url_array[0] = “index.php?s=secao&a=artigo”. O que precisamos fazer é dividí-la novamente em pedaços, pegar os valores das variáveis que nos interessam, manipulá-las se for necessário e redirecionar para a URL correta.

$url = explode("?", $url_array[0]);
array_shift($url);
$url = explode("&", $url[0]);
$secao = explode("=", $url[0]);
$secao = $secao[1];
$artigo = explode("=", $url[1]);
$artigo = $artigo[1];
$url = "http://dominio.com/$secao/$artigo";
header("HTTP/1.1 301 Moved Permanently");
header("Location: " . $url);

Acho que não preciso explicar esse pedaço de código, não é? Bom, de qualquer maneira, você precisa adaptá-lo para o seu caso.

Por último temos que cuidar dos diretórios que eventualmente precisem ser manipulados diretamente pelo servidor web, sem a interferência do mod_rewrite e do nosso script. Por exemplo, você pode ter um diretório “/unsorted/” onde você guarda arquivos aleatórios e deseja que o conteúdo desse diretório seja listado da maneira padrão pelo apache. Ou então, diretórios com arquivos index.html que devem se comportar da maneira padrão. Ou ainda diretórios protegidos por senha.

Neste caso, será necessário adicionar uma regra de reescrita em nosso .htaccess para cada diretório desses. Em princípio eu imaginei que fosse possível colocar todos em uma regra só, utilizando o alternador “|” mas, por algum motivo que desconheço, não funciona. A regra é a seguinte:

RewriteRule   ^unsorted/.*$ - [L]

O “-” informa ao mod_rewrite para sair do caminho e deixar o apache cuidar sozinho da requisição e o “[L]” faz com que essa regra, se satisfeita, seja a última a ser executada. Nenhuma RewriteRule posterior será avaliada. No caso, seu .htaccess deve ficar mais ou menos assim:

RewriteEngine On
RewriteRule   ^unsorted/.*$ - [L]
RewriteRule !\.(gif|jpg|png|css)$ /raiz_do_site/urls.php

Concluindo, mais uma vez deixo claro que não há fórmula mágica para gerenciar suas URLs. Mas o processo não é complicado e, uma vez entendido, é simples aplicá-lo a qualquer caso. Desde que você planeje seu esquema de URLs da maneira adequada.

Um forte abraço !

Publicado em 19 de dezembro de 2008, em PHP e marcado como . Adicione o link aos favoritos. 1 comentário.

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

%d blogueiros gostam disto: