I am trying to do a small search engine for a website.
This is the simple code
if ( Input::issetGet('q') ) {
$q = Input::get('q');
if ( !empty($q) ) {
$keywords = explode(' ', $q);
$findPhones = $dbh->prepare("
SELECT
p.id AS pId, p.name AS pName, p.original_price, p.price, p.img, p.brand, p.model, p.color, p.o_s, p.status, p.description,
b.id, b.name AS bName,
m.id, m.name AS mName
FROM phones AS p
LEFT JOIN brands AS b ON p.brand = b.id
LEFT JOIN phone_models AS m ON p.model = m.id
WHERE p.name LIKE '%" . implode("%' OR p.name LIKE '%", $keywords) . "%'
OR p.description LIKE '%" . implode("%' OR p.description LIKE '%", $keywords) . "%'
OR b.name LIKE '%" . implode("%' OR b.name LIKE '%", $keywords) . "%'
ORDER BY p.id DESC
");
$findPhones->execute();
$phones = $findPhones->fetchAll();
}
}
Let me quickly explain. If I search for samsung
, this query will check if the p.name
, p.description
or b.name
contain this word. If I search for samsung computers
the query will check if p.name
, p.description
or b.name
contain either the word samsung
or computers
and so on for more search terms.
The problem is that I can't find a way to bind $keywords
, I would like not to hardcode it like in the query, but to pass it when I execute the query.
I tried with ?
and :keyword
, but none worked. If I dump the query, the LIKE
statements are empty, ""
.
My guess is that the problem lays in the implode function which is inside the query, it won't allow me to parameterize the array $keywords
.
At this point I simply query the database without binding values and I am open for SQL Injection.
Q: How can I bind the array keywords
, and if not possible, what's the best way to protect from SQL Injection in this case ?
Thank you