Paginação de resultados/links com PHP

outubro 22nd, 2008 | by DragaO~ |

olá pessoas :D
cah estou eu novamente trazendo mais um artigo/tutorial/etc neste blog :D
ha algum tempo eu jah vinha pensando sobre paginaçao de resultados com php, mas nao tinha muita certeza se seria legal postar sobre o assunto
foi entao que o colega Claiton Padilha me deu a ideia de faze-lo, entao, cah estou :D
admito que, antes de realizar este artigo, a paginaçao de resultados era algo meio “obscuro” para mim, sempre tive medo de fazer isso (acreditem, sempre que meu chefe me pedia pra fazer paginaçao eu dava um jeito de passar para outro XD)

bom, sem mais enrolaçoes, vamos ao que importa ;)
segue o codigo abaixo :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
<?
//onde o banco esta hospedado
$host = 'localhost';
//usuario que acessa o banco
$usuario = 'root';
//senha do usuario que acessa o banco
$senha = '';
 
//banco (database) que desejamos utilizar
$banco = 'banco_teste';
//tabela que queremos selecionar os dados
$tabela = 'tabela_teste';
//campo da tabela que desejamos mostrar na tela
$campo = "campo_teste";
 
//abrindo a conexao com o banco de dados
$sock = mysql_connect($host, $usuario, $senha);
//selecionando o banco que iremos utilizar
mysql_select_db($banco, $sock);
 
//aqui definimos quantos registros queremos mostrar por pagina
$mostrar = 10;
//contando o total de registros existente ateh o momento
$query = "SELECT COUNT(*) AS total FROM ".$tabela;
//enviando a consulta pro banco
$query = mysql_query($query, $sock);
//pegando o retorno do banco
$total = mysql_fetch_array($query);
//armazenando o total de paginas
$total_paginas = ceil($total['total'] / $mostrar);
 
//tirando a possibilidade de alguem fazer sql injection pela nossa variavel
$pagina_atual = htmlentities($_GET['pagina'], ENT_QUOTES);
//validando a pagina atual
if($pagina_atual > 0 && is_numeric($pagina_atual) && $pagina_atual <= $total_paginas)
{
    $pagina_atual = (int) $pagina_atual;
}
else
{
    $pagina_atual = 1;
}
 
//criando o calculo que nos dira qual vai ser o primeiro registro
if($pagina_atual != 1)
{
    $inicio_registros = ($pagina_atual * $mostrar) - ($mostrar);
}
else
{
    $inicio_registros = 0;
}
 
//criando a query (consulta) para mostrar os registros da pagina em questao
$query = "SELECT * FROM ".$tabela." LIMIT ".$inicio_registros.", ".$mostrar;
//mandando a query (consulta) para o banco
$query = mysql_query($query, $sock);
//criando uma saida qualquer apenas para exibir os dados
?>
<table>
<?
//mostrando os dados
while($dados = mysql_fetch_array($query))
{
?>
    <tr>
        <td>
            <?= $dados[$campo] ?>
        </tr>
    </tr>
<?
}
?>
    <tr>
        <td>
        <?
        //montando os links no rodape da pagina
        if($pagina_atual > 1)
        {
        ?>
            <a href="?pagina=<?= $pagina_atual-1 ?>">
                &lt;
            </a>
        <?
        }
        for(; $cont <= $total_paginas; $cont++)
        {
        ?>
            <a <?= ($cont == $pagina_atual) ? " style=\"font-weight: bold;\" " : "" ?> href="?pagina=<?= $cont ?>">
                <?= $cont ?>
            </a>
        <?
        }
        if($pagina_atual < $total_paginas)
        {
        ?>
            <a href="?pagina=<?= $pagina_atual+1 ?>">
                &gt;
            </a>
        <?
        }
        ?>
        </td>
    </tr>
</table>

vale lembrar que o foco deste artigo/tutorial nao eh o HTML ou CSS, e sim exclusivamente o PHP (caso notem que tem mais do que simples PHP no codigo :D)

bom, o codigo jah possui alguns comentarios mais “basicos”, agora detalharei cada linha dele ;)

2
3
4
5
6
7
//onde o banco esta hospedado
$host = 'localhost';
//usuario que acessa o banco
$usuario = 'root';
//senha do usuario que acessa o banco
$senha = '';

aqui nestas linhas estamos apenas setando algumas variaveis para nao ter que ficar digitando, e tambem para ficar mais facil de entender o codigo ;D
creio nao necessitar de explicacao, pois elas sao auto-explicativas (e ainda tem os comentarios no codigo neh ;D)

