I'm writing a simple password-recovery function for the website I'm developing and I was wondering about the expire time.
Getting to the point, I want to add an expire time of around 48h for the reset password link I'm gonna send. Do I have to create a new column to store the current time and check it out some time later to see if its still valid, or is there a simpler way?
That's my code so far:
public function forgotPass($email) {
$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) {
$stt = $conn->prepare("INSERT INTO Users(recovery) VALUES(?)");
$recovery = $this->randHash(8);
if (!$recovery)
return false;
$stt-> bind_param("s",$recovery);
$stt-> execute();
}
}
and here's my randHash code:
private static function randHash($lenght) {
if (!filter_var($lenght, FILTER_VALIDATE_INT)) {
return false;
}
$allowed = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
$max = strlen($allowed) - 1;
for ($i=1;$i<=$lenght;$i++) {
$hash .= $allowed[mt_rand(0, $max)];
}
return $hash;
}
Just save the expiration time with the reset token in the database, and when the time has expired just don't accept the reset token anymore. This is by far the easiest and safest method.
Another way would be creating a reset hash, appending the time, and encrypting that with a secret key. Decrypt and check the timestamp when you check the hash. If the key leaked, however, this method becomes as weak as just putting it in plain text in the URL.
Storing the current date in database is one way to go. Then you can easily check if its less then 48 hours off. Another way to go is to include the time in the email.
public function forgotPass($email) {
$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) {
$hash1 = md5(microtime().$email.'xx'); //create a unique number for email
$ctime = time();
$hash2 = md5($hash1.$ctime); //create a unique hash based on hash1 and time
$stt = $conn->prepare("INSERT INTO Users(recovery) VALUES(?)");
$recovery = $hash2;
if (!$recovery)
return false;
$stt-> bind_param("s",$recovery);
$stt-> execute();
//send email with link
// http://www.example.com/resetpass.php?hash=$hash1&time=$ctime
}
}
//and then in resetpass.php
//NEEDS CHECKS FOR VALID QUERYVALUES
if (time()-$_GET['time'] <= 48 * 60 * 60) {
$checkhash = md5($_GET['hash'].$_GET['time']);
//check database for hash
}
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;
}
Related
When signing into to the app with username, the email is not used hence the following error is throw and vice versa "Notice: Undefined index: email in /Applications/XAMPP/xamppfiles/htdocs/menthor/login.php on line 16"
I've tried putting the lines that were generating the error in conditions but those efforts proved futile
Login.php file(parts relevant to the error)
// STEP 1. Receive data / info paassed to current file
if ((empty($_REQUEST['username']) || empty($_REQUEST['password'])) && (empty($_REQUEST['email']) || empty($_REQUEST['password']))) {
$return['status'] = '400';
$return['message'] = 'Missing requird information';
echo json_encode($return);
return;
}
// securing received info / data from hackers or injections
$email = htmlentities($_REQUEST['email']);
$username = htmlentities($_REQUEST['username']);
$password = htmlentities($_REQUEST['password']);
// STEP 2. Establish connection with the server
require('secure/access.php');
$access = new access('localhost' , 'root', '' , 'menthor');
$access->connect();
// STEP 3. Check existence of the user. Try to fetch the user with the same email address
// STEP 3. Check availability of the login/user information
$username_aval = $access->selectUser_Username($username);
$email_aval = $access->selectUser_Email($email);
//$return = array();
// user is found
if ($username_aval) {
// Get encrypted password and salt from the server for validation
$encryptedPassword = $username_aval['password'];
$salt = $username_aval['salt'];
if ($encryptedPassword == sha1($password . $salt)) {
$return['status'] = '200';
$return['message'] = 'Successfully Logged In';
$return['id'] = $username_aval['id'];
$return['username'] = $username_aval['username'];
$return['email'] = $username_aval['email'];
$return['fullName'] = $username_aval['fullName'];
$return['lastName'] = $username_aval['lastName'];
$return['birthday'] = $username_aval['birthday'];
$return['gender'] = $username_aval['gender'];
$return['cover'] = $username_aval['cover'];
$return['ava'] = $username_aval['ava'];
$return['bio'] = $username_aval['bio'];
$return['allow_follow'] = $username_aval['allow_follow'];
} else {
// In event that encrypted password and salt does not match
$return['status'] = '201';
$return['message'] = 'Password do not match';
}
} else if ($email_aval) {
// Get encrypted password and salt from the server for validation
$encryptedPassword = $email_aval['password'];
$salt = $email_aval['salt'];
if ($encryptedPassword == sha1($password . $salt)) {
$return['status'] = '200';
$return['message'] = 'Successfully Logged In';
$return['id'] = $email_aval['id'];
$return['username'] = $email_aval['username'];
$return['email'] = $email_aval['email'];
$return['fullName'] = $email_aval['fullName'];
$return['lastName'] = $email_aval['lastName'];
$return['birthday'] = $email_aval['birthday'];
$return['gender'] = $email_aval['gender'];
$return['cover'] = $email_aval['cover'];
$return['ava'] = $email_aval['ava'];
$return['bio'] = $email_aval['bio'];
$return['allow_follow'] = $email_aval['allow_follow'];
} else {
// In event that encrypted password and salt does not match
$return['status'] = '202';
$return['message'] = 'Password do not match';
}
}else {
// In event that user is not found
$return['status'] = '403';
$return['message'] = 'User was not found';
}
// stop connection with server
$access->disconnect();
// pass info as JSON
echo json_encode($return);
Access.php file(parts relevant to error)
Will try to select any value in the database based on received Email
public function selectUser_Email($email) {
// array to store full user related information with the logic: key=>Value
$returnArray = array();
// SQL Language / Commande to be sent to the server
// SELECT * FROM users WHERE email='rondell#gmail.com'
$sql = "SELECT * FROM users WHERE email='" . $email . "'";
// executing query via already established connection with the server
$result = $this->conn->query($sql);
// result isn't zero and it has least 1 row / value / result
if ($result != null && (mysqli_num_rows($result)) >= 1) {
// converting to JSON
$row = $result->fetch_array(MYSQLI_ASSOC);
// assign fetched row to ReturnArray
if (!empty($row)) {
$returnArray = $row;
}
}
// throw back returnArray
return $returnArray;
}
// Will try to select any value in the database based on received Email
public function selectUser_Username($username) {
// array to store full user related information with the logic: key=>Value
$returnArray = array();
// SQL Language / Commande to be sent to the server
// SELECT * FROM users WHERE username='rondell'
$sql = "SELECT * FROM users WHERE username='" . $username . "'";
// executing query via already established connection with the server
$result = $this->conn->query($sql);
// result isn't zero and it has least 1 row / value / result
if ($result != null && (mysqli_num_rows($result)) >= 1) {
// converting to JSON
$row = $result->fetch_array(MYSQLI_ASSOC);
// assign fetched row to ReturnArray
if (!empty($row)) {
$returnArray = $row;
}
}
// throw back returnArray
return $returnArray;
}
Current results when logging in via web server
Notice: Undefined index: email in /Applications/XAMPP/xamppfiles/htdocs/menthor/login.php on line 16
{"status":"200","message":"Successfully Logged In","id":"44","username":"rondell","email":"rondell#gmail.com","fullName":"rondell","lastName":"","birthday":"","gender":"","cover":"","ava":"","bio":"","allow_follow":"1"}
Expected Results
{"status":"200","message":"Successfully Logged In","id":"44","username":"rondell","email":"rondell#gmail.com","fullName":"rondell","lastName":"","birthday":"","gender":"","cover":"","ava":"","bio":"","allow_follow":"1"}
use email as object or you can dump the request and see what is happening
Turns out the solution was pretty simple came to be after a bit of hard think... I just needed to simply create two login.php files... One dedicated to the users signing in with username and password and the other for users signing in with email and password...Cheers
The error that I occurred:
Fatal error: Call to a member function bind_param() on boolean in C:\wamp64\www\APU\SDP\reg-list-function.php on line 82
I'm writing a php script where the Admins are able to approve the registration of the user. I've checked through the formats of my database, column names, and even query, and still I've no idea why this error pops out. Any help or suggestions will be appreciated!
<?php
// we will only start the session with session_start() IF the session isn"t started yet //
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
?>
<?php
// including the conn.php to establish connection with database //
include "conn.php";
?>
<?php
// Begin of the function: Registration List's Verification Form: Registration //
// First we check the form has submitted or not //
if (isset($_POST['submit-list-reg'])) {
// If it is, then we will retreive data from the input forms //
$regid = $_POST["regid"];
$reg_acccode = mysqli_real_escape_string($con, $_POST['reg-acccode']);
$reg_pw = mysqli_real_escape_string($con, $_POST['reg-pw']);
// Taking the current time //
date_default_timezone_set("Etc/GMT-8");
$now = date("Y-m-d H:i:s");
// Variable to store Error Message //
$error = '';
// Alphanumeric Generator //
function random_strings($length_of_string) {
// String of all alphanumeric character
$str_result = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
// Shufle the $str_result and returns substring
// of specified length
return substr(str_shuffle($str_result), 0, $length_of_string);
}
// Sorting out the query related to the function //
// Verify the user is an admin or not //
$VERFYADMIN = "SELECT * FROM user
WHERE status = 2 AND active = 1 AND account_code = '".md5($reg_acccode)."' AND password = '".md5($reg_pw)."'";
$VERFYADMINQ = mysqli_query($con, $VERFYADMIN);
//***BEGIN OF PROCESS***//
if (mysqli_num_rows($VERFYADMINQ) < 1) {
// if the admin is not verified, then inform the user and send him back to admin panel //
echo "<script>alert('ALERT: Information unable to be verified. Please try again.');";
echo "window.location.href='admin_panel.html';</script>";
exit(0);
} else {
// begin the process of registration //
while (list($key,$val) = #each ($regid)) {
// Now to verify the user's legitimacy //
// Take the user's vercode into variable first //
$USERVERCODE = "SELECT * FROM registration_list
WHERE registration_id = $val AND verified = 0";
$USERVERCODEQ = mysqli_query($con, $USERVERCODE);
if (mysqli_num_rows($USERVERCODEQ) < 1) {
// if we are unable to retrieve the data of the registering user then something must gone wrong //
echo "<script>alert('WARNING: Unable to retrieve the data. Please try again.');";
echo "</script>";
} else {
while ($row = mysqli_fetch_array($USERVERCODEQ)) {
$vercode = $row["verification_code"];
}
// since we got the value of the vercode then we start to define the query //
$VERCODE = "SELECT * FROM verification_code WHERE verification_code = $vercode AND code_active = 1";
$VERCODEQ = mysqli_query($con, $VERCODE);
if (mysqli_num_rows($VERCODEQ) < 1) {
// if we are unable to retrieve the data of the registering user then something must gone wrong //
echo "<script>alert('WARNING: Unable to retrieve the info of VERCODE. Please try again.');";
echo "</script>";
} else {
while ($row = mysqli_fetch_array($VERCODEQ)) {
$status = $row["code_status"];
}
// we will first insert the user main information into the database: i.e. password, username, etc. //
$account_code = random_strings(8);
$APPROVE = "INSERT INTO user (username, password, email, account_id, account_code, active, status, registered_date, verification_code)
SELECT username, password, email, account_id, '".md5($account_code)."', 1, $status, $now, verification_code
FROM registration_list
WHERE registration_id = ?";
$stmt = $con->prepare($APPROVE);
$stmt->bind_param("i", $val); // Problem around here //
$stmt->execute();
if (($stmt->error) == FALSE) {
I expect the process will be no issue at all as I've checked everything and nothing seems wrong to me.
Reformatting your code to make it more legible and easier to understand, we now have:
<?php
// we will only start the session with session_start() IF the session isn"t started yet //
if (session_status() == PHP_SESSION_NONE)
{
session_start();
}
?>
<?php
// including the conn.php to establish connection with database //
include "conn.php";
?>
<?php
// Begin of the function: Registration List's Verification Form: Registration //
// First we check the form has submitted or not //
if (isset($_POST['submit-list-reg']))
{
// If it is, then we will retreive data from the input forms //
$regid = $_POST["regid"];
$reg_acccode = mysqli_real_escape_string($con, $_POST['reg-acccode']);
$reg_pw = mysqli_real_escape_string($con, $_POST['reg-pw']);
// Taking the current time //
date_default_timezone_set("Etc/GMT-8");
$now = date("Y-m-d H:i:s");
// Variable to store Error Message //
$error = '';
// Alphanumeric Generator //
function random_strings($length_of_string)
{
// String of all alphanumeric character
$str_result = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
// Shufle the $str_result and returns substring
// of specified length
return substr(str_shuffle($str_result), 0, $length_of_string);
}
// Sorting out the query related to the function //
// Verify the user is an admin or not //
$VERFYADMIN = "SELECT * FROM user
WHERE status = 2 AND active = 1 AND account_code = '".md5($reg_acccode)."' AND password = '".md5($reg_pw)."'";
$VERFYADMINQ = mysqli_query($con, $VERFYADMIN);
//***BEGIN OF PROCESS***//
if (mysqli_num_rows($VERFYADMINQ) < 1)
{
// if the admin is not verified, then inform the user and send him back to admin panel //
echo "<script>alert('ALERT: Information unable to be verified. Please try again.');";
echo "window.location.href='admin_panel.html';</script>";
exit(0);
}
else
{
// begin the process of registration //
while(list($key,$val) = #each ($regid))
{
// Now to verify the user's legitimacy //
// Take the user's vercode into variable first //
$USERVERCODE = "SELECT * FROM registration_list WHERE registration_id = $val AND verified = 0";
$USERVERCODEQ = mysqli_query($con, $USERVERCODE);
if (mysqli_num_rows($USERVERCODEQ) < 1)
{
// if we are unable to retrieve the data of the registering user then something must gone wrong //
echo "<script>alert('WARNING: Unable to retrieve the data. Please try again.');";
echo "</script>";
}
else
{
while ($row = mysqli_fetch_array($USERVERCODEQ))
{
$vercode = $row["verification_code"];
}
// since we got the value of the vercode then we start to define the query //
$VERCODE = "SELECT * FROM verification_code WHERE verification_code = $vercode AND code_active = 1";
$VERCODEQ = mysqli_query($con, $VERCODE);
if (mysqli_num_rows($VERCODEQ) < 1)
{
// if we are unable to retrieve the data of the registering user then something must gone wrong //
echo "<script>alert('WARNING: Unable to retrieve the info of VERCODE. Please try again.');";
echo "</script>";
}
else
{
while ($row = mysqli_fetch_array($VERCODEQ))
{
$status = $row["code_status"];
}
// we will first insert the user main information into the database: i.e. password, username, etc. //
$account_code = random_strings(8);
$APPROVE = "INSERT INTO user (username, password, email, account_id, account_code, active, status, registered_date, verification_code)
SELECT username, password, email, account_id, '".md5($account_code)."', 1, $status, $now, verification_code
FROM registration_list
WHERE registration_id = ?";
$stmt = $con->prepare($APPROVE);
$stmt->bind_param("i", $val); // Problem around here //
$stmt->execute();
if (($stmt->error) == FALSE)
{
In here are several things that I wouldn't personally do. As has been mentioned, using variables supplied by user input, even MD5 ones, directly in SQL queries should be best avoided.
The line "while(list($key,$val) = #each ($regid))", which sets the $val variable has an ampersand to suppress any error messages, this in turn could be causing you issues further down. It's best not to suppress these messages, but to find out why they are occurring, this could be the cause of a non numeric value being passed to your "bind_param" function. I'd also use single quotes instead of double quotes with the function as well.
Solved after I changed the variables that contained string value with this format -> ' " . $variable . " ' .
A user will request a file by number via a URL like script.php?userid=222. This example would show the record of file #222.
Now I want to limit the number of files per (remote IP) user to a maximum of 5 different records in a minute. However, the user should be able to access the same id record any number of time.
So the user could access file #222 any number of times, but if the (remote IP) user accesses more than 5 other different records in a minute, then it should show an error.
For example, suppose within a minute the following requests are made:
script.php?userid=222
script.php?userid=523
script.php?userid=665
script.php?userid=852
script.php?userid=132
script.php?userid=002
then at the last request it should show the error message.
Here is the basic code:
$id = $_GET['userid'];
if (!isset($_GET['userid']) || empty($_GET['userid'])) {
echo "Please enter the userid";
die();
}
if (file_exists($userid.".txt") &&
(filemtime($userid.".txt") > (time() - 3600 * $ttime ))) {
$ffile = file_get_contents($userid.".txt");} else {
$dcurl = curl_init();
$ffile = fopen($userid.".txt", "w+");
curl_setopt($dcurl, CURLOPT_URL,"http://remoteserver.com/data/$userid");
curl_setopt($dcurl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($dcurl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
curl_setopt($dcurl, CURLOPT_TIMEOUT, 50);
curl_setopt($dcurl, CURLOPT_FILE, $ffile);
$ffile = curl_exec($dcurl);
if(curl_errno($dcurl)) // check for execution errors
{
echo 'Script error: ' . curl_error($dcurl);
exit;
}
curl_close($dcurl);
$ffile = file_get_contents($userid.".txt");
}
Instead of relying on the IP address, you could use the session mechanism. You can create a session scope via session_start(), and then store information that sticks with the same user session.
I would then suggest to keep in this session scope the list of unique IDs used in previous requests that user made, together with the time of the request, ignoring any repeated requests, which are always allowed. As soon as this list contains 5 elements with a time stamp within the last minute and a new ID is requested, you show the error and refuse the lookup.
Here is the code that does this. You should place it right after you have checked the presence of the userid argument, and before the retrieval of the file contents:
// set the variables that define the limits:
$min_time = 60; // seconds
$max_requests = 5;
// Make sure we have a session scope
session_start();
// Create our requests array in session scope if it does not yet exist
if (!isset($_SESSION['requests'])) {
$_SESSION['requests'] = [];
}
// Create a shortcut variable for this array (just for shorter & faster code)
$requests = &$_SESSION['requests'];
$countRecent = 0;
$repeat = false;
foreach($requests as $request) {
// See if the current request was made before
if ($request["userid"] == $id) {
$repeat = true;
}
// Count (only) new requests made in last minute
if ($request["time"] >= time() - $min_time) {
$countRecent++;
}
}
// Only if this is a new request...
if (!$repeat) {
// Check if limit is crossed.
// NB: Refused requests are not added to the log.
if ($countRecent >= $max_requests) {
die("Too many new ID requests in a short time");
}
// Add current request to the log.
$countRecent++;
$requests[] = ["time" => time(), "userid" => $id];
}
// Debugging code, can be removed later:
echo count($requests) . " unique ID requests, of which $countRecent in last minute.<br>";
// if execution gets here, then proceed with file content lookup as you have it.
Deleted session cookies...
Sessions are maintained by cookies on the client. The user may delete such cookies, an so get a new session, which would allow the user to make new requests without regard of what was previously requested.
One way to get around this is to introduce a cool-down period for each new session. For instance, you could have them wait for 10 seconds before a first request can be made. To do that, replace in above code:
if (!isset($_SESSION['requests'])) {
$_SESSION['requests'] = [];
}
By:
$initial_delay = 10; // 10 seconds delay for new sessions
if (!isset($_SESSION['requests'])) {
$_SESSION['requests'] = array_fill(0, $max_requests,
["userid" => 0, "time" => time()-$min_time+$initial_delay]
);
}
This is of course less user friendly as it affects any new session, also of users who are not trying to cheat by deleting cookies.
Registration
The better way is to only allow the lookup services to registered users. For this you must provide a user database and authentication system (for example password based). The requests should be logged in the database, keyed by the user's ID. If then a new session starts, the user must first authenticate again, and once authenticated the request history is retrieved from the database. This way the user cannot cheat around it by changing something on their client configuration (IP address, cookies, employing multiple devices in parallel, ...)
<?php
// session_start();
// session_destroy();
// exit;
echo index();
function index()
{
$id = rand(000,020);
$min_time = 60;
$max_requests = 5;
// $id = 0;
session_start();
$repeat = false;
if(!isset($_SESSION["countRecent"]) && !isset($_SESSION["countRecent"]) && !isset($_SESSION["countRecent"])){
$_SESSION["countRecent"] = 1;
$_SESSION["time"] = time();
$_SESSION['userid'][] = $id;
}else{
if ($_SESSION["countRecent"] >= $max_requests) {
if(!in_array($id,$_SESSION['userid'])){
if ($_SESSION["time"] <= time() - $min_time) {
$_SESSION["countRecent"] = 1;
$_SESSION["time"] = time();
}else{
return("Too many requests in a short time wait ". ( $_SESSION["time"] - (time() - $min_time) )). " Seconds";
}
}
}else{
if(!in_array($id,$_SESSION['userid'])){
$_SESSION["countRecent"] = $_SESSION["countRecent"] + 1;
$_SESSION['userid'][] = $id;
}
}
}
return "Your Result goes here.. id: $id Counts: ". $_SESSION["countRecent"];
}
Try this. Fast , low memory usage
But not secure;
also use database
<?php
$conn = mysqli_connect("localhost", "root", "","db_name") or die("Could not connect database");
$id = rand(0,99);
// $id = 100;
echo index($id);
function index($id,$user=1,$ip='192.168.0.10',$max_requests = 5,$min_time = 20)
{
global $conn;
$time = time();
$req = "INSERT INTO `limit_api_by_ip2`(`id`, `ip`, `time`, `user`, `req`)
VALUES (null,INET_ATON('$ip'),'$time','$user',1)
ON DUPLICATE KEY UPDATE req=req+1;";
$req2 = "INSERT INTO `limit_api_by_ip2`(`id`, `ip`, `time`, `user`, `req`)
VALUES (null,INET_ATON('$ip'),'$time','$user',1)
ON DUPLICATE KEY UPDATE req=1,`time`='".time()."' ;";
$reqid = "INSERT INTO `limit_api_by_ip2_count`(`id`, `user`, `ids`) VALUES (null,'$user',$id)";
$getid = "SELECT `ids` FROM `limit_api_by_ip2_count` WHERE user = $user and ids = $id limit 1;";
$gettime = "SELECT `time`,`req` FROM `limit_api_by_ip2` WHERE user = $user and ip = INET_ATON('$ip') limit 1;";
// $id = 0;
$q = mysqli_query($conn,$getid);
$c = mysqli_num_rows($q);
if($c==0){
$get_time = mysqli_query($conn,$gettime);
$c1 = mysqli_num_rows($get_time);
if($c1==0){
mysqli_query($conn,$req);
mysqli_query($conn,$reqid);
}else{
$row = mysqli_fetch_row($get_time);
if ($row[1] >= $max_requests) {
if ($row[0] <= (time() - $min_time)) {
mysqli_query($conn,$req2);
mysqli_query($conn,$reqid);
}else{
return "Too many requests in a short time wait ".($row[0]-(time() - $min_time))." Seconds";
}
}else{
mysqli_query($conn,$req);
mysqli_query($conn,$reqid);
}
}
}else{
}
if(isset($row[1]))
{
$cc = "Counts: ".$row[1];
$dd = "new id: $id";
}else{
$cc = '';
$dd = "old id: $id";
}
return "Your Result goes here.. $dd ".$cc;
}
i use from below code for login.
$sid = trim($_POST["id"]);
$pcode = trim(md5($_POST["pcode"]));
include_once "../conf.php";
$pdo = connect();
$sql_log = "select * from `manager` where `sid` = $sid limit 1";
$do_log = $pdo->prepare($sql_log);
$do_log->execute();
$num_log = $do_log->rowCount();
if($do_log){
if($num_log == 1){
while($row_log = $do_log->fetch()){
$pcode_db = $row_log["pcode"]; //md5 password
}
if(var_dump($pcode == $pcode_db)){ //or $pcode == $pcode_db, both return false
return true;
}else{
return false; // i get false for any password}
}
}
}
i can not login to right password! i set md5 password in database manually with phpmyadmin
I don't know why this works, but it did. I set md5 password (do md5 with PHP) in my database manually with phpMyAdmin(insert)!
structure column pcode >>varchar(32)
The md5 password has 32 characters, but when it's set from insert in phpMyAdmin, the pcode column only contains 31 characters... So I used SQL in phpMyAdmin for setting the md5 password!
update `manager` set `pcode` = MD5("my password") where `sid` = 7283
and then it is completely set to 32 characters. Could someone explain why this happens?
i set md5 password in database manually with phpmyadmin
MySQL MD5 is not the same algoritham as PHP MD5. You need to use one or the other.
Following code is just like your code but little change sql query.
$sid = trim($_POST["id"]);
$pcode = trim(md5($_POST["pcode"]));
include_once "../conf.php";
$pdo = connect();
$sql_log = "select * from `manager` where `sid` = $sid and `pcode` = $pcode";
$do_log = $pdo->prepare($sql_log);
$do_log->execute();
if($do_log){ // if incoming sid and pcod will match
return true;
}else{
return false;
}
I don't know how to work of your connect() function. Another way to connect sql is like that:
$sid = trim($_POST["id"]);
$pcode = trim(md5($_POST["pcode"]));
include_once "../conf.php";
mysql_connect('server_name','user_name','password');
mysql_select_db('DB_name');
$query = mysql_query("select * from `manager` where `sid` = $sid and `pcode` = $pcode");
if(mysql_fetch_array($query)){
return true;
}else {
return false;
}
I used this hash function for a while (got it from the internet). The thing is it used to work immediately but now it is complaining about a paramter. The following is the code:
function generateHash($plainText, $salt = null)
{
if ($salt === null)
{
$salt = substr(md5(uniqid(rand(), true)), 0, SALT_LENGTH);
}
else
{
$salt = substr($salt, 0, SALT_LENGTH);
}
return $salt . sha1($salt . $plainText);
}
So I would use this code in the method call:
validateUserInput($userid, $pass);
and validateUserInput is:
function validateUserInput($username, $password)
{
//$username = mysql_real_escape_string($username);
//$password = mysql_real_escape_string($password);
if(!$username || !$password)
{
//$errors['credentials'] = 'Missing Credentials!';
//$_SESSION['errors_array'] = $errors;
//echo $errors['credentials'];
header("LOCATION:XXXXXXX.php");
}
$local_salt = generateHash($password);
//echo $local_salt;
$groupid;
if($username != null && $password !=null)
{
connectToServer();
$result = mysql_query("SELECT * FROM users WHERE hashkey = '{$local_salt}'");
while($row_access = mysql_fetch_array($result))
{
$groupid = $row_access['groupid'];
}
if(!isset($result))
{
$errors['not_found_user'] = 'No Users Found with Provided Credentials!';
//$_SESSION['errors_array'] = $errors;
$userfound = 0;
$_SESSION['user_available'] = $userfound;
}elseif(isset($result)){
$_SESSION['user_logged'] = array('username' => $username, 'password' => $password, 'salt' => $local_salt, 'groupid' => $groupid);
$userfound = 1;
//echo "stored";
$_SESSION['user_available'] = $userfound;
}
}
}
finally the error is:
Warning: substr() expects parameter 3 to be long, string given in /home/XXXX.php on line 64
This is pointing to the function generateHash()
The error itself tells you everything. The constant SALT_LENGTH is not a long. I suspect it's not defined at all, so PHP converts the bare string to a string ("SALT_LENGTH") and passes that to substr(), which complains.
That being said... This code is dangerously wrong:
if(!isset($result)): Really? This condition will always be false because $result will always be set (unless you run into a problem with mysql_query(), but that doesn't tell you anything about the valididty of the login). And since mysql_query() never returns null, no logins will ever be rejected.
This query:
SELECT * FROM users WHERE hashkey = '{$local_salt}'
Is invalid. $local_salt = generateHash($password);. From the generateHash function, if a salt is not given, one will be randomly created for you. Thus, every call to generateHash will generate a new hash, which means it can't be compared to anything in the database.
On the basis of the two (very) egregious mistakes above, I would throw away this piece of code for good.
The correct way to check for a valid hash when a salt is used is something like:
$_SESSION['user_logged'] = null;
// fetch hashed pw from db, where username is the submitted username
$result = mysqli_query("SELECT hash FROM users WHERE username = '{$username}'");
if ($result->num_rows != 0)
{
$row = $result->fetch_assoc();
$hash = $row['hash'];
$salt = substr($hash, 0, SALT_LENGTH); // extract salt
if (generateHash($password, $salt) == $hash)
{
// login successful.
$_SESSION['user_logged'] = $username; // don't store passwords here
}
}
// if $_SESSION['user_logged'] is not set, the login failed
if (!isset($_SESSION['user_logged']))
{
// you *don't* want to tell people which one (login or pw) is invalid
echo 'Invalid login or password';
}
Note: It's very important that the SALT_LENGTH is at most 32, or this won't work because of the way generateHash() is implemented.
Clearly SALT_LENGTH is not an integer. Find where it's defined and correct this.
Instead of making a new hashing function each time you write an application , you should utilize the one provided to you by php: crypt() ( i would recommend to go with any blowfish or sha256+ hash ).
And when selecting information from database, you should select it by username and then, with php, check if hash fits the password.