How would I stop multiple emails OR username? - php

I have the following code in my registration form to prevent against multiple usernames being created:
connect_db();
$check = mysql_query("SELECT username FROM school_users WHERE username = '$username'") or die(mysql_error());
$check2 = mysql_num_rows($check);
if ($check2 != 0) {
respond("error", "Sorry, the username ".$_POST['username']." is already in use. Please choose a different username.");}
However, I also want to check for email, in the same statement:
connect_db();
$check = mysql_query("SELECT username, email FROM school_users WHERE username = '$username' or email = '$email'") or die(mysql_error());
$check2 = mysql_num_rows($check);
if ($check2 != 0) {
if (???username???){
respond("error", "Sorry, the username ".$_POST['username']." is already in use. Please choose a different username.");}}
else if (???email???) {
respond("error", "Sorry, the username ".$_POST['username']." is already in use. Please choose a different username.");}}

You could try doing:
connect_db();
$check = mysql_query("SELECT 'User' validation
FROM school_users
WHERE username = '$username'
UNION ALL
SELECT 'Email'
FROM school_users
WHERE email = '$email'") or die(mysql_error());
$row = mysql_fetch_assoc($check);
if($row)
{
if ($row["validation"] == 'User') {
respond("error", "Sorry, the username ".$_POST['username']." is already in use. Please choose a different username.");}}
else if ($row["validation"] == 'Email') {
respond("error", "Sorry, the email ".$_POST['email']." is already in use. Please choose a different email.");}}
}
OR you could just do it separately...
//Validate UserName
connect_db();
$check = mysql_query("SELECT username FROM school_users WHERE username = '$username'") or die(mysql_error());
$check2 = mysql_num_rows($check);
if ($check2 != 0) {
respond("error", "Sorry, the username ".$_POST['username']." is already in use. Please choose a different username.");}
//Validate Email
connect_db();
$checkEmail = mysql_query("SELECT email FROM school_users WHERE email = '$email'") or die(mysql_error());
$checkEmail2 = mysql_num_rows($check);
if ($checkEmail2 != 0) {
respond("error", "Sorry, the email ".$_POST['email']." is already in use. Please choose a different email.");}
Additionally, your code is vulnerable to SQL Injection attacks and you are using deprecated MySQL php functions. If you do want to make your code better an less vulnerable, take a look at the following links:
Why shouldn't I use mysql_* functions in PHP?
What could i use instead of mysql_ functions?
Prepated Statements
Prepared Statements with MySQLi

The original code isn't that far from the solution as you might think.
$check = mysql_query("SELECT username, email FROM school_users WHERE username = '$username' or email = '$email' LIMIT 1") or die(mysql_error()); //Limit one reduces the time mysql searches the db since it stops on the first occurence
$check2 = mysql_fetch_assoc($check); //we do not only want to know the count of matching rows, but the values return in email and username field
//trimming makes sure we do not have any spaces at the beginning or end
//strtolower makes sure we set UserName == usERnaME == username etc.pp.
if (strtolower(trim($row['username'])) == strtolower(trim($_POST['username']))){ // check the result
respond("error", "Sorry, the username ".$_POST['username']." is already in use. Please choose a different username.");}
}
else if (strtolower(trim($row['email'])) == strtolower(trim($_POST['email']))) { // and again for email adress
respond("error", "Sorry, the email ".$_POST['email']." is already in use. Please choose a different email.");}
}