9
10
11
12
13
14
//banco (database) que desejamos utilizar
$banco = 'banco_teste';
//tabela que queremos selecionar os dados
$tabela = 'tabela_teste';
//campo da tabela que desejamos mostrar na tela
$campo = "campo_teste";

aqui continuamos setando algumas variaveis que eu achei comodo setar para este exemplo, logicamente voce nao vai apenas mostrar um campo da tabela como eu estou fazendo aqui :D

16
17
18
19
//abrindo a conexao com o banco de dados
$sock = mysql_connect($host, $usuario, $senha);
//selecionando o banco que iremos utilizar
mysql_select_db($banco, $sock);

ufa, estamos quase chegando no que interessa :D

21
22
//aqui definimos quantos registros queremos mostrar por pagina
$mostrar = 10;

agora sim começou o que importa ;)
à variavel “$mostrar”, damos o valor de quantos registros por paginas nós queremos mostrar, bem simples

23
24
//contando o total de registros existente ateh o momento
$query = "SELECT COUNT(*) AS total FROM ".$tabela;

aqui estamos criando uma query e atribuindo-a à uma variavel
esta query vai ser responsavel por nos “dizer” quantos registros a nossa tabela possui

25
26
27
28
29
30
//enviando a consulta pro banco
$query = mysql_query($query, $sock);
//pegando o retorno do banco
$total = mysql_fetch_array($query);
//armazenando o total de paginas
$total_paginas = ceil($total['total'] / $mostrar);

aqui enviamos a consulta para o banco, pegamos o resultado dela e armazenamos em uma variavel
notem a ultima linha : pegamos o nosso total de registros (”$total['total']“) e divimos pela quantidade que queremos mostrar em cada pagina, e executamos a funçao “ceil()” (caso nao saiba o que a funçao faça, leia o link para entender, e prossiga com a leitura) à este resultado, para depois atribuir-mos à uma variavel
e eis que temos o total de paginas que nossa consulta vai ter :D
porque utilizamos a funçao “ceil()“? eh muito simples, caso nosso resultado seja um numero exato como “2″, “10″, “34″, etc; nao teremos problemas, mas e com um numero como “3 paginas e meia” (3.5) ?
nao podemos simplesmente deixar meia pagina de fora, e nem realizar uma query começando no registro “3 e meio”, por isso arredondamos o numero para cima utilizando a funçao “ceil()
no exemplo do “3.5″ o retorno seria “4″, para “2.3″ o retorna ficaria “3″, e assim por diante ;)

32
33
//tirando a possibilidade de alguem fazer sql injection pela nossa variavel
$pagina_atual = htmlentities($_GET['pagina'], ENT_QUOTES);

nao entrarei em detalhes nesta linha pois seria abordar segurança (talvez em um post futuro ;D)
mas caso queiram entender o que eu fiz aqui, basta ler a documentaçao da funçao htmlentities()
comentario besta : eu uso em 100% dos meus scripts nas quais possuem qualquer tipo de entrada de dados ;D

35
36
37
38
39
40
41
42
if($pagina_atual > 0 && is_numeric($pagina_atual) && $pagina_atual <= $total_paginas)
{
	$pagina_atual = (int) $pagina_atual;
}
else
{
	$pagina_atual = 1;
}

tah começando a ficar interessante XD
vamos pensar um pouco :
1 – nao podemos ter paginas negativas
2 – podemos ter apenas paginas numericas (ou esja “1″, “2″, “3″, etc; e nao “a”, “b”, “%$$”, etc)
3 – nao podemos ter mais paginas do que registros
agora vamos ler o if : se a pagina atual for maior que zero e a pagina atual for um numero e a pagina atual for menor ou igual ao total de paginas
perceberam que na linha 37 eu coloquei um “(int)” “inutil” ali ? bem, pois eh, ele nao eh nem um pouco inutil :D
aquele “(int)” ali se chama “cast” (e nao somente ele, todos os tipos de variaveis, estruturas, etc; conhecidos podem fazer isso, exemplo : (int) $variavel, (float) $variavel, (minha_estrutura) $variavel, etc)

mas o que o “cast” faz?

o que ele faz eh simplesmente converter uma variavel para o tipo na qual tem nele definido, simples :D
caso tu fizesse

int $variavel;

a variavel “$variavel” seria do tipo int (inteiro) e passaria a aceitar apenas atribuiçoes de numeros inteiros à ela (ok, o php converte automaticamente um tipo para o outro, mas vamos esquecer isso e pensar como acontece no C, por exemplo)
o que eu fiz foi mais uma coisinha de segurança :D
lembra aquele “if” que fazia tres testes ? quais eram os testes que ele fazia ?

