I am trying to make simple form where you put user_id etc. etc. and it will change in mysql, which works pretty fine but the question is, is there any way I could instead of users_ids use usernames ? thanks
if(isset($_POST['btn-change'])) {
$account = strip_tags($_POST['account']);
$value = strip_tags($_POST['value']);
$string = strip_tags($_POST['string']);
$account = $DBcon->real_escape_string($account);
$value = $DBcon->real_escape_string($value);
$string = $DBcon->real_escape_string($string);
$sql = "UPDATE tbl_users SET $value='$string' WHERE user_id=$account";
if ($DBcon->query($sql) === TRUE) {
$msg1 = '<div class="alert alert-success">
<i class="fa fa-info" aria-hidden="true"></i> Successfully changed !
</div>';
} else {
$msg1 = '<div class="alert alert-danger">
<i class="fa fa-info" aria-hidden="true"></i></span> Something went wrong !
</div>';
}
$DBcon->close();
}
The original MySQL extension has been removed in PHP7 and was deprecated in PHP 5.5.
Don't be intimidated by PDO though, it's actually super simple and much better.
Require this code at the start of any PHP files that need to make database queries.
$host = "127.0.0.1";
$port = "3306";
$dbname = "NameOfTheDatabase";
$dsn = "mysql:host=$host;dbname=$dbname;port=$port;";
$dbuser = "UsernameForDatabase";
$dbpass = "PasswordForDatabase";
$options = array(PDO::MYSQL_ATTR_INIT_COMMAND => "set names utf8");
$database = new PDO($dsn, $dbuser, $dbpass, $options);
Note that it can be improved upon drastically but for the sake of example, we'll keep things simple. Usually you would want to load this information from a protected config file.
Now let's say we want to select the user by their username.
$statement = $database->prepare("
SELECT user_id
FROM tbl_users
WHERE username LIKE :username
");
$statement->bindParam("username", $_POST['username'], PDO::PARAM_STR);
$statement->execute();
$result = $statement->fetch(PDO::FETCH_OBJ);
echo $result->user_id;
Basically what we're doing here is telling PDO to store a query that we've prepared in the $statement variable. We then tell it to use bindParam() to replace or bind :username with the POST variable (this will take care of escaping).
After the statement is executed using execute(), we have two options. The fetch() function essentially takes the next (or in this case, first) returned row and stores it in the $result variable. After that, you can access the returned columns using their names, in this case, $result->user_id. However if you SELECTed the rank, for example, you would be able to access it with $result->rank.
The second option is the fetchAll() function which works in nearly the same way, except that it takes every row returned and stores it in an array. Even if only one row is returned. That means that you'd need to access the data using $result[0]->user_id where 0 is the returned row.
foreach($result as $row){
echo $row->user_id;
}
Or you can loop over the result array using foreach as above. One of the greatest features of PHP in my opinion.
Updating and inserting works in nearly the same way except that no rows are returned by the execute function. Instead, the amount of rows that were changed is returned.
$statement = $database->prepare("
UPDATE tbl_users
SET email = :email
WHERE user_id = :user_id
");
$statement->bindParam("email", $_POST['email'], PDO::PARAM_STR);
$statement->bindParam("user_id", $_POST['account'], PDO::PARAM_INT);
$statement->execute();
echo "Rows changed: ".$statement->rowCount();
In that example, we're just updating the user's email address using a POST variable for the email and the account variable for the user_id. Notice that I used PDO::PARAM_INT for the third parameter of bindParam, that's just because the user_id is an integer. Usually you can get away with PDO::PARAM_STR but it's supposed to be for strings.
If you want a bit more detail by somebody far better at explaining things than me, check this introduction to PDO out. Hope this gets you on the right track!
Related
I am fairly new to PHP and have been following the Lynda.com tutorials (although they still use mysql in stead of mysqli or PDO).
I'm having problems with using the data I get from my queries.
I'll use my login page as example, leaving out the connect to db part:
$login_username = trim(htmlspecialchars($_POST['username']));
$password = trim(htmlspecialchars($_POST['password'])); // from login form
$stmt = $db->prepare("SELECT * FROM users
WHERE username = :login_username");
$stmt->bindParam(':login_username', $login_username);
$stmt->execute();
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if($stmt->rowCount() > 0 && $result = password_verify($password,$result['hashed_password'])) {
$_SESSION['logged_in_id'] = $result['id'];
$_SESSION['logged_in_username'] = $login_username; //this was the only way I could pass the username as I could not get it from $result['username']
$_SESSION['first_name'] = $result['first_name'];
$_SESSION['last_name'] = $result['last_name'];
Nothing gets passed to the session and there are no errors. I also can't echo out the value of $result. If I just try to echo $result, then I just get the value 1
Please help!
Your problem is:
... && $result = password_verify($password,$result['hashed_password'])
Note that $result is an array that contains the row that you just fetched and you are assigning it a new value here; you are overwriting your $result variable so all assignments afterwards will fail.
You probably want something like:
... && password_verify($password,$result['hashed_password'])
Also note that you should not rely on the rowCount() as that is not necessarily what you expect for a SELECT statement.
As you are fetching a row already, you can simply do:
if ($result && password_verify($password,$result['hashed_password']))
If there is no result, the second condition will never be checked so it will not lead to warnings or errors.
I've been trying to write a function to draw a usernames name from the database fetch he result then return it back to the parent page but nothing I have tried works and I don't even know where to go from here. my old code that I used mysql on works perfect and was easy to put together but this mysqli and all its double parameters and stuff I cant figure it out. so basically I am asking for anyone who knows how to set one of these up.
(SELECT name FROM users WHERE username = '" .$_SESSION['username']. "')
I want to mysqli_real_escape the value if possible so if anyone knows how to set up a function to return a value back to its parent page I would much appreciate it.
It's very similar to using mysql_* functions:
function get_user_name()
{
global $conn;
$sql = "SELECT name FROM users WHERE username = ?";
if ($stmt = $conn->prepare($sql)) {
$stmt->bind_param("s", $_SESSION['username']);
$stmt->execute();
$result = $stmt->get_result();
$data = mysqli_fetch_assoc($result);
return $data['name'];
}
}
I have a pretty stupid question, but I can't get it to work immediately.
How do I load only one field of the result array of a query into a session (array) using a single PDO statement?
I commented the missing code below:
public function getPermissions($user_role_id){
if(!isset($user_role_id) || empty($user_role_id)){
$_SESSION['user']['user_permissions'] = '';
}else{
$db = Database::get_database();
$query = "
SELECT
rp.role_id, rp.permission_id
FROM
role_permission_tbl rp
WHERE
rp.role_id = :role_id";
$query_params = array(
':role_id' => $user_role_id
);
try
{
$stmt = $db->prepare($query);
$result = $stmt->execute($query_params);
}
catch(PDOException $ex)
{
die("Failed to run query: " . $ex->getMessage());
}
$row = $stmt->fetchAll();
if($row){
//I only want to retrieve the field "permission_id"
$_SESSION['user']['user_permissions'] = $row;
}else{
$_SESSION['user']['user_permissions'] = '';
}
}
}
Thanks
After seeing your later comments, it looks as though you're wanting to save all permission data in a session variable so that you can look it up by permission ID:
$rows = $stmt->fetchAll();
foreach($rows as $row){
//Add to session, keyed by permission ID.
$_SESSION['user']['user_permissions'][$row['permission_id']] = $row;
}
//Then, if you want to see if said permission ID #21 exists:
if(isset($_SESSION['user']['user_permissions'][21])){
echo 'This user has permissions with ID 21!';
$permissionDetails = $_SESSION['user']['user_permissions'][21];
var_dump($permissionDetails);
}
Like any other "get it to work immediately" this question has contradicting conditions.
Like any other PHP code, it is ten times long than needed.
Like many other SO questions, it can be solved by quick manual lookup.
In case you need your permissions in array
public function getPermissions($user_role_id){
$sql = "SELECT permission_id FROM role_permission_tbl WHERE role_id = ?";
$stm = Database::get_database()->prepare($sql);
return $stm->execute(array($user_role_id))->fetchAll(PDO::FETCH_COLUMN);
}
note that assigning variables inside functions is a very bad practice. So, better call it this way
$_SESSION['user']['user_permissions'] = $user->getPermissions($user_role_id);
isset() is useless in conjunction with empty() as latter covers the former.
both isset() and empty() are useless for the function variable too, as it is always set by design
a verification for this particular input variable can be done, but for the sanely designed application it would be unnecessary.
setting a variable you are going to test with in_array() to an empty string will produce an error.
there is no use for the alias with single table.
PDO methods can be called dramatically shorter way, there is no use for stretching one simple query call to a whole screen of code.
echoing a system error message to a site user is an awful practice.
the very manual page for the fetchAll() contains an exact example for this very question of getting single column out of the query result.
there is no use for testing returned value explicitly, as it already contains either result or empty value (and luckily, fetchAll() will return even empty value of desired type).
Can you try $row = $stmt-> fetch(); instead of $row = $stmt->fetchAll(); if it is fetch only one record from table,
$row["permission_id"];
I have a little login script.
function login($sql) {
try {
$fbhost = "localhost";
$fbname = "foodbank";
$fbusername = "root";
$fbpassword = "";
$DBH = new PDO("mysql:host=$fbhost;dbname=$fbname",$fbusername,$fbpassword);
$DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$STH = $DBH->query($sql);
$STH->setFetchMode(PDO::FETCH_ASSOC);
session_start();
if ($row = $STH->fetch()) {
$_SESSION['username'] = "$row[username]";
header("Location:index.php");
}
} catch(PDOException $e) {
echo $e->getMessage();
}
}
EDITS:
index.php
$sql = "SELECT username from users where username = ". $_POST['username'] ." AND password = ". $_POST['password'] ."";
login($sql);
Changed above from insert to select query. Now I get new error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'pvtpyro' in 'where clause'
Based on your latest edit: You can't fetch results with PDO after executing an INSERT query. See here: http://www.php.net/manual/en/pdostatement.fetch.php#105682
Edit: I suppose, since the function's called "login", you want to have something like this as $sql: "SELECT password FROM users WHERE username = :username", and then iterate over the results with the while loop, and then log in the user if the password matches?
Edit2: Based on your edit to provide a SELECT query: DO NOT USE THIS QUERY. What you are doing is NOT SQL injection proof. Never ever use variables from user input (i.e. $_POST, $_GET et al) and put them unfiltered into an SQL query. Please look up the term "prepared statements" here at SO or Google.
As you can see, since you forgot to put single ticks (apostrophes) before and after the double quotes, MySQL thinks that your input refers to another column ("pvtpyro") instead of comparing the value in the column against a string. ALWAYS use the ":username", ":password" syntax (the one with prepended colons) or your queries will be unsafe and enormously dangerous to your application.
The constructor of PDO uses 2 variables which are not defined in the code you supplied - $fbhost and $fbname.
EDIT:
You're calling session_start() inside the while loop, which can cause errors. Take it out of the loop.
EDIT 2:
You should really debug the code. Either via putting die in different parts of the code, outputting some helpful information just before (which is the less preferred way) OR by using xdebug and an IDE, which will allow you to run line by line, and see the exact state of each variable and such.
If I undestand correctly, $data $STH->execute($data); should be an array, even if value is one. So, you may try replacing that query with $STH->execute(array($data));
edited:
Change your lines to this:
$data = array($_POST["username"], $_POST["password"]);
$sql = "INSERT INTO users (username, password) value (?, ?)";
$STH = $DBH->prepare($sql);
$STH->execute($data);
Seems to me that you're not connected to your database properly... I had this error earlier today and it was for that reason. Either that or you have an incorrect string
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;
}