Wordpress: wpdb prepare with conditional variable - php

I currently have a table. If the user searches for something, I would like the query to return the filtered results. If the user doesn't search for something, it should return all results. I'm not too sure how to do this with wpdb prepare.
if($search_query!=="all") {
$search_query = '%' . $search_query . '%';
$where = 'WHERE column_name LIKE %s';
}
$results = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->prefix}table_name ".$where." ORDER BY id DESC LIMIT %d, %d", $search_query,$current_page,$rows_per_page));
Right now nothing returns when the search field is empty because the query is erroring out because it's throwing the parametrization off and passing $search_query to the %d beside LIMIT. Is it possible to make this variable conditional? Is there a way to do this without an IF statement ?

It looks like you can pass an array to prepare, as well as a list of variables, according to the WordPress documentation
That means that you could do something like this:
$where = "";
$parameters = array($search_query,$current_page,$rows_per_page);
if($search_query!=="all") {
array_push($parameters, '%' . $search_query . '%');
$where = 'WHERE column_name LIKE %s';
}
$results = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->prefix}table_name ".$where." ORDER BY id DESC LIMIT %d, %d", $parameters));
Your WHERE clause will be empty if there's no data, so concatenating it into your query won't cause issues.

Why not do the prepare in the "If" statement? You can then do the other prepare (without the where clause) in the "Else" and just use the get_results on the proper prepared query?
if($search_query!=="all") {
$search_query = '%' . $search_query . '%';
$where = 'WHERE column_name LIKE %s';
$prepared = $wpdb->prepare("SELECT * FROM {$wpdb->prefix}table_name ".$where." ORDER BY id DESC LIMIT %d, %d", $search_query, $current_page, $rows_per_page) ;
} else {
$prepared = $wpdb->prepare("SELECT * FROM {$wpdb->prefix}table_name ORDER BY id DESC LIMIT %d, %d", $current_page, $rows_per_page);
}
$results = $wpdb->get_results($prepared);

You can escape the like parameter yourself and add it as a where clause if needed like this:
function like($str)
{
global $wpdb;
return "'" . '%' . esc_sql($wpdb->esc_like($str)) . '%' . "'";
}
if($search_query!=="all") {
$where = 'WHERE column_name LIKE ' . like($search_query);
}
and remove the search_query param from the prepared statement

Related

Codeigniter create a prepared statement or use active record for search with concat

I was wondering how I can prevent sql injections with this search query of mine? Unfortunately I had to use the string due to me needing to concatenate the first and last names to search. I have tried prepared statements but they don't seem to work here too. I hope someone can help me with this. Thank you.
My function
public function admin_search($input,$limit,$start){
$sql = "SELECT * FROM agent_accounts as aa LEFT JOIN person as p ON aa.person_id = p.id "
. "WHERE CONCAT_WS('', p.first_name, p.last_name) LIKE '%$input%' "
. "OR p.email LIKE '%$input%' OR p.phone_number LIKE '%$input%' "
. "OR aa.account_number LIKE '%$input%' LIMIT $limit OFFSET $start";
$query = $this->db->query($sql);
if($query->num_rows()>0){
foreach($query->result()as $row){
$documents[] = $row;
}
return $documents;
}else{
return false;
}
}
Codeigniter Active records automatically escape queries to prevent from SQL injection
Like this
$query = $this->db->get_where('table_name', array('id' => $id), $limit, $offset);
But if you use query siblings
Try this :
$sql = "SELECT * FROM agent_accounts as aa LEFT JOIN person as p ON aa.person_id = p.id "
. "WHERE CONCAT_WS('', p.first_name, p.last_name) LIKE ? "
. "OR p.email LIKE ? OR p.phone_number LIKE ? "
. "OR aa.account_number LIKE ? LIMIT ? OFFSET ?";
$query = $this->db->query($sql,array('%{$input}%','%{$input}%','%{$input}%','%{$input}%',$limit,$start));
The question marks in the query are automatically replaced with the values from array.

MySQL syntax error in string built by PHP