testava se era maior que zero…testava se era numero e se era menor ou igual ao total de paginas

exato ;)
agora diga-me, se eu acessar a pagina “3.5″, “3.5″ nao se encaixaria perfeitamente nesse “if” como verdadeiro ? ;)
pois eh, encaixa, porem nao podemos ter paginas “quebradas” (”x.x”), devemos possuir apenas paginas “inteiras” eh eh isso que aquele cast ali faz : pega o resultado do calculo e transforma-o em um numero inteiro, descartando o que vem depois da virgula/ponto ;D
e caso a variavel “$pagina” nao se encaixe nos requisitos, o usuario vai apenas ver a primeira pagina da listagem ;)

44
45
46
47
48
49
50
51
52
//criando o calculo que nos dira qual vai ser o primeiro registro
if($pagina_atual != 1)
{
	$inicio_registros = ($pagina_atual * $mostrar) - ($mostrar);
}
else
{
	$inicio_registros = 0;
}

chegando neste ponto do codigo, nossa variavel “$pagina” certamente vai ter um valor numerico valido, ou “1″
acontece que, se a pagina for “1″, nos devemos começar no primeiro registro, se nao for a primeira pagina, devemos mostrar, caso a pagina seja 2, por exemplo, os registros “10″ ateh o registro “19″ (lembre-se, os registros começaram em “0″ (zero), se for a pagina “3″, devemos mostrar os registros “20″ ao registro “29″, e assim por diante
como eu nao consegui chegar à um calculo que “incluisse” a possibilidade de pagina “1″, fiz este “if” (caso alguem tenha uma ideia melhor e que funcione igual, sinta-se à vontade para dizer e/ou melhorar :D)
o nosso calculo baseia-se no seguinte :
vamos pegar o “2″ como exemplo, ok ? ;)
como eu posso chegar à “10″ (inicio dos resultados que queremos mostrar (lembre-se, os registros começaram em “0″ (zero)) tendo um “2″ (numero da pagina) e um “10″ (total de registros que vamos mostrar por pagina) ?
eu pensei na seguinte maneira (lembrem-se, existem outras) :

(2 x 10) - (10)
(20) - (10)
10

mas o calculo deve servir para ter um “3″ (pagina que estamos mostrando) um “10″ (total de registros que queremos mostrar) para chegarmos em um “20″ (inicio dos registros que vamos mostrar)

(3 x 10) - (10)
(30) - (10)
20

opa, serviu ;)
agora colocando na nossa programaçao, temos o codigo acima :

44
45
46
47
48
49
50
51
52
//criando o calculo que nos dira qual vai ser o primeiro registro
if($pagina_atual != 1)
{
	$inicio_registros = ($pagina_atual * $mostrar) - ($mostrar);
}
else
{
	$inicio_registros = 0,;
}

agora, seguindo adiante…

54
55
//criando a query (consulta) para mostrar os registros da pagina em questao
$query = "SELECT * FROM ".$tabela." LIMIT ".$inicio_registros.", ".$mostrar;

aqui esta a linha “magica” :D
eh bem simples, acreditem XD
esse comando sql diz :

selecione todos campos da tabela limitando-se a começar no registro “x” e mostrando um total de “y”

simples nao ? :D
acho que nao tem mais o que explicar sobre essa linha, mas em caso de duvidas, pergunte ;D

58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
//criando uma saida qualquer apenas para exibir os dados
?>
<table>
<?
//mostrando os dados
while($dados = mysql_fetch_array($query))
{
?>
	<tr>
		<td>
			<?= $dados[$campo] ?>
		</tr>
	</tr>
<?
}
?>

aqui estamos mostrando o conteudo do nosso campo especificado no inicio do codigo, acho que nao tem nenhuma novidade ai nao eh ? ;)

74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
	<tr>
		<td>
		<?
		//montando os links no rodape da pagina
		if($pagina_atual > 1)
		{
		?>
			<a href="?pagina=<?= $pagina_atual-1 ?>">
				&lt;
			</a>
		<?
		}
		for(; $cont <= $total_paginas; $cont++)
		{
		?>
			<a <?= ($cont == $pagina_atual) ? " style=\"font-weight: bold;\" " : "" ?> href="?pagina=<?= $cont ?>">
				<?= $cont ?>
			</a>
		<?
		}
		if($pagina_atual < $total_paginas)
		{
		?>
			<a href="?pagina=<?= $pagina_atual+1 ?>">
				&gt;
			</a>
		<?
		}
		?>
		</td>
	</tr>

aqui estamos montando os links que irao fazer a navegaçao pela nossa pagina ^^

