prevent duplicate usernames adding a sequence number after username - php

I'm trying to Implement the facebook registration. It works and i'm getting back all the data I need. Now I want to assign a username to the user like this:
$username = ''.$first_name.'.'.$lastname.'';
The problem is that I don't know if a user with the same name and last name will register to the website and i would like to check if the username is taken and add a sequence number to the basic $username (facebook does the same), like this:
name.lastname
name.lastname.1
name.lastname.2
etc
I tried with:
$temp_username = ''.$first_name.''.$last_name.'';
$check_username = mysql_query("SELECT username FROM users WHERE username = '$temp_username'");
$num_rows = mysql_num_rows($check_username);
if ($num_rows == 0){
$username = strtolower($temp_username);
} else {
$username = strtolower(''.$temp_username.'.'.$num_rows.'');
}
but of course it doesn't work because there is always just one user with that username.
EDIT*** this is how I fix it (thanks to zander):
$temp_username = ''.$first_name.''.$last_name.'';
$num_rows = mysql_num_rows(mysql_query("SELECT username FROM users WHERE username = '$temp_username' OR username LIKE '$temp_username%' "));
$username = strtolower(''.$temp_username.'.'.$num_rows.'');

$num_rows = mysql_num_rows(mysql_query("SELECT username FROM users WHERE username = '$temp_username' OR username LIKE '$temp_username.%' ")); will return the number of rows you actually expect. Then, use $username = strtolower(''.$temp_username.'.'.$num_rows.''); to get it done. No need of loops.

The following SELECT determines the user with the highest number if there are any
select max(reverse(SUBSTRING(reverse(username), 1, LOCATE('.', reverse(username))-1))) trail
from users
where username like 'John.Smith.%';
SQL Fiddle Demo
Add it to PHP like this
...
if ($num_rows == 0){
    $username = strtolower($temp_username);
} else {
... query for the max number here
... concatenate the username with the max number
}
Ah and last but not least. Make sure your code is not vulnerable to SQL injection. Use bind parameters. Good start is this answer: Best way to defend against mysql injection and cross site scripting

There are many existing answers that correctly suggest using the LIKE operator in your WHERE clause. But there is one critical issue that none of the existing answers have addressed.
Two people could attempt to add the same username at the same (or nearly the same) time. Each would SELECT the count of existing usernames that are LIKE that name, and they each would generate the same number suffix, and you still get duplicates.
I am neither a mysql developer nor php developer, so I won't provide much in the way of specific syntax.
You will want to make sure your users table uses the InnoDB storage engine. Your code will need to:
START TRANSACTION
SELECT FOR UPDATE to make sure only one person can get the count of
a particular username at a given time
INSERT your new user
COMMIT your transaction.
See Select for update for more information.

Use this code instead:
$check_username = mysql_query("SELECT username FROM users WHERE username = '$temp_username' OR username LIKE '$temp_username.%' ");
example this will match:
johnsmith or joshnsmith.X where x will be 1 , 2 , 3 .......etc

DB Dump
CREATE TABLE Users (
`username` varchar(255) PRIMARY KEY,
`firstname` varchar(255),
`lastname` varchar(255)
);
INSERT INTO Users (`username`, `firstname`, `lastname`) VALUES (
'praveen.kumar', 'Praveen', 'Kumar'
),(
'praveen.kumar.1', 'Praveen', 'Kumar'
),(
'praveen.kumar.2', 'Praveen', 'Kumar'
);
Now to the SQL, we can do this way:
SELECT *
FROM `Users`
WHERE `username` LIKE "praveen.kumar%"
ORDER BY `username` DESC
Gives an output:
+-----------------+-----------+----------+
| USERNAME | FIRSTNAME | LASTNAME |
+-----------------+-----------+----------+
| praveen.kumar.2 | Praveen | Kumar |
| praveen.kumar.1 | Praveen | Kumar |
| praveen.kumar | Praveen | Kumar |
+-----------------+-----------+----------+
And you can get the latest one this way:
SELECT *
FROM `Users`
WHERE `username` LIKE "praveen.kumar%"
ORDER BY `username` DESC
LIMIT 1
The PHP Code:
<?php
# Outputs the largest number with that username.
$nextUser = substr($userNameFromDB, strrpos($userNameFromDB, "."));
$nextUser++;
?>
SQL Fiddle: http://sqlfiddle.com/#!2/ad149/1

