What's the correct way to code the following
SELECT * FROM table WHERE value = $row['item']
$row['item'] echos correctly, but does not seem to work in the mysql query. Been having this problem for a few days. I've tried .$row['item']. and a few other variations but I must be doing something wrong.
The better more appropriate approach is to use mysqli and prepared statements ie:
$stmt = $mysqli->prepare("SELECT * FROM table WHERE value =?");
$stmt->bind_param("s",$row['item']); // I am assuming row['item'] is a string
$stmt->execute();
If you can't use mysqli or absolutely refuse to you can use this:
$query = "SELECT * FROM table WHERE value = '".mysql_real_escape_string($row['item'])."'";
The answer sort of depends on what is held within the $row['item'] variable. If it's a numeric value, then the query above should be fine. Since it's not working, I assume that the value of that variable is actually a string. In that case, you need to surround the value in quotes so that the database can correctly identify it as a string value (otherwise, it would just be gibberish "commands" that the database can't identify, causing the query to fail).
Regardless of the above, you shouldn't be directly inserting variables into a query under pretty much any circumstances. The reason is that it opens you up to SQL injection if you're not extremely careful. For example, if your $row['item'] variable was wrapped in single quotes in the query, but contained a single quote in its value, then the database would interpret the quote within the variable as the ending quote for the entire parameter, and it would screw up the query. Worse still, a hacker could take advantage of this to end your query entirely, then add a second query of his own making onto it (or they could introduce a UNION query on the end of the original, etc.). At the very least, you should be running something like mysql_real_escape_string() on the variable before using it:
$sql = "SELECT * FROM table WHERE value = " .
mysql_real_escape_string($row['item']);
The best way to get around this and secure your queries is to use prepared statements. These are queries that have placeholders in them instead of concatenated variables. You prepare the query with these placeholders, then you issue additional commands to the database to tell it what values to place in those placeholders. The database then takes care of the tricky issue of sanitizing these variables so that they don't cause any damage. You can use PDO for this:
try {
$dbh = new PDO(DB_DSN,
DB_USER,
DB_PASS,
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)
);
} catch (PDOException $e) {
echo "Connection failed: " . $e->getMessage();
exit();
}
// create query with a named placeholder
$sql = "SELECT * FROM table WHERE value = :value";
try {
$stmt = $dbh->prepare($sql);
// tell PDO to substitute the value in $row['item']
// for the named parameter specified above.
$stmt->bindValue(":value", $row['item']);
// execute the query and load the results into an array
$stmt->execute();
$records = $stmt->fetchAll();
} catch (PDOException $e) {
echo "Query failed: " . $e->getMessage();
exit();
}
foreach ($records as $record) {
// use db records
}
The way I usually recommend doing it is something like this:
$sql = sprintf("SELECT * FROM table WHERE value = '%s'",
mysql_real_escape_string($row['item']));
$item = mysql_real_escape_string($row['item']);
$mysqlQuery = "SELECT * FROM table WHERE value = '" . $item . "'";
you are missing single quotes
SELECT * FROM table WHERE value = '{$row['item']}'
PHP example
Related
I am a php beginner.
I have the following script which works if I do not use _GET['version'] in the query, but works if I remove it. There is no error; I am not sure why it is not working.
<?php
// Specify your table name
$hostname = 'localhost';
$dbname = 'stats';
$table_name = 'st_stats';
$username = 'test';
$password = 'test';
try
{
$conn = new PDO("mysql:host=$hostname;dbname=$dbname",$username,$password);
//By default mode is silent and exception is not thrown. So I it to throw ex
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// If the query is like this no error is given but page shows up blank
$stmt = $conn->query("SELECT * FROM $table_name where version = $_GET['version']", PDO::FETCH_ASSOC);
// This works if uncomment below line instead and comment line above
//$stmt = $conn->query("SELECT * FROM $table_name", PDO::FETCH_ASSOC);
$count = $stmt->rowCount();
echo("<h1>currently $count records</h1>");
}
catch(PDOException $e)
{
echo 'ERROR: ' . $e->getMessage();
}
?>
I want to access the page like this
http://www.mydomain/records.php?version=1.2
Note that version column does exit in the table
You could try to avoid a bit of sql injection here by preparing the statement properly:
$v_term = $_GET['version'];
$query = "SELECT * FROM $table_name where version = :term";
$result = $conn->prepare($query);
$result->bindValue(":term",$v_term);
$result->execute();
Also, run the statement straight from the db if you can to make sure you are getting records back. Other than that, there is no other way to debug this for you from what you given us.
Maybe version is not an integer therefore need quotes ?
"SELECT * FROM $table_name where verion = '".$_GET['version']."'",
Anyway you are vulnerable to sql injection and also misusing PDO
You should at least bindParam/bindValue
Or use execute() and past the $_GET value
As documented under Variable parsing:
There are two types of syntax: a simple one and a complex one.
[ deletia ]
Example #8 Simple syntax example
[ deletia ]
echo "He drank some $juices[koolaid1] juice.".PHP_EOL;
[ deletia ]
Complex (curly) syntax
This isn't called complex because the syntax is complex, but because it allows for the use of complex expressions.
[ deletia ]
// Works, quoted keys only work using the curly brace syntax
echo "This works: {$arr['key']}";
That is, you can reference associative arrays from within a double-quoted string in one of two ways:
// simple - don't quote your keys
"... $_GET[version] ..."
// complex - you may quote your keys, but must surround the expression in braces
"... {$_GET['version']} ..."
HOWEVER, you shouldn't be doing either here. You should instead be using a parameterised statement in order to prevent SQL injection attacks:
$stmt = $conn->prepare("SELECT * FROM $table_name WHERE verion = ?");
$stmt->execute([$_GET['version']]);
This doesnt work because you're trying to access $_GET['version'] an array variable within a string here
"SELECT * FROM $table_name where version = $_GET['version']", PDO::FETCH_ASSOC
placing {} around the variable will fix this one issue
$stmt = $conn->query("SELECT * FROM $table_name where verion = {$_GET['version']}", PDO::FETCH_ASSOC);
But you should also sanitize this value before you put it right int a sql statement
You have verion rather than version in your query. You're also not passing the value of $_GET['version'], you're passing the string "$_GET['version']" right into the query. Update your query to this:
$stmt = $conn->query("SELECT * FROM $table_name where version = {$_GET['version']}", PDO::FETCH_ASSOC);
Wrapping a variable that's inside a double quoted string ("") in curly braces ({}) evaluates to the value of the variable.
If you do this you will be wide open to SQL injection attacks. Be sure to sanitize the variable before you run the query, or better yet consider prepared statements.
I am trying to query my database using php, to then display the results of the query. For this example, I only want the number of elements in my MySQL database.
My code is:
<?php
print("This is just a test");
print("This is another test");
// Create connection
$con=mysqli_connect("mysql.netsons.com","****","****","****");
// Check connection
if (mysqli_connect_errno()) {
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
print("A third test");
$result = mysqli_query($con, "SELECT COUNT(*) FROM MyGames");
echo $result;
echo mysqli_fetch_array($result);
print("A forth test");
mysqli_close($con);
?>
This is the result:
This is just a testThis is another testA third test
What am I doing wrong?
mysql_fetch_array fetches ... an array.
$row = mysqli_fetch_array($result);
echo $row["COUNT(*)"];
I think it would be better to alias that column too:
SELECT COUNT(*) AS count FROM MyGames
...
echo $row['count'];
I would recomend using a diferent method of querying that is much safer(As far as I know there is no SQL Injection to worry about) and it saves a lot of time and space.
First you need to create an mysqli object
$stateConnect = new mysqli("localhost", "root", "PASS", "DBTable");
This does the same thing as mysqli_connect and mysqli_select_db
Then you want to define your SQL query
$sql = "SELECT `userVotes` FROM `users` WHERE `userEmail`=?";
Next you want to create a variable called a statement with your SQL "attached to it"
$statement = $stateConnect->prepare($sql);
Notice how in my SQL I didn't directly put the value required for userEmail, instead I put an '?'. This acts as a variable that we will later define(However it will always be a '?'
To define this variable we need to use.
$statement->bind_param('s', $SESSION['email']);
This binds $SESSION['email'] to the first qustion mark, the s is saying that the first question mark will be a string. Lets say we had to varribles:
$sql = "SELECT `userVotes` FROM `users` WHERE `userEmail`=? AND `userName`=?";
We would then use:
$statement->bind_param('ss', $SESSION['email'], "USERNAME");
Each s replresents a question mark and each value after that represents a question mark.
Now we have to execute our query with.
$statement->execute();
If we are expecting a result to be returned then we have to use
$statement->bind_result($userVotesText);
To bind the results to a variable, If I was expecting to columns of results I would need to put a second variable in.
Now to set those varribles we need to use
if($statement->fetch()){
$userVotesResult = userVotesText;
}
This method is much better than other for querying databases and is called Prepared Statement
So in this program I'm writing, I actually grab a SQL query from the user using a form. I then go on to run that query on my database.
I know not to "trust" user input, so I want to do sanitization on the input. I'm trying to use mysql_real_escape_string but have been unsuccessful in getting it to work.
Here's what I'm trying, given the input:
select * from Actor;
//"query" is the input string:
$clean_string = mysql_real_escape_string($query, $db_connection);
$rs = mysql_query($clean_string, $db_connection);
if (!$rs)
{
echo "Invalid input!";
}
This is ALWAYS giving me the
"Invalid input!"
error.
When I take out the clean_string part and just run mysql_query on query, the
"invalid
input"
message is not output. Rather, when I do this:
$rs = mysql_query($query, $db_connection);
if (!$rs)
{
echo "Invalid input!";
}
It does NOT output
"invalid input".
However, I need to use the mysql_real_escape_string function. What am I doing wrong?
Update:
Given
select * from Actor; as an input, I've found the following.
Using echo statements I've
found that before sanitizing, the string holds the value:
select * from Actor;
which is correct. However, after sanitizing it holds the incorrect
value of select *\r\nfrom Actor;, hence the error message. Why is
mysql_real_escape_string doing this?
use it on the actual values in your query, not the whole query string itself.
example:
$username = mysql_real_escape_string($_POST['username']);
$query = "update table set username='$username' ...";
$rs = mysql_query($query);
Rather than using the outdated mysql extension, switch to PDO. Prepared statement parameters aren't vulnerable to injection because they keep values separate from statements. Prepared statements and PDO have other advantages, including performance, ease of use and additional features. If you need a tutorial, try "Writing MySQL Scripts with PHP and PDO".
mysql_real_escape_string() is the string escaping function. It does not make any input safe, just string values, not for use with LIKE clauses, and integers need to be handled differently still.
An easier and more universal example might be:
$post = array_map("mysql_real_escape_string", $_POST);
// cleans all input variables at once
mysql_query("SELECT * FROM tbl WHERE id='$post[id]'
OR name='$post[name]' OR mtime<'$post[mtime]' ");
// uses escaped $post rather than the raw $_POST variables
Note how each variable must still be enclosed by ' single quotes for SQL strings. (Otherwise the escaping would be pointless.)
You should use mysql_real_escape_string to escape the parameters to the query, not the entire query itself.
For example, let's say you have two variables you received from a form. Then, your code would look like this:
$Query = sprintf(
'INSERT INTO SomeTable VALUES("%s", "%s")',
mysql_real_escape_string($_POST['a'], $DBConnection),
mysql_real_escape_string($_POST['b'], $DBConnection)
);
$Result = mysql_query($Query, $DBConnection);
manual mysql_real_escape_string()
Escapes special characters in a string
for use in an SQL statement
So you can't escape entire query, just data... because it will escape all unsafe characters like quotes (valid parts of query).
If you try something like that (to escape entire query)
echo mysql_real_escape_string("INSERT INTO some_table VALUES ('xyz', 'abc', '123');");
Output is
INSERT INTO some_table VALUES (\'xyz\',
\'abc\', \'123\');
and that is not valid query any more.
This worked for me. dwolf (wtec.co)
<?php
// add data to db
require_once('../admin/connect.php');
$mysqli = new mysqli($servername, $username, $password, $dbname);
/* check connection */
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
$post = $mysqli->real_escape_string($_POST['name']);
$title = $mysqli->real_escape_string($_POST['message']);
/* this query with escaped $post,$title will work */
if ($mysqli->query("INSERT into press (title, post) VALUES ('$post', '$title')")) {
printf("%d Row inserted.\n", $mysqli->affected_rows);
}
$mysqli->close();
//header("location:../admin");
?>
What would be the best way to protect this query from sql injection?
This example is just an example, I've read a few articles on internet but can't get my head around parametrised queries. Any links to useful articles will get a vote up but I think seeing this example would help me best.
$id = $_GET["id"];
$connection = odbc_connect("Driver={SQL Server};Server=SERVERNAME;Database=DATABASE-NAME;", "USERNAME", "PASSWORD");
$query = "SELECT id firstname secondname from user where id = $id";
$result = odbc_exec($connection, $query);
while ($data[] = odbc_fetch_array($result));
odbc_close($connection);
Thanks,
EDIT: I didn't make it obvious but I'm using SQL Server not mysql.
This is just an example, it won't always be a number I'm searching on.
It would be nice if the answer used parametrised queries as many people suggest this and it would be the same for all query's instead of different types of validation for different types of user input.
I think PDO objects are the best.
In a nutshell, here is how you use them.
$databaseConnection = new PDO('mysql:host='. $host .';dbname=' . $databaseName, $username, $password);
$sqlCommand = 'SELECT foo FROM bar WHERE baz=:baz_value;';
$parameters = array(
':baz_value' => 'some value'
);
$preparedStatement = $databaseConnection->prepare($sqlCommand);
$preparedStatement->execute($parameters);
while($row = $preparedStatement->fetch(PDO::FETCH_ASSOC))
{
echo $row['foo'] . '<br />';
}
The values you would enter for the SELECT criteria are replaced with parameters (like :field_value) that begin with a colon. The paramters are then assigned values in an array which are passed separately.
This is a much better way of handling SQL queries in my opinion.
The parameters are sent to the database separately from the query and protects from SQL injection.
Use prepared statements. First build a statement with the odbc_prepare() function, then pass the parameters to it and execute it using odbc_execute().
This is much more secure and easier than escaping the string yourself.
Lewis Bassett's advice about PDO is good, but it is possible to use prepared statements with ODBC without having to switch to PDO.
Example code, untested!
try {
$dbh = new PDO(CONNECTION_DETAILS_GO_HERE);
$query = 'SELECT id firstname secondname from user where id = :id';
$stmt = $dbh->prepare($query);
$stmt->bindParam(':id', $id, PDO::PARAM_STR);
$result = $stmt->execute();
$data = $stmt->fetchAll();
} catch (PDOException $e)
echo 'Problem: ', $e->getMessage;
}
Note: $e->getMessage(); may expose things you don't want exposed so you'll probably want to do something different on that line when your code goes live. It's useful for debugging though.
Edit: Not sure if you wanted a PDO or ODBC example but it's basically the same for both.
Edit: If you're downvoting me please leave a comment and tell me why.
To begin with, be careful with the variables you use in your queries, specially those that come from external sources such as $_GET, $_POST, $_COOKIE and $_FILES. In order to use variables inside your queries you should:
Cast numeric data to integer or float (whichever is appropriate)
Use appropriate escaping to escape other data
A simple example for mysql databases:
$id = $_GET["id"]; // contains: OR 1 = 1
$name = $_GET["name"]; // contains: ' OR '' ='
$query = "SELECT * FROM table WHERE id = " . intval($id) . " AND name = '" . mysql_real_escape_string($name) . "'";
// SELECT * FROM table WHERE id = 0 AND name = '\' OR \'\' =\''
For other database, the escaping practice varies. But generally you're supposed to escape the ' character with '', so:
$id = $_GET["id"]; // contains: OR 1 = 1
$name = $_GET["name"]; // contains: ' OR '' ='
$query = "SELECT * FROM table WHERE id = " . intval($id) . " AND name = '" . str_replace("'", "''", $name) . "'";
// SELECT * FROM table WHERE id = 0 AND name = ''' OR '''' ='''
Having said that, perhaps you might want to switch to PDO. It allows you to use prepared statements, the PDO driver does all the escaping.
The mysql variant came with a method called mysql_real_escape_string, which was appropriate for the version of SQL being targeted. The best thing you can do is write a method to escape the Id. It's important that your escape method is appropriate for the target database. You can also do basic type checking like is_numeric for numeric inputs will reject SQL string injections immediately.
See How to escape strings in SQL Server using PHP?
and follow some of the related links for explicit examples
So in this program I'm writing, I actually grab a SQL query from the user using a form. I then go on to run that query on my database.
I know not to "trust" user input, so I want to do sanitization on the input. I'm trying to use mysql_real_escape_string but have been unsuccessful in getting it to work.
Here's what I'm trying, given the input:
select * from Actor;
//"query" is the input string:
$clean_string = mysql_real_escape_string($query, $db_connection);
$rs = mysql_query($clean_string, $db_connection);
if (!$rs)
{
echo "Invalid input!";
}
This is ALWAYS giving me the
"Invalid input!"
error.
When I take out the clean_string part and just run mysql_query on query, the
"invalid
input"
message is not output. Rather, when I do this:
$rs = mysql_query($query, $db_connection);
if (!$rs)
{
echo "Invalid input!";
}
It does NOT output
"invalid input".
However, I need to use the mysql_real_escape_string function. What am I doing wrong?
Update:
Given
select * from Actor; as an input, I've found the following.
Using echo statements I've
found that before sanitizing, the string holds the value:
select * from Actor;
which is correct. However, after sanitizing it holds the incorrect
value of select *\r\nfrom Actor;, hence the error message. Why is
mysql_real_escape_string doing this?
use it on the actual values in your query, not the whole query string itself.
example:
$username = mysql_real_escape_string($_POST['username']);
$query = "update table set username='$username' ...";
$rs = mysql_query($query);
Rather than using the outdated mysql extension, switch to PDO. Prepared statement parameters aren't vulnerable to injection because they keep values separate from statements. Prepared statements and PDO have other advantages, including performance, ease of use and additional features. If you need a tutorial, try "Writing MySQL Scripts with PHP and PDO".
mysql_real_escape_string() is the string escaping function. It does not make any input safe, just string values, not for use with LIKE clauses, and integers need to be handled differently still.
An easier and more universal example might be:
$post = array_map("mysql_real_escape_string", $_POST);
// cleans all input variables at once
mysql_query("SELECT * FROM tbl WHERE id='$post[id]'
OR name='$post[name]' OR mtime<'$post[mtime]' ");
// uses escaped $post rather than the raw $_POST variables
Note how each variable must still be enclosed by ' single quotes for SQL strings. (Otherwise the escaping would be pointless.)
You should use mysql_real_escape_string to escape the parameters to the query, not the entire query itself.
For example, let's say you have two variables you received from a form. Then, your code would look like this:
$Query = sprintf(
'INSERT INTO SomeTable VALUES("%s", "%s")',
mysql_real_escape_string($_POST['a'], $DBConnection),
mysql_real_escape_string($_POST['b'], $DBConnection)
);
$Result = mysql_query($Query, $DBConnection);
manual mysql_real_escape_string()
Escapes special characters in a string
for use in an SQL statement
So you can't escape entire query, just data... because it will escape all unsafe characters like quotes (valid parts of query).
If you try something like that (to escape entire query)
echo mysql_real_escape_string("INSERT INTO some_table VALUES ('xyz', 'abc', '123');");
Output is
INSERT INTO some_table VALUES (\'xyz\',
\'abc\', \'123\');
and that is not valid query any more.
This worked for me. dwolf (wtec.co)
<?php
// add data to db
require_once('../admin/connect.php');
$mysqli = new mysqli($servername, $username, $password, $dbname);
/* check connection */
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
$post = $mysqli->real_escape_string($_POST['name']);
$title = $mysqli->real_escape_string($_POST['message']);
/* this query with escaped $post,$title will work */
if ($mysqli->query("INSERT into press (title, post) VALUES ('$post', '$title')")) {
printf("%d Row inserted.\n", $mysqli->affected_rows);
}
$mysqli->close();
//header("location:../admin");
?>