Paginação de resultados com PHP e MySQL
Amostra de técnica de paginação, para mostrar em diferentes páginas os resultados de uma consulta à base de dados. O exemplo está desenvolvido em PHP e MySQL.
Por Miguel Angel Alvarez - Tradução de JML
Em muitas ocasiões, quando se apresentam numa página web registos de uma base de dados, deveriam-se mostrar demasiados registos como para colocá-los todos numa única página. Nestas ocasiões costumasse paginar os resultados, talvez centenas, em diferentes páginas com conjuntos de registos muito menos numerosos. Por exemplo, poderíamos apresentar os resultados em páginas de 10 elementos ou 20, dependendo do que queremos fazer e do tipo de dados que se estejam a visualizar. Este efeito podemos observa-lo inúmeras vezes nos portais mais representativos.
Poderíamos desenvolver diversos scrips para paginar resultados em PHP. Neste artigo vamos explicar uma possibilidade baseada na utilização de uma base de dados MySQL e sentenças SQL as que indicaremos o conjunto de registos que queremos mostrar em cada página. Os comandos SELECT da linguagem SQL, na base de dados MySQL e muitas outras, têm uma clausula chamada LIMIT, com a que podemos indicar os registos a mostrar, por exemplo, 10 registos começando pelo registo 180.
select * from pais limit 180,10
Como vemos LIMIT tem dois argumentos, o primeiro indica-nos por onde começar os resultados e o segundo o número de resultados a seleccionar no conjunto de registos resultantes.
Deste modo, neste exercício de paginação a clausula LIMIT será a chave para mostrar os registos em grupos do tamanho desejado.
Podemos ver o resultado que vamos obter neste artigo agora e assim teremos mais facilidade para identificar as diferentes partes de código que vamos ver.
Código de paginação
Existem varias partes do código que servirão especificamente para implementar a paginação. O primeiro é saber qual é a página que se deseja mostrar. Em principio mostraria-se a primeira página de resultados, mas se um visitante selecciona com os links de baixo outra página diferente da primeira, teríamos de a mostrar também. O índice da página a mostrar, se não for a primeira vez que se acede, recebe-se por parâmetro na URL.
//Limito a busqueda
$TAMANHO_PAGINA = 10;
//examino a página a mostrar e o inicio do registo a mostrar
$pagina = $_GET["pagina"];
if (!$pagina) {
$inicio = 0;
$pagina=1;
}
else {
$inicio = ($pagina - 1) * $TAMANHO_PAGINA;
}
Estou a definir o tamanho da página. A seguir tento receber a página por parâmetro na URL. Se não se recebeu nada, entende-se que a página a ser mostrada é a primeira, e a variável &inicio, que guarda o primeiro registo a mostrar (para indica-lo na sentença SQL), será zero. Se tínhamos recebido algo como página, calculo o inicio com uma simples multiplicação da página a mostrar vezes o tamanho de página definido antes.
É habitual nestas páginas de resultados informar um pouco sobre a quantidade de registos encontrados e os dados da página que estamos a ver. Estes dados podem-se obter com umas poucas contas.
//vejo o número total de campos que há na tabela com essa busqueda
$ssql = "select * from pais " . $criterio;
$rs = mysql_query($ssql,$conn);
$num_total_registos = mysql_num_rows($rs);
//calculo o total de páginas
$total_paginas = ceil($num_total_registos / $TAMANHO_PAGINA);
//ponho o número de registos total, o tamanho de página e a página que se mostra
echo "Número de registos encontrados: " . $num_total_registos . "<br>";
echo "Mostram-se páginas de " . $TAMANO_PAGINA . " registos cada uma<br>";
echo "A mostrar a página " . $pagina . " de " . $total_paginas . "<p>";
Nota: Este código poderia mostrar uma informação como esta: Número de registos encontrados: 256 Mostram-se páginas de 10 regisros cada uma A mostrar a página 19 de 26
O primeiro a fazer é uma busqueda na base de dados com o critério que se esteja a utilizar para saber quantos registos se obtêm em total sem a paginação (a seguir veremos de onde obtemos a variável $critério).
A continuação posso calcular o número total de páginas de resultados para gerar a busqueda. A função ceil() aproxima números em virgula flutuante ou reais para cima, isto é, retorna o inteiro por cima mais próximo.
As seguintes linhas, onde se utiliza echo, têm como objetivo mostrar os dados na página.
Agora veremos o código que realiza a búsqueda na base de dados, extraindo e mostrando só aqueles registos que correspondem com a página a mostrar.
//construo a sentença SQL
$ssql = "select * from pais " . $criterio . " limit " . $inicio . "," . $TAMANHO_PAGINA;
$rs = mysql_query($ssql);
while ($fila = mysql_fetch_object($rs)){
echo $fila->nome_pais . "<br>";
}
//fechamos o conjunto de resultado e a conexão com a base de dados
mysql_free_result($rs);
mysql_close($conn);
Constroi-se a sentença SQL para obter os dados com o critério, que veremos mais tarde de onde se obtém, mas que em principio podemos toma-la como uma cadeia vazia. Também se utiliza LIMIT, como já se indicou: ponde os valores definidos antes como inicio e tamanho de página.
O resto é um recorrido típico através de um conjunto de registos, neste caso os países da nossa base de dados, onde se vão mostrando todos os elementos desde o principio até ao fim. Finalizado este recorrido não vamos realizar mais nenhuma acção com a base de dados, pelo qual podemos fechar o resultado da busqueda e a conexão com a base de dados.
Agora podemos ver o código que mostra a parte de baixo os números de todas as páginas que são geradas pela busqueda, para que o visitante possa seleccionar uma página e mover-se entre os resultados.
//mostro os diferentes índices das páginas, se é que há várias páginas
if ($total_paginas > 1){
for ($i=1;$i<=$total_paginas;$i++){
if ($pagina == $i)
//se mostro o índice da página actual, não coloco link
echo $pagina . " ";
else
//se o índice não corresponde com a página mostrada actualmente, coloco o link para ir a essa página
echo "<a href='index.php?pagina=" . $i . "&criterio=" . $txt_criterio . "'>" . $i . "</a> ";
}
}
A primeira linha verifica se realmente há várias páginas de resultados, se assim não for, não mostra nada. Se efectivamente há várias páginas para mostrar recorrem-se todas e para cada uma delas mostra-se o índice.
O índice a mostrar pode que seja o da página que se está a visualizar nesse momento e nesse caso simplesmente pomos o numero, mas não o link para ir a esse documento, pois já estamos nele. No caso de que seja uma página de resultados diferente, mostra-se um link para ir a essa página, onde se inclui passando por parâmetro tanto o índice da página que se deseja ver como o critério da busca que se estava a realizar.
Até aqui temos o código imprescindível para a paginação, mas ainda vamos ver mais alguma coisa.
Código de busca
Para fazer um workshop um pouco mais complete e poder oferecer uma página de amostra com funcionalidades de busca, criámos a possibilidade de acrescentar um critério para encontrar só elementos relacionados com ele. Para além do mais, os códigos de paginação costumam utilizar-se em situações nas que se estão a realizar buscas em bases de dados.
O critério poderá ser definido numa caixa de texto e teremos um botão de procurar que chame à mesma página mas passando o texto com as palavras a ser procuradas na base de dados.
<form action="index.php" method="get">
Criterio de búsqueda:
<input type="text" name="criterio" size="22" maxlength="150">
<input type="submit" value="Buscar">
</form>
Reparamos que o método pelo que passámos este formulário é GET. Isto porque não queremos complicar o código e como estamos a utilizar GET noutros sítios, utilizamos o mesmo método.
Colocamos o formulário debaixo, mas haverá também um bocado de código que recolherá a informação e a tratará para adapta-la a uma sentença de busca na base de dados. Colocaremos este código na parte de cima da página.
//inicio o critério e recebo qualquer cadeia que se deseje procurar
$criterio = "";
if ($_GET["criterio"]!=""){
$txt_criterio = $_GET["criterio"];
$criterio = " where nome_pais like '%" . $txt_criterio . "%'";
}
Inicia-se o critério com uma cadeia vazia e depois verificamos se se recebeu algo pelo método GET no campo critério. Em caso afirmativo podemos recolher o texto recebido e construir o critério, que é uma clausula WHERE onde se procuram os elementos, neste caso paises, cujo nome contenham por algum sitio as letras que se receberam como texto do critério.
Base de dados
Tal e como dissemos, está-se a utilizar uma base de dados MySQL. No Manual de programação em PHP de CriarWeb.com mostra-se a maneira de trabalhar com bases de dados.
No nosso exemplo falta-nos por indicar as sentenças para conectar com MySQL e seleccionar a base de dados a utilizar. Seriam umas parecidas a estas.
//conecto com a base de dados
$conn = mysql_connect("servidor","usuario","password");
mysql_select_db("nome_bbdd",$conn);
Pode-se ver aqui o exemplo em funcionamento.
Para aqueles que quiserem esclarecer melhor o método de paginação, o código completo deste exercício é o seguinte:
<form action="pag_php_mysql_ex.php" method="get">
Criterio de busca:
<input type="text" name="criterio" size="22" maxlength="150">
<input type="submit" value="Buscar">
</form>
<?
//inicio o critério e recebo qualquer cadeia que se deseje procurar
$criterio = "";
if ($_GET["criterio"]!=""){
$txt_criterio = $_GET["criterio"];
$criterio = " where nome_pais like '%" . $txt_criterio . "%'";
}
//conecto com a base de dados
$conn = mysql_connect("servidor","usuario","password");
mysql_select_db("nome_bbdd",$conn);
//Limito a busca
$TAMANHO_PAGINA = 10;
//examino a página a mostrar e o inicio do registro a mostrar
$pagina = $_GET["pagina"];
if (!$pagina) {
$inicio = 0;
$pagina=1;
}
else {
$inicio = ($pagina - 1) * $TAMANHO_PAGINA;
}
//vejo o número total de campos que há na tabela com essa busca
$ssql = "select * from pais " . $criterio;
echo "
$ssql</p>";
$rs = mysql_query($ssql,$conn);
$num_total_registos = mysql_num_rows($rs);
//calculo o total de páginas
$total_paginas = ceil($num_total_registos / $TAMANHO_PAGINA);
//ponho o número de registros total, o tamanho de página e a página que se mostra
echo "Número de registros encontrados: " . $num_total_registros . "<br>";
echo "Mostram-se páginas de " . $TAMANHO_PAGINA . " registros cada uma<br>";
echo "A mostrar a página " . $pagina . " de " . $total_paginas . "<p>";
//construo a sentença SQL
$ssql = "select * from pais " . $criterio . " limit " . $inicio . "," . $TAMANHO_PAGINA;
$rs = mysql_query($ssql);
while ($fila = mysql_fetch_object($rs)){
echo $fila->nome_pais . "<br>";
}
//fechamos o conjunto de resultado e a conexão com a base de dados
mysql_free_result($rs);
mysql_close($conn);
//mostro os diferentes índices das páginas, se é que há várias páginas
if ($total_paginas> 1){
for ($i=1;$i<=$total_paginas;$i++){
if ($pagina == $i)
//se mostro o índice da página atual, não coloco link
echo $pagina . " ";
else
//se o índice não corresponde com a página mostrada atualmente, coloco o link para ir a essa página
echo "<a href='pag_php_mysql_ex.php?pagina=" . $i . "&criterio=" . $txt_criterio . "'>" . $i . "</a> ";
}
}
?>