PDO parameterized query not returning anything - php

I am converting old mysql_query code to PDO parameterized queries. Here's what I have so far. It doesn't seem to return anything. I have tried the same query in phpmyadmin, and in the old code with the same input, and the query returns rows those ways.
public function searchArticle($input)
{
$db = new PDO("mysql:host=localhost;dbname=thecorrectdbname", "root", "supersecretpassword");
$statement = $db->prepare("SELECT * FROM news WHERE headline LIKE '%:title%'
OR content LIKE %:content%'
OR author LIKE '%:author%'
ORDER BY id DESC");
$statement->execute(array('title' =>$query,
'content' =>$query,
'author'=>$query));
$result = $statement->fetchAll();
print_r($result);
if (!$result || $statement->rowCount() <= 0)
{
echo'nothing in this array';
return false;
}
return $result;
}
This returns
Array ( ) nothing in this array
Using the same $db connection I can manage to INSERT data into the DB, so the connection is working.
Two questions.
What am I doing wrong in this code?
Suppose I would get the code working. Is the $result object returned by a PDO prepared statement structurally the same as a mysql_query $result object? If not, how do I convert a PDO resultset to a mysql_query one?

Your replacement variables will get escaped and quoted automatically by PDO, which means you cannot have a variable within quotes.
change the following:
$statement = $db->prepare("SELECT * FROM news WHERE headline LIKE :title
OR content LIKE :content
OR author LIKE :author
ORDER BY id DESC");
$statement->execute(array('title' =>'%'.$query.'%',
'content' =>'%'.$query.'%',
'author'=>'%'.$query.'%'));

You are doing an invalid use of placeholder. Placeholder must be used in the place of whole value.
$statement = $db->prepare("SELECT * FROM news WHERE headline LIKE :title
OR content LIKE :content
OR author LIKE :author
ORDER BY id DESC");
$statement->execute(array('title' =>"%$query%",
'content' =>"%$query%",
'author'=>"%$query%"));

Related

search not returning query

Sorry my english. I'm trying to search mysql database that contains hashtags, but it returns all.
eg Search #NBA returns: #NBA, #NBA2021, #NBAscoreBoard, etc
I've tried every preg_replace on here. eg #(^|\s)#(\w*[a-zA-Z_]+\w*)# But how do I break after the specific search is met?
$_GET["tag"]='#nba'; // $_GET is from a query string
$fulltag = preg_replace("/[^a-zA-Z0-9_]/", '', $_GET["tag"]); //trying to isolate this problem
$sql='SELECT * FROM status WHERE data LIKE "%#'.$fulltag.'%" LIMIT 12';
//
//
//
echo //the result containing the "# $fulltag";
As I said in my comment--just doing two queries with one to test if data = fullTag, and then if that returns nothing, then doing the wildcard search--is probably going to be simpler.
However, if you really want this to be a single query, you could do something like this, wherein you test to see if it is an exact match within a sub-query, then order by whether it's an exact match so that if there is an exact match, it will be the first result.
SELECT *
FROM (
SELECT
data,
CASE
WHEN data = "#NBA"
THEN 1
ELSE 0
END AS is_exact
FROM status
WHERE data LIKE "%#NBA%"
LIMIT 12
) AS matches
ORDER BY is_exact DESC
A separate note: You code right now is very vulnerable to SQL Injection. You should try using parameterized prepared statements instead of manually building your queries. See PDO or MySQLi prepared statements.
Here is an example of the above query using PDO, and this method of using CONCAT to safely add wildcards to your query:
$_GET["tag"]='#nba'; // $_GET is from a query string
$fulltag = preg_replace("/[^a-zA-Z0-9_]/", '', $_GET["tag"]); //trying to isolate this problem
$pdo = new PDO(/* your connection details */);
$sql =
'SELECT *
FROM (
SELECT
data,
CASE
WHEN data = CONCAT("#", :tag1)
THEN 1
ELSE 0
END AS is_exact
FROM status
WHERE data LIKE CONCAT("%#", :tag2, "%")
LIMIT 12
) AS matches
ORDER BY is_exact DESC
';
$stmt = $pdo->prepare($sql);
$stmt->execute([
':tag1' => $fulltag,
':tag2' => $fulltag,
]);
Here's your simpler query using the same, safer approach:
$_GET["tag"]='#nba'; // $_GET is from a query string
$fulltag = preg_replace("/[^a-zA-Z0-9_]/", '', $_GET["tag"]); //trying to isolate this problem
$pdo = new PDO(/* your connection details */);
$sql = 'SELECT * FROM status WHERE data LIKE CONCAT("%#", :fullTag, "%") LIMIT 12';
$stmt = $pdo->prepare($sql);
$stmt->execute([':fullTag' => $fulltag]);

handling database with php best option

i am doing a mini project of social networking , i am having a doubt about table .
let see , i need to provide post in their page. to do this,should i have to create table for each user or just create one table and use it for multiple users (data can be fetched by selecting particular user name and display it in their page ).
which is the best way?
my php code:
<?php
$query="select * from table_name where user=$username order by time desc;";
?>
To answer your question
It's best to just use 1 table of users and have a separate able for your posts. Your users table should have all the information for each specific users with 1 unique value that is automatically generated by the MySQL database. (Use auto-increment) And in the posts table you should have all the data for each post with a user_id column that holds the unique value from the users table, this way you know who posted it.
Here is a mockup table structure:
Users table:
uid | name | email
Posts table:
uid | user_id | message
user_id in the posts table should always be equal to some uid in the users table.
Every single table should always have some unique value that is assigned its primary value
My real concern
I am very concerned with the security of your application. Prepared statements are WAY easier to use, and WAY more secure.
In the code snippet that you shared:
<?php
$query="select * from table_name where user=$username order by time desc;";
?>
this query is very insecure, as Bobby Tables would tell you. I'm not sure why type of database connection you are using, but I suggest PDO. I wrote a function that makes this very very easy, here is the snippet for that:
This is a file I usually call connection.php that you can import on any page you need to use your database.
<?php
$host = 'localhost';
$db = '';
$user = '';
$pass = '';
$charset = 'utf8';
$dsn = "mysql:host={$host};dbname={$db};charset={$charset}";
$opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new PDO($dsn, $user, $pass, $opt);
function pdoQuery($query, $values = []) {
global $pdo;
if(!empty($values)) {
$stmt = $con->prepare($query);
$stmt->execute($values);
} else {
$stmt = $con->query($query);
}
return $stmt;
}
?>
This function allows you to EASILY use prepared statements by just
including the connection.php page and writing queries in a way that is
readable, clean, and secure. As I'm sure a lot of people reading this are not used to Prepared Statements or know how they
work, the rest of this post will explain that.
One of the biggest differences here is that instead of using String
Interpolation in
your query, you will set variables as question marks ?, so your
query looks like this: UPDATE table SET user=? instead of UPDATE
table SET user='$user' - and the variables will be sent later for
safety, so this prevents SQL Injection.
This it the way your query would look now:
pdoQuery("SELECT * FROM `table_name` WHERE user=? ORDER BY `time` DESC", [$username]);
This is basically how it works:
pdoQuery(string $query, array $variables)
If you pass no variables, it automatically uses the query() function, if you do pass variables it automatically binds and executes the statements. No matter what query you do, the function always returns the query as an object, so you can act on it using any method you can normally use on a PDO query after the execute.
If you know how these work, you can stop reading here :) I put some
exmaples below of some of the ways you can manipulate the return data
to do what you need to do.
This function returns the object of the query you requested, so if you wanted to loop through all of the results of your query you use it like this:
$stmt = pdoQuery("SELECT * FROM `table_name` WHERE `user`=? ORDER BY time DESC", [$username])->fetchAll();
foreach($stmt as $row) {
$row['name']."<br>";
}
Or if you just wanted to get a single column from a specific row, you could use it like this:
$username = pdoQuery("SELECT `username` FROM `users_table` WHERE uid=? ORDER BY `time` DESC", [$uid])->fetchColumn();
Which will return the username from user where uid=$uid as a string
or if you wanted several values from 1 specific row, you could do
$user = pdoQuery("SELECT `username`,`name`,`email` FROM `users_table` WHERE uid=? ORDER BY time DESC", [$uid])->fetch();
Which will return to $user as an array that has the username, name, and email of the user.
You can also use this function to INSERT, UPDATE, or basically any type of query you can think of. This is how you insert:
pdoQuery("INSERT INTO `table_name` (`name`,`col2`, `col3`) VALUES (?,?,?)", [$name, $col1, $col2]);
My PDO Class
Since writing this post, I have created a new database wrapper class called GrumpyPDO (Hosted on Github).
This class method returns the object of the query you requested, so if you wanted to loop through all of the results of your query you use it like this:
Fetch All
GrumpyPDO Long Syntax
$stmt = $db->run("SELECT * FROM `table_name` WHERE `user`=? ORDER BY time DESC", [$username])->fetchAll();
GrumpyPDO Short Syntax
$stmt = $db->all("SELECT * FROM `table_name` WHERE `user`=? ORDER BY time DESC", [$username]);
Loop:
foreach($stmt as $row) {
$row['name']."<br>";
}
Single Column Return
Or if you just wanted to get a single column from a specific row, you could use it like this:
//Long Syntax
$username = $db->run("SELECT `username` FROM `users_table` WHERE uid=? ORDER BY `time` DESC", [$uid])->fetchColumn();
//Short
$username = $db->cell("SELECT `username` FROM `users_table` WHERE uid=? ORDER BY `time` DESC", [$uid]);
Which will return the username from user where uid=$uid as a string
Entire Row Return
or if you wanted several values from 1 specific row, you could do
//Long Syntax
$user = $db->run("SELECT `username`,`name`,`email` FROM `users_table` WHERE uid=? ORDER BY time DESC", [$uid])->fetch();
//Short Syntax
$user = $db->row("SELECT `username`,`name`,`email` FROM `users_table` WHERE uid=? ORDER BY time DESC", [$uid]);
Which will return to $user as an array that has the username, name, and email of the user.
DML Queries
You can also use this function to INSERT, UPDATE, or basically any type of query you can think of. This is how you insert (All DML's are similar):
$db->run("INSERT INTO `table_name` (`name`,`col2`, `col3`) VALUES (?,?,?)", [$name, $col1, $col2]);

PDO bindParam not working as expected

This has been bugging for a long time, and I still can't figure out what i'm doing wrong.
In the code I want to select a few users with a comma separated string. The string will always be legit and valid.
In the first example, the one I would like to use, uses bindParam to assign the value of $postId to the SQL query. I have been using bindParam() for lots of other calls, but in this specific case, it fails.
$postId = "1,2,3";
$stm = $this->db->prepare('SELECT * FROM posts WHERE find_in_set(userId, "?") ORDER BY id DESC');
$stm->bindParam(1, $postId, PDO::PARAM_STR);
$stm->setFetchMode(PDO::FETCH_ASSOC);
$stm->execute();
$results = $stm->fetchAll();
return print_r($results,true);
This code returns:
array (
)
In this other code which I really wouldn't like to use, I just pass the value of $postId right into the sql query.
$stm = $this->db->prepare('SELECT * FROM posts WHERE find_in_set(userId, "'.$postId.'") ORDER BY id DESC');
$stm->setFetchMode(PDO::FETCH_ASSOC);
$stm->execute();
$results = $stm->fetchAll();
return print_r($results,true);
This code returns all the rows it is supposed to retrieve.
My question is; What is the specific problem and how can I avoid doing this again?
You shouldn't have quotes around the placeholder in yout query:
$stm = $this->db->prepare('SELECT * FROM posts WHERE find_in_set(userId, ?) ORDER BY id DESC');
See additional docs here.
Although it's not directly related to the question, it's also a handy habit to get into to use named params. When you have only one param to pass, it's not too bad, but when you start getting five or so question marks in the query, it's MUCH easier to actually read if you used named params:
SELECT * FROM posts WHERE find_in_set(userId, :someID) ORDER BY id DESC
Then you bind them as named params in your code:
$sth->bindParam(':someID', $postId, PDO::PARAM_STR);
You don't need to add the double quotes "?" when referencing the value
'SELECT * FROM posts WHERE find_in_set(userId, "?") ORDER BY id DESC'
Should be
'SELECT * FROM posts WHERE find_in_set(userId, ?) ORDER BY id DESC'

Using PDO in PHP to count all from database and the 'WHERE' is a variable that has to be cleaned

I'm trying to count all of the rows from an item list where the id matches a user input. I am switching all of my code from mysql to PDO as I have learned it is much better.
The code below is what I found to work in my situation.
$id = '0';
$sql="SELECT count(*) FROM item_list WHERE item_id = $id";
$data=$connMembers->query($sql)->fetchcolumn();
echo $data;
However, It is not safe for a live site due to sql injections.
I want to know how can I change it to work whare it sanatizes the user input.
I would prefer using a prepare and execute functions so the variables are kept seperately.
So is there something I can do?
This is where you start binding parameters. I prefer to do it using ? and one array for inputs.
Assuming $connMembers is your PDO object:
$sql="SELECT COUNT(*) FROM item_list WHERE item_id = ?";
$input=array($id); //Input for execute should always be an array
$statement=$connMembers->prepare($sql);
$statement->execute($input);
$data=$statement->fetchObject();
var_dump($data);
To add more variables to your sql, just add another ? to the query and add the variable to your input.
$sql="SELECT COUNT(*) FROM item_list WHERE item_id = ? AND item_name=?";
$input=array($id, $name); //Input for execute should always be an array
$statement=$connMembers->prepare($sql);
$statement->execute($input);
$data=$statement->fetchObject();
var_dump($data);
OR you can use bindParam:
$sql="SELECT COUNT(*) FROM item_list WHERE item_id = :itemID";
$statement=$connMembers->prepare($sql);
$statement->bindParam(':itemID', $id);
/*Here I am binding parameters instead of passing
an array parameter to the execute() */
$statement->execute();
$data=$statement->fetchObject();
var_dump($data);

selecting mysql data inside an array with PDO fetchAll

I'm trying to get a certain data from mysql with fetchAll.
I currently have this:
$sql1= $dbh->query("SELECT * FROM information");
$comments= $dbh->prepare("SELECT * FROM comments WHERE idinformation= ?");
if($retail){
while($row = $retail -> fetch(PDO::FETCH_ASSOC)){
$comments->execute(array($row['idproducts']));
$json['data'][] = array(
'id'=>$row['idproducts'],
"headline"=>$row['headline'],
'price'=> array ("full_price" => $row['full_price']),
'description'=>$row['description'],
"comments" => $comments->fetchAll(PDO::FETCH_ASSOC)
);
}
$json_encode = json_encode($json);
$obj = json_decode($json_encode,true);
}
My comments is output all the columns in my database. What if I only want comments,time,id,etc... how would I distinguish this in this syntax?
Thanks in advance!
When querying a SQL database, SELECT statements should also include a list of columns you want returned. This not only saves time because the SQL database doesn't have to retrieve a list of columns on each query, but it requires you to think about what you need. In your case, if you only want: comments, time, id then you should specify it:
$comments= $dbh->prepare("SELECT id, time FROM comments WHERE idinformation= ?");
Change the line
$comments= $dbh->prepare("SELECT * FROM comments WHERE idinformation= ?");
to
$comments= $dbh->prepare("SELECT comments,time,id FROM comments WHERE idinformation= ?");
Edit:
Alternatively use group_concat(comments time id, ', ') in a single SQL query. You could do this as a single "JOIN"ed query, and group_concat the comments if you can get the separator you need. Everything is then done SQL-side = faster.
Documentation: http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-concat

Categories