0

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.'');
Mat
  • 6,236
  • 9
  • 42
  • 55
  • 2
    No need to use leading, intermediate, or trailing concatenation with empty strings; `$first_name.$lastname` or `$first_name.'.'.$lastname` suffices. Or use `"$first_name$lastname"` and `"$first_name.$lastname"` instead. – Gumbo Oct 07 '12 at 10:54
  • you're right... sorry I'm tired....;-)) – Mat Oct 07 '12 at 11:00

8 Answers8

2

$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.

venkatKA
  • 2,399
  • 1
  • 18
  • 22
  • @mattia - You still have a serious potential problem that can lead to duplicates. See [my answer](http://stackoverflow.com/a/12768768/1012053) – dbenham Oct 07 '12 at 14:14
  • @mattia The odds of what dbenham says occurring is too low. But considering it is good indeed. – venkatKA Oct 07 '12 at 14:18
2

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

Community
  • 1
  • 1
hol
  • 8,255
  • 5
  • 33
  • 59
  • yes but if there is only one user, the result of the string would null... can you please explain looking at my code... thanks – Mat Oct 07 '12 at 12:16
  • Oh! So, someone did an SQLFiddle after all... I remember reading a question about it here a couple of months ago. – Alix Axel Oct 07 '12 at 12:16
  • 1
    Agree. You would then check against null and make it number 1. But the accepted solution is the best for your problem. You may want to check that a user does not call his last name "Smith.3" or something like this. Then you would get maybe a duplicate key at one point. That is why I thought is is a save way to check for the maximum number. – hol Oct 07 '12 at 20:27
  • @hol thanks, as I said... I fetch this info from facebook... I wanted to use their username but for some silly reason I wasn't able to get it requesting {"name":"username"}... – Mat Oct 08 '12 at 19:08
1

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:

  1. START TRANSACTION

  2. SELECT FOR UPDATE to make sure only one person can get the count of a particular username at a given time

  3. INSERT your new user

  4. COMMIT your transaction.

See Select for update for more information.

dbenham
  • 127,446
  • 28
  • 251
  • 390
  • +1...thanks for pointing that out. I use that code only for fb registration and I think that it's really unlikely that a user with the same name and last name register at the same time. – Mat Oct 08 '12 at 01:33
0

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

Shehabic
  • 6,787
  • 9
  • 52
  • 93
0

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

Praveen Kumar Purushothaman
  • 164,888
  • 24
  • 203
  • 252
  • The problem with this is that this SQL will also cover the username as praveen.kumar123 which is different from praveen.kumar or praveen.kumar.xxx. – sarcastyx Oct 07 '12 at 11:07
0

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.

Clodoaldo Neto
  • 118,695
  • 26
  • 233
  • 260
0

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.

Jack Brown
  • 84
  • 8
-1

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++
  }
}
JvdBerg
  • 21,777
  • 8
  • 38
  • 55
  • $temp_username .= $first_name . $last_name . '.' . $i; Would you not get enormous usernames after just two iterations? Mind the .= –  Oct 07 '12 at 11:44
  • You should do the query all at once instead of multiple queries. This approach will have a much higher performance overhead. – Nathan Wall Oct 07 '12 at 11:55