What I'm trying to do is go from a search URL such as this:
search.php?president=Roosevelt,+F.&congress=&nomination_received_by_senate=&state=CT
To a MySQL query like this:
SELECT `name` FROM `nominations` WHERE president=`Roosevelt, F.` AND state=`CT`
I have some code that strips any empty values from the URL, so I have an array as such:
Array ( [president] => Roosevelt, F. [state] => CT )
Going from this to the SQL query is what is giving me trouble. I was hoping there might be some simple means (either by some variation of PHP's join() or http_build_query()) to build the query, but nothing seems to work how it needs to and I'm pretty lost for ideas even after searching.
Not sure if it would require some messy loops, if there is a simple means, or if the way I'm going about trying to accomplish my goal is wrong, but I was hoping someone might be able to help out. Thanks in advance!
Edit: To clarify, sometimes the inputs could be empty (as in the case here, congress and nomination_received_by_senate), and I'm hoping to accommodate this in the solution. And yes, I intend to implement means to avoid SQL injection. I have only laid out the basics of my plan hoping for some insight on my methods.
You could build up your query string like this if your GET params match your db fields:
$field_array = array('president', 'congress', 'nomination_received_by_senate', 'state');
$query = 'SELECT `name` FROM `nominations` WHERE ';
$conditions = array();
foreach($field_array as $field) {
$value = $_GET[$field];
if(empty($value)) continue;
$condition = mysql_real_escape_string($field) . '` = ';
$quote = '';
if(!is_numeric($value)) $quote = '"';
$condition .= $quote . mysql_real_escape_string($value) . $quote;
$conditions[] = $condition;
}
$query .= implode(' AND ', $conditions) . ';';
//perform query here...
To access the $_GET variables you could just do $_GET["president"] and $_GET["state"] and get the information. Make sure you sanitize the input.
$president = sanitize($_GET["president"]);
$state = sanitize($_GET["state"]);
$result = mysql_query("SELECT name FROM nominations WHERE president='".$president."' AND state='".$state"'");
Sanitize would be a function like mysql_real_escape_string() or your own function to clean up the input. Make sure you check if the $_GET variables are set using the isset() function.
Related
Is there any way to run mysqli query dynamically ? I am working on a small project who has dynamic form generation option. And then they want to filer those forms. Obviously we dont know how much will be form fields and how many filters they want. So is there any such way through which I can perform this action? Suppose if i can do something
SELECT * FROM table WHERE fld1 = 1 OR fld2 = 2 OR fld3 = 3....
Where those 1, 2, 3,... Can be something or maybe its empty depend on filters.
You can dynamically build your query in php by examining your $_POST values and then building out your where statement. Here's some pseudo code
foreach($_POST as $name=>$value)
{
$where[] = "`$key` = '$value'";
}
$sql = "SELECT * FROM table WHERE ".implode("OR", $where);
Of course you will need to either sanitize or use a prepared statement to make sure this is safe.
The best way to run it dynamically is by using PDO and classes, if youre confused about any of those two things check out the PHPGuru Jeffery Way found here: https://laracasts.com/series/php-for-beginners and check out his PHP tutorials, youll quickly learn what you need to do to be able to make a class that allows you to dynamically connect to your database!
Maybe do something like:
$Where = array();
foreach($_POST['form-field'] as $Field=>$Value){
if($Value){
$Where[] = $Field."=".$Value;
}
}
$Query = "SELECT * FROM table WHERE ".implode(" OR ",$Where);
You can use IN clause of in MySQL query.
Similar like this.
SELECT * FROM table
WHERE fld1 IN (1, 2, 3);
Hope this will help you.
$filter = '';
$filter .= 'fld1 = 1 OR ';
$filter .= 'fld2 = 2 OR ';
$filter .= 'fld3 = 3 OR ';
...
...
if(!empty($filter)) {
$filter = substr($filter,0,-2); // delete last OR
}
$query = "SELECT * FROM table WHERE ".$filter."";
...
Something like this would work, you have to modify the way you populate $filter
Hope this'll help.
I try to make query to database, base on user input, because I have multiple inputs in single form it's a big more complicated.
I decide to check if input is filled like:
$query = "";
if((trim($searchParams->firstname)))
$query .= "firstname,";
which works correctly for me, and after I check each input I explode string to array by , and foreach it
$querys = explode(",", $query);
foreach($querys as $q)
{
...
}
What basically create an array of all filled inputs, however just their names base on what i need to get values as well.
So I try to add something like this to query
$searchParams->$q;
But this doesn't work (say it's empty despite the fact if i echo it before it's filled)
I try to do something really dirt as:
$param = "$searchParams->".$q;
$values .= $param;
which say
Object of class could not be converted to string ( if i var_dump($q) it say its string so i dont understand)
I think I 'm doing it really badly but thats the only thing I found out as potentially useful. Any advise to fix this will be helpful.
p.s. Here is how final query should looks like:
"SELECT * FROM candidates WHERE firstname = ? AND surname = ?" ,$searchParams->firstname, $searchParams->surname
I have a form that submits an array of transaction IDs to $_POST['transid'] so those transaction records can be deleted.
I typically use mysqli_real_escape_string to help prevent attacks, but I am not sure how to go about it with an array. The following is my query:
$query = 'DELETE FROM TRANSACTIONS WHERE (transid) IN ("'.implode('","',$_POST[transid]).'")'
...which gives me something like this:
$query = 'DELETE FROM TRANSACTIONS WHERE (transid) IN ("123","124","138","145")'
This seems to be asking for trouble. How can I protect myself from disaster (malicious or otherwise)? Is there an efficient way to sanitize the array? Or should I go about this another way?
Any thoughts or guidance would be appreciated.
You're probably better off sanitizing the $_POST before you use it to implode and for that you'll have to traverse it. #user870018 beat me to the punch on the structure but here's what I'd do anyway:
function sanitize($n)
{
return your_escape_function_here($n);
}
$values = implode(",", array_map("sanitize", $_POST[transid]));
$query = 'DELETE FROM TRANSACTIONS WHERE (transid) IN ('.$values.')';
Use a foreach loop before building your query;
foreach ($_POST[transid] as &$x) $x = your_escape_function_here($x);
Or (if you use arrays in this manner regularly) build it into a function to keep the overall program a bit cleaner;
function sqlEscapeArray($arr){
foreach ($arr as &$x)
$x = your_escape_function_here($x);
return $arr;
}
Then use it like so;
$query = 'DELETE FROM TRANSACTIONS WHERE (transid) IN ("'.implode('","',sqlEscapeArray($_POST[transid])).'")';
Of course, replace your_escape_function with, well.... Your escape function.
I have successfully gotten queries to execute and print in PDO, but I'm doing something wrong here. The important part of the code for this question is in the last couple blocks of code; I'm including the first portion just for clarity.
This code connects to an HTML form with multiple input fields. The PHP constructs a query by appending the data from each field with ANDs in the WHERE statement.
This is what throws me: I echo the $query variable, and I can see that the query is formed properly, but when I then try to print the query results, no results are printed.
I wrestled with using prepared statements here, and decided to try getting the code to work first without them after failing to construct a prepared statement with varying numbers of parameters. I did try, with the help of this post: LIKE query using multiple keywords from search field using PDO prepared statement
So, setting aside prepared statements for the moment, can anyone tell me what I'm doing wrong here? Any help would be greatly appreciated.
<?php
if(isset($_POST['submit'])) {
// define the list of fields
$fields = array('titleSearch', 'keywordSearch', 'fullSearch', 'fromYear', 'toYear',
'fromSeconds', 'toSeconds', 'withSound', 'withColor');
$conditions = array();
// loop through the defined fields
foreach($fields as $field){
// if the field is set and not empty
if(isset($_POST[$field]) && $_POST[$field] != '') {
// create a new condition, using a prepared statement
$conditions[] = "$field LIKE CONCAT ('%', $_POST[$field], '%')";
}
}
// build the query
$query = "SELECT keyframeurl, videoid, title, creationyear, sound, color,
duration, genre FROM openvideo ";
// if there are conditions defined, append them to the query
if(count($conditions) > 0) {
$query .= "WHERE " . implode(' AND ', $conditions);
}
//confirm that query formed correctly
echo $query;
//print query results
foreach ($dbh->query($query) as $row){
print $row['videoid'].' - '.$row['title'].'<br />';
}
}
?>
Instead of posting your query you have to run it.
That's the only way to fix the problem
a Stack Overflow passer-by do not have a database server in their head to run your query.
a Stack Overflow passer-by do not have your particular database server in their head to run your query.
So, you are the only one who can run your query against your database and ask it what's going wrong.
Turn on error reporting. Make sure sure you can see errors occurred. Try to add intentional error and see if it works.
Double-check your database data if it really contains desired values.
Double-check your input data, if it really match database values.
Run your assembled query against database in console or phpadmin.
Dig to some certain problem. Do not just sit and wait. Asking a question "I have a code it doesnt work" makes very little sense. Code have to be run, not stared into.
$conditions[] = "$field LIKE CONCAT ('%', $_POST[$field], '%')";
is the culprit: sending "something" for the title ends up in something like
WHERE titleSearch LIKE CONCAT('%', something, '%')
but you want
WHERE titleSearch LIKE CONCAT('%', 'something', '%')
with more quotes.
Be sure not to roll this out into production though, as you might end up with somebody posting "xxx') OR 1=1; --" just for the perofrmance fun, or even worse, depedning on their mood.
You've forgotten quotes around the $_POST values that you're directly inserting into your queries:
$conditions[] = "$field LIKE CONCAT ('%', '$_POST[$field]', '%')";
^-- ^--
so while this will fix your immediate problem, you'll still be wide open to sql injection attacks.
You don't even need the CONCAT built-in function, you can model the whole string as $conditions[] = "{$field} LIKE '%{$_POST[$field]}%'". But you should use prepared statements if you don't want to face serious SQL injection attacks in the short-term future.
Why don't you try something like this? (using PDO as an example):
if ($pdo = new \PDO("mysql:host=localhost;dbname=testdb;charset=utf8", "user", "password")) {
$fields = ["titleSearch","keywordSearch","fullSearch","fromYear","toYear","fromSeconds","toSeconds","withSound","withColor"];
$parameters = array_map(function ($input) { return filter_var($input, FILTER_SANITIZE_STRING); }, $fields)
$conditions = array_map(function ($input) { return (!empty($_POST[$input]) ? "{$input} LIKE ?" : null); }, $fields);
$query = "SELECT `keyframeurl`,`videoid`,`title`,`creationyear`,`sound`,`color`,`duration`,`genre` FROM `openvideo`" . (sizeof($conditions) > 0 ? " " . implode(" AND ", $conditions) : null);
if ($statement = $pdo->prepare($query, [\PDO::ATTR_CURSOR => \PDO::CURSOR_FWDONLY])) {
if ($statement->execute((!empty($parameters) ? $parameters : null))) {
$result = $statement->fetchAll(\PDO::FETCH_ASSOC);
}
}
}
Haven't tested it (just coming to my mind right now), but it should set up PDO, prepare a statement based on the conditions you seem to look for, add the parameters in the execute() method (pre-filtered, although there's FAR better filtering techniques) and return all results associated with your query.
Even if you decide not to use this, give it a thought at least... it's a good starting point on PDO and, of course, get a nice tutorial on GET/POST variable filtering (or use a 3rd-party tool like HTML Purifier, for that matter).
Hope that helps ;)
I need some guidance to make an advanced search script for a website I'm working on.
I already know how to search the database for simple queries. The problem I'm encountering right now is how to search, when using multiple select boxes. For example:
This is just a simple form with different search options. The question is:
The visitor can choose to search on a country or city, both or even with all three options.
How do I catch that in the PHP script? Do I have to check if for example a city has been chosen, and fire a query based on that? But if I do that I would have to make different queries based on each select option.
In pseudo-code it would be something like this: (I imagine)
if country and city and something else is not null, launch a query to search in all three tables in the database.
But what to do when just the country has been chosen? Or just the city?
Is there a simple way to accomplish this?
Thanks in advance.
I like using an array to join conditions so I don't have to worry about leading or trailing AND's.
$conditions = array();
if ($formCondition1) {
$conditions[] = 'state = "'.$somevalue.'"';
}
if ($formCondition2) {
$conditions[] = 'country = "'.$somevalue.'"';
}
...
if ($formConditionN) {
$conditions[] = 'N = "'.$somevalue.'"';
}
//finally join the conditions together, the simplest case is with ANDs (if you need to add ORs, which it sounds like you don't, then this code would be a bit more complex)
$sqlStatement = 'SELECT field1, field2 FROM tableABC WHERE '.implode(' AND ', $conditions);
EDIT: don't forget to escape the input to prevent injection attacks, and of course test to make sure there are at least 1 condition before running the query.
EDIT: lol jswolf and I think very much alike :)
I make a $where array, add my conditions to it as necessary, and then implode it with ' AND ' as the glue. So something like:
$where = array();
if $city is defined
$where[] = "city = '".mysql_real_escape_string($city)."'";
fi
if $country is defined
$where[] = "country = '".mysql_real_escape_string($country)."'";
fi
...
if(count($where)) {
$query.= ' WHERE '.implode(' AND ', $where);
}
I would try something like:
$qry = "SELECT * FROM table WHERE ";
if ($country != '') {
$qry .= "country='".mysql_real_escape_string($country)."' AND "
}
if ($city != '') {
$qry .= "city='".mysql_real_escape_string($city)."' AND "
}
$qry .= '1';
$res = mysql_query($qry);
The query is built up depending on what is set. Note the "1" on the end of the query string which is always true. This is needed to follow the "WHERE" if $country and $city are both empty, or to follow the last "AND" if they are not.