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.
Related
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();
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.
I am a bit stuck with my code.
I am practising and would like to achive the following.
Before an user sign up, i want to check the users username exists, if exists than increase the name by one.
So my logic works like this. User gives his/her first and last name, generates an username based on that.
function
function unique_name($first_name, $last_name) {
$username = strtolower($first_name.'.'.$last_name)
$check = mysqL_query(" SELECT username WHERE username = '".$username."' ");
if(count($check == 1)) {
$i = 2;
foreach($check as $user) {
return $user['username'].$i;
$i++;
}
} else {
return $username;
}
}
$username = unique_name($_POST['first_name'], $_POST['last_name']);
// saveing the increased username
So actually the script should check if the generated unique username exsits if exsits increase, and encrease it even if it exsits with a number
example
Tom Anderson signs up, username will be tom.anderson, saved as tom anderson
Second Tom Anderson signs up, username will be tom.anderson, it already exists, save the new one as tom.anderson2.
The third user signs up he is tom anderson too, username tom.anderson* exsits twice, increase to tom.anderson3.
So i dont have a problem checking if the user exsits and saveing it, my problem is, how to increase every username if exist?
I am not asking anybody to write this for me i am nust looking for a hint
Thank you
EDIT
Thank you for the replies but this does not work
if(count($check) == 1) {
$i = 2;
foreach($check as $user) {
return $user['username'].count($check);
$i++;
}
} else {
return $username;
}
This only check the username with out a number, so if username tom.anderson exists it increases to tom.anderson1 but if tom.anderson1 exists too it wont increase to tom.anderson2
Can you have something that just appends the count of the rows returned, unless it's 0?
if(count($check) > 0) {
return $user['username'].count($check);
} else {
return $username;
}
change the SQL:
" SELECT username WHERE username LIKE '".$username."%' "
Try to give like this
if(count($check) == 1) {
$i = 2;
foreach($check as $user) {
return $user['username'].count($check);
$i++;
}
} else {
return $username;
}
You may add new field into user table, and called it base_username.
Them fetch count rows with given username, and increase every username on count found
Something like this
`function unique_name($first_name, $last_name) {
$unique_name = $username = strtolower($first_name.'.'.$last_name)
$cnt = get_row(" SELECT COUNT(*) from `users` WHERE base_username = '".$username."' LIMIT 1 ");
if($cnt){
$unique_name = $username . $cnt + 1;
}
return $unique_name;
}`
I'm a little confused about breaking out and continuing out of loops etc. I have 2 SQL queries that match user priveleges against the user's actual priveleges with the new ones put it. However, if some of the new priveleges match the one the user has, I want to skip the SQL insert and move on to the next one:
public static function insertPriveleges($user_id,$priveleges)
{
$ex = explode(",",$priveleges); // separated by commas
if(count($ex)>0)
{
$x = false;
foreach($ex as $i => $priv)
{
$check_user = mysql_query("SELECT * FROM users_access_codes WHERE user_id='$user_id'") or die(mysql_error()); // get user's current priveleges
while($check_data = mysql_fetch_array($check_user))
{
if($check_data['access_code']!=$priv)
{
//if it doesn't match, insert
$sql = "INSERT INTO users_access_codes (uaID,user_id,access_code) VALUES (NULL,'".$user_id."','$priv')";
}
}
}
}
}
I almost never have a situation that needs to match more than two things in loops. I need to make sure I don't end up with double priveleges for that user. I know there must be a 'continue' statement somewhere in the inner loop, but not sure where.
After your INSERT statement, you can add continue 2 to bring you back to the top of your foreach ($ex as .... You can also use break; in this case because there's nothing after your inner while.
However, you don't actually need it if you do it differently. Instead of reading the table for each privilege, just read all of them once and them compare.
This code will get all privileges from the database and then only inserts those that are missing, based on $ex; it uses array_diff() to calculate the difference between the two.
public static function insertPriveleges($user_id, $priveleges)
{
$ex = explode(",", $priveleges); // separated by commas
if (count($ex) > 0) {
// get user's current priveleges
$check_user = mysql_query("SELECT * FROM users_access_codes
WHERE user_id='$user_id'") or die(mysql_error());
$actual = array();
while ($row = mysql_fetch_array($check_user)) {
$actual[] = $row['access_code'];
}
foreach (array_diff($ex, $actual) as $priv) {
//if it doesn't match, insert
$sql = "INSERT INTO users_access_codes (uaID,user_id,access_code) VALUES (NULL,'".$user_id."','$priv')";
mysql_query($sql);
}
}
}
Btw, you could consider using INSERT IGNORE INTO because of race conditions, but because you're not checking the statement return value, it won't matter here :)
Simply add a break after the INSERT:
public static function insertPriveleges($user_id,$priveleges)
{
$ex = explode(",",$priveleges); // separated by commas
if(count($ex)>0)
{
$x = false;
foreach($ex as $i => $priv)
{
$check_user = mysql_query("SELECT * FROM users_access_codes WHERE user_id='$user_id'") or die(mysql_error()); // get user's current priveleges
while($check_data = mysql_fetch_array($check_user))
{
if($check_data['access_code']!=$priv)
{
//if it doesn't match, insert
$sql = "INSERT INTO users_access_codes (uaID,user_id,access_code) VALUES (NULL,'".$user_id."','$priv')";
break;
}
}
}
}
}
To be complete I would recommand the reading of the following link:
http://php.net/manual/en/faq.databases.php#faq.databases.mysql.deprecated
$this->db->select('secretsalt,session_id');
$getSaltAndSessionIDFromDb = $this->db->get_where('Client', array('email' =>$ClientEmail)); // generated via registration
$result = $getSaltAndSessionIDFromDb->result_array();
$saltFromDb = $result[0]['secretsalt'];
$saltedPasswordToVerify = $ClientPassword.$saltFromDb; // combine inputted pass + salt from the db
$isValidUser = $this->db->get_where('Client',array('email'=>$ClientEmail,'pass'=>$saltedPasswordToVerify)); // compare inputted pass + salt vs db entry.
// If [1] row found, login
if($isValidUser->num_rows() == 1 ){
// set the "Logged in" vars:
$loggedInValue = 1;
$this->db->set('loggedIn',$loggedInValue); // Set valid row loggedIn value = 1.
// Validate using the below model (loginfunctionmodel) that there is:
// 1. valid session_id
// 2. loggedIn=1
$this->load->model('pages/loginfunctionmodel');
$this->loginfunctionmodel->check_if_loggedin();
}
else{
// nothing at the moment
}
I want to get the value of secretsalt and use it in the above code where {{HERE}} is listed. How do I do so?
if($getSaltAndSessionIDFromDb->num_rows() ==1)
$result = $getSaltAndSessionIDFromDb->result_array();
$salt = $result[0]['secretsalt'];
$saltedPasswordToVerify = $ClientPassword.$salt;
That should work
$rs = $this->db->select('secretsalt,session_id')->from('tablename')->get();
$result = $rs->result_object();
Then use the result.
$saltedPasswordToVerify = $ClientPassword.$result->secretsalt;
If I have understood your question, that should work.