Preventing bad input from GET variable - php

I have a variable, that gets the value from the URL.
if (isset($_GET['page'])) {
$getPage = $_GET['page'];
} else {
$getPage = "";
}
if ($getPage == "" || $getPage == "1") {
$page = 0;
} else {
$page = ($getPage * 6) - 6;
}
After it get this value it sends a query to the database, to ask for information. How can I make sure that the input is numeric and doesn't exceed the available amount?
Here is the query:
$query = "SELECT * FROM dbname LIMIT $page,6 ";
$select_all_list_items = mysqli_query($connection, $query);
Right now if i alter the url manually and put in a number that exceeds the page count, it shows nothing, or if I put in letters there it shows an error. In both cases I would like to redirect the user back to the first page.

To check numeric input and invalid page number,
$pageCount = $totalRecords / $recordsPerPage;
/* where $totalRecords is count of total records from db and $recordsPerPage is total rows per page */
if(!is_numeric($_GET['page']) || $_GET['page']>$pageCount){
$getPage = "1";
}

First you'll need to retrieve the total pages from your database:
$countQuery = 'SELECT COUNT(*) FROM dbname';
$countResult = mysqli_query($connection, $countQuery);
$countResultRow = mysqli_fetch_row($countResult);
$numPages = intval($countResultRow[0]);
Then you will need to implement some checks to your get variable:
if ($numPages < 0) {
throw new Exception('No pages to show!');
}
if (!is_numeric($getPage)) {
$getPage = 1;
}
if ($getPage > $numPages) {
$getPage = 1;
}
if ($getPage < 1) {
$getPage = 1;
}
Be careful passing GET values directly into your SQL query, this is a security risk as it can lead to database manipulation via URL. Read up about SQL injection for more information about "escaping" your data pre-query.

Something, like this
$page = 1; //default page 1
if(isset($_GET['page']) && preg_match('/[a-z]/i', $_GET['page'])){
// if set and alpha
header('Location: url of first page');
exit;
}else{
//not sure of this part but ( that's what the OP has so i'll go with it )
$page = ( $_GET['page'] * 6 ) - 6; ///could be 0 on page 1 6*1-6, just saying
}
Personally I'd run a query first to count the total rows, divide that by rows per page, for the total pages, and use that in the if statement... etc.

Related

How to use Android Jetpack Paging 3 with PHP

I have succesfully implemented Android Pagination Library in my App,
The problem is - I dont know the proper way to use it with my PHP code as BackEnd with regards to number of items to load etc.
get_feed.php
<?php
$limit = 2;
//find out how many rows are in the table
$sql = "SELECT count(*) FROM uploads";
$result = $conn->prepare($sql);
$result->execute();
$total = $result->fetchColumn();
//total pages
$totalpages = ceil($total/$limit);
//get the current page or set a default
if (isset($_GET['page']) && is_numeric($_GET['page'])) {
// cast var as int
(int) $currentpage = $_GET['page'];
} else {
//default page num
$currentpage = 1;
}
//if current page is less than first page...
if ($currentpage < 1) {
// set current page to first page
$currentpage = 1;
}
//the offset of the list, based on current page
$offset = ($currentpage - 1) * $limit;
$stmt = "SELECT * FROM uploads ORDER by id DESC LIMIT $offset, $limit";
//I get all requiresd data, send and encode in json
echo json_encode($obj);
?>
All I want to do from this PHP code is to load 2 items at a time from the database.
Android codes
ApiService.kt
#GET(EndPoints.GET_RANDOM_FEED)
suspend fun getRandomFeed(
#Query("page") page: Int
) : PostsResponse
FeedSource.kt
class FeedSource(private val apiDataSource: ApiDataSource) : PagingSource<Int, Posts>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Posts> {
return try {
//start from page 1 for undefined
val nextPage = params.key ?: 1
val response = apiDataSource.getRandomFeed(nextPage)
LoadResult.Page(
data = response.feeds,
prevKey = if (nextPage == 1) null else nextPage - 1,
nextKey = nextPage.plus(1)
)
} catch (e: Exception){
LoadResult.Error(e)
}
}
}
FeedViewModel.kt
#Singleton
class FeedViewModel constructor(private val apiDataSource: ApiDataSource) : ViewModel() {
//I want to load 10 items at first
val feeds = Pager(PagingConfig(pageSize = 10)) {
FeedSource(apiDataSource)
}.flow.cachedIn(viewModelScope)
}
As it is, All items are loaded at once. I have set up the loadState Adapter which should only show a spinner when items are loading or error as the case may be.
But right now, the spinner only shows when all item has been loaded and throws a HTTP 429 error
How do I make the app load 10 items initialy, then 2 at a time according to my PHP code?

PHP Pagination issues and errors

