I am trying to implement a delete function in my MVC site. I have the following error
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 'id=27' at line 1
At the moment while I am trying to fix the error I have hard coded in the id 27, I have looked through the syntax for a simple row delete everywhere (eg. http://www.w3schools.com/php/php_mysql_delete.asp) but cant seem to find why I am getting the error?
deleteItem function
function deleteItem($parameters) {
$id = '27';
if ($this->model->deleteItem( $id )) {
$this->model->hasDeleteFailed = false;
$this->model->setDeleteItemConfirmation();
return (true);
}
else
$this->model->deleteItemError ( DELETE_ITEM_ERROR_STR );
}
SQL Code
public function deleteItem($id) {
$delId = $id;
$sqlQuery = "DELETE FROM items";
$sqlQuery .= "WHERE id=$delId;";
$result = $this->getDbManager () -> executeQuery ( $sqlQuery );
}
The code
$sqlQuery = "DELETE FROM items";
$sqlQuery .= "WHERE id=$delId;";
is the problem, since your SQL statement pretty much amounts to:
DELETE FROM itemsWHERE id=$delId
Notice that there is no space between the word "items" and the word "WHERE" in the SQL statement.
Also, you might as well refactor your code to
$sqlQuery = "DELETE FROM items WHERE id=$delId";
since there is no benefit to creating the SQL statement over two strings.
Also, you NEED to properly escape your SQL input parameters to prevent SQL Injection attacks. I don't know which PHP Framework you're using, so you'll need to look at how the framework does it. Take a look at the mysqli_real_escape_string function for this.
Also, you need to validate that the $id variable is actually an integer to prevent SQL Injection, since mysqli_real_escape_string is not entirely safe on its own. Use intval for this.
In your case you only need to make sure that $id is an integer value.
Thus, you should change your code to something like:
public function deleteItem($id) {
$delId = intval($id);
if ($delId <= 0)
return /* fail since ID is invalid */;
$sqlQuery = "DELETE FROM items WHERE id=$delId;";
$result = $this->getDbManager () -> executeQuery ( $sqlQuery );
}
This:
$sqlQuery = "DELETE FROM items";
$sqlQuery .= "WHERE id=$delId;";
Should be:
$sqlQuery = "DELETE FROM items "; // note the extra space at the end
$sqlQuery .= "WHERE id=$delId;";
Or:
$sqlQuery = "DELETE FROM items";
$sqlQuery .= " WHERE id=$delId;"; // note the extra space at the beggining
public function deleteItem($id) {
$delId = $id;
$sqlQuery = "DELETE FROM items";
$sqlQuery .= " WHERE id=$delId;";
$result = $this->getDbManager () -> executeQuery ( $sqlQuery );
}
Use space in $sqlQuery as I mention.
Related
I have a relatively small search form that I want people to use to search my SQL database.
The only way I've done this before was with a billion nested if statements. Is there a better way to do this?
I am parsing my URL query string, so I have my variables of say:
$city
$bedrooms
$elementaryschool
If I were to just try to try:
$sql = "SELECT * FROM $table_name WHERE ";
if(isset($city)) {
$sql .= " `City` LIKE " . $city;
}
if(isset($bedrooms)) {
$sql .= " AND `Bedrooms` >= " . $bedrooms;
}
if(isset($elementaryschool)) {
$sql .= " AND `ElementarySchool` = " . $elementaryschool;
}
Then I run into an issue when $city isn't set because my query ends up with "SELECT * FROM $table_name WHERE AND Bedrooms >= $bedrooms"
That wouldn't exactly work. What are my options?
I completely understand how to do it if I am including all parameters in my query, which seems to be what all previous questions have asked. But how do I do this when not all fields will have a value? I have a total of 12 possible fields to use for searching, and they can search by just 1 or by all 12.
As I mentioned before, all of the questions I have been able to find refer to coming up with one static SQL query, instead of one that will have varying number of parameters.
I would go with:
$sql = "SELECT * FROM $table_name";
$where = array();
$params = array();
and then:
if(isset($city)) {
$where[] = "City LIKE ?";
$params[] = $city;
}
if(isset($bedrooms)) {
$where[] = "Bedrooms >= ?";
$params[] = $bedrooms;
}
if(isset($elementaryschool)) {
$where[] = "ElementarySchool = ?";
$params[] = $elementaryschool;
}
and finally:
if(!empty($where)) {
$sql .= "WHERE " . implode(" AND ", $where);
}
$result = $db->prepare($sql)->execute($params);
PLEASE NOTE that here, since I do not know what kind of database layer/abstraction you are using, $db represents the database connection, prepare() is used to create a prepared statement, and execute() tu run it, as you would do using PDO; this also protects against SQL injection.
I have a php code with a query:
$query = "SELECT * FROM TDdb WHERE status = $status AND occupation =$occupation";
I am sending the values status and occupation with a client application to this php code.
This works when I send both status and occupation. But I want it to return rows if I just send status but not occupation also ( I mean no matter what the occupation is).
does anyone have any suggestions?
I would appreciate any help.
PS: I want to do it without if statement and just but changing the query
Personally I would create a base query and append conditions wherever you have them, like so:
$sql = 'SELECT * FROM TDdb';
$conditions = array();
$args = array();
if ($action) {
$conditions[] = 'status = :status';
$args[':status'] = $status;
}
if ($occupation) {
$conditions[] = 'occupation = :occupation';
$args[':occupation'] = $occupation;
}
if ($conditions) {
$sql .= ' WHERE ' . join(' AND ', $conditions);
}
$stmt = $db->prepare($sql);
$stmt->execute($args);
Looks like you've got a few good options for how to do it in SQL, or how to make the SQL string variable in PHP.
One reason to consider using an 'if' in the PHP code for the database access performance.
When you introduce an 'or' condition like that in SQL, you're not going to get index access. It is much harder for the database to determine what path it should take than for the PHP code because the SQL engine optimizes the query without knowing what the variable will resolve to at execution.
You already know in the PHP which version of the query you really want. This will perform better if you make that choice there.
This will work if you pass an occupation or a NULL value.
SELECT *
FROM TDdb
WHERE status = $status
AND ($occupation IS NULL OR occupation = $occupation)
"SELECT * FROM TDdb WHERE status = '$status' AND (occupation = '$occupation' OR occupation IS NULL)";
Apart from the solution provided by #Tom and #Damien Legros, you may create two query strings one with occupation and one without occupation. Something like:
$query = "SELECT * FROM TDdb WHERE status = $status";
if ($occupation != "") {
/*When you have value for occupation*/
$query .= " AND occupation =$occupation";
}
So in this case, data will be returned if you have only the status field. Secondly, please check if the status and occupation fields in table are varchar then you have to enclose them in single quotes (').
Thanks everyone for help. specially jack.
finally i created my query like this:
$query = 'SELECT * FROM TDdb';
if ($status) {
$query = $query." WHERE status = '".$status."'";
}
if ($occupation) {
$query = $query." AND occupation = '".$occupation."'";
}
My code is here :
$array_letter = array("A","B","C","Ç","D","E","F","G","H","I","İ","J","K","L",
"M","N","O","P","R","S","Ş","T","U","Ü","V","Y","Z");
$sql = "SELECT id,city FROM city WHERE city LIKE '" .$array_letter[$i]."%'";
And after these codes :
for ($i=0;$i<27;$i++) {
$result = mysql_query($sql);
while ($row = mysql_fetch_array($result)) {
echo "<h3>".$row['city']."</h3>";
}
}
$sql is meaningless because $array_letter[$i]will not work there. But $sql must be top of these codes for design. Because I coded switch-case statement. According to requests, $sql will change for this reason I can not write $sql under for loops. But all my queries depens on $array_letter. How can I make $array_letter work?
You should use the mysqli driver and prepared statements:
$st = $mysqli->prepare("SELECT id,city FROM city WHERE city LIKE ?'");
for ($i=0;$i<27;$i++) {
$st->bind_param("s", $array_letter[$i].'%');
$st->execute();
$result = $st->get_result();
while ($row = $result->fetch_assoc()) {
echo "<h3>".$row['city']."</h3>";
}
}
Although for this case, I would recommend just doing one big query since it looks like you are getting everything: SELECT id,city FROM city ORDER BY city...
For educational purposes, an alternative approach would be to do something like:
$sql = "SELECT * FROM foo WHERE bar='%s'";
mysql_query(sprintf($sql, "42"));
That can be useful in other situations, but again, if you are writing SQL, use prepared statements as they solve this problem more gracefully with the extra protection of helping to prevent SQL injection attacks and minimizing the amount of SQL parsing the server has to do.
You should use prepared statements, as Matthew mentioned in his answer.
Otherwise consider this (using PHP 5.3 closures):
$sql = function($i) use ($array_letters) {
return "SELECT id,city FROM city WHERE city LIKE '" .$array_letter[$i]."%'";
}
Then inside your loop:
mysql_query($sql($i));
This will help to reduce the database calls.
$array_letter = array("A","B","C","Ç","D","E","F","G","H","I","İ","J","K","L",
"M","N","O","P","R","S","Ş","T","U","Ü","V","Y","Z");
for($i=0;$i<count($array_letter);$i++){
if($i!=count($array_letter)-1)
$qstring.="city like '".$array_letter[$i]."%' or ";
else
$qstring.="city like '".$array_letter[$i]."%'";
}
$sql = "SELECT id,city FROM city WHERE ".$qstring;
$result = mysql_query($sql);
while ($row = mysql_fetch_array($result)) {
echo "<h3>".$row['city']."</h3>";
}
Whenever I try to perform my query, It gives me an unknown column error, because it is using my variable as the column name.
essentially
$search="lname";
$term="asdas";
(both of those are variables from a form on another page)
I run this:
if (isset($term))
{
$query = "SELECT * FROM test
WHERE $search = $term ";
}
else
{
$query = "SELECT * FROM test";
}
echo $query;
$result=mysql_query($query) or die(mysql_error());
and then I get this as my error:
Unknown column 'asdas' in 'where clause'
You need to enclose the search term in single quotes(also use mysql_real_escape_string to avoid any issues with quotes in the search string.).
i.e:
if (isset($term))
{
$query = "SELECT * FROM test WHERE $search = '" . mysql_real_escape_string($term) . "' ";
}
You need to quote it.
if (isset($term))
{
$query = "SELECT * FROM test
WHERE $search = '$term' ";
}
else
{
$query = "SELECT * FROM test";
}
echo $query;
$result=mysql_query($query) or die(mysql_error());
Other comments
It is always better to use parameterized queries if the driver supports it. It will prevent SQL injection. As it stands, someone could send in a string "' or ''='" and the query turns out to be
SELECT * FROM test WHERE col1 = '' or ''=''
which is really benign but unexpected behaviour. If the string contains single quotes, it also breaks your query (input is "o'neil")
SELECT * FROM test WHERE col1 = 'o'neil' # << unmatched quotes
So, at the very least use mysql_real_escape_string if you cannot use parameters, i.e.
$query = "SELECT * FROM test
WHERE $search = '" . mysql_real_escape_string($term) . "' ";
You need to quote your $term parameter:
// protect from trivial sql injection attacks.
$term = mysql_real_escape_string("adas");
$query = "SELECT * FROM test
WHERE $search = '$term'";
You have to surround the term value with quotes:
SELECT *
FROM test
WHERE lname='asdas'
otherwise any SQL server out there will think asdas is a field name and try to find it in the table.
Add ' around your columns
$query = "SELECT * FROM test WHERE $search = '$term' ";
you need to put single quotes around $term so that the SQL thinks it's a string
put single quote string always be quoted. Do not forgot use mysql_real_escape_sring()
$query = "SELECT * FROM test
WHERE $search = '$term' ";
Put single quotes around $term
if (isset($term))
{
$query = "SELECT * FROM test WHERE $search = '$term'";
}
else
{
$query = "SELECT * FROM test";
}
echo $query;
$result=mysql_query($query) or die(mysql_error());
I want to make an category-system CMS. Everything is fine, except a big trouble.
How can I can handle and generate the mysql query depends by some inputs like:
site.com/some-category&sortby=views&from=smt&anotherInput=key
For example, for this input my query should be something like
SELECT * FROM `articles` WHERE from='smt' AND afield='key' ORDER BY VIEWS
But these inputs will be different. How I can write this code? I don't know much things about designs patterns, but, I've heard about Factory pattern, is this a part of my solution?
Than
Factory pattern can help you with e.g. connecting/quering various databases without need to rewrite the entire code. This has nothing to do about query itself.
You can look at PDO extension, I usually use it together with prepared statements.
It will let you write queries like this:
$prepare = $db->prepare('
SELECT
*
FROM
articles
WHERE
from=:from AND afield=:afield
ORDER BY
views
');
$prepare->bindValue(':from', $_GET['from'], PDO::PARAM_STR);
$prepare->bindValue(':afield', $_GET['afield'], PDO::PARAM_STR);
$prepare->execute();
return $prepare;
The good thing about it is that you don't need to protect this from sql injections as PDO makes it for you. Also, the query is cached and you can run it several times with different params.
Very bad practice to use raw GET params in query directly, i.e. you shouldn't make constructions like
SELECT * FROM articles WHERE from=$_GET['from'] AND afield='key' ORDER BY VIEWS
but instead something like
if ($_GET['from'] == 'smt') $from = 'smt'
SELECT * FROM articles WHERE from='$from' AND afield='key' ORDER BY VIEWS
and so on
P.S. keyword is 'sql injection'
You can build the query string as pieces depending on what you need:
$query = "SELECT * FROM `articles` WHERE 1 = 1";
$where = ''
if (isset($_GET['from'])) {
$where .= " AND `from` = '" . mysql_real_escape_string($_GET['from']) . "'"
}
if (isset($_GET['anotherInput'])) {
$where .= " AND `from` = '" . mysql_real_escape_string($_GET['anotherInput']) . "'"
}
if (isset($_GET['sortby'] == 'views') {
$orderby = " ORDER BY `views` DESC"
} else {
$orderby = " ORDER BY `id` DESC"
}
$query = $query . $where . $orderby;
$result = mysql_query($query);
This is sort of the straight PHP/MySQL way, but I actually do suggest that you use prepared statements as in Pavel Dubinin's answer.
This has nothing to do with patterns. Use the $_GET superglobal variable to dynamically generate your query string.
$query = "SELECT * FROM articles WHERE from='".
$_GET['from'].
"' AND afield='".
$_GET['anotherInput'].
"' ORDER BY ".
$_GET['sortby'];
Disclaimer: This is prone to SQL injection. Use input escaping and prepared statements, ex PDO, in a production environment like:
$query = "SELECT * FROM articles WHERE from='?' AND afield='?' ORDER BY ?";
$clean_from = htmlentities($_POST['from'], ENT_QUOTES, 'UTF-8');
$clean_anotherInput = htmlentities($_POST['anotherInput'], ENT_QUOTES, 'UTF-8');
$clean_sortby = htmlentities($_POST['sortby'], ENT_QUOTES, 'UTF-8');
$clean_inputs = array($clean_from, $clean_anotherInput, $clean_sortby);
$sth = $dbh->prepare($query);
$sth->execute($clean_inputs);