A combinação do PHP e uma base de dados como MySQL nos proporciona uma maneira bem simples de criar um modelo de paginação estilo o que estamos acostumados a ver todos os dias no Google ou aqui mesmo no Tutsup. Utilizando o limite do MySQL podemos dividir todo o conteúdo da nossa consulta em partes menores, que proporcionam facilidade para o usuário navegar pelo seu site.

Neste artigo você vai entender como funciona o processo de criação da paginação utilizando especificamente PHP e MySQL, mas a teoria funciona para outras linguagens de programação também.

Como funciona a paginação?

O limite (limit) da consulta MySQL nos permite selecionar valores de duas formas:

  • Especificando um limite único;
  • Especificando a linha onde iniciar a contagem e o limite;

O segundo formato nos proporciona uma opção rápida para criar paginação no seguinte formato:

/* Mostra 10 começando do 0 */
SELECT * FROM tabela LIMIT 0,10;
/* Mostra 10 começando do 10 */ 
SELECT * FROM tabela LIMIT 10,10;
/* Mostra 10 começando do 20 */ 
SELECT * FROM tabela LIMIT 20,10;

No trecho de código acima, teríamos linhas sendo exibidas de 10 em 10.

No PHP, precisamos saber o seguinte:

  • Qual o total de linhas da consulta MySQL;
  • Quantas linhas serão exibidas por vez;
  • Qual o número de páginas serão exibidas para o usuário;

A última opção é necessária para que bases de dados muito grandes não exibam uma quantidade excessiva de números de páginas para o usuário, quebrando o layout do site.

Para obter o número total de página, basta dividirmos o número total de linhas pela quantidade de linhas exibidas por vez, assim podemos fazer um laço com o número total de página e exibir para o usuário final.

Cada página tem seu próprio link, que normalmente utiliza HTTP GET para obter o número da página atual. Sabendo tal número, podemos até mesmo estilizar cada número em um formato único, indicando que é a página atual para o usuário que está navegando pelo seu site.

O Google utiliza uma maneira muito peculiar para fazer isso, como todos já devem ter percebido.

Paginação do Google

Paginação do Google

É importante lembrar que a paginação depende da sua consulta e do sistema que está criando. Talvez o código que você vai ver neste artigo deva ser modificado para seu sistema, de maneira que se adapte às suas necessidades.

Vamos ver um pouco de código?

 Criando a base de dados, tabela e valores

Para o exemplo desse tutorial, vamos precisar de um servidor local onde possamos testar tudo o que estamos fazendo sem afetar um site em produção. Você pode fazer isso com o EasyPHP (tutorial abaixo):

Depois de instalado, podemos utilizar PDO para criar nossa base de dados, tabela e valores. Vou detalhar como criar tudo isso um pouco mais adiante neste artigo.

Criando as pastas

Vamos começar criando as pastas que vamos utilizar nesse tutorial, então faça o seguinte:

  • Abra a pasta “localweb” do seu EasyPHP (a pasta onde estão os arquivos disponíveis via HTTP);
  • Crie uma pasta chamada paginacao_simples;
  • Dentro da pasta paginacao_simples, crie outras duas pastas chamadas de “bd” e “functions“;

Cada um dos arquivos que vamos precisar vai dentro de uma das pastas acima, vou descrever onde colocá-los no momento de sua criação.

Arquivo de detalhes da conexão

Vamos criar um arquivo que contém apenas os detalhes da nossa conexão, assim podemos reutilizá-lo em cada uma das partes de nosso código, conforme necessário.

Abra seu editor de textos preferido e crie um arquivo com o seguinte código:

<?php
// Charset UTF-8
header('Content-Type: text/html; charset=utf-8');

// Detalhes da conexão
$servidor = 'localhost';
$usuario  = 'root';
$senha    = '';
$bd       = 'paginacao_tutsup';
$tabela   = 'noticias_exemplo';
$prefixo  = 'noticia_';
$charset  = 'utf8';

Salve este arquivo com o nome de “detalhes_conexao.php” dentro da pasta “bd“.

As variáveis acima contém as configurações padrão do EasyPHP, tais como o servidor, usuário e senha (em branco). Você deve modificar isso caso seu servidor tenha configurações diferentes.

O cabeçalho na linha 3 apenas indica que vamos utilizar UTF-8 como charset. Você pode alterar isso se preferir.

Observação importante: A função header do PHP não pode aparecer após algo ser exibido na tela, por isso, ao incluir este arquivo em outros arquivos, certifique-se de que nada foi exibido anteriormente.

Arquivo de configuração

Crie outro arquivo dentro da pasta “bd” chamado de “configura.php“. Este arquivo será temporário e servirá apenas para criar nossa base de dados, tabela e inserir os valores que vamos utilizar para testar.