Use the count() function and the like operator:
$check_username = mysql_query("
SELECT count(username)
FROM users
WHERE username like '$temp_username%'
");
It will return the number of existent names. No need to call mysql_num_rows.

You should use the count() function
$query = mysql_query("
SELECT count(user_name) cnt
FROM users
WHERE username = '$just_registered_username'
");
and then fetch the result using
$row = sql_fetchrow($query);
And then get the count of users as
$next_index = $row->cnt;
Then append it to the new username
$new_username = "{$just_registered_username}.{$next_index}";
Don't forget to add comments to your final code.
Also try and use PDO for database access.

If you want to find a user name that does not exist, you have to try combinations, until you find a non existing username.
Therefore, loop until you find a non existing name:
$temp_username = $first_name . $last_name;
$i=1;
$found = false;
while(!$found) {
$check_username = mysql_query(
"SELECT username FROM users WHERE username = '$temp_username'");
$found = mysql_num_rows($check_username);
if ($found){
$username = strtolower($temp_username);
}
else{
$temp_username = $first_name . $last_name . '.' . $i;
$i++
}
}

Related

mysql: apostrophe not being read from varchar column in database?

i have the following table for new_supplier_request:
Id | ref | User | Manager (Varchar)
1 12 James Henry O'Brien
I also have my internal_users table:
Id | User_firs_name | user_last_name(Varchar)
1 Henry O'Brien
i am using the following mysql query to give a manager permission (who is logged in) to view some content if the managers name appears for that row of data in the manager column of my new_supplier_request table
$_SESSION['username'] = internal_users.user_first_name
$_SESSION['username2'] = internal_users.user_last_name
$user = $_SESSION['username']." ".$_SESSION['username2'];
$sql34 = "select * from new_supplier_request, internal_users where new_supplier_request.status!= 'complete' and new_supplier_request.action_taken ='none' AND new_supplier_request.user_id = internal_users.user_id AND requestee_manager = '$user'";
$result = $conn->query($sql34);
For some reason this works fine if the last name does not contain an apostrophe, but because this managers last name is O'Brien for some reason when i check in my query it is failing because it is having difficulty reading the apostrophe in the name, if i change henry's last name to something like James then it works. can someone please explain what i am doing wrong? Thanks
You should consider using PDO's prepared statements with bound parameters.
This way, your requests would be safer and a lots of problem with string parameters should be solved.
$query = $pdo->prepare('
select *
from new_supplier_request, internal_users
where new_supplier_request.status <> :status
and new_supplier_request.action_taken = :action_taken
AND new_supplier_request.user_id = internal_users.user_id
AND requestee_manager = :user
');
$query->bindValue(':status', 'complete');
$query->bindValue(':action_taken', 'none');
$query->bindValue(':user', $user);
$query->execute();
$results = $query->fetchAll();
Check this one:
$_SESSION['username'] = mysqli_real_escape_string($conn, internal_users.user_first_name);
$_SESSION['username2'] = mysqli_real_escape_string($conn, internal_users.user_last_name);
Pass $conn->real_escape_string($user) instead of $user in the query. You should NEVER use variable values directly in the query without enforcing a type or escaping them as you will leave the code vulnerable to SQL injection attacks.

Check two tables in one query

I have the following function:
function login_check($email, $password)
{
$email = mysql_real_escape_string($email);
$password = md5($password);
$login_query = mysql_query("SELECT COUNT(`id`) as `count`, `id` FROM `table_name` WHERE `email`='$email' AND `password`='$password'");
return (mysql_result($login_query, 0) == 1) ? mysql_result($login_query, 0, 'id') : mysql_error();
}
I want it to check if the user login is correct in two different tables not only one since I've made another table for users who have authenticated their twitter account with my site.
You'd be better off with a single table that has an "authenticated with Twitter" flag but you can check both with something like this:
select exists(
select 1 from table_name where email = '$email' and password = '$password'
union
select 1 from twitter_table where email = '$email' and password = '$password'
)
MySQL will give you a one (AKA true) if at least one of the tables has what you're looking for and a zero (AKA false) if neither has a match.
Using the select exists(select 1...) trick will also be faster than counting as the database only needs to find one match or check the indexes to know that there are no matches before it returns from the query.
You could create an union view of both tables:
CREATE VIEW combined_accounts AS
(SELECT id, twitter_mail AS mail, password FROM twitter_accounts)
UNION
(SELECT id, mail, password FROM my_accounts);

MYSQL>PHP - Trouble with a query relating to function that checks if a table contains a row of user details

I am having trouble with a function that checks if a set of user entered info (username and password) exists within either of the two possible tables where this information is stored.
The first table is the users table. It contains the first set of specific user information.
The last table is the listings table. It contains the second set of specific user information.
I have basically modified my original code to include the new listings table, and hence the trouble coming from within that task. The old code basically counted the number of results in the users table, if the result was greater than 0, then the function returned true, else false.
Now I have been stuck on the best way to go about adding another table to the query, and function. So I have been playing around with a union.
This was the original query:
SELECT COUNT(*) FROM users
WHERE id='$accNum' AND password='$password'
This returned a count of either 0 or 1 based on the info stored in the users table.
This is how I have reworked the query to include a count of the additional listings table:
SELECT count . *
FROM (
SELECT COUNT( * )
FROM users
WHERE id = '$accNum'
AND PASSWORD = '$password'
UNION (
SELECT COUNT( * )
FROM listings
WHERE id = '$accNum'
AND PASSWORD = '$password'
)
)count
This returned a result set of two rows, the first relating to the users table, and the second relating to the listings table. Then a column called COUNT (*) that contained the result count. This is the result set that I see within php myadmin.
Now this is the function:
function databaseContainsUser($accNum, $password)
{
include $_SERVER['DOCUMENT_ROOT'] . '/../../includes/db.inc.php';
$accNum = mysqli_real_escape_string($link, $accNum);
$password = mysqli_real_escape_string($link, $password);
$sql = "SELECT count . *
FROM (
SELECT COUNT( * )
FROM users
WHERE id = '$accNum'
AND PASSWORD = '$password'
UNION (
SELECT COUNT( * )
FROM listings
WHERE id = '$accNum'
AND PASSWORD = '$password'
)
)count
";
$result = mysqli_query($link, $sql);
if (!$result)
{
$error = 'Error searching for user.';
include 'error.html.php';
exit();
}
$row = mysqli_fetch_array($result);
if ($row[0] > 0)
{
return TRUE;
}
else
{
return FALSE;
}
}
The problem that I have, is trying to work out how exactly to check the results to ascertain if the given log in credentials are valid.
I tried this: if (($row[0] > 0) || ($row[0] > 0)) But a var dump on $row showed that only the first row (count of users table) was being added to the array.
So I decided that this was complicated, and a long way to the final result.
So I tried selecting only the id column of the result as in:
...
`COUNT( * )` to `id`
...
$data = mysql_query($sql);
$num_sql = mysql_num_rows($data);
if ($num_sql > 0)
...
But this did not work out for me either.
But in either instance, my hours of trial and error have provided me with no success... So I've decided to seek help from the knowledgeable members of Stack Overflow!
So my question is this, what would be a logical way of going about this task? I am looking for any suggestions, or positive input what so ever here.
As I am fairly new to dabbling with PHP and mysql, if you would like to provide some code to explain your suggestions or input on the matter, it would more than likely help me to better understand the answer.
If you are checking existence only try doing this that way:
select case when
exists (SELECT 1 FROM users WHERE id = '$accNum' AND PASSWORD = '$password') or
exists (SELECT 1 FROM listings WHERE id = '$accNum' AND PASSWORD = '$password')
then 1 else 0
end as itDoesExist
It returns always one row with one column with 1 when record exists in at last one table (else 0).
Do not use count to check whether some specific record/-s exist/-s in table, it's usually slower than simple exists.
Looks like you're going to get two rows in the result no matter what. Try this:
$sql = "SELECT id,password
FROM users
WHERE id = '$accNum' AND password = '$password'
UNION
SELECT id,password
FROM listings
WHERE id = '$accNum' AND password = '$password'
";
Now you can just check mysql_num_rows() to see if there's a match in either of the tables.
There are a couple of ways to go about this; if we are to stick with the approach you started with; you can simplify the query to:
$sql = "SELECT COUNT(1) FROM users
WHERE id = '$accNum'
AND PASSWORD = '$password'
UNION (SELECT COUNT(1) FROM listings
WHERE id = '$accNum'
AND PASSWORD = '$password')";
The reason you are only seeing one result, is because thats the way mysql_fetch_array() works, try doing this to get all results:
while ($row = mysql_fetch_array($result)) {
$data[] = $row;
}
var_dump($data);
Now you should have both values in there to validate with your conditional statements.

adding up tables in mysql

Hello I have a table with 11 in and about 7 tables with 1 in
Each has 2 column username and clicks. The problem is that i have to add up all the clicks were username = username Is there anyway i can do that ?
I'm using
$result1233 = mysql_query("SELECT * FROM urls_non_loggedin WHERE username='$_SESSION[username]'");
$num_row3s = mysql_num_rows($result1233);
But I want to add up all the clicks "the column name " where username = $_SESSION[username]
If you get what I mean ?
So there is a table with 2 columns clicks and username I want to grab all the numbers in clicks and add them up were username = usersname
You can use the SQL SUM operator. Like this:
SELECT username, SUM(clicks) As number_of_clicks FROM urls_non_loggedin WHERE username='$_SESSION[username]' GROUP BY username
Although you should be careful from passing variables into your queries that you have not sanitized.
EDIT: I replaced * with username in accordance to the comment from the moderator

how to print out a username and user age based on session login

i am fairly new to php. I am trying to print out the username and age based on the user session login, and cant seem to figure it out.
I have two separate table, one for login and another that contains the users info.
user table id-> 1 | logon -> shawn#aol.com | passwrd -> somthing
usersinfo id-> 1 | logon ->shawn#aol.com | username -> mathewkng1 | age -> 23
i can print out the session login using $_SESSION['logon'], this will give shawn#aol.com
what i want to do is instead of printing out shawn#aol.com i want to print out mathewkng1, age 23.
i tried,
SELECT users.*, usersinfo.* FROM users, userinfo WHERE users.logon = userinfo.logon
$logon = session_start();
if($_SESSION['logon']){
while($rows = mysql_fetch_array($user )){
$username = $rows['username '];
$age= $rows['age'];
}
echo " .$username." <br> ".$age." ";
}
i get the following error $username and $age not defined.
First advice is not to relay on the logon as a key for the second table. Rather use a field id_user instead of logon an id in the userinfo table.
then you can change also the select to
Select * from users join userinfo on users.id = userinfo.id_users
then you have an typo in
$username = $rows['username '];
i don't see where you do $_SESSION['logon'] and what you add there but i guess that it is an ID of that users table, so you should add that to the select up there.
$username = $rows['username '];
There is a space within the string behind username. I guess that shouldn't be there. Also, I cannot see if these tables contain an age. If $username is not defined, it might be because there is no record returned. Assumingly there is an error in your query (could by a Duplicate Fieldname error because both returned tables will contain the same logon field), but there could also be an error in the way you execute the query.
Please try these suggestions and check for the result of mysql_query and mysql_fetch_* to see if an error occurred. If mysql_query returns false (check using the === operator), get the result of mysql_error() to see what the exact error is.
Post that error and a little more code if you need more help.
Looking at your table structure, you don't need the join.
This sould be sufficient:
SELECT * from usersinfo where logon = 'shawn#aol.com'
session_start();
if($_SESSION['logon'])
{
$query = "SELECT * FROM usersinfo WHERE logon=" . $_SESSION['logon']
$res = mysql_query($user, $sqlConnection)
while($row = mysql_fetch_array($res))
{
$username = $row['username'];
$age= $row['age'];
}
echo $username ." <br /> ".$age;
}

Categories