I'm trying to recall data from database to post later on
When someone logs in using this code:
function login($email, $password, $mysqli)
{
// Using prepared statements means that SQL injection is not possible.
if ($stmt = $mysqli->prepare("SELECT id, username, password, salt, phnumber, realname, age, sex FROM members WHERE email = ? LIMIT 1")) {
$stmt->bind_param('s', $email); // Bind "$email" to parameter.
$stmt->execute(); // Execute the prepared query.
$stmt->store_result();
// get variables from result.
$stmt->bind_result($user_id, $username, $db_password, $salt, $phnumber, $realname, $age, $sex);
$stmt->fetch();
}
}
Then I set variables for email and name using this code:
$realname = preg_replace("/[^a-zA-Z0-9_\-]+/", "", $realname);
$_SESSION['realname'] = $realname;
$email = preg_replace("/\b[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}\b/", "", $email);
$_SESSION['email'] = $email;
Then when I recall all the variables using print_r($_SESSION); The email is posted without # or . for example: johnsmithyahoocom and also the name is posted without space like JohnSmith Which is undesirable. How can I make it post the right email form and space between names?
Why are you using preg_replace?
And I would recommend, if you are already using a database, to store only the users ID in the SESSION and fetch the other data from the database, when you need the users Information.
Sorry for wasting your time on this
Everything was going fine I just had to relogin to apply changes I made
/\b[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}\b/ is working fine and recalls the right email form from database I just had to restart the SESSION to see changed I made.
Related
I'm setting up a password change script for php. All variables are in the function updatePasswordInDatabase($password, $email) { ..}.
I've triple checked that the values that the function receives are correct.
For the insertion in the database (mysql) i'm using mysqli with prepared statements.
For example, I'm inputting:
$2y$12$X/jIjlqpWfSSMg70u0RE8O0VWH3ocqychlUPy7CSG2vMhkj/F5d.q
(as $password) along with:
test#test.com ($email).
I get those values in the function correctly.
However after the update, i'm getting a different value in the password column:
i1VjH4sRf5nqv3tnShnXNTSX57jRGnbZJt7w0VLX49nZdKRsRT
What am I doing wrong?
Thanks
function updatePasswordInDatabase($password, $email) {
require $mysql;
$stmt = $conn->prepare('UPDATE `users` SET Password = ? WHERE Email = ?');
$stmt->bind_param("ss", $password, $email);
$stmt->execute();
}
I have been on this all day and after searching many websites (including this one) i came to the conclusion that my question hasn't been asked before probably due to my incompetence.
I have a prepared statement here that i would like to update my password field in my DB depending on the username and email, the reason it is updating and not inserting is because its part of my security to not approve site photographers until they have been sent a link
<?php
if (isset($_POST['approved-photographer'])) {
require 'dbh.php';
$username = $_POST['username'];
$email = $_POST['mail'];
$password = $_POST['password'];
$password2 = $_POST['password-repeat'];
if (empty($username) || empty($email) || empty($password) ||
empty($password2))
{
header("location:signup.php?error=emptyfields&username=" . $username
. "&mail=.$email");
exit();
} elseif ($password !== $password2) {
header("location:approvedphoto.php?error=passwordcheck&username=" .
$username . "&mail=" . $email);
exit();
} else {
$sql = "SELECT Password
FROM photographers
WHERE Username= '$username'
AND Email= '$email'";
$stmt = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt, $sql)) {
header("location:approvedphoto.php?error=sqlerror");
exit();
} else {
$sql = "INSERT INTO photographers (Password) VALUES (?)";
$stmt = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt, $sql)) {
header("location:approvedphoto.php?error=sqlerror2");
exit();
} else {
$hashedpwd = password_hash($password, PASSWORD_DEFAULT);
mysqli_stmt_bind_param($stmt, "s", $hashedpwd);
mysqli_stmt_execute($stmt);
header("location:signin.php?signup=success");
exit();
}
}
}
}
Any Help would be greatly appreciated. Thanks for reading
The short answer for your MySQLi usage is you didn't bind the parameters, which you can do using mysqli_stmt_bind_param (Future readers, this last statement is now irrelevant due to edits). Overall your sql statements post-editing seem unclear, you would typically either be updating a password (in which case you need a WHERE clause so you don't update everyone's password), or you should be inserting a new user with a password.
This is a more-or-less tangential answer, but I would like to throw my hat into the ring for the use of PDO (instead of mysqli). MySQLi works with only one form of database flavor, MySQL. Additionally it allows for a much less object-oriented solution to db interactions. Here's an example of how you could accomplish this through PDO:
//specifies the driver, ip/database etc. Swap out for your ip and database used
$driverStr = 'mysql:host=<ip>;dbname=<database>;charset=utf8';
//you can set some default behaviors here for your use, I put some examples
//I left a link below so you can see the different options
$options = [
//spew exceptions on errors, helpful to you if you have php errors enabled
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
//substite what you need for username/password here as well, $options can be omitted
$conn = new PDO($driverStr, '<username>', '<password>', $options);
Link to the aforementioned attributes
Now that we've made our connection:
//I used a "named parameter", e.g. :password, instead of an anonymous parameter
$stmt = $conn->prepare("UPDATE Photographers SET password = :password WHERE Username = :username");
//with our prepared statement, there's a few ways of executing it
//1) Using #bind*
//there's also #bindValue for not binding a variable reference
//for params, PARAM_STR is default and can be safely omitted
$stmt->bindParam(':password', $password, PDO::PARAM_STR);
$stmt->bindParam(':username', $username);
$stmt->execute();
//2) Using execute directly
$stmt->execute(['password' => $password, 'username' => $username]);
Then, were the statement a query and not just a database update/insert, we can simply retrieve the results of the statement. By using #bindParam you can also just update the variable's values and re-execute the statement if you like, which may be useful to you for some other statements.
//see #fetch and #fetchAll's documentation for the returned data formatting
$results = $stmt->fetchAll(PDO::FETCH_OBJ); //return it as a php object
$results = $stmt->fetch(PDO::FETCH_NUM)[0]; //unsafely retrieve the first value as a number
Over the years I've found this to be much cleaner and more managable than any of the mysqli_* or even the deprecated mysql_* methods.
I've done a login and registration for my site and it works fine.
Now I just want to make a simple profile page where the user can see all their details.
I'm only able to get back the username, so I'm unsure how to get the rest of their details.
Here is the code for registering and logging in:
function selectUser($conn, $username, $password)
{
$query = "SELECT password FROM login WHERE username = :username";
$stmt = $conn->prepare($query);
$stmt->bindValue(':username', $username);
$stmt->execute();
if ($row = $stmt->fetch(PDO::FETCH_OBJ))
{
if (md5($password) == $row->password)
{
$_SESSION['username'] = $username;
//$_SESSION['password'] = $password; DO NOT DO THIS
echo "Welcome, you are now logged in as " . $username;
return true;
}
return false;
} else {
//echo "Your details were not found";
return false;
}
}
function selectNew($conn, $name, $username, $password, $contact, $occupation, $role, $picture)
{
$query = "INSERT INTO login VALUES (NULL, :name, :username, :password, :contactNumber, :occupation, :role, :pic)";
$stmt = $conn->prepare($query);
$stmt->bindValue(':name', $name);
$stmt->bindValue(':username', $username);
$stmt->bindValue(':password', $password);
$stmt->bindValue(':contactNumber', $contact);
$stmt->bindValue(':occupation', $occupation);
$stmt->bindValue(':role', $role);
$stmt->bindValue(':pic', $picture);
$affected_rows = $stmt->execute();
if ($affected_rows == 1)
{
return true;
} else {
return false;
}
}
Don't worry, the password has been hashed.
heres what I've tried:
function selectUser($conn, $username, $password)
{
$query = "SELECT * FROM login WHERE username = :username";
$stmt = $conn->prepare($query);
$stmt->bindValue(':username', $username);
$stmt->execute();
$row = $stmt->fetch();
echo $row['occupation'];
echo $row['role'];
}
2nd attempt:
if(isset($_SESSION["username"]))
{
echo "Welcome, you are now logged in as <b>".$_SESSION['username']."</b> <img class='clientView' src='images/loginIcon.png' alt='client'>"; }
else {
echo "You are currently not logged in";
}
$user = $_SESSION["username"];
$query = "SELECT * FROM login WHERE username = :username";
$term = $conn->prepare($query);
$term->bindValue(':username', $user);
$term->execute();
if ($username = $term->fetch(PDO::FETCH_OBJ))
{
echo "<li><h3>" . $user->username ." ". $user->user_ID . "</h3></li>";
}
The simple answer is to replace your query in selectUser(...) with SELECT * FROM login WHERE username = :username. Note the * after the SELECT command, which functions as a wild card and thus asks for every single column of each row it finds (instead of just the password column as you are currently asking for.
You could then, as you iterate over the returned rows, access other columns of the user via your $row variable. Just like you access the user's hashed password with $row->password, you could access $row->contactNumber.
A note about good practice:
Depending on the case, I would not recommend doing a wildcard (*) SELECT command at login. In fact, I would recommend simply hashing the password prior to the query and attempting to then qualify your query with WHERE username = :username AND password = :password (obviously, bind the hashed password to :password). Instead of asking for the password column, or wildcard columns, you could SELECT the row's unique ID.
This way, you don't even need to iterate over the returned rows at all...you only have to make sure any row returned (see num_rows) to see if the user can be successfully "logged in". You can then cache the returned row's unique ID into your session, and then do subsequent queries as necessary for other pieces of information...such as the user's role or contact number. This effectively brings the complexity of all of your query processing down from linear time to constant time...a minor, but still non-trivial, improvement for an application.
Also, as a word of warning, this login system is very simple and easily spoofed. PHP sessions provide some security, but they are not full-proof. A sniffer snagging the session cookie will allow them to log in as the user whom they sniffed it from. I would recommend looking into adding in your own session layer as well once you have the rest of your login system implemented. And absolutely use SSL.
A note about optimization:
Using a wildcard (*) in a SELECT command is actually a prime place for a speed bottleneck to occur. If you know exactly what columns you want from the database, it is best to ask for them explicitly. For example, instead of *, you could do password,occupation,role.
$_SESSION['username'] = $username;
You have user name in session right.
Just pass this value in where condition of mysql .and get the entire record from login table .just show where ever you want to show.
You can change your SELECT statement to return the other values you want to store in your $_SESSION variables and then access them each with $row->{variable}
Just make sure you populate the $_SESSION after you do your password check
Not dissimilar to your existing code - use the session variable you set when the user logs in
$username=!empty( $_SESSION['username'] ) ? $_SESSION['username'] : false;
$sql='select * from `login` where `username`=:username;';
$stmt=$conn->prepare( $sql );
if( $stmt && $username ){
$stmt->bindValue(':username',$username);
$result=$stmt->execute();
if( $result ){
$rs=$stmt->fetchAll( PDO::FETCH_OBJ );
/* display results from $rs */
/*
There should most likely only be one record!!
*/
$row=$rs[0];
foreach( $row as $column => $value )echo $column.' '.$value;
}
}
For some reason, my code isn't registering the user when they click register. I was first using regular mysqli, and when I changed the code to a prepared statement, it didn't work. If the registration was successful, it's supposed to show a message, and it is showing the message even though the values haven't been inserted into the database.
Here is my code:
<?php
session_start();
// variable declaration
$username = "";
$email = "";
$errors = array();
$_SESSION['success'] = "";
// connect to database
$db = mysqli_connect('localhost', 'root', 'password', 'cubetastic');
// REGISTER USER
if (isset($_POST['reg_user'])) {
// receive all input values from the form
$username = $_POST['username'];
$email = $_POST['email'];
$password_1 = $_POST['password_1'];
$password_2 = $_POST['password_2'];
// form validation: ensure that the form is correctly filled
// I don't think this part is relevant here
// register user if there are no errors in the form
if (count($errors) == 0) {
$_SESSION['verify'] = "Your account has been created, please verify it by clicking the activation link that has been sent to your email.";
$hash = md5(rand(0,1000)); // Generate random 32 character hash and assign it to a local variable.
// Example output: f4552671f8909587cf485ea990207f3b
$password = md5($password_1);//encrypt the password before saving in the database
$query = "INSERT INTO users (username, email, password, hash)
VALUES(?, ?, ?, ?)";
$stmt = mysqli_prepare($db, $query);
mysqli_stmt_bind_param($stmt, 's, s, s, s', $username, $email, $password, $hash);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
}
}
?>
The manual on mysqli_stmt_bind_param() clearly shows no commas are used in order to state which data types to pass as the arguments and in conjunction with that, the number of binds.
I have to state that MD5 is no longer considered to be a safe hashing method, especially in a live environment.
Use both password_hash() and password_verify() respectively and make sure that the (password) column is long enough to accomodate its length.
The manual suggests to use a minimum of 60 length, yet states that a length of 255 is a good bet.
References:
http://php.net/manual/en/function.password-hash.php
http://php.net/manual/en/function.password-verify.php
As I (also) stated in comments: Use mysqli_error($db) on the query. That would have thrown you something about this syntax error. Always use this during development testing and always read the official manuals; that's what they're there for.
When I bind data in my php file to my database. I check by database and the values are all NULL? What is wrong?
Also: How can I pass a hashed password to be stored in my database? I know how to password_hash and password_verify. I can't figure out how to store a hashed password.
/*the variables are declared in a html form in another file. The action attribute
calls this php file with this code here. I use POST to get the user input for
each of the variables first, last, password, and initials*/
//create database connection
$dbc = mysqli_connect ('domain', 'root', 'password', 'database')
or die ('Error connecting');
//my condition to check for value when user enters data from html form. I use POST and isset.
if (isset($_POST['first']) && isset($_POST['last']) && isset($_POST['password']) &&
isset ($_POST['initials'])) {
//This is where I bind the data to prevent sql injection attacks.
$thisdb= mysqli_prepare($dbc, "INSERT INTO database VALUES (?, ?, ?, ?)");
mysqli_stmt_bind_param($stmt, 'sssd', $first, $last, $password, $initials);
mysqli_stmt_execute($thisdb);
mysqli_stmt_close($thisdb);
}
else
{ echo('user missing data'); exit();}
// close database
mysqli_close ($dbc);
Use:
mysqli_stmt_bind_param($stmt, 'sssd', $_POST['first'], $_POST['last'], $_POST['password'], $_POST['initials']);
You were binding to variables that you never assigned.
Apart from the undefined variables that are already mentioned, you might run into problems as you are declaring your initials as a double:
mysqli_stmt_bind_param($stmt, 'sssd', $first, $last, $password, $initials);
^ are you sure initials is supposed to be a double?
You probably want:
mysqli_stmt_bind_param($stmt, 'ssss', $_POST['first'], $_POST['last'], $_POST['password'], $_POST['initials']);
You should add error handling to your database to see where what problem occurs exactly.
Note: Storing passwords in plain text is a very bad idea, you need to salt and hash them.