You can also do this in one statement:
SELECT username
FROM school_users
WHERE username = '$username' or email = '$email'
If you do this, you'll need to change the message to the user . . . "Your user name or email (or both) are already in use".
To customize the message in one statement, you can use aggregation:
select (case when max(username = '$username') = 1 and max(email = '$email' = 1
then 'both'
when max(username = '$username') = 1
then 'username'
when max(email = $email) = 1
then 'email'
end) as WherePresent
from school_users
WHERE username = '$username' or email = '$email'
This returns 0 rows if everything is ok. Otherwise, it returns one row with one of "both", "username", "email", indicating which is duplicated.

Related

one query, one table, two count()

I want to check if username and email taken in my registration script.
This is how I check with query:
$emailcheck = "SELECT COUNT(email) AS nume FROM members WHERE email = :email";
//bindValue
//execute
//fetch
if($rowe['nume'] > 0){
$errors[] = "E-mail exist.";
}
And also I'm doing the same thing for username;
$usercheck = "SELECT COUNT(username) AS numu FROM members WHERE username = :username";
//bindValue
//execute
//fetch
if($rowu['numu'] > 0){
$errors[] = "Username taken.";
}
*
I want to go one step further and handle all of stuff with one query.
But I couldn't came up with such query.
I tried:
$check = "SELECT COUNT(username) AS numu and COUNT(email) AS nume FROM members WHERE username = :username OR email = :email";
but probably It's ridiculous.
How to handle what I want with one query?
And after I want to check like that:
if($row['numu'] > 0){
$errors[] = "Username taken.";
}
if($rowe['nume'] > 0){
$errors[] = "E-mail exist.";
}
So it will be less code, instead of connecting same table twice and bindValue, execute, fetch for second time.
You can just do Union All to unite those queries:
SELECT COUNT(email) AS num FROM members WHERE email = :email
UNION ALL
SELECT COUNT(username) AS num FROM members WHERE username = :username
Then extract 2 according rows.
OR, MySQL allows this thing:
SELECT
(SELECT COUNT(email) FROM members WHERE email = :email) as nume,
(SELECT COUNT(username) FROM members WHERE username = :username) as numu
if you want 1 rows with 2 columns.
Do that only if you need to see which one is already present. Otherwise just do this:
SELECT 1 FROM members WHERE email = :email OR username = :username LIMIT 1
Yes, consider not doing count() because you don't need to count all the rows. You just need to stop if you find just one. So either do a LIMIT or IF EXISTS()
I don't think you really need to count. Assuming you want to check if either username or email already exist because they are required to be unique on your user table, you can do this:
First, add a unique index to each of those columns in your database. You may already have this, but if you want those values to be unique, this will ensure that even if your PHP code fails to do so for some reason.
Then you can use this query:
SELECT username, email FROM members WHERE username = :username OR email = :email
This will return either zero, one, or two rows, where:
0 = neither username nor email was found
1 = one row was found having either username, email, or both
2 = username was found in one row and email was found in another
Then you can loop over your results, comparing them to the user input, and set your errors.
while ($row = //fetch) {
if ($row['username'] == $username) {
$errors[] = "Username taken.";
}
if ($row['email'] == $email) {
$errors[] = "E-mail exist.";
}
}
You can try this after removing and between count
$check = "SELECT COUNT(username) AS uname ,
COUNT(email) AS uemail FROM members
WHERE (username = :username OR email = :email)";

PHP empty variables check with logical operator only works if both variables are not empty

I am trying to do a check on my database table.
It checks if, for a provided username, there exists an email address or password. In the event that either of them are present in the database for the provided username, the user is shown an error message and records are not altered.
Problem: However, for some reason my check only works if both, the password and email is present for the record (it does not display the error message if the email address is empty but password is not). Below is my code:
require ('core/dbcon.php');
$user = mysqli_real_escape_string($con, $_GET['user']);
$acc_status = mysqli_real_escape_string($con, $_GET['status']);
if(empty($_POST['form']) === false){
$usr_email = mysqli_real_escape_string($con, $_POST['email']);
$pwd = mysqli_real_escape_string($con, $_POST['password']);
$rpwd = mysqli_real_escape_string($con, $_POST['rpwd']);
$qry = mysqli_query($con, "SELECT * FROM users WHERE email='$usr_email'") or die(mysqli_error($con));
$usr_details = mysqli_fetch_assoc($qry);
if(empty($usr_details['email'])=== true && empty($usr_details['password'])=== true){
if(mysqli_num_rows($qry) == 0){
if($pwd && $rpwd && $usr_email){
if($pwd === $rpwd){
$pwd = md5($pwd);
$query = mysqli_query($con, "SELECT * FROM users WHERE username='$user' AND email='$usr_email'") or die(mysqli_error($con));
if (mysqli_num_rows($query)== 1){
//update database table
}else{
$errors[] = 'Error! Your details were not added to the system due to a technical error. Please contact the Admin.';
}
}else{
$errors[] = 'Please make sure that the password entered in both fields are the same.';
}
}else{
$errors[] = 'Please complete all fields marked with a red asterisk';
}
}else{
$errors[] = 'Error! <b>'.$usr_email.'</b> already existis in our system.';
}
}else{
$errors[] = 'Error! It looks like the username you have entered has been assigned an email address and password already.';
}
}
I have a record with username 'testuser', email 'test#email.com', and password 'password'. My check works fine as it stands, it displays the error "Error! It looks like the username you have entered has been assigned an email address and password already." However, when I delete the email address form the database it somehow assumes the following conditions have been met: if(empty($usr_details['email'])=== true && empty($usr_details['password'])=== true){ when empty($usr_details['password'])===false.
I have tried changing the logical operator from && to || but I get the same issue (as OR should accept one empty and one non-empty variable in the first place). Your assistance will be greatly appreciated.
Instead of :
if(empty($usr_details['email'])=== true && empty($usr_details['password'])=== true){
Try this :
if($usr_details['email'] === NULL || $usr_details['password'] === NULL){
For empty database value, NULL is better.
Edit:
Your query will return empty cause you check $usr_details['email'] only, which is not found in database. So condition will be meet.
If you want to get this properly try to query with username or unique id
$qry = mysqli_query($con,"select * from user where id=1");
or
$qry = mysqli_query($con,"select * from user where username='username'");
or alternatively you should check both username and password in query:
$qry = mysqli_query($con,"select * from user where email='email' OR password='password'");
I just found that the issue lied with my query as hinted by Lukas Hajdu:
$qry_email = mysqli_query($con, "SELECT email FROM users WHERE email='$usr_email'") or die(mysqli_error($con));
For some reason it only did the if(empty($usr_details['email'])=== true && empty($usr_details['password'])=== true){ check only if the email address existed in the database already.
To resolve this I had to form another query:
$qry_user = mysqli_query($con, "SELECT * FROM users WHERE username='$user'") or die(mysqli_error($con));
$usr_details = mysqli_fetch_assoc($qry_user);
I don't know why this is the case and how I could improve my code. So please feel free to provide suggestions :)

why isn't my code working to check if username has already been taken?

$query = ("SELECT * FROM users");
$result = mysqli_query($connection, $query);
if (!empty($_POST)){
while ($row = mysqli_fetch_assoc($result)){
if ($username == $row['username']){
echo "Username Taken, Try again";
}else if (empty($username) || !isset($username)) {
echo "Please enter a valid username";
} else if (empty($email) || !isset($email)){
I want to check whether the username is already taken when they update or register their details. I have noticed that i check if the username field is empty and set AFTER i check whether its been taken. I will change this. However, i can still register a username that is already taken?
Like some of the comments said, let me re-phrase it for you.
Ideally, you should be checking if the username exists in the table instead of fetching all the username and check against each (which is redundant and not needed).
So you should be doing:
if (!empty($_POST)){
//get the submitted username cleaned
$username = mysqli_real_escape_string($connection,$_POST['username']);
//get username where username=posted username
$query = mysqli_query($connection,"SELECT username FROM users WHERE username='{$username}'");
//get the number of rows returned from above query
$count = mysqli_num_rows($query);
//if a row is found, that means the username exists
//so post the error
if($count==1){
echo "Username Taken, Try again";
}
}
Look up on prepared statements with mysqli. It automatically does the mysqli_real_escape_string() function for you and is more secure against injection. I have just started learning it on PDO so I'm not familiar with the mysqli way of doing it and thus couldn't put it up with this answer.

Checking whether username exists or not code in sql and php

I have written a code to check whether the username exists in the database or not. It seems to return that there is no such username exists even if there's a same username existing.
$conu=mysqli_connect("localhost","db_user","db_pass","db_name");
$result = mysql_query("SELECT 1 FROM member WHERE username = $username");
if ($result && mysql_num_rows($result) > 0) {
$user_err = "<i><span class='error'>Usernme already exists</span></i>";
$errflag = true;
}
elseif(preg_match("/^[0-9a-zA-Z_]{5,}$/", $username) === 0) {
$user_err = "<i><span class='error'>Usernme must be bigger than 5 chararacters and can contain only digits, letters and underscore</span></i>";
$errflag = true;
}
Try
mysql_query("SELECT username FROM member WHERE username = '$username' LIMIT 1;");
SELECT 1 is not actually using the database; it's always returning 1, hence why your result is always the same regardless of the contents of the member table.
Usernames I take it are some sort of varchar? If that is the case, you might want to put its value in quotes:
$result = mysql_query("SELECT `username` FROM `member` WHERE `username` = '".$username."' LIMIT 1;");
your query is subject to sql injections btw.
At first, you are trying to return a column that probably doesn't exist: "1"
Second, I hope that you are cleaning the $username or else you are allowing anyone to inject your database.
The correct query is
mysql_query("SELECT * FROM `member` WHERE `username`='$username'");
You are using mysqli to connect, but mysql to perform your query.
When you SELECT 1 FROM member WHERE username = $username, the result will always be 1.
You need to put $username in the query in quotes. Something like SELECT username FROM member WHERE username = '$username'.
You forgot to include the part of the code for when there is no such username in your posting.

PDO and checking if username or email is taken

I am converting to PDO and I'm having a problem converting at the section where it checks to see if the username and email is taken or not.
below is the code:
<?php
session_start();
$host = "localhost";
$username = "root";
$password = "123";
$dbname = "test";
$conn = new PDO("mysql:host=$host;dbname=$dbname",$username,$password);
?>
<?php
if(isset($_POST['register'])){
$username = $_POST['username'];
$password = $_POST['password'];
$email = $_POST['email'];
$usernamecheck = $conn->query("SELECT `id` FROM `user` WHERE username='$username'");
$emailcheck = $conn->query("SELECT `id` FROM `user` WHERE email='$email'");
if(mysql_num_rows($usernamecheck) > 0){
echo "That username is already taken";
}elseif(mysql_num_rows($emailcheck) > 0){
echo "That e-mail address is already in use";
}
?>
The errors I get are at the two following lines:
if(mysql_num_rows($usernamecheck) > 0){
}elseif(mysql_num_rows($emailcheck) > 0){
Thanks in Advance.
You're using mysql_num_rows() for a PDO query. You can't mix these APIs.
You're also interpolating $_POST variables directly into your SQL, which is a no-no for security. The benefit of using PDO is that you can easily use SQL query parameters instead, which is much easier and more secure.
Here's how I'd code this task:
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $conn->prepare("SELECT COUNT(*) AS count FROM `user` WHERE username=?");
$stmt->execute(array($username));
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$username_count = $row["count"];
}
if ($username_count > 0) {
echo "That username is already taken";
}
$stmt = $conn->prepare("SELECT COUNT(*) AS count FROM `user` WHERE email=?");
$stmt->execute(array($email));
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$email_count = $row["count"];
}
if ($email_count > 0) {
echo "That email address is already in use";
}
Also keep in mind that even if you check first, you should assume that someday two people may be trying to create the same username simultaneously, and if the code for their respective requests executes in just the wrong sequence, they could both be told the username does not exist, go ahead and INSERT it. So you should define a UNIQUE KEY on the columns that must be unique. Only the first one to INSERT will succeed, the other will get an error. So you must check for errors.
First of all, the entire task is rather pointless. Making a username unique makes no sense. Given email is used to identify a user, the username - or, rather - display name could be anything and allow duplicates, just like it is done right here, on Stack Overflow.
But if you want the username to be unique, obviously it can be done in one query, without any num rows functionality which being essentially useless
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "SELECT username, email AS count FROM `user` WHERE username=? OR email=?";
$stmt = $conn->prepare($sql);
$stmt->execute([$username, $email]);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
if ($row['username'] === $username) {
$errors[] = "Username is taken";
}
if ($row['email'] === $email) {
$errors[] = "Email is taken";
}
}

Categories