I'm learning PHP at the moment.
I want to make my HTML page pagination.
Here is the code I have:
I'm trying to make 6 videos only per page. And to do that I'm going to search how many ID's I have it means I have that same value of videos so I can make X pages.
At the moment, I'm having this error:
Notice: Object of class mysqli_result could not be converted to int in C:\xampp\htdocs\Site\index.php on line 20
$stmt3 = $db->prepare ("SELECT COUNT(ID_Video) as total FROM Videos");
$stmt3->execute();
$result2 = $stmt3->get_result();
$result2->fetch_assoc();
// Remember to round it up always!
$VideosPerPage = 6;
$totalPages = ceil($result2 / $VideosPerPage);
// Check that the page number is set.
if(!isset($_GET['page'])){
$_GET['page'] = 0;
}else{
// Convert the page number to an integer
$_GET['page'] = (int)$_GET['page'];
}
// If the page number is less than 1, make it 1.
if($_GET['page'] < 1){
$_GET['page'] = 1;
// Check that the page is below the last page
}else if($_GET['page'] > $totalPages){
$_GET['page'] = $totalPages;
}
You are seeing this error because $result2 is PDO result- not an integer. You need to assign the fetched value from the result in a variable. You can use fetchColumn() as you are getting one column. Your first few lines could look like following:
$result2 = $stmt3->get_result();
$totalVideos = $result2->fetchColumn(); // will get the number from single column
// Remember to round it up always!
$VideosPerPage = 6;
$totalPages = ceil($totalVideos / $VideosPerPage);

How to hide the next button when no pages to dispaly

Can someone help me please? I am sure it is easy for you guys. I am battling to find a solution on how to hide the next link when there are no pages to display my code is as follows:
if (!isset($_GET['page']) or !is_numeric($_GET['page'])) {
$page = 0;
} else {
$page = (int)$_GET['page'];
}
$pages_query=mysql_query ("SELECT COUNT * FROM hardware");
$result = mysql_query("SELECT * FROM hardware LIMIT $page, 3");
echo 'Next<p>';
$prev = $page - 3;
//only print a "Previous" link if a "Next" was clicked
if ($prev >= 0) {
echo 'Previous';
}
You can use mysql_num_rows($result) to get the number of records in hardware:
$result = mysql_query("SELECT * FROM hardware LIMIT $page, 3");
$record_count = mysql_num_rows($result);
if ($record_count > 1)
echo 'Next';
in your if statement check if the $page is greater than 0 then according to the outcome of the value of $page write your code. you can use another if statement in the first if statement and make it detect the situation and decide what to do. The other thing is if the user clicked next then the user is on the second page so your previous should appear if $prev is higher than 1 it should make it
something along the lines of:
$itemsPerPage = 3;
$sql = "SELECT * FROM hardware";
$result = mysql_query($sql);
$count = mysql_num_rows($result);
$pageCount = $count/$itemsPerPage;
if($pageCount > $page) { //Are there more pages worth of items stored, than we're currently looking at?
echo 'next';
}
You want to be using OFFSET in your SQL syntax, as well as LIMIT.
LIMIT limits the number of rows returned.
OFFSET tells it to start a number of rows into the result set.
You need to limit to the number of items you want on a page. and offset by that number*page.
Hopes this helps.

How to split search results into pages?