Segue seu conteúdo:

<?php
// Inclui os detalhes da conexão
require 'detalhes_conexao.php';

// Tenta conectar e executar a configuração
try {
    // Cria o objeto da conexão PDO
    $conexao = new PDO("mysql:host=$servidor;charset=$charset;", $usuario, $senha);
    
    // Cria a base de dados e a tabela
    $verifica = $conexao->exec(
        "CREATE DATABASE IF NOT EXISTS `$bd`;
        GRANT ALL ON `$bd`.* TO '$usuario'@'localhost';
        FLUSH PRIVILEGES;
        CREATE TABLE IF NOT EXISTS `$bd`.`$tabela` (
          `{$prefixo}id` INT (11) NOT NULL AUTO_INCREMENT,
          `{$prefixo}titulo` VARCHAR (255),
          PRIMARY KEY (`{$prefixo}id`)
        ) CHARSET = $charset ;"
    );
    
    // Insere 50 valores na tabela
    for ( $i = 1; $i <= 50; $i++ ) {
        $conexao->exec("INSERT INTO `$bd`.`$tabela` ( `{$prefixo}id`, `{$prefixo}titulo` ) VALUES ( $i, 'Título $i' )");
    }
    
    // Verifica se tudo ocorreu conforme esperado
    if ( $verifica ) {
        echo 'Base de dados, tabela e valores inseridos com sucesso!';
    } else {
        // Caso contrário, mostra os detalhes do erro.
        echo 'Erro ao inserir dados. Detalhes:';
        $erro = $conexao->errorInfo();
        
        echo '<pre>';
        print_r( $erro );
        echo '</pre>';
    }
    
} catch(PDOException $e) {
    // Se não conectar, mostra o erro
    echo $e->getMessage();
    exit;
}

Observação: Se você quiser criar a base de dados, tabela e inserir os valores manualmente, este arquivo não será necessário.

Uma vez salvo, acesse este arquivo pelo seu navegador preferido e certifique-se de que os dados foram inseridos com sucesso. Caso verdadeiro, exclua-o.

Arquivo de conexão

Agora que já temos nossa base de dados, tabela e valores, vamos criar um arquivo chamado “conexao.php” (ainda dentro da pasta “bd”). Este arquivo será responsável por fazer a conexão com a base de dados utilizando PDO.

Veja seu conteúdo:

<?php
// Inclui os detalhes da conexão
require 'detalhes_conexao.php';

// Tenta conectar e executar a configuração
try {
    // Cria o objeto da conexão PDO
    $conexao = new PDO("mysql:host=$servidor;dbname=$bd;charset=$charset;", $usuario, $senha);    
} catch(PDOException $e) {
    // Se não conectar, mostra o erro
    echo $e->getMessage();
    exit;
}

 Criando a função de paginação

Ao invés de termos que criar uma paginação para cada parte do nosso sistema, vamos criar uma função genérica que gera os números pra gente. Vamos precisar apenas enviar os três valores: “Total de linhas”, “Linhas por página”, “Offset” (páginas a serem exibidas).

A função de paginação deve ser criada na pasta “functions”, em um arquivo chamado “paginacao.php”.

Veja seu conteúdo:

<?php
/**
 * Paginação
 *
 * Cria uma paginação simples.
 *
 * @param int $total_artigos Número total de artigos da sua consulta
 * @param int $artigos_por_pagina Número de artigos a serem exibidos nas páginas
 * @param int $offset Número de páginas a serem exibidas para o usuário
 *
 * @return string A paginação montada
 */
function paginacao( 
    $total_artigos = 0, 
    $artigos_por_pagina = 10, 
    $offset = 5
) {    
    // Obtém o número total de página
    $numero_de_paginas = floor( $total_artigos / $artigos_por_pagina );
    
    // Obtém a página atual
    $pagina_atual = 1;
    
    // Atualiza a página atual se tiver o parâmetro pagina=n
    if ( ! empty( $_GET['pagina'] ) ) {
        $pagina_atual = (int) $_GET['pagina'];
    }
    
    // Vamos preencher essa variável com a paginação
    $paginas = null;
    
    // Primeira página
    $paginas .= " <a href='?pagina=0'>Home</a> ";
    
    // Faz o loop da paginação
    // $pagina_atual - 1 da a possibilidade do usuário voltar
    for ( $i = ( $pagina_atual - 1 ); $i < ( $pagina_atual - 1 ) + $offset; $i++ ) {
        
        // Eliminamos a primeira página (que seria a home do site)
        if ( $i < $numero_de_paginas && $i > 0 ) {
            // A página atual
            $página = $i;
            
            // O estilo da página atual
            $estilo = null;
            
            // Verifica qual dos números é a página atual
            // E cria um estilo extremamente simples para diferenciar
            if ( $i == @$parametros[1] ) {
                $estilo = ' style="color:red;" ';
            }
            
            // Inclui os links na variável $paginas
            $paginas .= " <a $estilo href='?pagina=$página'>$página</a> ";
        }
        
    } // for

    $paginas .= " <a href='?pagina=$numero_de_paginas'>Última</a> ";
    
    // Retorna o que foi criado
    return $paginas;
    
}

