I am just learning mysqli prepared statements and now i have run into a problem and could not get a way out of it. It is the registration form and takes in "username" "email" and "password". if username and email already exists in the database then it doesnot allow registeration. i've used post method and the code is as,
//validating email
if(!filter_var($user_email, FILTER_VALIDATE_EMAIL) === true) {
echo "invalid email";
exit();
}
//valid email
else{
//prepared query
$query_name = "SELECT * FROM users WHERE user_name = ?";
$query_email = "SELECT * FROM users WHERE user_email = ?";
//prepared statements
$stmt_name = mysqli_prepare($conn, $query_name);
$stmt_email = mysqli_prepare($conn, $query_email);
//if bind failure
if((!mysqli_stmt_bind_param($stmt_name, "s", $user_name)) && (!mysqli_stmt_bind_param($stmt_email, "s", $user_email))){
echo "bind unsuccessfull";
exit();
}
else{
//if execution fails
if( !mysqli_stmt_execute($stmt_name) && !mysqli_stmt_execute($stmt_email)){
echo "stmt execution failed";
exit();
}
//else if execution success
else{
$result_name = mysqli_stmt_store_result($stmt_name);
$result_email = mysqli_stmt_store_result($stmt_email);
//rows
$row_name = mysqli_stmt_num_rows($stmt_name);
$row_email = mysqli_stmt_num_rows($stmt_email);
echo $row_name;
echo $row_email;
}
}
}
it looks like the first part before && in if condition works and the second doesnot work at all. i have tried registering it with existing "email" in the database but the result is still 0.
the connection is fine and works!
Any help will be appreciated>
Instead of doing so much complex code, use single query to do your job
//validating email
if(!filter_var($user_email, FILTER_VALIDATE_EMAIL) === true) {
echo "invalid email";
exit();
}
else{
$stmt = mysqli_prepare($conn, "SELECT * FROM users WHERE user_name = ? OR user_email = ?");
mysqli_stmt_bind_param($stmt, 'ss', $user_name, $user_email);
if( !mysqli_stmt_execute($stmt)){
echo "stmt execution failed";
exit();
}else{
$result_name = mysqli_stmt_store_result($stmt_name);
$result_email = mysqli_stmt_store_result($stmt_email);
//rows
$row_name = mysqli_stmt_num_rows($stmt_name);
$row_email = mysqli_stmt_num_rows($stmt_email);
echo $row_name;
echo $row_email;
}
}
$query_name = "SELECT * FROM users WHERE user_name = ? OR user_email = ?";
you don't need to check the condition twice at same time.If someone will login through email or username then this query will check for both username and email.
I would be tempted to roll both queries together using an or condition in conjunction with a try/catch block so that you can throw exceptions at certain stages if a condition is not met.
if( !isset( $user_email ) or !filter_var( $user_email, FILTER_VALIDATE_EMAIL ) === true ) {
exit("invalid email");
} else {
try{
if( isset( $user_name, $user_email ) ){
$sql='select `user_name`,`user_email` from `users` where `user_name` = ? or user_email = ?'
$stmt=$conn->prepare( $sql );
if( $stmt ){
$stmt->bind_param('ss', $user_name, $user_email );
$result=$stmt->execute();
if( $result ){
$stmt->store_result();
if( $stmt->num_rows == 1 ){
/* user name &/or email already exists */
$stmt->bind_result( $name, $email );
$stmt->fetch();
printf('whoohoo! - found user "%s" with email "%s"', $name, $email );
} else {
/* no record for username or email*/
/* sql query to insert new user */
}
$stmt->free_result();
$stmt->close();
} else {
throw new Exception('sql query failed to return any results');
}
} else {
throw new Exception('unable to prepare sql');
}
} else {
throw new Exception('username &/or email are missing');
}
}catch( Exception $e ){
echo $e->getMessage();
}
Related
When I try to login it doesn't display any information, it didn't get the data in database.
if($_SERVER['REQUEST_METHOD']=='POST'){
//filter this variable for security
$username = strip_tags(mysqli_real_escape_string($conn, trim($_POST['username'])));
$password = strip_tags(mysqli_real_escape_string($conn, trim($_POST['password'])));
$stmt = $conn->prepare("SELECT id FROM students WHERE s_id = ?");
$stmt->bind_param("s",$username);
$stmt->execute();
$user = $stmt->fetch();
if($user == FALSE) {
die("Incorrect");
}else {
$password_hash = $user['password'];
$validPassword = password_verify($password, $password_hash);
if($validPassword){
echo "success";
} else{
//$validPassword was FALSE. Passwords do not match.
echo 'Incorrect username / password combination!<br/>';
echo $user['password'];
}
}
}
Your query only selects the id. Change your query to select your id and password.
$stmt = $conn->prepare("SELECT * FROM students WHERE s_id = ?");
Then you will have your hashed password $user['password'] in the results.
I'd be tempted to wrap everything in a try/catch block and raise exceptions at key points to determine where the code breaks. Also I think the result from the query should be bound to a variable prior to fetching the results using $stmt->bind_result
When using a prepared statement I'd suggest that you do NOT use mysqli_real_escape_string nor use trim as it would be perfectly valid for a password to start or end with a space - the database engine will process the statement in a manner that is safe.
if( $_SERVER['REQUEST_METHOD']=='POST' && isset($_POST['username'],$_POST['password']) ){
try{
$args=array(
'username' => FILTER_SANITIZE_STRING,
'password' => FILTER_SANITIZE_STRING
);
$_POST=filter_input_array( INPUT_POST, $args );
extract( $_POST );
$stmt = $conn->prepare("select `password` from `students` where `s_id` = ?");
if( $stmt ){
$stmt->bind_param( "s", $username );
$result = $stmt->execute();
if( $result ){
/* There should be only 1 record - bind to a variable */
$stmt->bind_result( $pwdhash );
/* fetch the results of the query */
$stmt->fetch();
/* is the password correct? */
$validpassword = password_verify( $password, $pwdhash );
echo $validpassword ? 'Success' : 'Error: Incorrect username or password';
$stmt->close();
} else {
throw new Exception('No results returned');
}
} else {
throw new Exception('failed to prepare sql query');
}
} catch( Exception $e ){
exit( $e->getMessage() );
}
}
I have made a login system which enables a user to sign in using a previously defined email and password, however in the testing section, I have noticed the passwords say they don't match although I know they are correct as I wrote the test one down as I made it. I cant seem to see why this is happening, I think it may be something to do with my hashing of the passwords but I don't know what.The login page check is from document, login.php:
if(empty($errors))
{
$sql = "SELECT accountID, password FROM users WHERE emails=?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$data['email']]);
if(!$row = $stmt->fetch())
{
// email didn't match
$errors['login'] = "Login failed. on email";
}
else
{
// email matched, test password
if(!password_verify($data['password'],$row['password']))
{
// password didn't match
$errors['login'] = "Login failed. on password";
}
else
{
// password matched
$_SESSION['user_id'] = $row['accountID'];
header('location: welcome.php');
die;
}
}
}
The insertion to the database with hashing is, from insert.php:
if (isset($_POST['name'])){
$name = $_POST['name'];
}
if (isset($_POST['email'])){
$email = $_POST['email'];
}
if (isset($_POST['password'])){
$pword = $_POST['password'];
}
if (isset($_POST['busName'])){
$busName = $_POST['busName'];
}
if (empty($name)){
echo("Name is a required field");
exit();
}
if (empty($email)){
echo ("email is a required field");
exit();
}
if (empty($pword)){
echo("You must enter a password");
exit();
}
$pword = password_hash($pword, PASSWORD_DEFAULT)."/n";
//insert html form into database
$insertquery= "INSERT INTO `cscw`.`users` (
`accountID` ,
`businessName` ,
`name` ,
`emails` ,
`password`
)
VALUES (
NULL , '$busName', '$name', '$email', '$pword'
);";
and on the web page i am shown from login.php, "Login failed. on password". If you need to see any more code please let me know.
It does not recognize $row['password'].
Be always organized with your query **
1)Prepare
2)Execute
3)Fetch
4)Close
5)THEN YOU EXPLOIT the fetched data.
The fetched data need to be sorted as shown with the returnArray function.
Hoping that there are UNIQUE emails and the $data array exists.Try this.
if(empty($errors))
{
$sql = "SELECT accountID, password FROM users WHERE emails=:emails";
$stmt = $pdo->prepare($sql);
$stmt->bindParam(':emails', $data['email']);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt->CloseCursor();
$stmt=null;
/* Return the results is a more handy way */
function returnArray( $rows, $string )
{
foreach( $rows as $row )
{
return $row[ $string ];
}
}
if( empty($rows) )
{ // email didn't match
$errors['login'] = "Login failed. on email";
}
else
{ // email matched, test password
if( !password_verify( $data['password'], returnArray($rows,'password') ) )
{
// password didn't match
$errors['login'] = "Login failed. on password";
}
else
{
// password matched
$_SESSION['user_id'] = $row['accountID'];
header('location: welcome.php');
die;
}
}
}
The login Page is not finished the query is not inserting. Be carefull you might be vunerable to SQL injections because your do not escape user manipulated variables.(To strengthen security add a form validation, it will be great).
You have used $pword = password_hash($pword, PASSWORD_DEFAULT)."/n";
I removed ."/n" part. I seems that you are using a concatenation operator '.' to add /n add the end of the password_hash.
Your $insertquery is not finished and not readable. You don't need to insert backticks in your query. And no need to SELECT accountID it will autoincrement (See if A_I for accountID is ticked in your database).
Do something like this in your login page.
/* trim and escape*/
function escapeHtmlTrimed( $data )
{
$trimed = trim( $data );
$htmlentities = htmlentities( $trimed, ENT_QUOTES | ENT_HTML5, $encoding = 'UTF-8' );
return $htmlentities;
}
if ( isset( $_POST['name'] ) ){
$name = escapeHtmlTrimed( $_POST['name'] );
}
if ( isset($_POST['email']) ){
$email = escapeHtmlTrimed( $_POST['email'] );
}
if ( isset($_POST['password']) ){
$pword = escapeHtmlTrimed( $_POST['password'] );
}
if ( isset($_POST['busName']) ){
$busName = escapeHtmlTrimed( $_POST['busName'] );
}
if ( empty($name) ){
echo("Name is a required field");
exit();
}
if ( empty($email) ){
echo ("email is a required field");
exit();
}
if ( empty($pword) ){
echo("You must enter a password");
exit();
}
/*Remove this your adding "./n"*/
$pword = password_hash($pword, PASSWORD_DEFAULT);
//insert html form into database
$insertquery= "INSERT INTO users (businessName ,name ,emails,
password) VALUES (:busName , :name, :email , :pword)";
$stmt = $pdo->prepare($insertquery);
$stmt->bindParam(':busName', $busName);
$stmt->bindParam(':name', $name);
$stmt->bindParam(':email', $email);
$stmt->bindParam(':pword', $pword);
$stmt->execute();
$stmt->CloseCursor();
$stmt=null;
I've started a thread or two so far but nothing has got resolved. I'm not able to use the mysqlnd because i'm using a shared hosting account with godaddy.
All i need to do is check if my email address and/or username is in use; if they are in use throw and error, if not.. all is well.
Here is my code:
$input_errors = array();
if (!empty($_POST['username'])) {
$user = $_POST['username'];
} else {
$input_errors['username'] = "Must fill out username";
}
$email = filter_input(INPUT_POST, 'usermail', FILTER_VALIDATE_EMAIL);
if (false === $email) {
$input_errors['usermail'] = "Not a valid email address";
}
if(count($input_errors) > 0) {
print_r($input_errors); die();
}
$sql = "SELECT COUNT(*) as amount FROM people WHERE username = ?
OR email = ?";
if ($stmt = $mysqli->prepare($sql)) {
$stmt->bind_param("ss", $user, $email);
$stmt->execute();
$results = $stmt->get_result();
$data = mysqli_fetch_assoc($results);
if ($data['amount'] > 0)
{
print "User already exists";
}
}
else {
$stmt = $mysqli->stmt_init();
if (!$stmt) {
echo "Init failed";
} else {
$cmd = "INSERT INTO people (username, email, sign_up_date) VALUES (?, ?, NOW() )";
if ($stmt->prepare($cmd)) {
$stmt->bind_param('ss', $user, $email );
$stmt->execute();
echo $stmt->affected_rows . " row(s) inserted";
$stmt->close();
} else {
echo "Prepare failed";
}
mysqli_close($mysqli);
}
}
bind_result() does not work.
Change your sql statement to the following:
$sql = "SELECT COUNT(*) as amount FROM people WHERE username = '".mysqli_real_escape_string($_POST['username'])."' OR email = '".mysqli_real_escape_string($email)."'";
I've made a user class which validates the data passed through the form and then subsequently updates the database table users. I want to add extra functionality such as checking if the username and email exists in the table, I've added a little script however it doesn't seem to be working.
I inserted a duplicated email address and I did not get the error message "email exists" instead I get the success message "1 row inserted":
Am I doing something wrong below? Is there perhaps a better way to approach this?
public function insert() {
if (isset($_POST['submit'])) {
$email = isset($_POST['email']) ? $this->mysqli->real_escape_string($_POST['email']) : '';
$result = $this->mysqli->prepare("SELECT * FROM users WHERE email='".$email."'");
if ($result->num_rows) {
echo "email exisits!";
}
else
{
$stmt = $this->mysqli->prepare("INSERT INTO users (username, password, name, email) VALUES (?, ?, ?, ?)");
$stmt->bind_param('ssss', $username, $password, $name, $email); // bind strings to the paramater
//escape the POST data for added protection
$username = isset($_POST['username']) ? $this->mysqli->real_escape_string($_POST['username']) : '';
$cryptedPassword = crypt($_POST['password']);
$password = $this->mysqli->real_escape_string($cryptedPassword);
$name = isset($_POST['name']) ? $this->mysqli->real_escape_string($_POST['name']) : '';
$email = isset($_POST['email']) ? $this->mysqli->real_escape_string($_POST['email']) : '';
/* execute prepared statement */
$stmt->execute();
printf("%d Row inserted.\n", $stmt->affected_rows);
/* close statement and connection */
$stmt->close();
}
You are using the worst API you ever can choose.
With safeMysql it would be
$exists = $this->db->getOne("SELECT 1 FROM users WHERE email=?s", $_POST['email']);
if ($exists) {
echo "email exisits!";
}
With PDO it is slightly longer but usable
$stmt = $this->db->prepare("SELECT 1 FROM users WHERE email=?");
$stmt->execute(array($_POST['email']));
$exists = $stmt->fetchColumn();
if ($exists)
{
echo "email exisits!";
}
But with raw mysqli you will need a screenful of code only to check if user exists.
So, the whole function using safeMysql would be
public function insert()
{
if (!isset($_POST['submit'])) {
return FALSE;
}
$sql = "SELECT 1 FROM users WHERE email=?s";
$exists = $this->db->getOne($sql, $_POST['email']);
if ($exists)
{
echo "email exisits!";
return FALSE;
}
$sql = "INSERT INTO users SET ?u";
$allowed = array('username', 'name', 'email');
$insert = $this->db->filterArray($_POST, $allowed);
$insert['password'] = crypt($_POST['password']);
$this->db->query($sql, $insert);
return $this->db->afectedRows();
}
you need to use this code after prepare statement
$stmt->execute();
$stmt->store_result();
put this
if ($result->num_rows > 0) {
echo "email exisits!";
}
instead of
if ($result->num_rows) {
echo "email exisits!";
}
First, you are using prepare (great!) but then you are just passing in the value of email, effectively defeating the benefit of prepared statements.
Second, you never execute the query, which is why you don't get anything in num_rows.
public function insert() {
$result = $this->mysqli->prepare("SELECT COUNT(*) FROM users WHERE email=?");
$result->bind_param("s", $_POST['email']);
$result->execute();
$result->bind_result($email_count);
if ($email_count) {
echo "email exisits!";
} else {
# your other logic
From what I can see you're not assigning a value to num_rows prior to testing it with if ($result->num_rows), so it will always be 0
Problem & Explanation
Hello I have just coded a function that first does checking if account exists in database with that name, and then if email exists in database with that entered email.
If not, return true + insert data.
But in this case, nothing happens on submit, it just shows the form, but doesn't inserts the data..
What is wrong with it?
function createAccount($name, $password, $email)
{
global $pdo;
$check_in = $pdo->prepare("SELECT * FROM users WHERE user_name = :username LIMIT 1");
$check_in->execute( array(':username' => $name) );
if (!$check_in->rowCount())
{
$check_in = email_exists($email);
if ($check_in === false)
{
$insert_in = $pdo->prepare
("
INSERT INTO
users
(user_name, user_password, user_email)
VALUES
(:name, :password, :email)
");
$insert_in->execute( array
(
':name' => $name,
':password' => $password,
':email' => $email
));
return true;
}
else
{
return 'exists';
}
}
else
{
return 'user_in_use';
}
}
function email_exists($email)
{
global $pdo;
$check = $pdo->prepare("SELECT * FROM users WHERE user_email = :email LIMIT 1");
$check->execute( array(':email' => $email) );
if ($check->rowCount())
{
return true;
}
else
{
return false;
}
}
This is how I make up the register:
# Creating shortcuts
if (isset($_POST['username']) && isset($_POST['password']) && isset($_POST['email']))
{
$name = $_POST['username'];
$password = $_POST['password'];
$email = $_POST['email'];
}
# Creating errors array
$errors = array();
if (isset($_POST['submit']))
{
$check_in = createAccount($name, $password, $email);
if ($check_in === true)
{
echo 'Created account sucessfully!';
}
else if ($check_in == 'already_in_use')
{
echo 'Could not create account because name already in use..';
}
else if($check_in == 'exists')
{
echo 'Email already in use..';
}
}
Question:
What is wrong with this code & how do I fix this? I have no errors at all.
It just won't insert any data to the Database.
Yes, the PDO connection & statements are right, because the login works perfectly.
Thanks a lot!
EDIT!
if ($check_in === true)
{
echo 'Created account sucessfully!';
}
else if ($check_in == 'already_in_use')
{
echo 'Could not create account because name already in use..';
}
else if($check_in == 'exists')
{
echo 'Email already in use..';
} else {
echo 'Error is there...';
}
It's echoing 'Error is there...' apon submit!
I just want to slap myself!.....
The problem was: The fields were set as INT, therefore we could not store anything but ints...