Reputation: 386
I have a form with 3 select boxes: age,room,type.
<form action="results.php" method="get">
<div class="form-group">
<select name="age">
<option value>Any</option>
<option value="1">15</option>
<option value="2">25</option>
<option value="3">30</option>
<option value="4">40</option>
</select>
</div>
<div class="form-group">
<select name="room">
<option value>Any</option>
<option value="1">1</option>
<option value="2">2</option>
</select>
</div>
<div class="form-group">
<select name="type">
<option value>Any</option>
<option value="1">Personal</option>
<option value="2">Business</option>
</select>
</div>
</form>
What i am trying to do with PDO is to make a small search. If all variables are empty then my condition is:
$search = $db->query("SELECT * FROM table");
If 1 of them (as example the age) is not empty then i have:
if(!empty($_GET['age'])){
$age = $_GET['age'];
$search = $db->query("SELECT * FROM table WHERE age = '$age'");
}
Now, if 2 of them are npt empty i have:
if(!empty($_GET['age']) && !empty($GET['room'])){
$age = $_GET['age'];
$room = $_GET['room'];
$search = $db->query("SELECT * FROM table WHERE age = '$age' AND room = '$room'");
}
In order to avoid all possible search combinations, how can i make a search with the term if is not empty. I had made one in the past:
if(!empty($age)){
$where = "WHERE age = '$age'";
}
if(!empty($room)){
$where .= "and room = '$room'";
}
$query = "SELECT * FROM table $where";
How can i make it happen with PDO?? :/
Upvotes: 1
Views: 972
Reputation: 5668
You will need to make a query builder of some kind. You will also want to use prepared statements, rather than directly injecting user-provided input into the sql query. That might look something like this:
<?php
$search = [
'age' => 42,
'room' => 'Millyway',
];
$criteria = [];
$params = [];
foreach($search as $field => $value) {
$criteria[] = "$field = :$field";
$params[$field] = $value;
}
$where = ($criteria ? ('WHERE ' . implode(' AND ', $criteria)) : '');
$query = "SELECT * FROM tablename $where";
$stmt = $db->prepare($query);
$stmt->execute($params);
while($obj = $stmt->fetchObject()) {
// iterate over your result set
}
Given search terms as key-values in $search
(which can be any column and value in the table, and will need to be populated from wherever those values come from), this code will build $criteria
, a set of WHERE
clause fragments (using a parameterized sql parameter name, rather than injecting the value directly), and $params
, the list of parameters to be passed into the (upcoming) prepared statement.
It then builds the full WHERE
clause in $where
, by either combining all of the $criteria
that were built, or returning an empty string. This is then added directly into the query, and the query is executed using the parameters array that was built up. You then iterate over the result set like any other PDO query.
Among others, the main benefit of using parameterized SQL over injecting variables directly is that it protects you from SQL Injection attacks.
Note that there are many ways this code could be improved. You could easily put it in a function; add complexity to allow for different types of comparisons (e.g. <>
or LIKE
); even use it as the basis for a more complicated query builder that allows more complicated logic such as ((age = :age AND room = :room1) OR (room = :room2))
; and so on. What you do is up to the needs of your application.
Upvotes: 0
Reputation: 108380
I'd do something like this:
$param = array();
$query = 'SELECT ... FROM t WHERE 1=1';
if(!empty($_GET['age'])){
$param['age'] = $_GET['age'];
$query .= ' AND t.age = :age';
}
if(!empty($_GET['room'])){
$param['room'] = $_GET['room'];
$query .= ' AND t.room = :room';
}
if(!empty($_GET['type'])){
$param['type'] = $_GET['type'];
$query .= ' AND t.type = :type';
}
$dbh->prepare($query)->execute($param);
You might want to separate out the prepare
and the execute
. Check the return from the prepare
before you try calling execute
. Or, configure PDO can throw an exception when an error occurs, e.g.
$dbh->setAttribute(PDO::ERRMODE_EXCEPTION);
Upvotes: 1