I am trying to sanitize my $_GET input but for some reason, mysql doesn't retrieve the data from the DB. If I do this:
$user = mysqli_real_escape_string($connection, $_GET['id']);
//execute query to call user info
$query = "SELECT user
FROM company
WHERE user={$_GET['id']} ";
this will work and the results are displayed; however if I do this:
$user = mysqli_real_escape_string($connection, $_GET['id']);
//execute query to call user info
$query = "SELECT user
FROM company
WHERE user= '$user' ";
I don't get a database error, but nothing shows up.
Am I not sanitizing right? What's going on here? HELP, please!
Best way to avoid such situations is using prepared queries:
How can I prevent SQL injection in PHP?
It's very simple and effective:
$q = $db->prepare('SELECT user FROM company WHERE user=?');
$q->bind_param('i', $user);
$q->execute();
$result = $q->get_result();
while ($row = $result->fetch_assoc()) {
// do something with $row
}
It's cool because it's OOP and it's safe. Some links:
Connection to DB
Prepare statement
Bind parameters
Related
I am new to PHP and have a really basic question.
If I know the result of a query is only a single value (cell) from a single row in MySQL how can I simplify the below without having to go through an array of results and without increasing the risk of SQL injection ?
In the example below I would just need to echo a single email as the result of the query.
I found a couple of posts suggesting different approaches with fetch_field for this but I am not sure what is the best way here since some of these seem to be pretty old or deprecated now.
My PHP:
$stmt = $conn->prepare("SELECT email FROM Users WHERE userName = ? LIMIT 1");
$stmt->bind_param('s', $userName);
$stmt->execute();
$result = $stmt->get_result();
$arr = $result->fetch_assoc();
echo $arr["email"];
Many thanks in advance.
You can avoid caring what the column is called by just doing this:
<?php
$stmt = $conn->prepare("SELECT email FROM Users WHERE userName = ? LIMIT 1");
$stmt->bind_param('s', $userName);
$stmt->execute();
$email = $stmt->get_result()->fetch_object()->email;
echo $email;
Is there a good standard solution to deal with characters like ' and " from being used in user inputs on a web platform?
I'm using php for a webpage and if I have, for example, a search bar which have the following query behind it.
$sql = "select * from aTable where aColumn like '%".$searchedKeyword."%'";
If I search for like Greg's icecream the ' will break the script. Also, I'm guessing if I search for something like 1' or ID>0 my script will have a false effect.
What is the common solution here? Do you usually filter away undesired characters, or is there maybe some method or similiar built-in to php?
You can us PDO and prepared statements to prevent SQL injection.
http://php.net/manual/en/pdo.prepared-statements.php
$searchedKeyword = "mykeyword";
//Database details
$db = 'testdb';
$username = 'username';
$password = 'password';
//Connect to database using PDO (mysql)
try {
$dbh = new PDO('mysql:host=localhost;dbname='.$db, $username, $password);
} catch (PDOException $e) {
var_dump("error: $e");
}
//Prepared SQL with placeholder ":searchedKeyword"
$sql = "select * from aTable where aColumn like '%:searchedKeyword%'";
$sth = $dbh->prepare($sql);
//Bind parameter ":searchedKeyword" to variable $searchedKeyword
$sth->bindParam(':searchedKeyword', $searchedKeyword);
//Execute query
$sth->execute();
//Get results
$result = $sth->fetchAll(); //fetches all results where there's a match
For some reason, the query when run through PHP will not return the results. I have tried both queries in the MySQL command line, and they work perfectly there. Here is the code (mysql_connect.php is working perfectly, to clarify).
<?php
error_reporting(-1);
// retrieve email from cookie
$email = $_COOKIE['email'];
// connect to mysql database
require('mysql_connect.php');
// get user_id by searching for the email it corresponds to
$id = mysqli_query($dbc,"SELECT user_id FROM users WHERE email=$email")or die('couldn\'t get id');
// get data by using the user_id in $id
$result = mysqli_query($dbc,"SELECT * FROM users WHERE user_id=$id")or die('couldn\'t get data');
//test if the query failed
if($result === FALSE) {
die(mysql_error());
echo("error");
}
// collect the array of results and print the ones required
while($row = mysql_fetch_array($result)) {
echo $row['first_name'];
}
?>
When I run the script, I get the message "could not get id", yet that query works in the MySQL command line and PHPMyAdmin.
Your code won't work for 2 reasons - $id will not magically turn into integer, but a mysqli result. And email is a string so it should be quoted.
But...
Why is all of that?
If you want to fetch all the data for user, for certain email, just make you second query fetch data by email and remove the first one:
SELECT * FROM users WHERE email='$email';
And don't forget to escape your input, because it's in cookie. Or, use prepared statements as suggested.
Your query is not valid, you should rewrite it with the following and make sure your you have mysqli_real_escape_string of the $email value before you put it into queries:
SELECT user_id FROM users WHERE email='$email'
Better approach is to rewrite your queries using MySQLi prepared statements:
Here how to get the $id value:
$stmt = mysqli_prepare($dbc, "SELECT user_id FROM users WHERE email = ?");
mysqli_stmt_bind_param($stmt, "s", $email);
mysqli_stmt_execute($stmt);
mysqli_stmt_bind_result($stmt, $id);
mysqli_stmt_fetch($stmt);
You wrote
mysqli_query($dbc,"SELECT user_id FROM users WHERE email=$email");
that is similar to
mysqli_query($dbc,"SELECT user_id FROM users WHERE email=example#example.com");
but it should be
mysqli_query($dbc,"SELECT user_id FROM users WHERE email='example#example.com'");
so you have to do this
mysqli_query($dbc,"SELECT user_id FROM users WHERE email='$email'");
or better
mysqli_query($dbc, 'SELECT user_id FROM users WHERE email=\'' . $email . '\'');
Beside this minor bug
You should be aware of SQL injection if someone changes the value of your cookie.
when i search for a user in database, i do:
$result = $dbh->query("SELECT user FROM table_user WHERE user = '".$user."' ");
$result->execute();
while ($user = $result->fetch(PDO::FETCH_ASSOC)) {
$array[] = $user['user'];
}
But i first get a result, when
user
and
$user
are exactly the same.
But i already need a result, when "$user" is part of "user", anybody knows how to do such a pattern matching?
Greetings!!
You are searching for the LIKE statement. Further note that when you interpolate $user this way you are vulnerable against SQL injections. You should use a prepared statement-
Use this:
$stmt = $dbh->prepare("SELECT user FROM table_user WHERE user LIKE :search");
$stmt->execute(array('user' => "%$user%"));
while($user = $stmt->fetch()) {
var_dump($user);
}
We know that all user input must be escape by mysql_real_escape_string() function before executing on mysql in php script. And know that this function insert a \ before any ' or " character in user input. suppose following code:
$_POST['username'] = 'aidan';
$_POST['password'] = "' OR ''='";
// Query database to check if there are any matching users
$query = "SELECT * FROM users WHERE user='".mysql_real_escape_string($_POST['username']."' AND password='".mysql_real_escape_string($_POST['password']."'";
mysql_query($query);
// This means the query sent to MySQL would be:
echo $query;
this code is safe.
But I find out if user enters her inputs with hexadecimal format then mysql_real_escape_string() can not do any thing and user can execute her sql injection easily. in bellow 27204f522027273d27 is same ' OR ''=' but in hex formated and sql execute without problem :
$_POST['username'] = 'aidan';
$_POST['password'] = "27204f522027273d27";
// Query database to check if there are any matching users
$query = "SELECT * FROM users WHERE user='".mysql_real_escape_string($_POST['username']."' AND password='".mysql_real_escape_string($_POST['password']."'";
mysql_query($query);
// This means the query sent to MySQL would be:
echo $query;
But whether this is true and if answer is yes how we can prevent sql injection in this way?
If you are using mysql_real_escape_string(), odds are you would be better served using a prepared statement.
For your specific case, try this code:
/*
Somewhere earlier in your application, you will have to set $dbh
by connecting to your database using code like:
$dbh = new PDO('mysql:host=localhost;dbname=test', $DBuser, $DBpass);
*/
$_POST['username'] = 'aidan';
$_POST['password'] = "' OR ''='";
$user = $_POST['username'];
$password = $_POST['password'];
// Query database to check if there are any matching users
$query = "SELECT * FROM users WHERE user=? AND password=?";
$stmt = $dbh->prepare($query);
$stmt->bindParam(1, $user);
$stmt->bindParam(2, $password);
$stmt->execute();
This does require you to use PDO for your database interaction, but that's a good thing overall. Here's a question discussing the differences between PDO and mysqli statements.
Also see this StackOverflow question which is remarkably similar to yours and the accepted answer, from which I poached some of this answer.