primeiro :
caso a pagina nao seja a primeira, deve existir a opçao de voltar uma pagina atras

segundo :
todas paginas devem possuir a possibilidade da pessoa “pular” para qualquer pagina à qualquer momento
notem que essa parte eu apenas coloquei em negrito caso seja a pagina atual, apenas para dar um destaque, mas o layout final eh com voces, pois este tutorial/artigo nao aborda isso ;)

terceiro :
se a pessoa nao estiver na ultima pagina, ela sempre tem a opçao de ir uma pagina adiante da atual

logicamente poderiam ter sido feitas paginas “inicio” e “fim” (aquelas famosas “setas duplas” (”<<" e ">>”))

105
</table>

e aqui finalmente fechamos a nossa tabela e terminamos o nosso script ;)

pois eh, o post acabou ficando muito grande…XD
mas espero que tenham curtido ler ele ateh o final, e que tenham aprendido e tirado algumas duvidas com este post ;)
pois eu fui pesquisar para ver como tava a qualidade dos artigos/tutoriais sobre o assunto, e realmente me decepcionei um pouco XD
bom, espero que tenham gostado :D
comentarios/sugestoes sao sempre bem vindos ^^

referencias das funçoes :
mysql_connect(), mysql_select_db(), mysql_query(), mysql_fetch_array(), ceil(), htmlentities(), is_numeric()

ateh o proximo post :D

VN:F [1.4.3_701]
Rating: 10.0/10 (2 votes cast)


