Having trouble fetching results from a MySQL table with PDO - php

I'm building a simple login system. What I'm having trouble with is fetching the password hash from the database.
This is what I have:
$statement = 'SELECT Pass FROM Emails WHERE Email = "?"';
$question = array($email);
try {
$DB->beginTransaction();
$preparedStatement = $DB->prepare($statement);
$preparedStatement->execute($question);
$resultArr = $preparedStatement->fetchAll();
print_r($resultArr);
$DB->commit();
} catch(\PDOException $ex) {
echo "Seriously bad error. ";
echo $ex->getMessage();
return false;
}
My problem is that $resultArr always contains no elements.
I know the SQL query itself works, as I've tested it directly in MySQL.
I believe that I have to use a prepared statement, as I'm sending user input to MySQL and have to defend against easy SQL injection attacks.
I'm using fetchAll() in order to make sure that there's only one result for a given email. Otherwise, there will be a huge problem.
What is my mistake here?

Just for sake of cleaning this extremely superfluous code
$stmt = $DB->prepare('SELECT Pass FROM Emails WHERE Email = ?');
$stmt->execute(array($email));
$pass = $stmt->fetchColumn();
these 3 lines is ALL you need to run a query and get result.
And yes, the problem is just quotes around ? mark.
To ensure there is no other email you ought to use unique index in Mysql

$query = 'SELECT Pass FROM Emails WHERE Email = :email';
try {
$DB->beginTransaction();
$preparedStatement = $DB->prepare($query);
$preparedStatement->bindParam("email", $email, PDO::PARAM_STR);
$preparedStatement->execute();
$resultArr = $preparedStatement->fetchAll();
print_r($resultArr);
$DB->commit();
} catch(\PDOException $ex) {
echo "Seriously bad error. ";
echo $ex->getMessage();
return false;
}

Related

How do you stop injection in this PHP/PDO

So I have look at so many post, web sites and video and now I am so confused! I can't seem to get it right.
How do you stop injection in this PHP/PDO. I have this code that works, but it allows injection.
//*THIS WORKS BUT ALLOWS INJECTION
//*
//The variable $word comes from another php file where the search is created.
public function getAllCards($word) {
$sql = "SELECT * FROM carddbtable WHERE businessNameDB='".$word."'";
foreach ($this->conn->query($sql) as $row) {
echo json_encode($row)."<br>"."<br>";
}
$db = null;
}
With this new code I am trying to remove the variable "$word" from the "SELECT * FROM " statement
to stop the injection and add the "prepare" and the error checking and the "execute" statement, but I can't get it right. How would I do this? FYI this is a GoDaddy shared server.
//Getting the search "word" from the GetCards.php
public function getAllCards($word) {
//Empty var to store all returned info from db
$returnArray = array();
// sql statement to be executed
$sql = "SELECT * FROM carddbtable WHERE businessNameDB=':word";
// prepare to be executed
$statement = $this->conn->prepare($sql);
// error occurred
if (!$statement) {
throw new Exception($statement->error);
}
// execute statement
$statement->execute( :word => '$word' );
//run the query
foreach ($this->conn->query($statement) as $row) {
echo json_encode($row)."<br>"."<br>";
}
// store all appended $rows in $returnArray to be sent to app
$returnArray[] = $row;
}
You've almost got it. PDO, like many database drivers, will be responsible for all of the escaping, so just leave the placeholder as plain as possible:
$sql = "SELECT * FROM carddbtable WHERE businessNameDB=:word";
No ' necessary there.
Now when you execute() a PDO statement you get a result which you need to capture into a variable:
$res = $statement->execute([ 'word' => $word ]);
As Ibu and chris85 point out the '$word' part is also incorrect. Avoid quoting single variables, it's not only pointless, it can cause trouble, like here where you're binding to literally dollar-sign word, not the value in question. This goes doubly for "$word".
Then you fetch from that. Right now you're calling query() on the statement, which is incorrect.
Another thing to note is kicking the habit of making throw-away variables like $sql as these are just junk. Instead pass the argument directly:
$statement = $this->conn->prepare("SELECT * FROM carddbtable WHERE businessNameDB=:word");
This avoids accidentally mixing up $sql3 with $sql8 if you're juggling a bunch of these things.
This is what i have now.
//Getting the search "word" from the GetCards.php
public function getAllCards($word) {
//Empty var to store all returned info from db
$returnArray = array();
// prepare to be executed sql statement to be executed if not entered word
$statement = $this->conn->prepare("SELECT * FROM carddbtable WHERE businessNameDB=:word");
// error occurred
// if (!$statement) {
// throw new Exception($statement->error);
// }
// execute statement
$res = $statement->execute([ 'word' => $word ]);
//run the query
foreach ($this->conn->query($res) as $row) {
echo json_encode($row)."<br>"."<br>";
}
// store all appended $rows in $returnArray to be sent to app
$returnArray[] = $row;
}
I got this working
//*FUNCTION TO GET CARD FROM SEARCH WORD CALLED FROM GetCards.php
public function getAllCards($word) {
//Connect to db using the PDO not PHP
$db = new PDO('mysql:host=localhost;dbname=xxxx', 'xxxx', 'xxxx');
//Here we prepare the SELECT statement from the search word place holder :word
$sql = $db->prepare('SELECT * FROM carddbtable WHERE businessNameDB=:word');
//We execute the $sql with the search word variable"$word"
$sql->execute([':word' => $word]);
//Looping through the results
foreach ($sql as $row)
//Print to screen
echo json_encode($row). "<br>"."<br>";
}

