Random UserID in PHP and MySQL - php

I have a PHP project in which i want to create and assign random User IDs to my customers when they sign-up in to our company's second website. It must be random generated user Ids that must not duplicate in our MySQL Database. User IDs should be like XYZ654986, HPR654986, WRU934765, SYW365824.
How can I create , check and insert user IDs like these ?

First of all, while random IDs for public services (like YouTube Video IDs) in the URL are useful, internally you shouldn't use random IDs. An ID which is used only backend could be made with AutoIncrement.
Nevertheless, you could have specific reasons to use a random ID.
First, you need to create a random code.
This creates a random code with the length 10 (you can change the length by changing $i<10):
$char = "0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z";
$chars = explode ( ",", $char );
$code = "";
for ($i=0; $i<10; $i++) {
$random = rand(0, (count($chars)-1));
$code .= $chars[$random];
}
Then, you need to check whether the code is already used or not.
If you have the codes in your MySQL database, you can use this:
$EveryID = array();
$statement = $pdo->prepare("SELECT ID FROM MyDatabase");
$statement->execute();
while($row = $statement->fetch()) {
array_push($EveryID, $row["ID"]);
}
$IDexists = false;
for ($i=0; $iy<count($EveryID), $i++) {
if ($EveryID[$i] == $code) {
$IDexists = true;
break;
}
}
And if $IDexists is true, you need to do the same (generate new code, etc.). I would do this with a while loop.
If $IDexists is false, you have a new unused code in $code. Then, you need to insert this code with other user information (e.g. name).
Here the full code:
$IDexists = true;
while ($IDexists == true) {
$char = "0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z";
$chars = explode ( ",", $char );
$code = "";
for ($i=0; $i<10; $i++) {
$random = rand(0, (count($chars)-1));
$code .= $chars[$random];
}
$EveryID = array();
$statement = $pdo->prepare("SELECT ID FROM MyDatabase");
$statement->execute();
while($row = $statement->fetch()) {
array_push($EveryID, $row["ID"]);
}
$IDexists = false;
for ($i=0; $iy<count($EveryID), $i++) {
if ($EveryID[$i] == $code) {
$IDexists = true;
break;
}
}
}
$statement = $pdo->prepare("INSERT INTO MyDatabase (ID, name, something) VALUES (:ID, :name, :sth)");
$statement->execute(array("ID" => $code, "Name" => $name, "sth" => $Something));
Requirements for this method are that you've made a PDO connection with your database at the beginning of your .php file. If you haven't made that, just google "php MySQL PDO" and look at a tutorial.
At last, I just want to say: If you use the IDs internally (that means the IDs aren't in the URL to the user's site), I'd recommend to make an Auto-Increment ID (that means, the first user has the ID 1, the second 2, etc.). You can set the ID in PhpMyAdmin as primary and check auto-Incrediment to do this (there are tutorials for this, too). That's way easier and for most use-cases more practical (but only if the IDs aren't in the URL on any place on your site).
Edit: Instead of
while($row = $statement->fetch()) {
array_push($EveryID, $row["ID"]);
}
you can use
$EveryID = $statement->fetchAll();

Related

How to generate unique username - PHP

I have strings of usernames in array . I want to generate a unique string of username which do not exits in array.(probably with some numbers following the username)
How do I achieve this?
I have summarize the code:
function generate_unique_username(){
$firstname = "james";//data coming from user
$lastname = "oduro";//data coming from user
$new_username = $firstname.$lastname;
$usersnames = array("james39","oduro32","kwame93","elvisasante","frimpong32","edward32","jamesoduro");
//Loop through ARRAY usernames and check elements against VAR $new_username
if (in_array($new_username, $usersnames)) {
//generate new username which is not inside array
//the new generated string should also be check against array to ensure is doens not exit.
}else{
return $new_username;
}
}
Thank you.
Generating username from the stored array is not a good practice, I would suggest you to use the database.
If you are using the database instead of the array, you can use the best method to generate the unique username as following:
function generate_unique_username(){
$firstname = "james";//data coming from user
$lastname = "oduro";//data coming from user
$new_username = $firstname.$lastname;
/* Note: writing here pseudo sql code, replace with the actual php mysql query syntax */
$query = "SELECT COUNT(id) as user_count FROM user WHERE username like '%".$new_username."%'";
$result = mysql_query($query);
$count = $result['user_count'];
if(!empty($count)) {
$new_username = $new_username . $count;
}
return $new_username;
}
I think in this case you should first off try and assign cooler user names to the users then when that fails you go for a number suffix. This is an approach I may use. You may need to change the code to your more preferred and secured mysqli call like using the PDO or MySQLI prepared statement.
//function that will be used to figure out if the user name is available or not
function isAvailable($userName){
global $mysqli;
$result = $mysqli->query("SELECT id FROM users WHERE user_name='$userName'") or die($mysqli->error());
// We know username exists if the rows returned are more than 0
if ( $result->num_rows > 0 ) {
//echo 'User with this username already exists!';
return false;
}else{
return true;
}
}
function generate_unique_username($firstname, $lastname, $id){
$userNamesList = array();
$firstChar = str_split($firstname, 1)[0];
$firstTwoChar = str_split($firstname, 2)[0];
/**
* an array of numbers that may be used as suffix for the user names index 0 would be the year
* and index 1, 2 and 3 would be month, day and hour respectively.
*/
$numSufix = explode('-', date('Y-m-d-H'));
// create an array of nice possible user names from the first name and last name
array_push($userNamesList,
$firstname, //james
$lastname, // oduro
$firstname.$lastname, //jamesoduro
$firstname.'.'.$lastname, //james.oduro
$firstname.'-'.$lastname, //james-oduro
$firstChar.$lastname, //joduro
$firstTwoChar.$lastname, //jaoduro,
$firstname.$numSufix[0], //james2019
$firstname.$numSufix[1], //james12 i.e the month of reg
$firstname.$numSufix[2], //james28 i.e the day of reg
$firstname.$numSufix[3] //james13 i.e the hour of day of reg
);
$isAvailable = false; //initialize available with false
$index = 0;
$maxIndex = count($userNamesList) - 1;
// loop through all the userNameList and find the one that is available
do {
$availableUserName = $userNamesList[$index];
$isAvailable = isAvailable($availableUserName);
$limit = $index >= $maxIndex;
$index += 1;
if($limit){
break;
}
} while (!$isAvailable );
// if all of them is not available concatenate the first name with the user unique id from the database
// Since no two rows can have the same id. this will sure give a unique username
if(!$isAvailable){
return $firstname.$userId;
}
return $availableUserName;
}
//Get the unique user id from your database, for now let's go with 30
$userId = 30;
echo generate_unique_username('john', 'oduro', $userId);
Also, it would be nice to provide a fallback feature where the user can change their user name to any other unique value, in case they do not like the auto-generated value.

How to generate voucher code, check the DB if it's unique, generate new one if not

I'm having a loop issue in my script. I've spent a lot of time trying to fix it but I still don't know how to fix the problem. I need your help and suggestions regarding this.
My goal is to create a voucher code generator script where the user enters the number of voucher codes to be generated.
Then, the script will generate the required number of vouchers in the database table, and each voucher code will be checked if it is unique - if not, a new voucher code will be generated and the script will proceed until all vouchers are saved.
The problem is that if voucher already exists in the DB, a new one needs to be generated. This newly generated voucher code needs to be checked again if it's already in the DB, if it's unique it will be saved to the DB and if not, the process will go on again. This is where the loop problem lies. I hope you get what i mean.
By the way, the voucher code is in this format: XXXX-XXXX-XXXX (uppercase letters only)
Here's the current codes that I have:
include 'conn.php';
function WriteCSV($flname,$values) {
$Filename = "./vouchers/$flname.csv";
$fh = fopen($Filename, 'a') or die("can't open file");
$filecontent = $values;
$filecontent .= PHP_EOL;
fwrite($fh,$filecontent);
fclose($fh);
}
function generateCode(){
$chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$res = "";
for ($i = 0; $i < 4; $i++) {
$res .= $chars[mt_rand(0, strlen($chars)-1)];
}
return $res;
}
function generateVCode(){
$c1 = generateCode();
$c2 = generateCode();
$c3 = generateCode();
$voucher = "$c1-$c2-$c3";
return $voucher;
}
function searchDB($con, $voucher){
$rs = mysqli_query($con,"SELECT count(*) AS cnt FROM vouchers WHERE vouchercode = '$voucher'");
$row = mysqli_fetch_assoc($rs);
$cnt = $row['cnt'];
if($cnt > 0){
return '1';
} else {
return '0';
}
}
function checkVoucher($con, $voucher, $vsource, $expiry, $today, $vnum, $vprice){
$dbres = searchDB($con, $voucher);
if($dbres == '1'){ //voucher found in db
$val = '0';
$voucher = generateVCode(); //generate a new voucher
checkVoucher($con, $voucher, $vsource, $expiry, $today, $vnum, $vprice); //repeat the process
} else { // voucher is unique
mysqli_query($con, "INSERT INTO vouchers (vouchercode, source, price, expires, generated) VALUES ('$voucher', '$vsource', '$vprice', '$expiry', '$today')");
$flname = "$vsource - ".date('d M Y')." ($vnum vouchers)";
WriteCSV($flname,$voucher);
$val = '1';
}
return $val;
}
$vnum = $_POST['vouchernum'];
$vsource = $_POST['source'];
$vprice = $_POST['amt'];
$expdate = $_POST['expdate'];
$expiry = $_POST['voucherexpiry'];
$today = date('Y-m-d');
$expconv = date('Y-m-d',strtotime("$expiry"));
$expfive = date('Y-m-d',strtotime("$expiry +5 years"));
for ($x = 1; $x <= $vnum; $x++) {
$vouchercode = generateVCode();
if($expdate == "no"){
$expiry = $expfive;
} else {
$expiry = $expconv;
}
do {
$result = checkVoucher($con, $vouchercode, $vsource, $expiry, $today, $vnum, $vprice);
} while ($result != '1');
header("location: index.php?s=1");
}
By the way, if you have suggestions on how to generate the voucher codes easier, please feel free to share.
I'm thinking the issue/problem here is on either the do-while statement or the checkVoucher() function.
I'd really appreciate you help and suggestions. Thanks.
I would go completely easier. Set the voucher column in your table to unique. Generate a code PHP side, do your insert, in the error callback function call to generate a new code.
Basically, this will self loop until inserted. Then in your success callback add it to your display. All of this is wrapped in a while loop. Once you get your 5, break the loop.
As far as generating a random string with minimal chance of a repeat, check this thread: PHP random string generator
I would generate the full length string and then just add your hyphens.
Using this approach to generate random unique data, the amount of processing required increases proportionally as more and more codes are generated.
What I would do instead is:
Generate a whole bunch of values (lets say a few thousand) values sequentially and store them in a redis/SQL database
Use a random number to index that record in the database, and remove the record from the table once it has been used
This reduces the processing required greatly, and also gives you a pre determined pool of voucher codes which could be useful for other purposes in your application
Mysql unique constraint may be the solution you are looking for.it ensures a value is always unique. It is like primary key. but unlike primary key a table can have multiple unique values.
Here is the link to w3school explaining this
www.w3schools.com/sql/sql_unique.asp
The best part is it will genrerate a Duplicate Entry error when adding a duplicate entry. so you can use it to add data to csv . add it only when you have no error.
But make sure the unique value is not null.

How to avoid exponential slowdown in PHP/MYSQL?

I'm the owner of an online browser based game that has around 300 players signed up. I've written a script to detect cheaters, but the issue is that the number of queries in said script will grow exponentially.
It works like this:
Send a query that gets player's information.
Inside of the query, run another query that gets the information of every player.
So basically I am running a query that gets every player's name and information, and inside of that query I run another query to get the information from every other player besides themself. I use this to compare and delete cheaters.
The issue is, since I have 300 players, I have to run 300 queries per player. That's 90,000 queries. If I reach 1,000 players, it would be 1,000,000 queries. There has to be a better way to do this.
My code:
<?php
require '../connect.php';
$rulerinfo = $conn->query("SELECT id, rulername, nationname, alliance, email, dateregister, user_agent, lastseen, password FROM players");
while ($rulerinfo2 = $rulerinfo->fetch_assoc()) {
$id = $rulerinfo2['id'];
$rulername = $rulerinfo2['rulername'];
$nationname = $rulerinfo2['nationname'];
$alliance = $rulerinfo2['alliance'];
$email = $rulerinfo2['email'];
$dateregister = $rulerinfo2['dateregister'];
$useragent = $rulerinfo2['user_agent'];
$lastseen = $rulerinfo2['lastseen'];
$password = $rulerinfo2['password'];
$playerinfo = $conn->query("SELECT id, rulername, nationname, alliance, email, dateregister, user_agent, lastseen, password FROM players WHERE id != '$id'");
while ($playerinfo2 = $playerinfo->fetch_assoc()) {
$id2 = $playerinfo2['id'];
$rulername2 = $playerinfo2['rulername'];
$nationname2 = $playerinfo2['nationname'];
$alliance2 = $playerinfo2['alliance'];
$email2 = $playerinfo2['email'];
$dateregister2 = $playerinfo2['dateregister'];
$useragent2 = $playerinfo2['user_agent'];
$lastseen2 = $playerinfo2['lastseen'];
$password2 = $playerinfo2['password'];
$rulerdistance = levenshtein($rulername, $rulername2);
$nationdistance = levenshtein($nationname, $nationname2);
$emaildistance = levenshtein($email, $email2);
$agentdistance = levenshtein($useragent, $useragent2) / 2;
$totaldistance = $rulerdistance + $nationdistance + $emaildistance + $agentdistance;
if ($password == $password2) {
$totaldistance = $totaldistance - 20;
}
if ($totaldistance < 0) {
$totaldistance = 0;
}
}
}
?>
You should only do the query once, put it in an array and work with it from there. I don't see the need to make almost the same query twice. Loop in your array a second time and just check if the id is not the same as the current.
$res = $conn->query("SELECT id, rulername, nationname, alliance, email, dateregister, user_agent, lastseen, password FROM players");
$array=array();
while ($row = $res->fetch_assoc()) {
$array[] = $row;
}
for($i=0; $i<count($array);$i++) {
for($j=0; $j<count($array); $j++) {
if ($i != $j) {
// Call your functions
$rulerdistance = levenshtein($array[$i]['rulername'], $array[$j]['rulername']);
...
}
}
}

Generate a Unique ID using PHP and MYSQL

Hi I am creating a system that processes and ID and a UID, The UID we are generating randomly but I am a little stuck, I need to always generate a UID that does not currently exist in the db as the field is a unique field used on the front end so as not to expose the real ID.
So to recap, I am trying to generate a unique id that does not currently exist in the DB the part I haven't got working is the cross checking in the db so it sometimes will give a number that already exists in the db even though it shouldn't thanks in advance.
This is my code so far:
function uniqueID($table)
{
$db = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
$possible = '1234567890';
$code = '';
$characters = mt_rand(7,14);
$i = 0;
while($i < $characters)
{
$code .= substr($possible, mt_rand(0, strlen($possible)-1), 1);
$i++;
}
$result = $db->query('
SELECT uniqueID
FROM '.$table.'
WHERE uniqueID = "'.$code.'"
LIMIT 1
');
$totalRows = $result->num_rows;
if(!$result)
{
return $db->error;
}
else
{
if($totalRows > 0)
{
return uniqueID($table);
}
else
{
return $code;
}
}
}
http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_uuid
To generate unic UID you can use time, i think it was a very small chanse that records will be added in the same second, with two random data.
write some function which return it to you like that
function generate_uid(){
return md5(mktime()."-".rand()."-".rand());
}
In PHP there's a function called uniqid()
http://php.net/manual/en/function.uniqid.php
I could talk about generating ids, like the others did, but this is not your question.
Your query seems fine. If it returns 0 rows but you seem to find the code in the database, then most likely it only looks the same, but actually isn't. It could be padded by whitespace.
One way to solve this is by selecting the last row of your user database and have your script to check for the id field (you can achieve this by performing a select ordering by ID in descendent mode) then you can use that info for randomize numbers greater than that ID.
EDIT
$result = $db->query('
SELECT uniqueID
FROM '.$table.'
');
$already_in_database = array();
while ($row = mysql_fetch_array($result)){
$already_in_database[] = $row['UID'];
}
$new = rand(0,$some_max_value);
while(in_array($new,$already_in_database)){
$new = rand(0,$some_max_value);
}
I figured out what the problem was already, As I mentioned to everyone the code generation was not the issue! The issue was that the cross check was not working correctly. So all I did was removed this loop
while($i < $characters)
{
$code .= substr($possible, mt_rand(0, strlen($possible)-1), 1);
$i++;
}
As this was causing my unique ID to end up wrong.

php sql find and insert in empty slot

I have a game script thing set up, and when it creates a new character I want it to find an empty address for that players house.
The two relevant table fields it inserts are 'city' and 'number'. The 'city' is a random number out of 10, and the 'number' can be 1-250.
What it needs to do though is make sure there's not already an entry with the 2 random numbers it finds in the 'HOUSES' table, and if there is, then change the numbers. Repeat until it finds an 'address' not in use, then insert it.
I have a method set up to do this, but I know it's shoddy- there's probably some more logical and easier way. Any ideas?
UPDATE
Here's my current code:
$found = 0;
while ($found == 0) {
$num = (rand()%250)+1; $city = (rand()%10)+1;
$sql_result2 = mysql_query("SELECT * FROM houses WHERE city='$city' AND number='$num'", $db);
if (mysql_num_rows($sql_result2) == 0) { $found = 1; }
}
You can either do this in PHP as you do or by using a MySQL trigger.
If you stick to the PHP way, then instead of generating a number every time, do something like this
$found = 0;
$cityarr = array();
$numberarr = array();
//create the cityarr
for($i=1; $i<=10;$i++)
$cityarr[] = i;
//create the numberarr
for($i=1; $i<=250;$i++)
$numberarr[] = i;
//shuffle the arrays
shuffle($cityarr);
shuffle($numberarr);
//iterate until you find n unused one
foreach($cityarr as $city) {
foreach($numberarr as $num) {
$sql_result2 = mysql_query("SELECT * FROM houses
WHERE city='$city' AND number='$num'", $db);
if (mysql_num_rows($sql_result2) == 0) {
$found = 1;
break;
}
}
if($found) break;
}
this way you don't check the same value more than once, and you still check randomly.
But you should really consider fetching all your records before the loops, so you only have one query. That would also increase the performance a lot.
like
$taken = array();
for($i=1; $i<=10;$i++)
$taken[i] = array();
$records = mysql_query("SELECT * FROM houses", $db);
while($rec = mysql_fetch_assoc($records)) {
$taken[$rec['city']][] = $rec['number'];
}
for($i=1; $i<=10;$i++)
$cityarr[] = i;
for($i=1; $i<=250;$i++)
$numberarr[] = i;
foreach($cityarr as $city) {
foreach($numberarr as $num) {
if(in_array($num, $taken[]) {
$cityNotTaken = $city;
$numberNotTaken = $number;
$found = 1;
break;
}
}
if($found) break;
}
echo 'City ' . $cityNotTaken . ' number ' . $numberNotTaken . ' is not taken!';
I would go with this method :-)
Doing it the way you say can cause problems when there is only a couple (or even 1 left). It could take ages for the script to find an empty house.
What I recommend doing is insert all 2500 records in the database (combo 1-10 with 1-250) and mark with it if it's empty or not (or create a combo table with user <> house) and match it on that.
With MySQL you can select a random entry from the database witch is empty within no-time!
Because it's only 2500 records, you can do ORDER BY RAND() LIMIT 1 to get a random row. I don't recommend this when you have much more records.

Categories