Postagens parecidas/interessantes:

  1. 12 Responses to “Paginação de resultados/links com PHP”

  2. By Claiton Padilha on out 23, 2008 | Reply

    Muito Bom o Artigo!!
    Eu tenho uma paginação muito mais complicada.
    Mas acho que vou começar a usar a “tua”…
    eauheue
    Só uma observação
    essa linha:
    $query = “SELECT * FROM “.$tabela.” LIMIT”.$inicio_registros.”, “.$mostrar;

    No PostgreSql tem uma pequena diferença
    seria assim:
    $query = “SELECT * FROM “.$tabela.” LIMIT “.$inicio_registros.” OFFSET “.$mostrar;
    Tem o OFFSET, no resto seria igual.
    FLw!
    E Parabéns!

    Quote

    VA:F [1.4.3_701]
    Rating: 0.0/5 (0 votes cast)
  3. By Rafael Diniz on out 25, 2008 | Reply

    Não funcionou aqui. Salvei em .php e mesmo assim não deu, criei as tabelas do BD e etc… e não funcionou. Apresentou erros na linha 86 e na 33.

    O que será?

    Quote

    VA:F [1.4.3_701]
    Rating: 0.0/5 (0 votes cast)
  4. By DragaO~ on out 26, 2008 | Reply

    Rafael Diniz,
    primeiramente, obrigado pelo comentario :D
    por favor, poste o codigo completo que tu tens e tambem os erros exatos que estao aparecendo para ti ;)

    bom, caso o codigo esteja EXATAMENTE igual ao meu, inclusive nos comentarios, um possivel erro da linha 33 é que tu não tenha a váriavel do tipo get “pagina” (o que, na verdade, geraria um “warning” (aviso) e nao um “fatal error” (erro fatal))

    quanto à linha 86, se teu código estiver igual ao meu, nao vejo uma possibilidade de “fatal error” (erro fatal), apenas de “warning” (aviso), por isso reforço a idéia de tu postar teu codigo exatamente como tu tem, para que eu possa ver exatamente onde está o teu problema

    e aconselho tambem, mesmo que não seja muito necessário, postar a estrutura da tua tabela ;)

    Quote

    VN:F [1.4.3_701]
    Rating: 0.0/5 (0 votes cast)
  5. By Rafael Diniz on out 31, 2008 | Reply

    Erro

    “Notice: Undefined variable: cont in C:\Arquivos de programas\EasyPHP 2.0b1\www\Tutos\index.php on line 86
    href=”">
    Notice: Undefined variable: cont in C:\Arquivos de programas\EasyPHP 2.0b1\www\Tutos\index.php on line 86″

    ________

    código PHP:

    0 && is_numeric($pagina_atual) && $pagina_atual

    1)
    {
    ?>

    <

    <?php
    }
    for(; $cont
    <a href=”">

    <?php
    }
    if($pagina_atual

    >

    ___________

    se puder me ajudar… curti seu blog em… =)

    Quote

    VA:F [1.4.3_701]
    Rating: 0.0/5 (0 votes cast)
  6. By Rafael Diniz on out 31, 2008 | Reply

    affff… num dá pra copiar e colar o código completo… seu blog tem um limite…

    Quote

    VA:F [1.4.3_701]
    Rating: 0.0/5 (0 votes cast)
  7. By Rafael Diniz on out 31, 2008 | Reply

    <?php
    }
    “linha 86:” for(; $cont

    Quote

    VA:F [1.4.3_701]
    Rating: 0.0/5 (0 votes cast)
  8. By Rafael Diniz on out 31, 2008 | Reply

    seu blog não suporta mesmo… =/ tem msn mano?

    Quote

    VA:F [1.4.3_701]
    Rating: 0.0/5 (0 votes cast)
  9. By DragaO~ on out 31, 2008 | Reply

    Rafael Diniz,
    imagine que desastre seria se o Wordpress aceitasse e interpretasse tags e comandos PHP, seria o fim dos blogs :D

    bom, eu andei testando e o wordpress aceita sim (meu blog eh feito em wordpress), basta tu colocar as tags necessarias antes do teu codigo, assim :

    <pre lang=”php” line=”1″>
    todo teu codigo php aqui
    </pre>

    aí a gente vai ver algo assim :

    1
    2
    
    //mostra "algo aqui"
    echo "algo aqui";

    peço-lhes que poste novamente teu código para que eu possa dar uma olhada
    sobre aos erros, eles são apenas “warnings” (avisos), não são exatamente “fatal error” (erro fatal)

    sobre o limite, eu verifiquei as tabelas do wordpress e ele aceita até 65 mil caracteres por comentário, portanto, limite não é problema ^^
    (ao menos nesse caso, lógico)

    bpm, desculpe pelo inconveniente :S

    Quote

    VN:F [1.4.3_701]
    Rating: 0.0/5 (0 votes cast)
  10. By Jefferson on jan 6, 2009 | Reply

    Para que server este sinal de igual – (<?= $dados[$campo)- depois do

    Explicando melhor:
    Só aparece o cabeçalho com os nomes de data inclusao, titulo, on line, off line, editar
    , ai vem o espaço do ; e ai vem a sequencia(número da pagina para paginação) das páginas.

    Se puder me ajudar obrigado. Jefferson(iniciante).

    Quote

    VA:F [1.4.3_701]
    Rating: 0.0/5 (0 votes cast)
  11. By DragaO~ on jan 6, 2009 | Reply

    Esse sinal de igual após a abertura da tag PHP, informa que eu estou querendo “ecoar” o valor da variável (ou string) que vem a seguir
    ou seja, fazer isso :

    <?= $dados[$campo] ?>

    é o mesmo que fazer

    <? echo $dados[$campo] ?>

    ou até mesmo

    <?php echo $dados[$campo] ?>

    acontece que, caso a tua diretiva “short_open_tag” esteja desabilitada no php.ini, a única forma de fazer isso é seguindo o terceiro modo, os outros dois anteriores servem apenas se a diretiva “short_open_tag” estivar ligada (ou seja, tiver o valor “on”)
    para não ter problemas quanto à isso, já que tu está iniciando, aconselho a usar o terceiro modo (a não ser que tu saiba configurar o php.ini, claro)

    peço também, adicionalmente, que se fores postar algum código php, utilize a seguinte sintaxe :
    <pre lang=”php”>
    //seu codigo php aqui
    </pre>
    que ele aparecerá assim :

    //seu codigo php aqui

    espero que entenda, pois essa é uma limitação do wordpress (se souber de algum plugin que ajude com isso serei grato)

    Obrigado pelo comentário, e em caso de dúvidas, pergunte que eu tentarei ajudar :D

    Quote

    VN:F [1.4.3_701]
    Rating: 0.0/5 (0 votes cast)
  12. By cjr_ssa (cleber jr) on mar 3, 2009 | Reply

    muito bom esse artigo sobre páginação, venho por meio de vc mesmo que me indicou lá no Gdh em um tópico que criei e me ajudou muito…
    muito interresante esse estilo de página e muito simples também pois vc além de comentar nos códigos, comenta passo-a-passo!!!!!

    cleber junior

    Quote

    VA:F [1.4.3_701]
    Rating: 0.0/5 (0 votes cast)
  13. By DragaO~ on mar 4, 2009 | Reply

    Obrigado pelo elogio :)

    Tento sempre manter o nível dos posts, comentando-os e dando o maior número de informações possíveis sobre o assunto

    Já que gostou, espero que eu o veja por aqui mais vezes :)

    Quote

    VN:F [1.4.3_701]
    Rating: 0.0/5 (0 votes cast)

Deixe um comentário

Vai postar algum código? Leia isso antes