I have some code which generates a MySQL query string called $query:
$query = "select * from Surveys where surveylayoutid='$surveyid' and customerid='" . $_SESSION['login_customerid'] . "' and (";
$clue = $_POST['postcode'];
$onwhat="Postcode";
$query .= $onwhat . " like '%$clue%') order by id desc";
$result = mysql_query($query, $connection) or die(mysql_error());
This returns something like:
select * from Surveys where surveylayoutid='12' and customerid='1' and (Postcode like '%dn%') order by id desc
which works fine. I've then altered the code because I want to search on more fields so it now reads:
$remap = array("Postcode", "Street", "HouseNum", "District", "Town");
$query = "select * from Surveys where surveylayoutid='$surveyid' and customerid='" . $_SESSION['login_customerid'] . "' and (";
for ($i=0; $i<=4; $i++) {
if ($_POST[strtolower($remap[$i])]!="") {
$clue = $_POST[strtolower($remap[$i])];
$query .= $remap[$i] . " like '%$clue%') order by id desc";
break;
}
}
This also returns:
select * from Surveys where surveylayoutid='12' and customerid='1' and (Postcode like '%dn%') order by id desc
which on the face of it is identical but it generates this error:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'like '%dn%' order by id desc' at line 1
In both cases $query contains the same "text" but for some reason isn't treated as a valid MySQL query in the updated code, can anyone tell me why?
One possible problem could be the interpretation of the content here.
If you use:
$query .= $remap[$i] . " like '%$clue%') order by id desc";
All that is inside "" gets to be interpreted. Thus there could be unwanted side effects that you don't see at first glance and can explain what is happening. To avoid this it would have to be changed to:
$query .= $remap[$i] . ' like ' . "'" . '%' . $clue . '%' . "') order by id desc";
Even though more clunky in terms of how big it is, it makes sure that $lue and also the % are not interpreted as all in between ' ' is not interpreted.
See if this help you solve your problem?
$remap = array(
"Postcode",
"Street",
"HouseNum",
"District",
"Town"
);
for ($i = 0; $i <= 4; $i++)
{
if ($_POST[strtolower($remap[$i]) ] != "")
{
$query = "select * from Surveys where surveylayoutid='12' and customerid='1' and (";
$clue = $_POST[strtolower($remap[$i]) ];
$query.= $remap[$i] . " like '%$clue%') order by id desc";
$query_done[] = $query;
unset($query);
$result = mysql_query($query_done[$i], $connection) or die(mysql_error());
// Display your result here
}
}
I tried changing your code abit, and it seems the result is something like this
select * from Surveys where surveylayoutid='12' and customerid='1' and (Postcode like '%Postcode%') order by id descselect * from Surveys where surveylayoutid='12' and customerid='1' and (Street like '%Street%') order by id descselect * from Surveys where surveylayoutid='12' and customerid='1' and (HouseNum like '%HouseNum%') order by id descselect * from Surveys where surveylayoutid='12' and customerid='1' and (District like '%District%') order by id descselect * from Surveys where surveylayoutid='12' and customerid='1' and (Town like '%Town%') order by id desc

sql LIKE does not show wanted results to fetch

