Pagination - How to don't allow the user to go further the existing pages?

Viewed 147

Sorry if the title of the question is too bad, i'm new on php and i don't know if there's a specific name for this.

I have only to 2 records and i limited the pagination to show only 1 records per page, then I will have 2 pages, and I can access these pages with &tab=1 and &tab=2, on my current code if i write on the URL: &tab=-2, &tab=-1, &tab=0, &tab=3, &tab=4, &tab=5 I can go to that page, and on that page I will see none records because as i said i have only 2 pages.

My questions:

1. There's any security issues on it?

2. How to don't allow the user to go further the existing pages?

This is my pagination code:

<?php
  if(empty($_GET['tab'])){}else{$page = $_GET['tab'];}
  if(isset($page)){$page = $_GET['tab'];}else{$page = 1;}
  $maximoVEP = 1;
  $startVEP = (($maximoVEP * $page) - $maximoVEP);
  $title     = 'Asic';

  $stmtVEP   = $db->prepare("SELECT count(*) FROM table WHERE data = 'vm' AND title = :title");
  $stmtVEP->bindValue(':title', $title, PDO::PARAM_STR);    
  $stmtVEP->execute();
  $total = $stmtVEP->fetchColumn();
  $total_pages = ceil($total/$maximoVEP);

  echo '<nav aria-label="Page navigation example">';
  echo '<ul class="pagination paginationEp ml-1 mr-1">';
  if ($page >= 2){

    echo '<li class="page-item">';
    echo '<a class="page-link" href="?p=';
    echo htmlentities($slug, \ENT_QUOTES, "UTF-8", false);
    echo '&tab='.($page-1).'"><i class="fas fa-angle-left"></i> ANTERIOR</a>';
    echo '</li>';
  }

  echo '<li class="page-item">';
  echo '<a class="page-link" href="';
  echo htmlentities($slug, \ENT_QUOTES, "UTF-8", false);
  echo '"><i class="fas fa-list-ul"></i></i></a>';
  echo '</li>';

  if ($page < $total_pages){

  echo '<li class="page-item">';
  echo '<a  class="page-link" href="?p=';
  echo htmlentities($slug, \ENT_QUOTES, "UTF-8", false);
  echo '&tab='.($page+1).'">PRÓXIMO <i class="fas fa-angle-right"></i></a>';
  echo '</li>'; 

  }
  echo '</nav>';

  $conn = null;             
?>

And the query:

$stmtUTP = $db->prepare("SELECT `id`, `title` FROM table WHERE data = 'vm' ORDER BY id DESC LIMIT :start, :max");
$stmtUTP->bindValue(':start', $startVEP, PDO::PARAM_INT); 
$stmtUTP->bindValue(':max', $maximoVEP, PDO::PARAM_INT);   
$stmtUTP->execute();
2 Answers

Move your count query above your $startVEP calculation. Then simply check to make sure $page does not exceed $total_pages , in order to lock the $page requested to the highest possible page available.

Additionally also check to make sure the requested page is a positive value, otherwise force the page to 1

Example: https://3v4l.org/91m8G

//applies to null, 0, false, empty string
//will default to 1 if empty or not a numeric value
$page = (empty($_GET['tab']) ? 1 : (int) $_GET['tab']);
if ($page <= 0) {
    //force a positive page value
    $page = 1;
}

$maximoVEP = 1;
$title     = 'Asic';

$stmtVEP   = $db->prepare("SELECT count(id) FROM table WHERE data = 'vm' AND title = :title");
$stmtVEP->bindValue(':title', $title, PDO::PARAM_STR);    
$stmtVEP->execute();
$total = $stmtVEP->fetchColumn();
$total_pages = ceil($total/$maximoVEP);

if ($page > $total_pages) {
    //limit requested page to the maximum number of pages
    $page = $total_pages;
}

$startVEP = (($maximoVEP * $page) - $maximoVEP);

//...

Results (assuming total records are 2)

$_GET['tab'] = not a number: 1
$_GET['tab'] = -1: 1
$_GET['tab'] = -2: 1
$_GET['tab'] = -0: 1
$_GET['tab'] = 0: 1
$_GET['tab'] = 1: 1
$_GET['tab'] = 2: 2
$_GET['tab'] = 3: 2
$_GET['tab'] = 4: 2

There is not really a security risk, since the offset is higher than available and you are using a prepared statement. Only potential issue is that $total_pages could be 0.

It's a good practice to validate or even try to whitelist anything that comes from user input, or from outside the app, in this case $_GET['tab'] and after you assign it to $page.

So you would want to make sure that is a positive integer and it's lesser than the total number of pages. You can use a conditional to check if is_numeric($page) and after you compute $total_pages you can use another conditional to check if $page >= 1 && $page <= $total_pages

Related