Isso deve gerar algo parecido com a imagem abaixo quando executado.

Paginação simples

Paginação simples

Vamos executar essa função no arquivo index.php, o que descreverei posteriormente.

Arquivo principal (index.php)

O arquivo index.php fica na raiz da pasta “paginacao_simples” e comanda tudo, ou seja, inclui todos os arquivos que criamos anteriormente, executa a consulta principal e executa a função de paginação.

Veja seu código:

<?php
// Inclui a conexão PDO
require 'bd/conexao.php';
require 'functions/paginacao.php';

// Número de artigos por página
$artigos_por_pagina = 9;

// Página atual onde vamos começar a mostrar os valores
$pagina_atual = ! empty( $_GET['pagina'] ) ? (int) $_GET['pagina'] : 0;
$pagina_atual = $pagina_atual * $artigos_por_pagina;

// Cria a consulta para o MySQL e executa
$stmt = $conexao->prepare("SELECT * FROM $tabela LIMIT $pagina_atual,$artigos_por_pagina");
$stmt->execute();

// Mostra os valores
while( $f = $stmt->fetch() ) {
   echo $f["{$prefixo}titulo"] . '<br>';
}

// Pegamos o valor total de artigos em uma consulta sem limite
$total_artigos = $conexao->prepare("SELECT COUNT(*) AS total FROM $tabela");
$total_artigos->execute();
$total_artigos = $total_artigos->fetch();
$total_artigos = $total_artigos['total'];

// Exibimos a paginação
echo paginacao( $total_artigos, $artigos_por_pagina, 5 );

Veja nos comentários acima o que cada uma das linhas faz.

Com isso já devemos ter uma paginação funcionando em nosso sistema. Não é nada complicado, é?

Download da paginação simples

Se você quiser baixar tudo o que criamos anteriormente para analisar melhor, segue o link abaixo:

paginacao_simples.zip

Observação: O arquivo acima inclui tudo o que criamos acima, não abaixo.

Paginação com URLs amigáveis

No método que detalhei anteriormente a paginação funciona perfeitamente, porém nossas URLs são feias. Todas elas ficam mais ou menos assim:

http://127.0.0.1/index.php?pagina=4

Onde seria ideal criamos algo como:

http://127.0.0.1/pagina/4/

Para resolver este problemas, temos que modificar várias coisas em nosso sistema, a começar pelo arquivo .htaccess que ainda não existe.

.htaccess

Abra o seu editor de textos favoritos e crie um arquivo chamado .htaccess com o seguinte conteúdo:

RewriteEngine On

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

RewriteRule ^(.+)$ index.php?p=$1 [QSA,L]

Isso faz com que qualquer coisa adicionada em nossa URL que não seja um arquivo ou um diretório (algo que não exista, por exemplo), caia no parâmetro “p” do HTTP GET.

Por exemplo:

127.0.0.1/paginacao_simples/teste/de/parametros

É igual a:

127.0.0.1/paginacao_simples/index.php?p=teste/de/parametros

Função para obter os parâmetros

Isso nos leva a criar um novo arquivo chamado de “parametros.php” dentro da pasta “functions”. O novo arquivo terá o seguinte:

<?php
/**
 * Obtém parâmetros de $_GET['p']
 *
 * Obtém os parâmetros de $_GET['p'] e retorna um array.
 * A URL deverá ter o seguinte formato:
 * http://www.example.com/parametro1/valor/parametro2/valor/etc...
 *
 * @return array Os parâmetros
 */
function obter_parametros () {
    
    $p = array();
    
    // Verifica se o parâmetro path foi enviado
    if ( isset( $_GET['p'] ) ) {

        // Captura o valor de $_GET['p']
        $p = $_GET['p'];
        
        // Limpa os dados
        $p = rtrim($p, '/');
        $p = filter_var($p, FILTER_SANITIZE_URL);
        
        // Cria um array de parâmetros
        $p = explode('/', $p);
    }
    
    return $p;
}

Aqui estamos simplesmente explodindo o que encontramos no parâmetro $_GET[‘p’] e gerando um array com tudo.

Modificando o arquivo index.php

Agora precisamos incluir a função para obter os parâmetros em nosso arquivo index.php. Além disso, precisamos trocar tudo onde aparece $_GET para o novo parâmetro.