For an related products part I'm making it does not show the results I want it to show.
This is my code:
// Info current t-shirt. Normally from database
$name = "T-shirt";
$description = "Stylish LUFTRAUSERS T-shirt designed by Amon26.";
$relatedSearch = $name . " " . $description;
// Query which searches for related items
$query = $db->prepare("SELECT * FROM tbl_products WHERE description LIKE '%' :relatedSearch '%' OR name LIKE '%' :relatedSearch '%' LIMIT 5");
$query -> bindParam("relatedSearch", $relatedSearch, PDO::PARAM_STR);
if($query -> execute()){
while($related = $query->fetch(PDO::FETCH_OBJ)) {
echo "<p style='color:black;'>" . $related->description . "</p></br>";
}
}
When I replace the bindparam $relatedSearch for $name it does show 5 results. But when I search for $relatedSearch variable it doesn't show anything. It seems that it searches for the full string and nothing matches that. Instead of that I just want it to look for single words in that string
Extra: Screenshot of the database http://puu.sh/eeviJ/133a2de7c9.png
You need to include the colon in your binding. I would also try structuring your query like this instead.
$query = $db->prepare("SELECT * FROM tbl_products
WHERE description
LIKE :relatedSearch OR name LIKE :relatedSearch LIMIT 5");
$query -> bindParam(":relatedSearch", '%' . $relatedSearch . '%', PDO::PARAM_STR);
But, maybe this is more like what you're looking for...
$query = $db->prepare("SELECT * FROM tbl_products
WHERE description
LIKE :description OR name LIKE :name LIMIT 5");
$query -> bindParam(":description", '%' . $description . '%', PDO::PARAM_STR);
$query -> bindParam(":name", '%' . $name . '%', PDO::PARAM_STR);
Maybe it is usefull for you.
Do not use single quote after %.
$query = $db->prepare("SELECT * FROM tbl_products WHERE description LIKE '% :relatedSearch %' OR name LIKE '% :relatedSearch %' LIMIT 5");

LIKE query is unable to retrieve data, why?

This query is unable to retrieve any data from MySQL for reasons I cannot figure out after countless hours..
public function search()
{
if(isset($_GET['search']))
{
$searchTerms = trim(strip_tags($_GET['search']));
$sth = $this->db->prepare("SELECT COUNT(*) FROM articles WHERE (article_content LIKE :search) OR (article_title LIKE :search)");
$sth->execute( array(':search' => '%' . $searchTerms . '%') );
if($sth->fetchColumn() > 0)
{
while($row = $sth->fetchAll(PDO::FETCH_ASSOC))
{
return "search results: " . $row['article_title'];
return "" . $row['article_content'];
}
} else {
echo "No results.";
}
}
}
No matter what keyword I type in the form it always returns "No results.". What could be the issue because from what I can see it should work..
Selecting all rows from the table structure and counting so that fetchColumn can be runned, it is selecting from the correct table (articles), where article_content and article_title are both rows in the table, so what is the issue?
$sth->execute(array(':search' => '%'.$searchTerms.'%'));
Should be:
$sth->execute(array(':search' => '\'%\' + \''.$searchTerms.'\' + \'%\''));
Each bind var needs to be an individual bind var, even when named, and even when they both contain the same value:
$sth = $this->db->prepare(
"SELECT COUNT(*)
FROM articles
WHERE (article_content LIKE :search1)
OR (article_title LIKE :search2)"
);
$sth->execute(
array(
':search1' => '%' . $searchTerms . '%',
':search2' => '%' . $searchTerms . '%'
)
);
Try this:
$sth = $this->db->prepare("SELECT COUNT(*) FROM articles WHERE (article_content LIKE :search0) OR (article_title LIKE :search1)");
$searchstring="%" . $searchTerms . "%";
$sth->execute( array(':search0' =>$searchstring ,':search1'=>$searchstring) );
pdo fails to retrieve values when the same placheholder is repeated in a query with LIKE in it.

PDO LIKE query not returning results

Well, I've been at this for a few hours, and for the life of me I can't figure out what is wrong. The code is as follows:
$str = "%" . $_POST['str'] . "%";
$offset = (int) $_POST['offset'];
try {
$stmt = $dbh->prepare("SELECT * FROM Spells WHERE :col LIKE :str ORDER BY :sort LIMIT 10 OFFSET :offset");
$stmt->bindParam(":col",$_POST['col']);
$stmt->bindParam(":str",$str);
$stmt->bindParam(":offset",$offset, PDO::PARAM_INT);
$stmt->bindParam(":sort",$_POST['sort']);
$stmt->execute();
}
catch (PDOException $e) {
echo "MySQL error: " . $e->getMessage() . "<br/>";
die();
}
The connection to the database works fine, no errors occur. If I type in % into the search field(which would be output as %%% in the query), results return as expected.
I've attempted the same query in phpMyAdmin and it works fine. I've been updating this script from the deprecated mysql_* functions, which worked fine before.
Example of the previous, deprecated query:
$sql = "SELECT * FROM Spells WHERE " . $col . " LIKE '%" . $str . "%' ORDER BY " . $sort . " LIMIT 10 OFFSET " . $offset;
As I may have already stated, I've been searching on this site as well, trying to find a solution; nothing has worked, not even MySQL's CONCAT('%',:str,'%').
The server I'm testing this on is running off of php version 5.3.17.
My question, in case I did not make it clear, is what am I doing wrong here? For those wondering(I thought that I put this but apparently I did not), there are no error messages.
The issue is that you cannot use parameters in place of identifiers. This means you cannot parameterise column or table names.
What your query essentially looks like when it is executed is
SELECT * FROM Spells WHERE 'some_column_name' LIKE '%something%'...
I would establish a whitelist of search and sort column names and use those to construct your query. Here's a very simple example
$search = array('col1', 'col2', 'col3');
$defaultSearch = 'col1';
$sort = array('col1', 'col2');
$defaultSort = 'col1';
$col = in_array($_POST['col'], $search) ? $_POST['col'] : $defaultSearch;
$sort = in_array($_POST['sort'], $sort) ? $_POST['sort'] : $defaultSort;
$sql = sprintf('SELECT * FROM Spell WHERE %s LIKE :str ORDER BY %s LIMIT 10 OFFSET :offset',
$col, $sort);
$stmt = $dbh->prepare($sql);
// bind :str and :offset, and so on

Categories