How to make a select correctly in PHP? - php

I have the following problem: There is a gigantic query that concatenates a set of user-selectable conditions (select boxes, text fields, etc.).
By default, if nothing is selected anyway (not have conditions), sorting according to various parameters (Order by). The problem is that if there is a conditions, we have to add the word "WHERE", and only once, but should not add it if there are no conditions, since it is impossible to write after WHERE ORDER BY. How to solve this problem?
$payment_select = "select payment_id,
payment_agreement,
payment_dateagreement,
payment_action,
payment_close,
payment_charge,
payment_pay,
study_id,
card_id,
name_nominative,
surname_nominative,
patr_nominative,
studgroups_number,
dep_name,
study_kurs`
from
study
inner join card on card_id = study_card_id
inner join name on name_id = card_name_id
inner join surname on surname_id = card_surname_id
inner join dep on dep_id = study_dep_id
inner join studgroups on study_studgroups_id = studgroups_id
left join payment on study_id = payment_study_id
left join patr on patr_id = card_patr_id
";
if (isset($name_filter) && ($name_filter)) {
$payment_select. = " and name_nominative like '%".$name_filter. "%' ";
}
if (isset($surname_filter) && ($surname_filter)) {
$payment_select. = " and surname_nominative like '%".$surname_filter. "%' ";
}
if (isset($patr_filter) && ($patr_filter)) {
$payment_select. = " and patr_nominative like '%".$patr. "%' ";
}
if (isset($group_filter) && ($group_filter)) {
$payment_select. = " and studgroups_number like '%".$group_filter. "%' ";
}
if (isset($agreement_filter) && ($agreement_filter)) {
$payment_select. = " and payment_agreement like '%".$agreement_filter. "%' ";
}
if (isset($debt_filter) && ($debt_filter == 1)) {
$payment_select. = " and (payment_charge - payment_pay) > 0 ";
}
if (isset($debt_filter) && ($debt_filter == 2)) {
$payment_select. = " and (payment_charge - payment_pay) <= 0 ";
}
if (isset($card_filter) && $card_filter) {
$payment_select. = " and card_id = '$card_filter' ";
}
if (isset($study_filter) && $study_filter) {
$payment_select. = " and study_id = '$study_filter' ";
}
if (isset($recordbook_filter) and $recordbook_filter){
$payment_select. = " and study_recordbook like '$recordbook_filter%' ";
}
if (isset($action_filter) && ($action_filter == 1)) {
$payment_select. = " and payment_action = 1 ";
}
if (isset($action_filter) && ($action_filter == 2)) {
$payment_select. = " and payment_action = 0 ";
}
if (isset($close_filter) && ($close_filter == 1)) {
$payment_select. = " and payment_close = 0 ";
}
if (isset($close_filter) && ($close_filter == 2)) {
$payment_select. = " and payment_close = 1 ";
}
if (isset($dep_filter) && ($dep_filter)) {
$dep = select_dep_array();
$payment_select. = " and dep_acronym like '".$dep[$dep_filter]. "' ";
}
if (isset($kurs_filter) && ($kurs_filter > 1)) {
$payment_select. = " and study_kurs = ". ($kurs_filter - 1). " ";
}
if (isset($educform_filter) && ($educform_filter >= 1)) {
$payment_select. = " and study_formeduc_id = ".$educform_filter. " ";
}
if (isset($progr_filter) && ($progr_filter >= 1)) {
$payment_select. = " and study_program_id = ".$progr_filter. " ";
}
if (preg_match("/^\d(\d)?\.\d(\d)?\.\d\d\d\d$/", $date_from_filter)) {
$date_from_mysql = date_user_to_mysql($date_from_filter);
} else {
if ($date_from_filter)
$error_msg = "Дата введена неправильно.";
}
if (preg_match("/^\d(\d)?\.\d(\d)?\.\d\d\d\d$/", $date_to_filter)) {
$date_to_mysql = date_user_to_mysql($date_to_filter);
} else {
if ($date_to_filter)
$error_msg = "Дата введена неправильно.";
}
if ((isset($date_from_mysql) && ($date_from_mysql)) && !(isset($date_to_mysql) && ($date_to_mysql))) {
$payment_select. = "and payment_date_agreement >= '".$date_from_mysql. "' ";
}
if (!(isset($date_from_mysql) && ($date_from_mysql)) && (isset($date_to_mysql) && ($date_to_mysql))) {
$payment_select. = "and payment_dateagreement <= '".$date_to_mysql. "' ";
}
if ((isset($date_from_mysql) && ($date_from_mysql)) && (isset($date_to_mysql) && ($date_to_mysql))) {
$payment_select. = "and payment_dateagreement >= '".$date_from_mysql.
"' and payment_dateagreement <= '".$date_to_mysql. "' ";
}
if (isset($order) && ($order)) {
if ($order == 3) {
if ($desc) {
$payment_select. = " order by surname_nominative desc, name_nominative desc, patr_nominative desc";
} else {
$payment_select. = " order by ".$order_array[$order];
}
} else {
$payment_select. = " order by ".$order_array[$order];
if ($desc) {
$payment_select. = " desc ";
}
}
}

Instead of directly extend your SQL, you can first collect all your "where clauses" in an array and then check if it is not empty and then implode it. Like this:
//your select
$payment_select = "SELECT ....";
//helper var
$where_clauses = [];
//from your example
if (isset($name_filter) && ($name_filter)) {
$where_clauses[] = "name_nominative like '%".$name_filter. "%'";
}
//from your example
if (isset($surname_filter) && ($surname_filter)) {
$where_clauses[] = "surname_nominative like '%".$surname_filter. "%'";
}
//now append the clauses if there any
if (! empty($where_clauses)) {
$payment_select .= " WHERE " . implode(" AND ", $where_clauses)
}

Related

MYSQL multiple words search result

When I type about three keywords or more it seems to only search the first keyword i.e bolt nut washer it will only search bolt.
I would like to search multiple keywords or the complete search term when inputted.
This is the code:
if (!(isset($_GET['pagenum']))) {
$pagenum = 1;
} else {
$pagenum = $_GET['pagenum'];
}
$page_limit = ($_GET["show"] <> "" && is_numeric($_GET["show"]) ) ? $_GET["show"] : 8;
try {
$keyword = trim($_GET["keyword"]);
if ($keyword <> "" ) {
$sql = "SELECT * FROM tbl_contacts WHERE 1 AND "
. " (first_name LIKE :keyword OR contact_no1 LIKE :keyword) ORDER BY first_name ";
$stmt = $DB->prepare($sql);
$stmt->bindValue(":keyword", $keyword."%");
} else {
$sql = "SELECT * FROM tbl_contacts WHERE 1 ORDER BY first_name ";
$stmt = $DB->prepare($sql);
}
$stmt->execute();
$total_count = count($stmt->fetchAll());
$last = ceil($total_count / $page_limit);
if ($pagenum < 1) {
num < 1) {
} elseif ($pagenum > $last) {
$pagenum = $last;
}
$lower_limit = ($pagenum - 1) * $page_limit;
$lower_limit = ($lower_limit < 0) ? 0 : $lower_limit;
$sql2 = $sql . " limit " . ($lower_limit) . " , " . ($page_limit) . " ";
$stmt = $DB->prepare($sql2);
if ($keyword <> "" ) {
$stmt->bindValue(":keyword", $keyword."%");
$stmt->execute();
$results = $stmt->fetchAll();
}
} catch (Exception $ex) {
echo $ex->getMessage();
}
I figured it out. Fixed by changing:
. " (first_name LIKE :keyword OR contact_no1 LIKE :keyword) ORDER BY first_name ";
to
. " (first_name LIKE '%".$keyword."%' OR contact_no1 LIKE '%".$keyword."%') ORDER BY last_name DESC ";
Now the search returns any keyword entered

Converting to PDO Parameter Binding

I'm using SensioLabsInsight to profile any vulnerabilities in my code.
I've received several errors for possible sql injection, and it recommends using parameter binding with PDO. This is fine since I'm already using PDO for my db driver.
Right now my model is passed a $data array and then checks for specific values in the array in order to add to the sql query if present, like so:
public function getDownloads($data = array()) {
$sql = "
SELECT *
FROM {$this->db->prefix}download d
LEFT JOIN {$this->db->prefix}download_description dd
ON (d.download_id = dd.download_id)
WHERE dd.language_id = '" . (int)$this->config->get('config_language_id') . "'";
if (!empty($data['filter_name'])) {
$sql .= " AND dd.name LIKE '" . $this->db->escape($data['filter_name']) . "%'";
}
$sort_data = array(
'dd.name',
'd.remaining'
);
if (isset($data['sort']) && in_array($data['sort'], $sort_data)) {
$sql .= " ORDER BY " . $data['sort'];
} else {
$sql .= " ORDER BY dd.name";
}
if (isset($data['order']) && ($data['order'] == 'DESC')) {
$sql .= " DESC";
} else {
$sql .= " ASC";
}
if (isset($data['start']) || isset($data['limit'])) {
if ($data['start'] < 0) {
$data['start'] = 0;
}
if ($data['limit'] < 1) {
$data['limit'] = 20;
}
$sql .= " LIMIT " . (int)$data['start'] . "," . (int)$data['limit'];
}
$query = $this->db->query($sql);
return $query->rows;
}
The error referenced from the SensioLabsInsight analysis references only the $data['sort'] clause as being a possible injection point.
My question is, do I need to test for $data array presence when creating a prepare statement, or will it simply return null if the array value is empty.
My proposed new query with parameter binding would look like so:
public function getDownloads($data = array()) {
$sql = "
SELECT *
FROM {$this->db->prefix}download d
LEFT JOIN {$this->db->prefix}download_description dd
ON (d.download_id = dd.download_id)
WHERE dd.language_id = '" . (int)$this->config->get('config_language_id') . "'";
if (!empty($data['filter_name'])) {
$sql .= " AND dd.name LIKE :filter_name%";
}
$sort_data = array(
'dd.name',
'd.remaining'
);
if (isset($data['sort']) && in_array($data['sort'], $sort_data)) {
$sql .= " ORDER BY :sort";
} else {
$sql .= " ORDER BY dd.name";
}
if (isset($data['order']) && ($data['order'] == 'DESC')) {
$sql .= " DESC";
} else {
$sql .= " ASC";
}
if (isset($data['start']) || isset($data['limit'])) {
if ($data['start'] < 0) {
$data['start'] = 0;
}
if ($data['limit'] < 1) {
$data['limit'] = 20;
}
$sql .= " LIMIT :start, :limit";
}
$this->db->prepare($sql);
$this->db->bindParam(':filter_name', $data['filter_name']);
$this->db->bindParam(':sort', $data['sort']);
$this->db->bindParam(':start', $data['start'], PDO::PARAM_INT);
$this->db->bindParam(':limit', $data['limit'], PDO::PARAM_INT);
$query = $this->db->execute();
return $query->rows;
}
Will this work as is, or do the parameter bindings need to be moved within the if/else conditionals?

Search multiple tables - leave table out if input is not filled in

I have a page with 3 input fields, to search a database. But not all users are going to fill in all fields, so I need a way to make sure the database is checked fine.
Now, I wrote 8 different sql-statements, and with if-statements I check which fields are filled out. This works, but I do feel there must be a better to do this.
ID's in the search form are found in other tables in my database and loaded with jQuery's autocomplete.
Code now used:
<form action="" method="post">
<div class="ui-widget">
<section>
<label for="tags">Trefwoord:</label>
<input name="tags" id="tags"><input type="hidden" name="tags_id" class="tags_id" value="">
</section>
<section>
<label for="categorie">Categorie:</label>
<input name="cats" id="categorie"><input type="hidden" name="cats_id" class="cats_id" value="">
</section>
<section>
<label for="competentie">Competentie:</label>
<input name="com" id="competentie"><input type="hidden" name="com_id" class="com_id" value="">
</section>
<input type="submit" name="submit">
</div>
</form>
<?php
if(isset($_POST['submit'])) {
$trefwoord_id = $_POST['tags_id'];
$categorie_id = $_POST['cats_id'];
$p_trefwoord = $_POST['tags'];
$p_categorie = $_POST['cats'];
$competentie_id = $_POST['com_id'];
$p_comptentie = $_POST['com'];
if($trefwoord_id == null) {$sql = "SELECT * FROM spel_cat LEFT JOIN spel_com ON spel_cat.spelid = spel_com.spelid WHERE '$categorie_id' = catid && '$competentie_id' = comid";}
if($categorie_id == null) {$sql = "SELECT * FROM spel_tw LEFT JOIN spel_com ON spel_tw.spelid = spel_com.spelid WHERE '$trefwoord_id' = twid && '$competentie_id' = comid";}
if($competentie_id == null) {$sql = "SELECT * FROM spel_tw LEFT JOIN spel_cat ON spel_tw.spelid = spel_cat.spelid WHERE '$trefwoord_id' = twid && '$categorie_id' = catid";}
if($trefwoord_id == null && $categorie_id == null) {$sql = "SELECT * FROM spel_com WHERE '$competentie_id' = comid";}
if($trefwoord_id == null && $competentie_id == null) {$sql = "SELECT * FROM spel_cat WHERE '$categorie_id' = catid";}
if($categorie_id == null && $competentie_id == null) {$sql = "SELECT * FROM spel_tw WHERE '$trefwoord_id' = twid";}
if($trefwoord_id == null && $competentie_id == null && $categorie_id == null) {$sql = ""; echo "<b>Gebruik minstens 1 zoekterm</b>";}
if($trefwoord_id != null && $categorie_id != null && $competentie_id != null) {$sql = "SELECT * FROM (spel_tw LEFT JOIN spel_cat ON spel_tw.spelid = spel_cat.spelid) LEFT JOIN spel_com ON spel_cat.spelid = spel_com.spelid WHERE '$trefwoord_id' = twid && '$categorie_id' = catid && '$competentie_id' = comid";
}
if($sql != null) {
$games = mysqli_query($link,$sql) or die(mysql_error());
$num = mysqli_num_rows($games);
// AND SO ON...
WORKING CODE (thanks to OrangeHippo)
<?php
if(isset($_POST['submit'])) {
$trefwoord_id = $_POST['tags_id'];
$categorie_id = $_POST['cats_id'];
$p_trefwoord = $_POST['tags'];
$p_categorie = $_POST['cats'];
$competentie_id = $_POST['com_id'];
$p_comptentie = $_POST['com'];
$from = array();
$where = " 1 = 1 ";
if($trefwoord_id != null) {
$from["str"] = "spel_tw str";
$where .= " AND twid = '$trefwoord_id' ";
}
if($categorie_id != null) {
$from["sca"] = "spel_cat sca";
if (isset($from["str"])) {
$where .= " AND sca.spelid = str.spelid ";
}
$where .= " AND catid = '$categorie_id' ";
}
if($competentie_id != null) {
$from["sco"] = "spel_com sco";
if (isset($from["str"])) {
$where .= " AND sco.spelid = str.spelid ";
}else if (isset($from["sca"])) {
$where .= " AND sco.spelid = sca.spelid ";
}
$where .= " AND comid = '$competentie_id' ";
}
$sql = "SELECT * FROM " . implode(",", $from) . " WHERE $where";
if($trefwoord_id == null && $competentie_id == null && $categorie_id == null) {$sql = ""; echo "<b>Gebruik minstens 1 zoekterm</b>";}
//echo $sql;
if($sql != null) {
$games = mysqli_query($link,$sql) or die(mysql_error());
$num = mysqli_num_rows($games);
//AND SO ON ...
Ideally you would construct the query depending on the values that are passed:
$from = array();
$where = " 1 = 1 ";
if($trefwoord_id != null) {
$from["str"] = "spel_tw str";
$where .= " AND twid = '$trefwoord_id' ";
}
if($categorie_id != null) {
$from["sca"] = "spel_cat sca";
if (isset($from["str"])) {
$where = " AND sca.spelid = str.spelid ";
}
$where .= " AND catid = '$categorie_id' ";
}
if($competentie_id != null) {
$from["sco"] = "spel_com sco";
if (isset($from["str"])) {
$where = " AND sco.spelid = str.spelid ";
}else if (isset($from["sca"])) {
$where = " AND sco.spelid = sca.spelid ";
}
$where .= " AND comid = '$competentie_id' ";
}
$query = "SELECT * FROM " . implode(",", $from) . " WHERE $where";
As you see this way you have a lot less of text, making the code cleaner. If you want to have the code even more clean you can look to use some query builder library like doctrine2 DBAL

PHP search to match all if the term is empty

I have written a simple search algorithm for my advanced search of my website.
There are several categories that the advanced search helps the user to limit his/her search. %$variable% is the matching that I use. I want the database to return every possible matches if the title is empty...what should be added/removed to/from this code?
if(isset($_POST['type']) && $_POST['type'] != 0)
{
$type = $_POST['type'];
if($wh == true)
{
$statement .= " AND `type` = '$type' ";
}
else
{
$wh = false;
$statement .= " WHERE `type` = '$type' ";
}
}
if(isset($_POST['sex']) && $_POST['sex'] != 0)
{
$sex = $_POST['sex'];
if($wh == true)
{
$statement .= " AND `sex` = '$sex' ";
}
else
{
$wh = false;
$statement .= " WHERE `sex` = '$sex' ";
}
}
if(isset($_POST['start']) && $_POST['start'] != 0)
{
$start = $_POST['start'];
if($wh == true)
{
$statement .= " AND `start` > '$start' ";
}
else
{
$wh = false;
$statement .= " WHERE `start` > '$start' ";
}
}
if($wh==true)
{
$statement .= " $branch_sentence AND( `title` LIKE '%$search_term%' OR `content` LIKE '%$search_term%' OR `keywords` LIKE '%$search_term%') ORDER BY stars DESC ";
}
else
{
$statement .= " WHERE `title` LIKE '%$search_term%' OR `content` LIKE '%$search_term%' OR `keywords` LIKE '%$search_term%' ORDER BY stars DESC ";
}
// echo $statement;
if($transorder = $site_db->query($statement))
{
$i=0;
while($row_obj = $transorder->fetch_object())
{
$item[$i]['id'] = $row_obj->id;
$item[$i]['pic_main'] = $row_obj->pic_main;
$item[$i]['title'] = $row_obj->title;
$item[$i]['province'] = $row_obj->province;
$item[$i]['stars'] = $row_obj->stars;
$i++;
}
}
}
}
What's wrong with:
if (empty($_POST['title']))
{
$statement = "SELECT id, pic_main, title, province, stars FROM "; // Incomplete b/c I don't know your table name from the question.
}
?

html <select multiple=multiple> + SQL Query Search

I'm trying to do a search based on
<select multiple=multiple name="chkUnr[]">
I'm getting out the values from select by running code:
for($i=0;$i<count($_POST["chkUnr"]);$i++)
{
if($_POST["chkUnr"][$i] != "")
{
$search_country = $_POST["chkUnr"][$i];
}
$query = "";
$query .= "SELECT users.* FROM users";
if (isset($_POST['singles_online']) ? $_POST['singles_online'] : 0 == 1) {
$query .= " LEFT JOIN online ON online.user_id = users.id";
}
$query .= " WHERE";
if (isset($_POST['vip']) ? $_POST['vip'] : 0 == 1) {
$query .= " users.vip = 1 AND";
}
if (isset($_POST['profile_image']) ? $_POST['profile_image'] : 0 == 2) {
$query .= " users.profile_image = '2' AND";
}
if (isset($_POST['singles_online']) ? $_POST['singles_online'] : 0 == 1) {
$query .= " online.is_online = 1 AND";
}
$query .= " (id NOT IN (SELECT user_id FROM users_blocked WHERE blocked_id = '$user_id')) AND";
$query .= " (users.user_age >= '$age_from' AND users.user_age <= '$age_to') AND";
$query .= " (users.gender = '$gender_search') AND";
$query .= " users.country IN ('$search_country')";
$search_query = mysql_query($query);
}
And i can print out the values but the problem comes when i do the SQL search.
It only pick up the first value in this case im using countries:
So when i select Sweden, Germany, Usa i can print them all out but when trying to do a SQL query only Sweden is being picked up.
I've tried with this code but still same result.
The problem here (and with the other answer) is that the in clause was surrounded by quotes, so that will not yield the result that we want. We need to effectively pass in an array to the query. Also your code is vulnerable to sql injection. I would strongly suggest moving to PDO/prepared statements. I added a slight protection to the countries, but that is not foolproof by any means.
function prepareForSql($value, $key) {
return addslashes($value);
}
array_walk($_POST["chkUnr"], "prepareForSql");
$search_country = "'" . implode("','", $_POST["chkUnr"]) . "'";
$query = "";
$query .= "SELECT users.* FROM users";
if (isset($_POST['singles_online']) ? $_POST['singles_online'] : 0 == 1) {
$query .= " LEFT JOIN online ON online.user_id = users.id";
}
$query .= " WHERE";
if (isset($_POST['vip']) ? $_POST['vip'] : 0 == 1) {
$query .= " users.vip = 1 AND";
}
if (isset($_POST['profile_image']) ? $_POST['profile_image'] : 0 == 2) {
$query .= " users.profile_image = '2' AND";
}
if (isset($_POST['singles_online']) ? $_POST['singles_online'] : 0 == 1) {
$query .= " online.is_online = 1 AND";
}
$query .= " (id NOT IN (SELECT user_id FROM users_blocked WHERE blocked_id = '$user_id')) AND";
$query .= " (users.user_age >= '$age_from' AND users.user_age <= '$age_to') AND";
$query .= " (users.gender = '$gender_search') AND";
$query .= " users.country IN ($search_country)";
$search_query = mysql_query($query);
Try
$search_country = implode(',',array_unique($_POST["chkUnr"]));
$query = "";
$query .= "SELECT users.* FROM users";
if (isset($_POST['singles_online']) ? $_POST['singles_online'] : 0 == 1) {
$query .= " LEFT JOIN online ON online.user_id = users.id";
}
$query .= " WHERE";
if (isset($_POST['vip']) ? $_POST['vip'] : 0 == 1) {
$query .= " users.vip = 1 AND";
}
if (isset($_POST['profile_image']) ? $_POST['profile_image'] : 0 == 2) {
$query .= " users.profile_image = '2' AND";
}
if (isset($_POST['singles_online']) ? $_POST['singles_online'] : 0 == 1) {
$query .= " online.is_online = 1 AND";
}
$query .= " (id NOT IN (SELECT user_id FROM users_blocked WHERE blocked_id = '$user_id')) AND";
$query .= " (users.user_age >= '$age_from' AND users.user_age <= '$age_to') AND";
$query .= " (users.gender = '$gender_search') AND";
$query .= " users.country IN ('$search_country')";
$search_query = mysql_query($query);

Categories