How to split the search results into pages? (like page 1, page 2, page 3...)
When the user searches for products on my e-commerce website, I want results to be split into several pages showing around 20 products per page. The search results are the outcome of database query.
For example: If the user searches for Samsung mobiles so my query will be:
SELECT * FROM PRODUCTS WHERE BRAND='SAMSUNG';
Suppose the above query returns 55 results, how to show them into pages (1,2 and 3)?
I am using PHP, MySQL, Apache on Windows machine.
The appropriate SQL would be adding:
LIMIT start, amount
You can navigate like
search.php?start=20
and then code like:
LIMIT $start, $amount
with
$start = intval($_GET['start']);
and
$amount = 20;
That will result in max 20 records a page.
Use SQL's LIMIT keyword to limit the amount of results from your query; for example:
SELECT * FROM PRODUCTS WHERE BRAND='SAMSUNG' LIMIT 20, 40;
This would select 20 elements, starting at the 40th
Here is the complete code:
<?php
// Requested page
$requested_page = isset($_GET['page']) ? intval($_GET['page']) : 1;
// Get the product count
$r = mysql_query("SELECT COUNT(*) FROM PRODUCTS WHERE BRAND='SAMSUNG'");
$d = mysql_fetch_row($r);
$product_count = $d[0];
$products_per_page = 20;
// 55 products => $page_count = 3
$page_count = ceil($product_count / $products_per_page);
// You can check if $requested_page is > to $page_count OR < 1,
// and redirect to the page one.
$first_product_shown = ($requested_page - 1) * $products_per_page;
// Ok, we write the page links
echo '<p>';
for($i=1; $i<=$page_count; $i++) {
if($i == $requested_page) {
echo $i;
} else {
echo ''.$i.' ';
}
}
echo '</p>';
// Then we retrieve the data for this requested page
$r = mysql_query("SELECT * FROM PRODUCTS WHERE BRAND='SAMSUNG' LIMIT $first_product_shown, $products_per_page");
while($d = mysql_fetch_assoc($r)) {
var_dump($d);
}
?>
Hope its help.
Yes you can run a query to get total record count and than use query using limit
exampe:
select count(id) from table_name
This will return total record count in database
In my php learning books, it provides a solution using a PHP class
it looks like this
<!-- language: php -->
<?php
error_reporting(0); // disable the annoying error report
class page_class
{
// Properties
var $current_page;
var $amount_of_data;
var $page_total;
var $row_per_page;
// Constructor
function page_class($rows_per_page)
{
$this->row_per_page = $rows_per_page;
$this->current_page = $_GET['page'];
if (empty($this->current_page))
$this->current_page = 1;
}
function specify_row_counts($amount)
{
$this->amount_of_data = $amount;
$this->page_total=
ceil($amount / $this->row_per_page);
}
function get_starting_record()
{
$starting_record = ($this->current_page - 1) *
$this->row_per_page;
return $starting_record;
}
function show_pages_link()
{
if ($this->page_total > 1)
{
print("<center><div class=\"notice\"><span class=\"note\">Halaman: ");
for ($hal = 1; $hal <= $this->page_total; $hal++)
{
if ($hal == $this->current_page)
echo "$hal | ";
else
{
$script_name = $_SERVER['PHP_SELF'];
echo "$hal |\n";
}
}
}
}
}
?>
then we call it on the script that require paging
<!-- language: php -->
<?php $per_page = 5;
$page = new Page_class($per_page);
error_reporting(0); // disable the annoying error report
$sql="SELECT * FROM table WHERE condition GROUP BY group";
$result=mysql_query($sql) or die('error'.mysql_error());
// paging start
$row_counts = mysql_num_rows($result);
$page->specify_row_counts($row_counts);
$starting_record = $page->get_starting_record();
$sql="SELECT * FROM table WHERE condition GROUP BY group LIMIT $starting_record, $per_page";
$result=mysql_query($sql) or die('error'.mysql_error());
$number = $starting_record; //numbering
$num_rows = mysql_num_rows($result);
if ($num_rows == 0 )
{ // if no result is found
echo "<div class=\"notice\">
<center><span class=note>NO DATA</span></center>
</div>";
}
else {
// while goes here ...
}
?>
// call the page link
<?php
$page->show_pages_link();
?>
hope it helps, just tried it hours ago to my search script page (learning from books)

Pagenav. By clicking next get next lets say "20" records (php/mysql)

