PDO pagination with LIKE - php

The following PHP SQL code shows error
Recoverable fatal error: Object of class PDOStatement could not be converted to string in /home/customer/xxxx/fetch_data.php on line 28
I was trying to display products information from the table filter
There are two $statement->execute();, one is to count total search results and another one is to display products for the current page.
I new to PDO method and not an expert in overall coding.
The $filter_query = $stmt . 'LIMIT '.$start.', '.$limit.''; is causing issues.
With that and related functions, the code works and displays data. But if I enable it, the error shows up.
$limit = '5';
$page = 1;
if($_POST['page'] > 1)
{
$start = (($_POST['page'] - 1) * $limit);
$page = $_POST['page'];
}
else
{
$start = 0;
}
$search = "%samsung%";
$stmt = $connect->prepare("SELECT * FROM filter WHERE product_name LIKE :needle");
$stmt->bindParam(':needle', $search, PDO::PARAM_STR);
##
##
$filter_query = $stmt . 'LIMIT '.$start.', '.$limit.'';
$statement->execute();
$total_data = $stmt->rowCount();
$stmt = $connect->prepare($filter_query);
$stmt->execute();
$result = $stmt->fetchAll();
$total_filter_data = $stmt->rowCount();
$output = '
<h3> '.$total_data.' results found </h3>
and display each product
I tried the following code as suggested by Your Common Sense and the pagination and total search result count is working fine, but no products are getting displayed.
$limit = '5';
$page = 1;
if($_POST['page'] > 1)
{
$start = (($_POST['page'] - 1) * $limit);
$page = $_POST['page'];
}
else
{
$start = 0;
}
$name=str_replace(' ', '%', $_POST['query']);
$search = "%$name%";
$base_sql = "SELECT %s FROM filter WHERE product_name LIKE ?";
##
##
####
$count_sql = sprintf($base_sql, "count(*)");
$stmt = $connect->prepare($count_sql);
$stmt->execute([$search]);
$total_data = $stmt->fetchColumn();
####
$data_sql = $count_sql = sprintf($base_sql, "*")." LIMIT ?,?";
$stmt = $connect->prepare($data_sql);
$stmt->execute([$search, $start, $limit]);
$result = $stmt->fetchAll();
##
$output = '
<h3> '.$total_data.' results found </h3> ';
if($total_data > 0)
{
foreach($result as $row)
{
and display each product
Using the following line makes the code show some data, but the pagination is not working.
$data_sql = sprintf($base_sql, "*");
$stmt = $connect->prepare($data_sql);
$stmt->execute([$search]);
$result = $stmt->fetchAll();

That's a not a trivial task as we need to run the same query twice but with minor differences. The first query will use count(*) SQL function to get the total number of records matching the search criteria. The second query will select actual fields with LIMIT clause to get the data for the single page.
$base_sql = "SELECT %s FROM filter WHERE product_name LIKE ?";
$count_sql = sprintf($base_sql, "count(*)");
$stmt = $connect->prepare($count_sql);
$stmt->execute([$search]);
$total = $stmt->fetchColumn();
$data_sql = $count_sql = sprintf($base_sql, "*")." LIMIT ?,?";
$stmt = $connect->prepare($data_sql);
$stmt->execute([$search, $start, $limit]);
$data = $stmt->fetchAll();
Important: In order for this code to work, make sure you are connecting to mysql properly. the proper connection will let a LIMIT clause to accept placeholders and also will warn you in case of any problems.

Related

simple echo function does not spit out number

Below is my pretty simple attempt at trying to count the number of times $name string occurs in the $related_company string row of a table.
I was hoping it would spit out a number, but when i upload it to my webserver, it doesnt spit out anything.
Any ideas?
<?php
$db = new SQLite3('database.sqlite3');
$red = $db->query('SELECT * FROM news');
$name = strtolower("Tesla");
$related_company = $red->fetchArray($row['related_company']);
while ($row = $red->fetchArray()) {
if (in_array($name, $related_company)){
$count+1;
}}
echo $count;
?>
You can do it all in a single query, without having to loop through the results. SQL has a LIKE operator to perform pattern matching in columns.
$db = new SQLite3('database.sqlite3');
$stmt = $db->prepare("SELECT COUNT(*) AS count FROM news WHERE related_company LIKE :name");
$name = '%' . strtolower("Tesla") . '%';
$stmt->bindParam(':name', $name);
$stmt->execute();
$row = $stmt->fetchArray(SQLITE3_ASSOC);
$count = $row['count'];
echo $count;
If the name comes from another table, you can join the tables.
$result = $db->query("
SELECT c.name, COUNT(*) as count
FROM Companies AS c
JOIN news AS n ON n.related_company LIKE '%' || LOWER(c.name) || '%'");
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
echo "{$row['name']}: {$row['count']}<br>";
}

Why is store_result() not returning num_rows equivalent to mysqli Regular Statement?

I've been combing through previous questions and trying many solutions but cannot figure this out. I'm trying to convert this query to a Prepared Statement:
$query = mysqli_query($this->con, "SELECT * FROM notifications WHERE user_to='$userLoggedIn' ORDER BY id DESC");
Here is what I have:
$query = $this->con->stmt_init();
$query->prepare('SELECT * FROM notifications WHERE user_to=? ORDER BY id DESC');
$query->bind_param('s', $userLoggedIn);
$query->execute();
$query->store_result();
$qty = $query->num_rows;
$query_result = $query->get_result();
Below this code I have variables being used like this:
if($qty == 0) {
echo "<li class='no-more-posts' style='height: 0px; text-transform: uppercase;'>- You have no notifications! -</li>";
return;
}
$num_iterations = 0; //Number of messages checked
$count = 1; //Number of messages posted
while($row = $query_result->fetch_assoc()) {
if($num_iterations++ < $start)
continue;
if($count > $limit)
break;
else
$count++;
$user_from = $row['user_from'];
etc.etc.
What I am getting is blank result in my dropdown. If I change the while statement back to the original while($row = mysqli_fetch_array($query)) { (which I know is wrong and from old statement) my result is always returning the li No More Posts to Show. This tells me that $qty = $query->num_rows; is returning 0. Based on documentation my understanding is that once I buffered the result set with store_result() I could call $qty = $query->num_rows; right after. What am I missing here?
I'm certain this isn't the most efficient way to do things, but it's all I have on it; decided to break the statement up.
First I did a statement for the count:
$query_count = $this->con->stmt_init();
$query_count->prepare('SELECT COUNT(*) FROM notifications WHERE user_to=?');
$query_count->bind_param('s', $userLoggedIn);
$query_count->execute();
$query_count_result = $query_count->get_result();
$rows_count = $query_count_result->fetch_array();
$qty = array_shift($rows_count);
Then I did a statement for the data:
$query = $this->con->stmt_init();
$query->prepare('SELECT * FROM notifications WHERE user_to=? ORDER BY id DESC');
$query->bind_param('s', $userLoggedIn);
$query->execute();
$query_result = $query->get_result();
It solved my problem & everything works as expected. I know there is a better way to do this, so if someone has that suggestion great. In the meantime this will have to do.

showing data from database using bindParam

i want to try to showing my data from database using bindParam but i get some error.
Recoverable fatal error: Object of class PDOStatement could not be converted to string in C:\xampp\htdocs\piratefiles\search.php on line 15
here my code
$category = htmlentities($_GET['c']);
$query = htmlentities($_GET['q']);
$page = (isset($_GET['page'])) ? $_GET['page'] : 1;
$limit = 20;
$limit_start = ($page - 1) * $limit;
$query = $db->prepare ("SELECT * FROM `posting` WHERE 'category' = :category AND 'file_name' like :query ORDER BY date DESC LIMIT ".$limit_start.",".$limit);
$query->bindParam(":category", $category);
$query->bindParam(":query", $query);
$query->execute();
$query was the user input, then you assigned it as the PDOStatement, then your the passing it back to bindParam
Change the var name.
$category = htmlentities($_GET['c']);
$query = htmlentities($_GET['q']);
$page = (isset($_GET['page'])) ? $_GET['page'] : 1;
$limit = 20;
$limit_start = ($page - 1) * $limit;
$stmt = $db->prepare ("SELECT * FROM `posting` WHERE 'category' = :category AND 'file_name' like :query ORDER BY date DESC LIMIT ".$limit_start.",".$limit);
$stmt->bindParam(":category", $category);
$stmt->bindParam(":query", $query);
$stmt->execute();
Since im using LIKE so, need to make another variable.
$keyword1 = "%".$category."%";
$keyword2 = "%".$query1."%";
Here's Full code.
$category = htmlentities($_GET['c']);
$query1 = htmlentities($_GET['q']);
$page = (isset($_GET['page'])) ? $_GET['page'] : 1;
$limit = 20;
$limit_start = ($page - 1) * $limit;
$query = $db->prepare ("SELECT * FROM `posting` WHERE category LIKE :category AND file_name LIKE :query1 ORDER BY date DESC LIMIT ".$limit_start.",".$limit);
$keyword1 = "%".$category."%";
$keyword2 = "%".$query1."%";
$query->bindParam(":category", $keyword1);
$query->bindParam(":query1", $keyword2);
$query->execute();

Pagination 2nd page not displaying

Pagination works fine when I don't use the WHERE statement in my SELECT statement. For some reason as soon as I add additional requests in the SELECT statement, only the 1st pagination page works. So it seems like the variable data is lost after the first page is displayed. Below is some of the code:-
<?php
include 'database.php';
include 'paginator.php';
$pdo = Database::connect();
$paginator = new Paginator();
$sql = "SELECT count(*) FROM customer_crm ";
$paginator->paginate($pdo->query($sql)->fetchColumn());
$query = $_GET["query"];
if (isset($query)) {
($_GET['query'])?('%'.$_GET['query'].'%'):'%';
$sql = "SELECT * FROM customer_crm WHERE firstname LIKE :query OR email LIKE :query OR telephone LIKE :query ";
}
else {
$start = (($paginator->getCurrentPage()-1)*$paginator->itemsPerPage);
$length = ($paginator->itemsPerPage);
//$sql = "SELECT * FROM customer_crm WHERE customer_group_id = $input OR date_followup= CURDATE() ORDER BY customer_group_id DESC limit $start, $length ";
$sql = "SELECT * FROM customer_crm ORDER BY date_followup DESC limit $start, $length ";
//$sql = "SELECT * FROM customer_crm WHERE customer_group_id = $input ORDER BY date_followup DESC limit $start, $length ";
}
$sth = $pdo->prepare($sql);
$sth->bindParam(':start',$start,PDO::PARAM_INT);
$sth->bindParam(':length',$length,PDO::PARAM_INT);
$sth->bindParam(':query',$query,PDO::PARAM_STR);
$sth->execute();
foreach ($sth->fetchAll(PDO::FETCH_ASSOC) as $row) {
Without knowing which Paginator are we talking about, I could only advise you to do something like
include 'database.php';
include 'paginator.php';
$pdo = Database::connect();
$paginator = new Paginator();
$query = (isset($_GET["query"]) && strlen($_GET["query"])>1)? '%'.$_GET["query"].'%':'%';
$countsql = "SELECT * FROM customer_crm WHERE firstname LIKE :query OR email LIKE :query OR telephone LIKE :query ";
$sthcount = $pdo->prepare($countsql);
$sthcount->bindParam(':query',$query,PDO::PARAM_STR);
$sthcount->execute();
$count=$sthcount->fetchColumn();
$paginator->paginate($count);
$start = (($paginator->getCurrentPage()-1)*$paginator->itemsPerPage);
$length = ($paginator->itemsPerPage);
$sql = $countsql . ' ORDER BY date_followup DESC limit :start, :length ';
$sth = $pdo->prepare($sql);
$sth->bindParam(':start',$start,PDO::PARAM_INT);
$sth->bindParam(':length',$length,PDO::PARAM_INT);
$sth->bindParam(':query',$query,PDO::PARAM_STR);
$sth->execute();
See, you where making two mistakes here:
getting your count value without considering the query. You should set the value of $query regardless of the existance of $_GET['query'], and use it in your count query as well as your results query.
binding parameters whose placeholders and values do not exist in the query you're executing. Make sure your results query contains :query, :start and :length or you will be binding more parameters than the query has.
You should also have wrapped your statements in try/catch blocks so you could debug what was happening.
try {
$sth = $pdo->prepare($sql);
$sth->bindParam(':start',$start,PDO::PARAM_INT);
$sth->bindParam(':length',$length,PDO::PARAM_INT);
$sth->bindParam(':query',$query,PDO::PARAM_STR);
$sth->execute();
} catch(\PDOException $e) {
die('Error in query: '. $e->getMessage());
}
That way you would have known that the query was failing because of
Invalid parameter number: parameter was not defined
NOTE I have no clue about how your paginator will know about the current page, nor can I see where are you setting the itemsPerPage value.

Getting correct Total Row count and Row Numbers for Pagination

Now I have done this easily with PDO and SQL server however I am struggling getting this working correctly for any general Query. Since I do want this to be reusable by our MySQL tables over any project I am turning here for help.
So the way I used it for PDO and SQL server
function pagedQuery($dbh,$q,$sort,$offset,$limit,$params = array()) {
$limit = preg_replace("/[^0-9]]/","",$limit);
$offset = preg_replace("/[^0-9]]/","",$offset);
$q = preg_replace("/^[^\w]*SELECT/i","SELECT COUNT(*) OVER() as num_rows, ROW_NUMBER() OVER(ORDER BY $sort) AS rownum,",$q);
$q = "SELECT * FROM (".$q.") as pagingTable WHERE rownum > $offset AND rownum <= ($offset+$limit)";
## Prepare Query
$stmt = $dbh->prepare($q);
try {
$stmt->execute($params);
} catch(PDOException $e) {
print $e->getMessage();
}
## Return Results
return $stmt->fetchAll();
Now obviously the OVER functionality does not exist and MySQL and this has to be modified. Here is my attempt at a new version:
function mysqlPagedQuery($dbh,$q,$table,$sort,$offset,$limit,$params = array()) {
$limit = preg_replace("/[^0-9]]/","",$limit);
$offset = preg_replace("/[^0-9]]/","",$offset);
$q = preg_replace("/^[^\w]*SELECT/i","SELECT (SELECT COUNT(*) as num_rows FROM ".$table.") AS num_rows, #rowN := #rowN + 1 AS rownum,",$q);
$q = "SELECT * FROM (".$q.") as pagingTable WHERE rownum > $offset AND rownum <= ($offset+$limit)";
## Prepare Query
$stmt = $dbh->prepare($q);
try {
$query = $dbh->query("set #rowN = 0;");
$stmt->execute($params);
} catch(PDOException $e) {
print $e->getMessage();
}
## Return Results
return $stmt->fetchAll();
Now this will "work" given that you give it a table but I soon realized that the num_rows will not return the correct value unless given all of the WHERE clause of the query sent into it. I would have to parse that in an inefficient manner and I feel there is a much easier way to do this than I am making it out to be.
I ended up with this thanks to bobkingof12vs posted link. Can't give answer credit to him directly because it was not posted here :(
function mysqlPagedQuery($dbh,$q,$sort,$offset,$limit,$params = array()){
$limit = preg_replace("/[^0-9]]/","",$limit);
$offset = preg_replace("/[^0-9]]/","",$offset);
//need to use the original query a few times to create paged
$tempQuery = $q;
//replaces query's select with a count to get numrows
$q1 = "SELECT sql_calc_found_rows * FROM (".$tempQuery.") AS tempTable";
## Prepare Query
$stmt1 = $dbh->prepare($q1);
$q2 = preg_replace("/^[^\w]*SELECT/i","SELECT FOUND_ROWS() as num_rows,",$tempQuery);
$q2 .= " ORDER BY ".$sort;
$q2 .= " LIMIT ".$offset.",".$limit;
//print $q2;
## Prepare Query
$stmt2 = $dbh->prepare($q2);
try{
$stmt1->execute();
$stmt2->execute($params);
}
catch(PDOException $e){
print $e->getMessage();
}
## Return Results
return $stmt2->fetchAll();
}

Categories