Trabalhando com URL amigável no PHP

A maioria dos tutoriais trata das url amigáveis da seguinte forma:

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

Só que desta forma fica extremamente difícil de fazer com mais de um parâmetro. Então como fazer para ser mais simples.

O que descrevo aqui eu uso neste Blog e meu site.

Criando o arquivo .htaccess

Os arquivos .htaccess (ou "arquivos de configuração distribuída") oferecem um meio de fazer mudanças nas configurações por-diretório. Um arquivo, contendo uma ou mais diretrizes de configurações, é colocado em um diretório em particular, e as diretrizes se aplicam para aquele diretório e todos os seu subdiretórios subseqüentes.
Leia mais: http://httpd.apache.org/docs/2.2/pt-br/howto/htaccess.html

Primeiro crie um arquivo .htaccess na pasta raiz do site ou sistema que você esta criando. A ele adicione o seguinte conteúdo.

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]

Se você estiver usando Linux ou MAC, este arquivo se tornará oculto. Para visualizá-lo no terminal digite ls -a.

Agora vamos entender o que escrevi em cada uma das linhas acima.

RewriteEngine On

Ativa o suporte à reescrita de URL. Isso significa que as URL poderão ser direcionadas para um determinado arquivo no apache.

RewriteCond %{SCRIPT_FILENAME} !-f

Não aplica a condição para arquivos que existam. Isso significa que as imagens, CSS, JS e outros arquivos que já existem continuarão funcionando perfeitamente.

RewriteCond %{SCRIPT_FILENAME} !-d

Não aplica a condição para diretórios que existam

RewriteRule . index.php [L]

Arquivo para onde deve ser direcionado as requisições. Isso significa que tudo que for digitado no browser, após a pasta que esta este .htacces e que não exista, será direcionado para o arquivo index.php.

Se tiver dúvida acesse o site do apache em http://httpd.apache.org/docs/current/mod/mod_rewrite.html.

Tratando as requisições

Mais agora você deve estar se perguntando. Como verifico as variáveis passadas para a minha aplicação? Simples, vamos criar uma classe Url que vai ler a URL, excluir tudo que não pertencer ao projeto.

Veja a classe abaixo:

<?php
class Url
{
    private static $url = null;
    private static $baseUrl = null;

    public static function getBase()
    {
        if( self::$baseUrl != null )
            return self::$baseUrl;

        global $_SERVER;
        $startUrl = strlen( $_SERVER["DOCUMENT_ROOT"] );
        $excludeUrl = substr( $_SERVER["SCRIPT_FILENAME"], $startUrl, -9 );
        if( $excludeUrl[0] == "/" )
            self::$baseUrl = $excludeUrl; 
        else
            self::$baseUrl = "/" . $excludeUrl;
        return self::$baseUrl;
    }

    public static function getURL( $id )
    {
        // Verifica se a lista de URL já foi preenchida
        if( self::$url == null )
            self::getURLList();
        
        // Valida se existe o ID informado e retorna.
        if( isset( self::$url[ $id ] ) )
            return self::$url[ $id ];
        
        // Caso não exista o ID, retorna nulo
        return null;
    }
    
    private static function getURLList()
    {
        global $_SERVER;
        
        // Primeiro traz todos as pastas abaixo do index.php
        $startUrl = strlen( $_SERVER["DOCUMENT_ROOT"] ) -1;
        $excludeUrl = substr( $_SERVER["SCRIPT_FILENAME"], $startUrl, -10 );
        
        // a variável$request possui toda a string da URL após o domínio.
        $request = $_SERVER['REQUEST_URI'];
        
        // Agora retira toda as pastas abaixo da pasta raiz
        $request = substr( $request, strlen( $excludeUrl ) );
        
        // Explode a URL para pegar retirar tudo após o ?
        $urlTmp = explode("?", $request);
        $request = $urlTmp[ 0 ];
        
        // Explo a URL para pegar cada uma das partes da URL
        $urlExplodida = explode("/", $request);
        
        $retorna = array();

        for($a = 0; $a <= count($urlExplodida); $a ++)
        {
            if(isset($urlExplodida[$a]) AND $urlExplodida[$a] != "")
            {
                array_push($retorna, $urlExplodida[$a]);
            }
        }
        self::$url = $retorna;
    }
}
?>

Como esta classe funciona

Lembre-se: Para evitar problemas de compatibilidade, é necessário que todas as URL sejam absolutas. Ou seja, devem referenciar desde a raiz.

URL absoluta é uma URL que aponta sempre para o mesmo ponto, independente de qual local no site ele esteja sendo chamado. Uma URL absoluta pode iniciar com HTTP:// e conter todo o domínio ou somente com / e referenciar a raiz do domínio.
Ex de URL absoluta:

<link rel="stylesheet" type="text/css" href="/code/10000/css/style.css"/>

URL relativa é uma URL que muda conforme a sua localização no site.
Ex de URL relativa:

<link rel="stylesheet" type="text/css" href="css/style.css"/>

Assim que chamamos pela primeira vês o método estático Url::getURL( $id ) ele verifica a URL e monta uma lista contendo as variaveis passadas ao sistema.

Então vamos criar um teste simples. Vou utilizar um exemplo do Maujor (goo.gl/60L5H) para isso.

Vamos ver o arquivo index.php usando a classe:

<?php
require "classes/Url.class.php";
?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pt-br">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="author" content="Mauricio Samy Silva / Eduardo Kraus" />
<link rel="stylesheet" type="text/css" href="<?php echo URL::getBase() ?>css/style.css"/>
<title>Trabalhando com URL amigável no PHP</title>
</head>
<body>
<div id="tudo">
    <div id="topo">TOPO</div>
    <div id="principal">
        <?php
        $modulo = Url::getURL( 0 );

        if( $modulo == null )
            $modulo = "modulo1";

        if( file_exists( "modulos/" . $modulo . ".php" ) )
            require "modulos/" . $modulo . ".php";
        else
            require "modulos/404.php";
        ?>
    </div>
    <div id="navegacao">
        <p><a href="<?php echo URL::getBase(); ?>modulo1">Módulo 1</a></p>
        <p><a href="<?php echo URL::getBase(); ?>modulo2">Módulo 2</a></p>
        <p><a href="<?php echo URL::getBase(); ?>modulo3">Módulo 3</a></p>
        <p><a href="<?php echo URL::getBase(); ?>modulo4">Módulo 4</a></p>
        <p><a href="<?php echo URL::getBase(); ?>modulo5">Módulo 5</a></p>
        <p><a href="<?php echo URL::getBase(); ?>modulo6">Módulo 6</a></p>
        <p><a href="<?php echo URL::getBase(); ?>modulo7">Módulo 7</a></p>
        <p><a href="<?php echo URL::getBase(); ?>modulo8/parametro/sei-la/alguma_coisa/25/quase-nada">
            Módulo 8 com sub-módulo</a></p>
        <p><a href="<?php echo URL::getBase(); ?>qualquer">Módulo 404</a></p>
        <p><a href="<?php echo URL::getBase(); ?>teste.php">Teste.php</a></p>
    </div>
    <div id="rodape">RODAPE</div>
</div>
</body>
</html>

Então, no módulo8 eu criei uma programação PHP para receber estes dados e analiza-lo. Veva os dois links abaixo:

Veja o exemplo rodando completo em php.eduardokraus.com/code/10000/

Quer o código fonte completo deste exemplo? Clique aqui.

Fique por dentro de nossas novidades, ideias e atualizações