PHP/MySQL PDO/Update Rows

I'm here trying to update my DB rows without deleting/creating new ones all the time. Currently, my DB creates new entries everytime I run this block of code. Instead of spamming my DB, I just want to change some of the values.
<?php
try {
$conn = new PDO("mysql:host=localhost;port=3306;dbname=dbname", Username, password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e){
echo "Connection failed: " . $e->getMessage();
}
if(isset($_POST['mUsername']))
{
$mUsername = urldecode($_POST['mUsername']);
$mEvent = urldecode($_POST['mEvent']);
$mChat = urldecode($_POST['mChat']);
$mlongitude = urldecode($_POST['mlongitude']);
$mlatitude = urldecode($_POST['mlatitude']);
$sqlUPDATE = "UPDATE users
SET lastEvent=:lastEvent, lastChat=:lastChat,
lastLong=:lastLong, lastLatt=:lastLatt
WHERE name=:name";
$stmt = $conn->prepare($sqlUPDATE);
$stmt->bindParam(':lastEvent', $mEvent);
$stmt->bindParam(':lastChat', $mChat);
$stmt->bindParam(':lastLong', $mlongitude);
$stmt->bindParam(':lastLatt', $mlatitude);
$stmt->bindParam(':name', $mUsername);
$stmt->execute();
}
echo "successfully updated";
?>
My assumption is my final line, the $results area. I believe it's just treating this an a new entry instead of an update. How do I go about just replacing values? some values will not change, like the username, and sometimes longitude/latitude won't need to be changed. Would that have to be a separate query, should I split this in to two scripts? Or could I just enter a blank, null value? Or would that end up overwriting the ACTUAL last coordinates, leaving me with null values? Looking for any help or guides or tutorials. Thank you all in advance.
lots of syntax error in your code. It is simple to use bindParam
$sqlUPDATE = "UPDATE users
SET lastEvent=:lastEvent, lastChat=:lastChat,
lastLong=:lastLong, lastLatt=:lastLatt
WHERE name=:name";// you forget to close statement in your code
$stmt = $conn->prepare($sqlUPDATE);
$stmt->bindParam(':lastEvent', $mEvent);
$stmt->bindParam(':lastChat', $mChat);
$stmt->bindParam(':lastLong', $mlongitude);
$stmt->bindParam(':lastLatt', $mlatitude);
$stmt->bindParam(':name', $mUsername);
$stmt->execute();
read http://php.net/manual/en/pdostatement.bindparam.php
When using prepared statements, you should also make a habbit of following the set rules. Use named parameters. Try this:
if(isset($_POST['mUsername']))
{
$mUsername = urldecode($_POST['mUsername']);
$mEvent = urldecode($_POST['mEvent']);
$mChat = urldecode($_POST['mChat']);
$mlongitude = urldecode($_POST['mlongitude']);
$mlatitude = urldecode($_POST['mlatitude']);
$sqlUPDATE = "UPDATE users SET lastEvent= :lastEvent, lastChat= :lastChat, lastLong= :lastLong, lastLatt= :lastLatt WHERE name= :name";
$q = $conn->prepare($sqlUPDATE);
$results = $q->execute(array(':name'=>$mUsername, ':lastEvent'=>$mEvent, ':lastChat'=>$mChat, ':lastLong'=>$mlongitude, ':lastLatt'=>$mlatitude));
}

How to escape during PDO query statement in php? [duplicate]

This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 7 years ago.
(Edit:Guys, Before jumping to any conclusions, I'm asking how do you escape a query variable from the Example#2 from php.net website. I tried lot of ways but they all gave me errors. If you can please read that Example and post your version of that exact Example#2. Also please read about why they have that example there.)
I was searching for a reliable 'row:count' method to use with PHP PDO across multiple database types, and came across below code from php.net
http://php.net/manual/en/pdostatement.rowcount.php (See Example:#2)
It says to do a row count to see if an entry exists in a database using a SELECT statement, the error proof method is to use PDO::query() instead of PDOStatement::fetchColumn().
My question is I know how to bind and execute with PDO, but I don't know how to assign a user submitted variable($username) to this $sql statement and escape it successfully?
Is it possible to bind parameters to this $sql mehod using PDO?
try{
$conn = new PDO($dsn, $db_username, $db_password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$this->db = $conn;
} catch(PDOException $e){
echo 'Error:'.$e;
}
public function usernameExists($username){
//Check db for a match.
$sql = "SELECT * FROM users WHERE username = '".$username."'";
$results = $this->db->query($sql);
if($results->fetchColumn() > 0){
//Matching username found in the db
return true;
}else{
//No matching username in db
return false;
}
}
You're looking for bindValue. With it, you can use a placeholder when writing your query, then pass the user's input afterward.
For example:
public function usernameExists($username){
//$result = $this->db->query('SELECT * FROM users WHERE username = ');
//Check db for a match.
$sql = "SELECT * FROM users WHERE username = :username";
$s = $conn->prepare($sql);
$s->bindValue(':username',$username);
$s->execute();
$results = $s->fetchAll();
if(count($results) > 0){
//Matching username found in the db
return true;
}else{
//No matching username in db
return false;
}
For more info, see the PHP manual.
You're going to want to use a parameterized query like this:
<?php
$value = "whatever";
$stmt = $dbh->prepare("SELECT * FROM TABLE_NAME where column_name = ?");
if ($stmt->execute(array($value))) {
while ($row = $stmt->fetch()) {
print_r($row);
}
}
?>
If you really wanted to quote+escape the string, then that's possible too. It even looks somewhat more legible with complex variable interpolation than your original string patching:
$sql = "SELECT * FROM users WHERE username = {$this->db->quote($username)}";
// ->quote itself adds ↑ 'quotes' around
Now of course: don't do that. Use a placeholder, and pass it per ->execute([$var]); instead. Strive for consistency.

Empty MySQL query result in PHP

Here's the problematic PHP function:
//Get data associated with $criteria from db
function getUserData($criteria, $value) {
//obtain user data from db based on $criteria=$value
global $pdo;
//echo $criteria . " " . $value;
try {
$sql = 'SELECT id, first, last, email, userid FROM users WHERE :criteria= :value';
//var_dump($sql);
$st = $pdo->prepare($sql);
$st->bindValue(':criteria', $criteria);
$st->bindValue(':value', $value);
$st->execute();
}
catch (PDOException $ex) {
$error = "Failed to obtain user data.";
$errorDetails = $ex->getMessage();
include 'error.html.php';
exit();
}
$row = $st->fetch();
//var_dump($row);
if ($row)
{
$userdata = array();
$userdata['id'] = $row['id'];
$userdata['first'] = $row['first'];
$userdata['last'] = $row['last'];
$userdata['email'] = $row['email'];
$userdata['userid'] = $row['userid'];
return $userdata;
}
return FALSE;
}
I use this function to return a whole row of data associated with specific column in it.
When used at it's current state, with a call like that getUserData("email", "John_Stewart_2013"), it returns false, meaning an empty result, while the same query runs fine in MySQL CLI.
If I, on the other hand, substitute the query string $sql with :
$sql = "SELECT id, first, last, email, userid FROM users WHERE $criteria='$value'";
And comment out the bindValue calls, Every thing runs fine in PHP, and the query returns as desired.
But the problem is, those function arguments are user-submitted form data, meaning the solution is vulnerable to SQL Injection.
What's wrong here in the first query form?
You can't use bindValue with column names I'm afraid.
If you think about what a prepared statement is, this should become more obvious. Basically, when you prepare a statement with the database server, it creates an execution plan for the query beforehand, rather than generating it at the time of running the query. This makes it not only faster but more secure, as it knows where it's going, and the datatypes that it will be using and which are going to be input.
If the column/table names were bindable in any way, it would not be able to generate this execution plan, making the whole prepared statement idea somewhat redundant.
The best way would be to use a hybrid query like so:
$sql = "SELECT id, first, last, email, userid FROM users WHERE $criteria = :value";
I'm going to hope that the $criteria column isn't entirely free form from the client anyway. If it is, you'd be best limiting it to a specific set of allowed options. A simplistic way to do would be to build an array of allowed columns, and check if it's valid with in_array, like so:
$allowed_columns = array('email', 'telephone', 'somethingelse');
if (!in_array($criteria, $allowed_columns))
{
$error = "The column name passed was not allowed.";
$errorDetails = $ex->getMessage();
include 'error.html.php';
exit;
}

Query returns null

Hello I've got this query to get users by email, which is an unique field in the db.
However, when i want to get the data on it, it simply returns null.
Here's the code
public function getUserByEmail($email)
{
$statement = "SELECT id_user,nome,email,permissao,activo FROM sys_users
WHERE email=$email";
try
{
$sth = $this->db->query($statement);
$sth->setFetchMode(PDO::FETCH_OBJ);
$rcs_users = $sth->fetchAll();
return $rcs_users;
}
catch(PDOException $e)
{
"DB Error".$e->getMessage();
}
}
And the respective function call
$user_rcs = $user->getUserByEmail($email);
var_dump($user_rcs); //returns null
$_SESSION['email'] = $email;
$_SESSION['user'] = $user_rcs->nome;
$_SESSION['permissao'] = $user_rcs->permissao;
And then I get this error
Notice: Trying to get property of non-object in C:\xampp\htdocs\inacesso\admin\modules\auth\authhandler.php on line 24
Glad if you could help me!
Strings in SQL have to be quoted, so unless $email arrives in the function with ' and ' around it, the SQL will error.
But you shouldn't be building SQL by mashing together PHP strings anyway. Use PDO or mysqli_* with bound parameters (and prepared statements) and that will take care of quoting (and escaping) for you.
First off, seriously have a look at PDO.
Secondly I would imagine the email column is a string. As such, you'll need to surround $email with quotes in your query (after having sanitized it vigorously of course...)
WHERE email='$email'
PDO version:
$pdo = new PDO(...);
$query = $pdo->prepare('SELECT id_user,nome,email,permissao,activo '.
'FROM sys_users '.
'WHERE email = ?');
$result = $query->execute(array($email));

Categories