Veja:

<?php
// Inclui a conexão PDO
require 'bd/conexao.php';
require 'functions/paginacao.php';

/*** Arquivo adicionado ***/
require 'functions/parametros.php';

/*** Função executada ***/
// Obtém os parâmetros da URL amigável
$parametros = obter_parametros();

// Número de artigos por página
$artigos_por_pagina = 9;

/*** $_GET alterado ***/
// Página atual onde vamos começar a mostrar os valores
$pagina_atual = ! empty( $parametros[1] ) ? (int)$parametros[1] : 0;
$pagina_atual = $pagina_atual * $artigos_por_pagina;

// Cria a consulta para o MySQL e executa
$stmt = $conexao->prepare("SELECT * FROM $tabela LIMIT $pagina_atual,$artigos_por_pagina");
$stmt->execute();

// Mostra os valores
while( $f = $stmt->fetch() ) {
   echo $f["{$prefixo}titulo"] . '<br>';
}

// Pegamos o valor total de artigos em uma consulta sem limite
$total_artigos = $conexao->prepare("SELECT COUNT(*) AS total FROM $tabela");
$total_artigos->execute();
$total_artigos = $total_artigos->fetch();
$total_artigos = $total_artigos['total'];

// Exibimos a paginação
echo paginacao( $total_artigos, $artigos_por_pagina, 5 );

Perceba nos comentários acima o que foi modificado.

Alterando nossa função de paginação

Também precisaremos alterar nossa função de paginação, se não fizermos isso nossas URLs não vão funcionar perfeitamente.

<?php
/**
 * Paginação
 *
 * Cria uma paginação simples.
 *
 * @param int $total_artigos Número total de artigos da sua consulta
 * @param int $artigos_por_pagina Número de artigos a serem exibidos nas páginas
 * @param int $offset Número de páginas a serem exibidas para o usuário
 *
 * @return string A paginação montada
 */
function paginacao( 
    $total_artigos = 0, 
    $artigos_por_pagina = 10, 
    $offset = 5
) {

    /*** Precisamos dos parâmetros aqui dentro da função ***/
    // Obtém os parâmetros
    global $parametros;
    
    /*** Vamos precisar de uma variável contendo a URL da home do site ***/
    // A URL da nossa home
    $url_site = 'http://127.0.0.1/cursos/php/paginacao';
    
    // Obtém o número total de página
    $numero_de_paginas = floor( $total_artigos / $artigos_por_pagina );
    
    // Obtém a página atual
    $pagina_atual = 1;
    
    /*** GET alterado ***/
    // Atualiza a página atual se tiver o parâmetro pagina/valor
    if ( 
        ( ! empty( $parametros[0] ) && $parametros[0] == 'pagina' ) &&
        ( ! empty( $parametros[1] ) )
    ) {
        $pagina_atual = (int)$parametros[1];
    }
    
    // Vamos preencher essa variável com a paginação
    $paginas = null;
    
    /*** URL alterada ***/
    // Primeira página
    $paginas .= " <a href='$url_site/pagina/0'>Home</a> ";
    
    // Faz o loop da paginação
    // $pagina_atual - 1 da a possibilidade do usuário voltar
    for ( $i = ( $pagina_atual - 1 ); $i < ( $pagina_atual - 1 ) + $offset; $i++ ) {
        
        // Eliminamos a primeira página (que seria a home do site)
        if ( $i < $numero_de_paginas && $i > 0 ) {
            // A página atual
            $página = $i;
            
            // O estilo da página atual
            $estilo = null;
            
            // Verifica qual dos números é a página atual
            // E cria um estilo extremamente simples para diferenciar
            if ( $i == @$parametros[1] ) {
                $estilo = ' style="color:red;" ';
            }
            
            /*** URL alterada ***/
            // Inclui os links na variável $paginas
            $paginas .= " <a $estilo href='$url_site/pagina/$página'>$página</a> ";
        }
        
    } // for
    
    /*** URL alterada ***/
    $paginas .= " <a href='$url_site/pagina/$numero_de_paginas'>Última</a> ";
    
    // Retorna o que foi criado
    return $paginas;
    
}

Veja nos comentários acima o que foi alterado.

Download da paginação com URL amigável

Caso queira baixar o trecho que criamos no trecho anterior, sinta-se à vontade:

paginacao.zip

Altere conforme preferir.

Concluindo

A paginação depende da sua consulta e do modo com que você deseja que ela seja feita, este tutorial visa exemplificar como as coisas são feitas para que você tenha uma base para criar seu próprio sistema de paginação em PHP.

Você pode utilizar o código dos exemplos caso queira, porém, tente compreender o que foi descrito primeiro.

Em caso de dúvidas, não hesite em comentar.