I've already created a query to mysql that will give 20 results from mysql table etc. "cat"
heres the calling:
if(isset($_GET['cat']))
{
$query = "SELECT game_title,game_desc,....
FROM games WHERE cat_id='".validate_input($_GET['cat'])."' LIMIT 20";
}
...
by this I manage to get the results I wanted. What I am asking here is how can I create a "button" that will load the next "20" records from table "cat" (something like Buttons).
<?
$cn=mysql_connect("localhost","root","root") or die(mysql_error());
mysql_select_db("db56") or die(mysql_error());
$sql="select count(*) from emp";
$result=mysql_query($sql);
$r=mysql_fetch_row($result);
$record=$r[0];
$pagesize=20;
$totalpages=$record/$pagesize;
$currpage=$_GET["pg"];
if(!isset($currpage))
$start=0;
else {
$currpage--;
$start= $currpage * $pagesize;
}
$end=$start+$pagesize;
$sql="select * from emp limit $start,$pagesize";
$result=mysql_query($sql);
if($result){
print "<table border='1'>";
print "<tr><th>No</th><th>Name</th><th>Date</th></tr>";
while($r=mysql_fetch_row($result))
{
print "<tr><td>$r[0]</td><td>$r[1]</td><td>$r[2]</td></tr>";
}
print "</table>";
}
for($i=1;$i<=$totalpages;$i++){
print "<a href='listemp.php?pg=$i'> $i </a>";
}
?>
If you keep track of what page you're on, in the URL or a hidden field or session variable, you can use that to work out the limit. For example, page 2 should show limit 20 from row 20 (20 times the page offset).
You can pass two SQL parameters to LIMIT (put a comma between them) If you do, the first tells SQL how many records to skip (ie the offset of the first record) and the 2nd parameter is the one you're already using (how many records to return).
So just put a variable in your "next" link that says what page to display. You can pass the offset in this link, but it's pretty common to pass the "page number" instead, and multiply by the number of records per page before sticking it in the sql.
next page
With a bit more work, you can make a "previous page" link, and make the correct links non-clickable when you're at the first/last page.
Pass along a parameter that tells the script that you want another chunk of the results and not just the first batch.
So for the link it could be like this:
example.com/results.php?cat=1&page=2
Where page= will tell the script what page you want to return.
Then you want to turn that LIMIT number you have so that you can work out some simple maths
$results_cnt = 20; //--rows you want per page of results
Now in your script you'll check to see if the page variable has been set. If not, default the start row to return from the first. But as you want to return different pages/sets of results, a little math is needed in order to start at the proper row.
if(isset($_GET["page"]) //--see if the variable is even there
{
$page_num = (int)$_GET["page"]; //--forcing it to always be an integer
$start_row = $results_cnt * ($page_num - 1);
/* --
what happens:
($results_cnt currently at 20)
on page one (page=1), start at row 0
math: 20 * (1 - 1) = 0
on page two (page=2), start at row 20
math: 20 * (2 - 1) = 20
on page three (page=3), start at row 40
math: 20 * (3 - 1) = 40
etc.
*/
}
else
$start_row = 0;
Now, having set the correct starting row, adjust the SQL query to use the variables like so:
if(isset($_GET['cat']))
{
$query = "SELECT game_title,game_desc,....
FROM games
WHERE cat_id='".validate_input($_GET['cat'])."'
LIMIT $start_row, $results_cnt";
}
OK I got it fixed I guess...
in index.php:
<?php
$games = array();
$count = 1;
$total = 0;
if(isset($_GET['cat']))
{
$query = "SELECT game_title,game_desc,.... FROM games WHERE cat_id='".validate_input($_GET['cat'])."' LIMIT 20";
$total = mysql_num_rows(mysql_query("SELECT 1 FROM games WHERE cat_id='".validate_input($_GET['cat'])."'"));
}
$query_result = #mysql_query ($query) OR error(mysql_error(), __LINE__, __FILE__, 0, '', '');
while ($info = #mysql_fetch_array($query_result))
{
/* -- here goes the infos.. */
$games[$info['game_title']]['game_title'] = $info['game_title'];
etc..
if(isset($_GET['cat']))
{
/* -- for template engine */
$page->SetLoop ('PAGES', pagenav($total,$_GET['page'],20,$config['site_url'].'?cat='.$_GET['cat'],1,$lang));
}
--end php
and in funct.php
--start php
function pagenav($total,$page,$perpage,$url,$posts=0)
{
$page_arr = array();
$arr_count = 0;
if($posts)
{
$symb='&';
}
else
{
$symb='?';
}
$total_pages = ceil($total/$perpage);
$llimit = 1;
$rlimit = $total_pages;
$window = 5;
$html = '';
if ($page<1 || !$page)
{
$page=1;
}
if(($page - floor($window/5)) <= 0)
{
$llimit = 1;
if($window > $total_pages)
{
$rlimit = $total_pages;
}
else
{
$rlimit = $window;
}
}
else
{
if(($page + floor($window/2)) > $total_pages)
{
if ($total_pages - $window < 0)
{
$llimit = 1;
}
else
{
$llimit = $total_pages - $window + 1;
}
$rlimit = $total_pages;
}
else
{
$llimit = $page - floor($window/2);
$rlimit = $page + floor($window/2);
}
}
if ($page>1)
{
$page_arr[$arr_count]['title'] = 'Prev';
$page_arr[$arr_count]['link'] = $url.$symb.'page='.($page-1);
$page_arr[$arr_count]['current'] = 0;
$arr_count++;
}
for ($x=$llimit;$x <= $rlimit;$x++)
{
if ($x <> $page)
{
$page_arr[$arr_count]['title'] = $x;
$page_arr[$arr_count]['link'] = $url.$symb.'page='.($x);
$page_arr[$arr_count]['current'] = 0;
}
else
{
$page_arr[$arr_count]['title'] = $x;
$page_arr[$arr_count]['link'] = $url.$symb.'page='.($x);
$page_arr[$arr_count]['current'] = 1;
}
$arr_count++;
}
if($page < $total_pages)
{
$page_arr[$arr_count]['title'] = 'Next';
$page_arr[$arr_count]['link'] = $url.$symb.'page='.($page+1);
$page_arr[$arr_count]['current'] = 0;
$arr_count++;
}
return $page_arr;
}
?>
and call it by
{LOOP: PAGES}{PAGES.title} {/LOOP: PAGES}
in an .html file..
it works perfectly but when I press the number 2 or next to get the next 20 records it jumps back to the first 20...
on the browser it reads http://siteurl/?cat=1&page=2
I can't figure out why.

Categories