How to combine 2 different filters - php

I created this simple filter for date interval, and different levels (0,1,2). I have this code so far:
if(isset($_POST['filtersubmit'])){
$datex = str_replace('/', '-', $_POST['firstdate']);
$date1 = date("Y-m-d", strtotime($datex));
$datey = str_replace('/', '-', $_POST['lastdate']);
$date2 = date("Y-m-d", strtotime($datey));
$projects = $_POST['projekt'];
if(isset($date1) && isset($date2)){
$query = mysqli_query($conn, "SELECT * FROM zapasy WHERE datum BETWEEN
'$date1' AND '$date2' ORDER BY id DESC");
}
if($projects == 0){
$query = mysqli_query($conn, "SELECT * FROM zapasy WHERE projekt = '0' ORDER BY id DESC") or die(mysqli_errno($conn). '-'. mysqli_error($conn));
} elseif($projects == 1){
$query = mysqli_query($conn, "SELECT * FROM zapasy WHERE projekt = '1' ORDER BY id DESC") or die(mysqli_errno($conn). '-'. mysqli_error($conn));
} elseif($projects == 2){
$query = mysqli_query($conn, "SELECT * FROM zapasy WHERE projekt = '2' ORDER BY id DESC") or die(mysqli_errno($conn). '-'. mysqli_error($conn));
}
}
Now if I select just one of these filters, it works good, but if I want both interval and level filters, it doesn't work. I am not really sure how to do it. I am really grateful for any help.

I would use something along these lines, using a prepared statement to protect you from SQL injection. Basically we form arrays of WHERE clauses, parameters and parameter types from each filter if it is present in the $_POST array. These are then imploded into the query, parameters are bound and the query executed.
if (isset($_POST['filtersubmit'])) {
$params = array();
$paramtypes = array();
$wheres = array();
if (isset($_POST['firstdate'], $_POST['lastdate'])) {
$date1 = date_create_from_format('m/d/Y', $_POST['firstdate']);
$date2 = date_create_from_format('m/d/Y', $_POST['lastdate']);
if (!empty($date1) && !empty($date2)) {
array_push($params, $date1->format('Y-m-d'), $date2->format('Y-m-d'));
array_push($paramtypes, 's', 's');
array_push($wheres, 'datum BETWEEN ? AND ?');
}
}
if (isset($_POST['projekt'])) {
$project = $_POST['projekt'];
if (is_numeric($project) && $project >= 0 && $project <= 2) {
array_push($params, $project);
array_push($paramtypes, 'i');
array_push($wheres, 'projekt = ?');
}
}
$sql = 'SELECT * FROM zapasy';
if (count($wheres)) {
$sql .= ' WHERE ' . implode(' AND ', $wheres);
}
$sql .= ' ORDER BY id DESC';
$stmt = $conn->prepare($sql) or die($conn->error);
if (count($wheres)) {
$stmt->bind_param(implode('', $paramtypes), ...$params);
}
$stmt->execute() or die($stmt->error);
// bind results
$stmt->bind_result(/* variables corresponding to each field in SELECT */);
while ($stmt->fetch()) {
// do something with the data
}
}

Related

PHP MySQL changing select query based on variables

I've got 4 variables (year, month, projectcode and type).
So if the person submits the year and leave the other 3 variables blank then the select query must be
select * from table where year(trandate) = $var
But if the user supplies the year & month then the query must be select * from table where year(trandate) = $var and month(trandate) = $var1
If the user selects year, month & projectcode and leave type blank then query must be select * from table where year(trandate) = $var and month(trandate) = $var1 and projcode = $var3
And so on. How do I go about programming this, otherwhise I will have an awful lot of combinations?
Hope the question is clear.
For example this is what I have so far but I can see that there is too much combinations:
if (empty($ej1year) && empty($ej1month) && empty($ej1proj) && empty($ej1type)) {
$rows = mysql_query("SELECT a.employee
,a.trandate
,CONCAT(a.workdone, '-', wc.BriefDescription) as WorkCodeActivity
,CONCAT(a.custname, '-', cl.ShortName) as clientdet
,a.qty
,a.rate
,a.amount
,a.ref
,a.projcode
,a.type
,a.qty*a.rate as costrate
FROM transaction as a
LEFT JOIN workcodes as wc ON a.workdone=wc.WorkCodeNo
LEFT JOIN clients as cl On a.custname=cl.EntityNo");
} elseif (empty($ej1year) && !empty($ej1month)) {
$rows = mysql_query("SELECT a.employee
,a.trandate
,CONCAT(a.workdone, '-', wc.BriefDescription) as WorkCodeActivity
,CONCAT(a.custname, '-', cl.ShortName) as clientdet
,a.qty
,a.rate
,a.amount
,a.ref
,a.projcode
,a.type
,a.qty*a.rate as costrate
FROM transaction as a
LEFT JOIN workcodes as wc ON a.workdone=wc.WorkCodeNo
LEFT JOIN clients as cl On a.custname=cl.EntityNo
where month(trandate) = '$ej1month'");
} elseif
Something like this should work:
<?php
$where = array();
$binds = array();
if ($_POST['month'] !== '') {
$where[] = 'month = ?';
$binds[] = $_POST['month'];
}
if ($_POST['year'] !== '') {
$where[] = 'year = ?';
$binds[] = $_POST['year'];
}
...
$query = 'select * from table where ' . implode(' AND ', $where);
$db->execute($query, $binds);
You'd want to add a check to see if any variables are set. If you don't mind if all are empty, you can change
$where = array();
to
$where = array(1);
Which will end up as "where 1" in the query, effectively selecting everything.
EDIT: I see you are using mysql_ functions, that's not ideal as they are deprecated. You should update to PDO or mysqli ASAP. Here's a version that will work with mysql_
<?php
$where = array();
if ($_POST['month'] !== '') {
$where[] = "month = '" . mysql_real_escape_string($_POST['month']) . "'";
}
if ($_POST['year'] !== '') {
$where[] = "year = '" . mysql_real_escape_string($_POST['year']) . "'";
}
...
$query = 'select * from table where ' . implode(' AND ', $where);
$result = mysql_query($query);
Try this.
if (!empty($year) && empty($month) && empty($projectcode) && empty($type)){
$query = 'select * from table where year(trandate) = $var';
}elseif (!empty($year) && !empty($month) && empty($projectcode) && empty($type)){
$query = 'select * from table where year(trandate) = $var and month(trandate) = $var1';
}elseif (!empty($year) && !empty($month) && !empty($projectcode) && empty($type)){
$query = 'select * from table where year(trandate) = $var and month(trandate) = $var1 and projcode = $var3'
}

Search results with pagination code won't return results

I'm having a hard time getting this search results with pagination code to work. It does successfully grab the search keyword entered in the html form on another page and brings it into this search.php page. if I echo $search I see the keyword on the page. But I get no results even though I should for the query. Can anyone see what might be going on?
require "PDO_Pagination.php";
if(isset($_REQUEST["search_text"]) && $_REQUEST["search_text"] != "")
{
$search = htmlspecialchars($_REQUEST["search_text"]);
$pagination->param = "&search=$search";
echo $search;
$pagination->rowCount("SELECT * FROM stories WHERE stories.genre = $search");
$pagination->config(3, 5);
$sql = "SELECT * FROM stories WHERE stories.genre = $search ORDER BY SID ASC LIMIT $pagination->start_row, $pagination->max_rows";
$query = $connection->prepare($sql);
$query->execute();
$model = array();
while($rows = $query->fetch())
{
$model[] = $rows;
}
}
else
{
$pagination->rowCount("SELECT * FROM stories");
$pagination->config(3, 5);
$sql = "SELECT * FROM stories ORDER BY SID ASC LIMIT $pagination->start_row, $pagination->max_rows";
$query = $connection->prepare($sql);
$query->execute();
$model = array();
while($rows = $query->fetch())
{
$model[] = $rows;
}
}
$query = "SELECT * FROM stories";
if(isset($_REQUEST["search_text"]) && $_REQUEST["search_text"] != "")
{
$search = htmlspecialchars($_REQUEST["search_text"]);
$pagination->param = "&search=$search";
$query .= " WHERE genre LIKE '%$search%'";
}
// No need for else statement.
$pagination->rowCount($query);
$pagination->config(3, 5);
$query .= " ORDER BY SID ASC LIMIT {$pagination->start_row}, {$pagination->max_rows}";
$stmt = $connection->prepare($query);
$stmt->execute();
$model = $stmt->fetchAll();
var_dump($model);
In your query do:
WHERE stories.genre LIKE '%string%');
instead of:
WHERE stories.genre = 'string');
Because the equals will want to literally equal the field.

make php function with two different mysql command

I want to create a function so that I won't repeat myself.
This is my current code
<?php
$targetpage = "index.php";
$limit = 20;
$sql1 = $db->prepare("SELECT * FROM classified ORDER BY date DESC");
/*** fetch Number of results ***/
$total_pages =$sql1->rowCount();
$stages = 3;
$page = ($_GET['page']);
if($page){
$start = ($page - 1) * $limit;
}else{
$start = 0;
}
$sql = $db->prepare("SELECT * FROM classified ORDER BY date DESC LIMIT $start,
$limit ")or die(print_r($sql->errorInfo(), true));
$sql->execute();
$result = $sql->fetchAll();
//Include pagination
require_once("pagination.php");
// pagination
echo $paginate;
foreach($result as $row){
$id = htmlentities($row['id'], ENT_QUOTES);
$id_city = htmlentities($row['id_city'], ENT_QUOTES);
$title = htmlentities($row['title'], ENT_QUOTES ,'utf-8');
$querya = $db->prepare("SELECT * FROM city WHERE id = :id_city");
/*** bind the paramaters ***/
$querya->bindParam(':id_city', $id_city, PDO::PARAM_INT);
/*** execute the prepared statement ***/
$querya->execute();
/*** fetch the results ***/
$resultya = $querya->fetchAll();
foreach($resultya as $rowa)
{
$city_name = htmlentities($rowa['city'], ENT_QUOTES, 'utf-8');
}
}
?>
Now I have another file that uses the same code except it has a condition when retrieving data from database.
So instead of:
$sql1 = $db->prepare("SELECT * FROM classified ORDER BY date DESC");
$sql = $db->prepare("SELECT * FROM classified ORDER BY date DESC LIMIT $start,
$limit ")or die(print_r($sql->errorInfo(), true));
The other file:
$sql1 = $db->prepare("SELECT * FROM classified where type = '1' ORDER BY date DESC");
$sql = $db->prepare("SELECT * FROM classified where type = '1' ORDER BY date DESC
LIMIT $start, $limit ")or die(print_r($sql->errorInfo(), true));
The difference is where type = 1
Is it possible to combine all this in one function?
Thanks
I added some notes into the code, does this make sense?
See below:
<?php
/*
$db - PDO object
$limit - number of listings to show on the page
$page - page to show
$where - the additional where condition to pass in
*/
function getItems($db=null,$limit=20,$page='',$where='') {
// check if $db exists before doing anything
if ($db) {
$sql1 = $db->prepare("SELECT * FROM classified ORDER BY date DESC");
/*** fetch Number of results ***/
$total_pages =$sql1->rowCount();
$stages = 3;
if($page){
$start = ($page - 1) * $limit;
}else{
$start = 0;
}
$sql = $db->prepare("SELECT * FROM classified $where ORDER BY date DESC LIMIT $start,
$limit ")or die(print_r($sql->errorInfo(), true));
$sql->execute();
$result = $sql->fetchAll();
} else {
// I return an empty array here so that if something should fail $result will still be populated with an array
return array();
}
}
$targetpage = "index.php";
$result = getItems($db,20,$_GET['page'],'where type = "1"');
//Include pagination
require_once("pagination.php");
// pagination
echo $paginate;
foreach($result as $row){
$id = htmlentities($row['id'], ENT_QUOTES);
$id_city = htmlentities($row['id_city'], ENT_QUOTES);
$title = htmlentities($row['title'], ENT_QUOTES ,'utf-8');
$querya = $db->prepare("SELECT * FROM city WHERE id = :id_city");
/*** bind the paramaters ***/
$querya->bindParam(':id_city', $id_city, PDO::PARAM_INT);
/*** execute the prepared statement ***/
$querya->execute();
/*** fetch the results ***/
$resultya = $querya->fetchAll();
foreach ($resultya as $rowa) {
$city_name = htmlentities($rowa['city'], ENT_QUOTES, 'utf-8');
}
}
?>
Yes. Have one file and either send a POST or GET to it that tells the page if type==1.
Example
if ($_GET['t']==1){ $type = "WHERE type = '1'"; }else{ $type = ""; }
$sql1 = $db->prepare("SELECT * FROM classified " . $type . " ORDER BY date DESC");
$sql = $db->prepare("SELECT * FROM classified " . $type . " ORDER BY date DESC
LIMIT $start, $limit ")or die(print_r($sql->errorInfo(), true));
If you call the page this is listed on with page.php?t=1, then it will put the where statement in there. If you just call page.php, it will not put anything there.

Rewrite query inside of loop in PDO format

I'm new to PDO and am currently trying to rewrite all of my queries. One query that I'm having trouble rewriting is this one because it's written inside of a loop:
$search = $_GET['search'];
$code = explode(" ", $search);
$code_count = count($code);
$query = "SELECT * FROM table";
if($search != "")
{
if($code_count == 1)
{
$query .= " WHERE team LIKE '%".mysql_real_escape_string($search)."%'";
} elseif($code_count > 1)
{
for($j=0;$j<$code_count;$j++)
{
if($j != 0)
{
$query .= " OR ";
} else
{
$query .= " WHERE team LIKE '%".mysql_real_escape_string($code[$j])."%' OR ";
}
$query .= " team LIKE '%".mysql_real_escape_string($code[$j])."%'";
}
$query .= "ORDER BY team ASC";
}
} else
{
$query = "SELECT * FROM table ORDER BY team ASC";
}
$result = mysql_query($query)or die(mysql_error());
With PDO, I have tried the following.
$query = "SELECT * FROM table";
if($search != "")
{
if($code_count == 1)
{
$query .= " WHERE team LIKE ?";
$stmt = $db->prepare($query);
$stmt->bindValue(1, "%$search%", PDO::PARAM_STR);
$stmt->execute();
} elseif($code_count > 1)
{
for($j=0;$j<$code_count;$j++)
{
if($j != 0)
{
$query .= " OR ";
} else
{
$query .= " WHERE team LIKE ? OR ";
}
$query .= " team LIKE ?";
$stmt = $db->prepare($query);
$stmt->bindValue(1, "%$code[$j]%", PDO::PARAM_STR);
$stmt->execute();
}
$query .= "ORDER BY team ASC";
}
} else
{
$query = "SELECT * FROM table ORDER BY team ASC";
}
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
Not much luck with this method. I keep getting an error message reading: "nvalid parameter number: number of bound variables does not match number of tokens"
Any ideas?
Thanks,
Lance
The bind parameters are named 1 to n when you don't assign a name yourself. You need to change this line:
$stmt->bindValue(1, "%$code[$j]%", PDO::PARAM_STR);
To this:
$stmt->bindValue($j + 1, "%" . $code[$j] . "%", PDO::PARAM_STR);
Since one can pass an array of parameters to PDOStatement::execute() instead of binding each manually, one can hugely simplify the whole thing:
$code = explode(' ', $_GET['search']);
$stmt = $db->prepare('
SELECT *
FROM table
WHERE FALSE ' . str_repeat(' OR team LIKE ?', count($code)) . '
ORDER BY team ASC
');
$stmt->execute($code);
You have several errors in your rewrite:
you are calling prepare / bind / execute several times during the construction of the query. You should call prepare just once, after your query string is fully constructed, and bind+execute after the query construction.
in every iteration of your loop, you add one or two ( if j == 0) parameter to your query, but you try to bind just one per loop - so the numbers won't add up.
Generally, to use parametric queries, you need to follow the following structure:
build your query string
prepare your query string
every time you want to run your query:
bind parameters
execute
fetch
So your code should be like:
// building query
if($search != "")
{
$query = 'SELECT * FROM table ';
if($code_count == 1)
{
// note: this if is unneccessary, the loop below would generate a good SQL even for code_count 0 or 1
$query .= "WHERE team LIKE ?";
} elseif($code_count > 1)
{
for($j=0;$j<$code_count;$j++)
{
if($j != 0)
{
$query .= " OR ";
} else
{
$query .= " WHERE ";
}
$query .= " team LIKE ? ";
}
$query .= "ORDER BY team ASC";
}
} else
{
$query = "SELECT * FROM table ORDER BY team ASC";
}
// preparing
$stmt = $db->prepare($query);
// binding parameters
if($search != '' && $code_count >= 1) {
for($j=0;$j<$code_count;$j++){
$stmt->bindValue($j+1, "%".$code[$j]."%", PDO::PARAM_STR);
}
}
// execute
$stmt->execute();
// fetch
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

Return results from mySQL even if the user does not fill all the criteria in form

The following code needs to make use of 3 variables given by the user. By default all of these variables equal to 0.
time (textbox)
city (drop down list)
type (drop down list)
If for example time and city is given by the user, but lets the type zero, it will not return any results.
My question is what is an effective and efficient way to modify my existing code so that if the user chooses not to select time, city or type or any combination of these, there will be results returned?
For example if time 21:00 is added with city number 3, it will show all the types that meet the 2 criteria should be listed.
$question= 'SELECT * FROM events WHERE ABS(TIMESTAMPDIFF( HOUR , `time`, :time )) < 2 AND city=:city AND type=:type';
$query = $db->prepare($question);
$query->bindValue(":time", $time, PDO::PARAM_INT);
$query->bindValue(":city", $city, PDO::PARAM_INT);
$query->bindValue(":type", $type, PDO::PARAM_INT);
$query->execute();
<?php
$question= 'SELECT * FROM events WHERE ';
$hasTime = false;
if(!empty($time)) { // #note better validation here
$hasTime = true;
$question .= 'ABS(TIMESTAMPDIFF( HOUR , `time`, :time )) < 2 ';
}
$hasCity = false;
if(!empty($city)) { // #note better validation here
$hasCity = true;
$question .= 'AND city=:city ';
}
$hasType = false;
if(!empty($type)) { // #note better validation here
$hasType = true;
$question .= 'AND type=:type';
}
$query = $db->prepare($question);
if($hasTime)
$query->bindValue(":time", $time, PDO::PARAM_INT);
if($hasCity)
$query->bindValue(":city", $city, PDO::PARAM_INT);
if($hasType)
$query->bindValue(":type", $type, PDO::PARAM_INT);
$query->execute();
$results = $query->fetchAll();
if(empty($results))
echo 'no results';
else
// $results is an array of arrays
I prefer using an array of conditions, and checking through to see if the conditions exist, to built the individual parts of the SQL query:
$conditions = array(); // Creating an array of conditions.
if ($time) // Checks to see if value exists.
{
$timeCondition = "ABS(TIMESTAMPDIFF( HOUR , `time`, :time )) < 2";
$conditions[] = $timeCondition; // Adds this condition string to the array.
}
if ($city)
{
$cityCondition = "city=:city";
$conditions[] = $cityCondition;
}
if ($type)
{
$typeCondition = "type=:type";
$conditions[] = $typeCondition;
}
$conditionString = implode(" AND ", $conditions); // Gluing the values of the array with " AND " in between the string conditions.
if (count($conditions) > 0) // If conditions exist, add "WHERE " to the condition string.
{
$conditionString = "WHERE ".$conditionString;
}
else // Otherwise, the condition string is blank by default.
{
$conditionString = '';
}
$question= 'SELECT * FROM events '.$conditionString; // If no conditions, will return all from events. Otherwise, conditions will be slotted in through $conditionString.
$query = $db->prepare($question);
if($time)
$query->bindValue(":time", $time, PDO::PARAM_INT);
if($city)
$query->bindValue(":city", $city, PDO::PARAM_INT);
if($type)
$query->bindValue(":type", $type, PDO::PARAM_INT);
$query->execute();
You can use a series of IF() statements in your SQL statement, and return true if the value isn't set. So something like this:
...WHERE IF(:time, ABS(TIMESTAMPDIFF(HOUR, `time`, :time)) < 2, 1)
AND IF(:city, city=:city, 1) AND IF(:type, type=:type, 1)
Build the query dynamically so that if the field is at its default, do not include it in the where clause.
$conditions = array();
if ($_POST['time']) {
$conditions[] = "ABS(TIMESTAMPDIFF( HOUR , `time`, :time )) < 2";
}
if ($_POST['city']) {
$conditions[] = "city=:city";
}
if ($_POST['type']) {
$conditions[] = "type=:type";
}
$conditionString = implode(" AND ", $conditions);
if (count($conditions) > 0) {
$conditionString = "WHERE " . $conditionString;
}
else {
$conditionString = '';
}
$question = 'SELECT * FROM events ' . $conditionString;

Categories