Apologies for the newbie question.
My website has a form.
<form action='' method='get'>
<select id="cSelector" name="cSelector">
<option value=""></option>
<option value="">Show All Items</option>
<option value="Compensation">Compensation</option>
</select>
<input type="submit" value="Submit">
</form>
My querystring, created on form submission, looks like this:
http://website.com/table_example.php?cSelector=Compensation
My query looks like this:
$stmt = $conn->prepare("
SELECT t1.CategoryID,t1.SubCategoryName, t1.CategoryName, t1.SubCategoryID, t2.ItemText from
(SELECT Category.CategoryID,CategoryName, SubCategoryName, SubCategoryID
FROM Category
JOIN SubCategory
ON Category.CategoryID = SubCategory.CategoryID) t1
RIGHT JOIN
(SELECT SubCategoryID, ItemText FROM Item) t2
ON (t1.SubCategoryID = t2.SubCategoryID)
WHERE 1 ".$searchQuery." AND CategoryName = ".$search2." ORDER BY ".$columnName." ".$columnSortOrder." LIMIT :limit,:offset");
The intended result produces a table queried by CategoryName.
My question. Why does this properly execute?
$search2='Compensation';
And this does not?
$search2 = "'".$_GET['cSelector']."'";
Any help would be very much appreciated. And thank you!
You're submitting this form via GET
<form action='' method='get'>
Your line though $search2 = "'".$_POST['cSelector']."'"; is using $_POST
It should be $_GET instead:
$search2 = "'" . $_GET['cSelector'] . "'";`
AFTER OP's CHANGES
This
$search2='Compensation';
and
$search2 = "'".$_GET['cSelector']."'";
are not the same. The top is just a string value. The bottom is a string value wrapped in quotes, so it isn't Compensation it is 'Compensation'.
The core of the issue is actually that you're not exactly sure what the query is. If the two strings sent were identical, they would both run, but they're not. Somehow.
The real need is visibility into your query. So something like
$strQuery = "SELECT t1.CategoryID,t1......";
echo "<pre>$strQuery</pre>";
$stmt = $conn->prepare($strQuery)
Now you can see what it's doing. You're operating blind as it is.
Two additional notes:
You'll hear from everyone that it's a bad idea to put paramaters you're getting from a get or post straight into a SQL query. They're not wrong.
String building for these things is always easier if you're a little more verbose about it. Grab the variable first, as you're going to want to do some processing on it anyway, trimming whitespace, protecting against quotes, etc. Then put it in your query string
Related
I'm looking for a way to get lots of user inputs, concatenate them into one sql query, and return the results from my database. I have tried a few different techniques so far including putting all the variables into an array then using implode() but I couldn't get it to work. For simplicity sake I have decided to just go with a couple of if statements to check if each variable has a value in it or not. If it does then it should add some sql. My error message from this is as follows:
You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use
near 'AND type = AND (city LIKE '%%') OR (addressLineOne LIKE
'%%') OR (`addres' at line 1
It appears that $type is not being picked up even though I gave it a input during the test. I have not given any other inputs values besides $type and $bedroom.
Any help and improvement on the code would be greatly appreciated. I'm new to PHP and SQL so sorry if it's something stupid, but I have tried to fix this for ages.
HTML
<form action="searchresults.php" method="get">
<fieldset>
<legend><h3>Search</h3></legend>
<p>Please enter criteria for your search.</p>
<label for="location">Location</label>
<input type="text" name="location" />
<select name="type">
<option value="Studio Flat" selected>Studio Flat</option>
<option value="Flat">Flat</option>
<option value="Detached">Detached</option>
<option value="Semi-detached">Semi-detached</option>
<option value="Terraced">Terraced</option>
<option value="Bungalow">Bungalow</option>
</select>
<label for="bedroom">Bedrooms</label>
<select name="bedroom">
<option value="1" selected>1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
</select>
<label for="min">Min Price</label>
<input type="number" name="min" />
<label for="max">Max Price</label>
<input type="number" name="max" />
<br />
<input type="submit" value="Search" />
</fieldset>
</form>
PHP
<?php
session_start();
include './auth.php'; // connection to db
$location = trim($_POST['location']);
$location = strip_tags($location);
$location = htmlspecialchars($location);
$bedroom = trim($_POST['bedroom']);
$bedroom = strip_tags($bedroom);
$bedroom = htmlspecialchars($bedroom);
$type = trim($_POST['type']);
$type = strip_tags($type);
$type = htmlspecialchars($type);
$max = trim($_POST['max']);
$max = strip_tags($max);
$max = htmlspecialchars($max);
$min = trim($_POST['min']);
$min = strip_tags($min);
$min = htmlspecialchars($min);
// build query
$query = "SELECT * FROM Listings WHERE `bedroom` = ".$bedroom." AND `type` = ".$type."";
if(isset($location)){
$query .= " AND (`city` LIKE '%".$location."%') OR (`addressLineOne` LIKE '%".$location."%') OR (`addressLineTwo` LIKE '%".$location."%') OR (`county` LIKE '%".$location."%')";
}
if(isset($max)){
$query .= " AND (`price` <= '%".$price."%')";
}
if(isset($min)){
$query .= " AND (`price` >= '%".$price."%')";
}
$query .= "ORDER BY price;";
// send query to database and return error if it fails
$input = mysqli_query($connect, $query) or die(mysqli_error($connect));
// output results
if(mysqli_num_rows($input)>0){ // if one or more results returned do this code
while($result = mysqli_fetch_array($input)){ // puts data in array then loops the following code
echo "<p><h3>".$result['addressLineOne']." ".$result['addressLineTwo']."
".$result['location']."</h3><h4>£".$result['price']."</h4>".$result['information']."</p><br /><hr />";
}
}else{ // no results then print the following
echo "Sorry, we couldn't find any results.
Please refine your search and try again.";
}
echo $query;
// close the connection
mysqli_close($connect)
?>
I know you're currently using mysqli, but PDO makes building dynamic queries much easier, so I strongly suggest you switch to it, if you're not very far along on this project.
In a mysqli prepared statement, you have to call mysqli_stmt::bind_param(), passing every parameter in the argument list. In contrast, PDO requires no binding, and the parameters are all passed to PDOStatement::execute() in an array. This answer will show you how your code would work with PDO.
<?php
$connection = new \PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass);
$query = "SELECT * FROM Listings WHERE bedroom = :bed AND type = :type AND (city LIKE :loc OR addressLineOne LIKE :loc OR addressLineTwo LIKE :loc OR county LIKE :loc)";
$parameters = [
":bed" => $_POST["bedroom"],
":type" => $_POST["type"],
":loc" => "%$_POST[location]%",
];
if(!empty($_POST["max"])) {
$query .= " AND price <= :max";
$parameters[":max"] = $_POST["max"];
}
if (!empty($_POST["min"])) {
$query .= " AND price >= :min";
$parameters[":min"] = $_POST["min"];
}
$query .= " ORDER BY price";
$stmt = $connection->prepare($query);
$stmt->execute($parameters);
$results = $stmt->fetchAll(\PDO::FETCH_ASSOC);
if (empty($results)) { // no results then print the following
echo "Sorry, we couldn't find any results. Please refine your search and try again.";
}
foreach ($results as $result) {
//escape for HTML output
$result = array_map("htmlspecialchars", $result);
echo <<< HTML
<p>
<h3>$result[addressLineOne] $result[addressLineTwo] $result[location]</h3>
<h4>£$result[price]</h4>
$result[information]
</p>
<br />
<hr />
HTML;
}
I've also simplified your HTML output by using a heredoc string, but you should really have your HTML and PHP separated.
If this is part of a much bigger existing project, you will likely be sticking with mysqli, in which case I urge you to learn how to use prepared statements; the days of building queries with string concatenation are long behind us!
Using PDO and bound parameters as #miken32 suggests is a possibility, but I advise against it because it has several downsides:
You are currently using mysqli, which also supports bound parameters, so no reason to switch to PDO just to get parameter binding
#miken32's solution uses a named parameter (something only PDO supports) multiple times in the query. This only works when client-side parameter binding is enabled (i.e. PDO::ATTR_EMULATE_PREPARES set to true) which itself has multiple problems:
I could not quickly find out what the default for PDO::ATTR_EMULATE_PREPARES is, apparently "it depends on the driver".
With PDO::ATTR_EMULATE_PREPARES switched on, you cannot use bound parameters in your LIMIT clause anymore
The errors returned from PDO are completely different depending on whether you use client-side or server-side parameter binding, a missing parameter for example causes an SQLSTATE of HY000 with server-side and HY093 with client-side parameter binding. This complicates proper error handling.
There is no way to see the actual query, an ability that can be very useful (essential in my opinion) for debugging.
So, I say go ahead and build your query manually, but in a clean and safe way. To do that you need to understand these concepts:
HTML encoding
In general, the only place where you need htmlspecialchars() is when you pass data (for example from the database) to the browser.
So, change every
$location = trim($_POST['location']);
$location = strip_tags($location);
$location = htmlspecialchars($location);
to
$location = trim($_POST['location']);
There is no need for strip_tags() nor htmlspecialchars() at this point. Form data from the browser arrives on the PHP side without any encoding. Of course, if someone would actually enter some<br>city into the location field, he would not find any rooms, but it will not break anything if you get the rest of your application right.
Also change every
echo "<p>".$result['addressLineOne']." ... </p><br /><hr />";
to
echo "<p>".htmlspecialchars($result['addressLineOne'])." ... </p><br /><hr />";
Otherwise the people entering the data into the database could run a "cross site scripting attack" - maliciously or accidentally.
SQL encoding
When sending data to the database as part of a query, you have to encode it in a way that the database knows that it's variable data and not part of the SQL command.
So, instead of for example
$query .= " AND (`city` LIKE '%".$location."%') ";
you have to write
$query .= " AND (`city` LIKE '%".addslashes($location)."%') ";
this makes sure that if there is a quote character (') inside your $location variable it will be escaped, so it does not end the string at that point.
If you work with a character set other than UTF-8, you should use mysql_real_escape_string() instead of addslashes() but you are probably using UTF-8, so it's just fine.
Furthermore in this case you might want to remove or escape % and _ in the value, because they have a special meaning in a LIKE query.
You have two more problems in your code:
$query = "SELECT * FROM Listings WHERE `bedroom` = ".$bedroom." AND `type` = ".$type."";
Here you not only have to add addslashes() but also the quotes around the value:
$query = "SELECT * FROM Listings WHERE `bedroom` = '".addslashes($bedroom)."' AND `type` = '".addslashes($type)."'";
And here:
$query .= " AND (`price` <= '%".$price."%')";
Obviously the percent signs make no sense here, you clearly meant:
$query .= " AND (`price` <= '".addslashes($price)."')";
Libraries and template engines
Later on you would be well advised using a library or framework that does those things for you (because it's very easy to forget an addslashes() somewhere), but it can't hurt to do it manually at first in order to learn how it works under the hood.
This question already has answers here:
When to use single quotes, double quotes, and backticks in MySQL
(13 answers)
Closed 6 years ago.
I have a database full of items for a video game. Swords, Shields, etc. I tagged all the items with level, effect, location found and stuff like that.
I can hard code pages to pull from the database. Such as a hard coded dagger that stuns query:
$results = $mysqli->query("SELECT name, type, level, effect
FROM Items
WHERE type = 'Dagger'
AND effect = "Stun"
ORDER BY name ASC");
while ($item= $results->fetch_assoc()) { $result_array[] = $item; }
However I want users to go through drop down menus so they can filter results from the database from themselves. I have no idea how to go about this. I have tried googling but a lot of it seems outdated or when I try it just doesn't work.
Something similair to this website - http://www.wowhead.com/items
So for example users could pick the "Effect" drop down and it creates another drop down where you can choose from; Freeze, Heal, Stun or whatever. Then pick level from drop down menu and enter 50. Then the database would pull the results from the database for daggers that stun and can be used at level 50.
Thanks!
It's pretty simple. First you have the form element.
<form type="post" action="controller.php">
<select name="weapon">
<option value="Dagger"> Dagger </option>
<option value="Sword"> Sword </option>
</select>
<select name="effect">
<option value="Stun"> Stun </option>
<option value="Knock Back"> Knock Back </option>
</select>
</form>
When the user selects a value from these dropdowns, they'll be sent over to the server in the $_POST array with their key's matching the "name" of the select element. The controller.php file is the file that will handle the form submission. You can change the location of this file etc.
Then in your form submission handler you want to handle the $_POST array and then create a prepared statement for security as we're dealing with user input.
/**
| ---------------------------------------------------
| controller.php
| ---------------------------------------------------
*/
if(isset($_POST)){
$weapon = isset($_POST['weapon']) ? $_POST['weapon'] : false;
$effect = isset($_POST['effect']) ? $_POST['effect'] : false;
if($weapon && $effect){
$mysqli = new mysqli('host', 'user', 'pass', 'database');
$result = $mysqli->prepare("SELECT name, type, level, effect
FROM Items
WHERE type = ?
AND effect = ?
ORDER BY name ASC");
$result->bind_param('ss', $weapon, $effect);
if($result->execute()){
while($row = $result->fetch_assoc()){
//access column names here by $row['index'];
}
}
}
}
The above script is checking if the post array is populated, then checks for our specific variables. from there, we establish the database connection, create the safe prepared statement, bind our parameters to our prepared statement, execute the query, then we iterate over the returned resultset with fetch_assoc.
I hope this helps you.
Firstly forgive the use of mysql_*, I appreciate it is depreciated but for completely ridiculous reasons I have to use it for this project.
So I have a dropdown menu populated out of my database with the use of this function
func.php
function artistQuery(){
$myData = mysql_query("SELECT * FROM artists");
while ($record = mysql_fetch_array($myData)){
echo '<option value="' . $record['artistID'] . '">' . $record['artistFirst'] . ' ' . $record['artistSurname'] . '</option>';
}
It populates the drop down menu on:
newprod.php
<h1>New Product Entry:</h1>
<form action="php/addproduct.php" method="_POST">
<p>Please select the artist:</p>
<select name="artist">
<?php artistQuery();
?>
</select>
</form>
So from my function although the first name and surname of the artist are displayed the option value is actually the artistID.
I then use
addproduct.php
<?php
include_once 'php/dbconn.php';
connect();
$artist = $_POST['artist'];
$query = "INSERT INTO products ('artistID') VALUES ('$artist')";
//execute query
$result = mysql_query($query) or die("Error in Query. $query. " . mysql_error());
echo "$artist";
?>
To write the artistID into the database, except it isn't writing.
I am assuming the issue lies somewhere in the newprod.php (Middle block of code) not assigning the artistID to the name of 'artist'.
Any and all help from you wonderful people would be appreciated.
EDIT: Missing letters!
In addproduct.php, try this:
$query = "INSERT INTO products (artistID) VALUES ('$artist')";
Instead of quoted column name (bad):
$query = "INSERT INTO products ('artistID') VALUES ('$artist')";
MySQL column name can be neither single quoted 'artistID', nor double quoted "artistID", nor [artistID] like in Access Database. It must be either bare name artistID, or anti-quoted like
`artistID`
It's useful when you have spaces in the column name like
`Artist Name`
.
It should be method="POST", not method="_POST".
_POST is invalid and is ignored by the browser. The browser will then use GET as method, which is the default for HTML forms.
Edit: The answer by #jacouh is also valid, you have to do both his and my change to make it work.
To avoid some sql injections try to use mysql_escape_string
$query = "INSERT INTO products ('artistID') VALUES ('".mysql_escape_string($artist)."')";
Check if $artist has value, maybe is not inserting in the db, because is null.
Or maybe is not the value the db is expecting, like artistID is an integer an $artist actually is a string.
Inside select box you should give some thing like this
<select name="artist">
<option value="artist"><?php artistQuery();?></option>
</select>
I'm currently building my first database in MySQL with an interface written in PHP and am using the 'learn-by-doing' approach. The figure below illustrates my database. Table names are at the top, and the attribute names are as they appear in the real database. I am attempting to query the values of each of these attributes using the code seen below the table. I think there is something wrong with my mysql_query() function since I am able to observe the expected behaviour when my form is successfully submitted, but no search results are returned. Can anyone see where I'm going wrong here?
<form name = "search" action = "<?=$PHP_SELF?>" method = "get">
Search for <input type = "text" name = "find" /> in
<select name = "field">
<option value = "Title">Title</option>
<option value = "Description">Description</option>
<option value = "City">Location</option>
<option value = "Company_name">Employer</option>
</select>
<input type = "submit" name = "search" value = "Search" />
</form>
$query = "SELECT Title, Descrition, Company_name, City, Date_posted, Application_deadline
FROM job, employer, address
WHERE Title = $find
OR Company_name = $find
OR Date_posted = $find
OR Application_deadline = $find
AND job.employer_id_job = employer.employer_id
AND job.address_id_job = address.address_id";
There seems to be at least four problems:
You don't have quotes around $find, i.e. WHERE Title = '$find'.
You don't seem to be using mysql_real_escape_string (or did you just omit that code in your question for brevity?)
You spelled Description incorrectly.
AND has higher precedence than OR so you probably want parentheses in your expression:
WHERE (Title = '$find'
OR Company_name = '$find'
OR Date_posted = '$find'
OR Application_deadline = '$find')
AND job.employer_id_job = employer.employer_id
AND job.address_id_job = address.address_id"
I suspect that one or more of these are the reason why it's not working. However to be sure you should post more of your code and your table structure.
Another point is that you are using the old ANSI-89 join syntax. I would recommend using the newer syntax added in SQL-92 (FROM a JOIN b ON ...). This would have prevented you from making the fourth error, as well as having numerous other advantages over the older syntax.
Also try using mysql_error to find out what the exact error message is. And please include the message in your question.
If you like to learn by doing then learn by doing it in PDO and bind the parameters. This is the safe and correct way to do it these days.
Use single quotes for values in where clause.
Try this one:
$fields= array('Title','Company_name', 'Date_posted','Application_deadline');
if(!in_array($_GET['field'],$fields)) die(); // do some error handling here
$query = "SELECT Title, Descrition, Company_name, City, Date_posted, Application_deadline
FROM job, employer, address
WHERE
$field = '".mysql_real_escape_string($_GET['find']) ."'
AND job.employer_id_job = employer.employer_id
AND job.address_id_job = address.address_id";
If single quotes isn't your only problem (it is certainly part of it), check the return of mysql_error().
Check the code samples here:
http://www.php.net/manual/en/function.mysql-query.php
I would suggest also using ezSQL to do all your query handling, it's easy to drop into your code and makes all the processing easy, just include the db info in a config file, include the classes for ezSQL in the config file, setup a global call to the class like
$db = new ez_SQL();
then in your referencin php files, just do this
global $db;
$results = $db->query("SELECT statment", ARRAY_A);
you can get ezsql from: http://justinvincent.com/ezsql
I have made the following search script but can only search one table column when querying the database:
$query = "select * from explore where site_name like '%".$searchterm."%'";
I would like to know how I can search the entire table(explore). Also, I would need to fix this line of code:
echo "$num_found. ".($row['site_name'])." <br />";
One last thing that is bugging me is when I push the submit button on a different page I always displays the message "Please enter a search term." even when I enter in something?
Thanks for any help, here is the entire script if needed:
<?php
// Set variables from form.
$searchterm = $_POST['searchterm'];
trim ($searchterm);
// Check if search term was entered.
if (!$serachterm)
{
echo "Please enter a search term.";
}
// Add slashes to search term.
if (!get_magic_quotes_gpc())
{
$searchterm = addcslashes($searchterm);
}
// Connects to database.
# $dbconn = new mysqli('localhost', 'root', 'root', 'ajax_demo');
if (mysqli_connect_errno())
{
echo "Could not connect to database. Please try again later.";
exit;
}
// Query the database.
$query = "select * from explore where site_name like '%".$searchterm."%'";
$result = $dbconn->query($query);
// Number of rows found.
$num_results = $result->num_rows;
echo "Found: ".$num_results."</p>";
// Loops through results.
for ($i=0; $i <$num_results; $i++)
{
$num_found = $i + 1;
$row = $result->fetch_assoc();
echo "$num_found. ".($row['site_name'])." <br />";
}
// Escape database.
$result->free();
$dbconn->close();
?>
Contrary to other answers, I think you want to use "OR" in your query, not "AND":
$query = "select * from explore where site_name like '%".$searchterm."%' or other_column like '%".$searchterm."%'";
Replace other_column with the name of a second column. You can keep repeating the part I added for each of your columns.
Note: this is assuming that your variable $searchterm has already been escaped for the database, for example with $mysqli->real_escape_string($searchterm);. Always ensure that is the case, or better yet use parameterised queries.
Similarly when outputting your variables like $row['site_name'] always make sure you escape them for HTML, for example using htmlspecialchars($row['site_name']).
One last thing that is bugging me is when I push the submit button on a different page I always displays the message "Please enter a search term." even when I enter in something?
Make sure that both forms use the same method (post in your example). The <form> tag should have the attribute method="post".
Also, what is wrong with the line of code you mentioned? Is there an error? It should work as far as I can tell.
A UNION query will provide results in a more optimized fashion than simply using OR. Please note that utilizing LIKE in such a manner will not allow you to utilize any indexes you may have on your table. You can use the following to provide a more optimized query at the expense of losing a few possible results:
$query = "SELECT * FROM explore WHERE site_name LIKE '".$searchterm."%'
UNION
SELECT * FROM explore WHERE other_field LIKE '".$searchterm."%'
UNION
SELECT * FROM explore WHERE third_field LIKE '".$searchterm."%'";
This query is probably as fast as you're going to get without using FULLTEXT searching. The downside, however, is that you can only match strings beginning with the searchterm.
To search other columns of table you need to add conditions to your sql
$query = "select * from explore where site_name like '%".$searchterm."%' or other_column like '%".$searchterm."%'";
But if you don't know that I would strongly advise going through some sql tutorial...
Also I didn't see anything wrong with this line
echo "$num_found. ".($row['site_name'])." <br />";
What error message are you getting?
Just add 'AND column = "condition"' to the WHERE clause of your query.
Be careful with adding lots of LIKE % conditions as these can be very slow especially if using a front wild card. This causes the RDBMS to search every row. You can optimize if you use an index on the column and only a trailing wildcard.
You are searching the whole table, just limiting the results to those where the site_name like '%".$searchterm."%'. If you want to search everything from that table, you need to remove the WHERE clause
Here's the corrected line. You had a few too many quotes in it.
echo $num_found.".".($row['site_name'])." <br />";
Regarding displaying the message, you have a typo in your code:
// Check if search term was entered.
if (!$serachterm)
should be:
// Check if search term was entered.
if (!$searchterm)
In the code you have written, !$serachterm always evaluates to true because you never declared a variable $seracherm (note the typo).
your code is very bugy for sql injection first do
do this
$searchterm = htmlspecialchars($searchterm);
trim($searchterm);
next
$query = mysql_real_escape_string($query);
finaly your search looks like this
$query = "select * from explore where site_name like '%$searchterm%';