EDIT: I received an email this morning regarding this answer and asking whether or not the hashing-part of my answer is just for making a really unique ID. The following is my response:
I went through and re-read the question on Stack Overflow. The code is not just for making a really unique ID (although it is important that there be no collisions). It is also to make it very hard for someone else to write their own password recovery link to gain access to a user account.
By creating a hash with a username and email (and without hashing the entire code), we would be able to include an additional validation on the user's identity. That is, merely having the link wouldn't be enough; a valid username and email address combination would also be needed to reset a password.
Strings are prepended to username, current time and email in a basic attempt to defeat rainbow tables. In retrospect, it would be better to replace the " " salts with base64_encode($row['username']) and base64_encode($email) respectively.
I would suggest creating two columns: recovery and recovery_expiry. Recovery_expiry holds when the link expires, and recovery holds the hash that must be compared. It consists of the username, a salt appended by the current time, and the current email address of the user.
function forgotPass($email)
{
$currTime = time();
$expiryTime = 60 * 60 * 24 * 2; // Two days
$bd = new Bd();
$conn = $bd->connect();
$stt = $conn->prepare("SELECT * FROM Users where email=?");
$stt->bind_param("s", $email);
$stt->execute();
$result = $stt->get_result();
if (mysqli_num_rows($result) == 1)
{
$row = mysqli_fetch_array();
$stt = $conn->prepare("INSERT INTO Users(recovery, recovery_expiry)"
. " VALUES(?,?)");
$hash = hash("sha256", " " . $row['username'])
. hash("sha256", "vivid" . $currTime)
. hash("sha256", " " . $email);
$stt->bind_param("s", $hash);
$stt->bind_param("i", $currTime + $expiryTime);
$stt->execute();
}
else
{
// Return that the given email address did not match any records
}
// Here would be the logic to send the forgotten password link to the user
}
function checkHash($hash)
{
$row = null;
$currTime = time();
$bd = new Bd();
$conn = $bd->connect();
$stt = $conn->prepare("SELECT * FROM Users WHERE recovery=? AND recovery_expiry < $currTime");
$stt->bind_param("s", $hash);
$stt->execute();
$result = $stt->get_result();
if (mysqli_num_rows($result) == 1)
{
$row = mysqli_fetch_array();
}
return $row;
}