Generate unique user id in PHP - php

I am developing an app using Laravel which will have a functionality to register user.
I want to provide customized unique id to every user (ie: User_id = SM129).
Userid will have following features:
1) User id will be auto-generated while registering.
2) Auto-generated user id should be Check to a database for its uniqueness.
Currently, I am using following code to generated unique user id based on current date. but there is a chance of duplicity on a username with this. Please help
<?php
//creates a unique id for user id
echo "<br>";
$day = date('D');
$month = date('F');
$year = date('Y');
$fmonth = substr($month, 0, 1);
$fyear = substr($year, 2, 2);
$fday = substr($day, 0, 1);
$uniq = rand();
$funiq = substr($uniq, 0, 2);
$funiq1 = substr($uniq, 0, 1);
$joint= 'ST'.$fmonth.$fday.$funiq1.$fyear.$funiq ;
?>
<input type="text" name="username" value = "<?php echo $joint; ?>">

It looks like it's actually better if you were to implement UUID in your Laravel Application:
https://medium.com/#steveazz/setting-up-uuids-in-laravel-5-552412db2088
UUID is short for “universal unique identifier” which is a set of 36 characters, containing letters and numbers. Each set should be unique, with there only being a chance for repetition each 100 years, you can read more about it and check out some cool statistics here and here.
Also don't put a value on your input - generate the unique ID server side (either in your controller/model).
If you leave the unique value in the input, there's nothing stopping users from actually changing that value.

Related

How to insert ID +1 and get last id?

I want to insert id and + 1 insert the form fields into a MySQL table. I want to get the last id for the insert operation as the return value of my query but I have some problems with it.
this is my code for get last id.
function GenIDInv()
{
$CI = get_instance();
$CI->db->select('n_id');
$CI->db->from('sltax_notification_name');
$CI->db->order_by("n_id", "desc");
$query = $CI->db->get();
$result = $query->row();
if(!empty($result)){
$result = $result->n_id;
$rid = substr($result,6,9);
$id = $rid+1;
echo date('Ym') . sprintf("%'.03d\n",$id);
}
}
when i insert id it not +1
What i understood is that you want 201812001 to 201812002
Try this:
$rid = substr($result, 8, 1);
//echo $rid; // $rid should contains 1
$id = $rid+1;
Codeigniter documents: http://codeigniter.org.cn/user_guide/database/query_builder.html?highlight=max#CI_DB_query_builder::select_max
SELECT Max(n_id) FROM sltax_notification_name;
I make an assumption that your field n_id is compose like this : [YYYYMM][XXX] => [DATE][ID]
first question what happens if your id is greater than 999 ?
i will assumpt that you want to handle id greater than 999.
So now, the problem we need to resolve is how to add 1 to the id part, and keep it padded with 0 on the left.
You get your last id from database that's nice, it is probably a string.
The first thing we want to do is get the id part separate from date part.
$n_id = $result->n_id;
$id = substr($n_id, 6, strlen($n_id)) // we know the first 6 characters are part of the date and the rest is part of id
then we want to add one to $id
$id += 1; // that statement will cast our string to int
#Now we want to cast it to string and pad with 0 if needed
if (strlen($id) < 3) {
$id = str_pad($id, 3, '0', STR_PAD_LEFT);
}
Now, we just have to stick the piece together
$date = new Datetime();
$newN_id = $date->format('Ym').(string)$id

can not get the id by using the foreach() and $_POST[]

okay friends,
I have two tables
1st table: social_networks
2nd table: members_social_accounts
In the user control panel, I have a page contains a form where I list all the social networks; and in a front of each one of them there is an input text box.
When the member opens that page, he will see all the social networks listed, and if he previously added his account in any social network, then he will see it in the text box, otherwise, the text box will be empty. I used the following code to that:
$s = mysqli_query($link, "SELECT social_networks.network_id, social_networks.network_name, members_social_accounts.member_account FROM social_networks LEFT JOIN members_social_accounts ON social_networks.network_id = members_social_accounts.network_id AND members_social_accounts.member_id = '$member_id' ORDER BY social_networks.network_id");
while($i = mysqli_fetch_assoc($s)){
$network_id = $i['network_id'];
$network_name = $i['network_name'];
$member_account = $i['member_account'];
}
and the input box is:
<?=$network_name;?> = <input type="text" name="ids[<?=$network_id;?>]" id="<?=$network_id;?>" value="<?=$member_account;?>" /><br />
Now, what I am trying to do is when the user update the page (submit the form), I want the code to update the database by the following steps:
If the member (e.g. $member_id =1 ) has already added his account to that network (e.g. $network_id = 1) then, we will UPDATE the members_social_accounts table with the member network account (e.g. $member_account = 1111111111). So, I DO NOT add a new record for the same member_id and the same network_id but with different account value.
so, the database table will be something like this:
else if the member (e.g. $member_id=1) is adding a new account (e.g. $member_account = 2222222222) to a network (e.g. $network_id = 3), then I want to INSERT that to the members_social_accounts table as a new record, and the table will be for example like the following:
What I've tried so far is the following:
<?php
if(isset($_POST))
{
foreach($_POST['ids'] AS $ids)
{
$s = mysqli_query($link, "SELECT * FROM members_social_accounts WHERE network_id = '{$ids}' AND member_id = '$member_id'");
echo $n = mysqli_num_rows($s);
if($n == 1)
{
// UPDATE the members_social_accounts table
}
else
{
// INSERT a new record in members_social_accounts table
}
}
}
?>
but I have a problem which is that $_POST[ids] AS $ids is getting the member_account (e.g. aaaaaaaaaa and bbbbbbbbbb) instead getting the netword_id (e.g. 1 and 2). Therefore, I am not able to update or insert in the members_social_accounts table.
I appreciate your help in pointing what is wrong with my code or logic.
Thanks in advance
P.S. You can download a copy of the files and the database from this link:
sample files and db
This is due to the fact that the actual value of your input is the member_account field.
<input type="text" name="ids[<?=$network_id;?>]" id="<?=$network_id;?>" value="<?=$member_account;?>" />
Take a look at the value which has been assigned the return from $member_account variable.
You could just do:
<input type="hidden" name="nid" value="<?=$network_id;?>"/>
Then you can do $_POST['nid'] to get the real value of the network id.

Regarding unique username

I am dealing with a student portal in which i have to create a unique login username for students. I have their firstname, lastname and DOB in a csv file. I tried to create a unique username using these three params for uniqueness. But it is possible that DOB will be null so it may conflict.
Also some of students which are user of portal for one session i.e for ex: 2012-13 will have details in csv sheet of 2013-14 and if we use same format with any unique timestamp or unique id, for username generation than there will be two username of same user.
I need a solution from which i generate a unique username with available details also can check that a every student enters in database only one time and have only one username.
I hope i am clear with details if not than please give your comments i will improve it.
below is the code which i used to generate Username from csv data ,
Logic - USERNAME = 'first 3 letter of firstname' + 'DOB' + 'first 3 letter of lastname'
foreach($result as $file_data){
//loop throgh the data and find errors
//check the duplicate entry in the file
if(count($accepted)>0){
foreach($accepted as $accepted_user){
if(($file_data['First name'] == $accepted_user['First name']) && ($file_data['Last name'] == $accepted_user['Last name']) && ($file_data['DOB'] == $accepted_user['DOB'] )){
$rejected[]=array("error"=> $this->lang->line('duplicate_entry_in_file'),"line_number"=>$error_count);
}
}
}
// Generate username from Firstname , Lastname & DOB (if null than we add auto generated DOB)
if($file_data['First name']=='' || $file_data['Last name']==''){ // check if first_name last_name and date-of_birth is empty
$rejected[]=array("error"=> "First Name , Last Name not available","line_number"=>$error_count);
}else{
if($file_data['DOB']==''){
$dob=date('dmy',mktime(0,0,0,date("m"),date("d")+1,date("Y")-10)); //
$date_of_birth= $dob['4'].$dob['5']."-".$dob['2'].$dob['3']."-".$dob['0'].$dob['1'];
$dob_username= $dob['0'].$dob['1']."-".$dob['4'].$dob['3']."-".$dob['4'].$dob['5'];
}else{
$dob = $file_data['DOB'];
if(strlen($dob) == 5 ){
$year_of_birth=$dob['3'].$dob['4'];
if($year_of_birth < date('y')){
$date_of_birth= "20".$dob['3'].$dob['4']."-".$dob['1'].$dob['2']."-0".$dob['0'];
$dob_username= "0-".$dob['0']."-".$dob['1'].$dob['2']."20".$dob['3'].$dob['4'];
}elseif($year_of_birth > date('y')){
$date_of_birth= "19".$dob['3'].$dob['4']."-".$dob['1'].$dob['2']."-0".$dob['0'];
$dob_username= "0-".$dob['0']."-".$dob['2'].$dob['1']."19".$dob['3'].$dob['4'];
}
}elseif(strlen($dob) > 5 ){
$year_of_birth=$dob['4'].$dob['5'];
if($year_of_birth < date('y')){
$date_of_birth= "20".$dob['4'].$dob['5']."-".$dob['2'].$dob['3']."-".$dob['0'].$dob['1'];
$dob_username= $dob['0'].$dob['1']."-".$dob['2'].$dob['3']."-20".$dob['4'].$dob['5'];
}else{
$date_of_birth= "19".$dob['4'].$dob['5']."-".$dob['2'].$dob['3']."-".$dob['0'].$dob['1'];
$dob_username= $dob['0'].$dob['1']."-".$dob['2'].$dob['3']."-19".$dob['4'].$dob['5'];
}
}
}
$first_name=$file_data['First name'];
$last_name=$file_data['Last name'];
$dateOfBirth = str_replace("-", '', $dob_username);
if((strlen($last_name) < 3 ) && (strlen($first_name) < 3 ) ){
$username=$last_name.$dateOfBirth.$first_name;
}elseif(strlen($last_name) < 3 ){
// $username=$last_name.$dateOfBirth.substr($first_name, 0, 3);
$username=$last_name.$dateOfBirth. mb_substr($first_name, 0, 3,'UTF-8');
}elseif(strlen($first_name) < 3){
$username=mb_substr($last_name, 0, 3,'UTF-8').$dateOfBirth.$first_name;
}else{
$username=mb_substr($last_name, 0, 3 ,'UTF-8').$dateOfBirth.mb_substr($first_name, 0, 3,'UTF-8');
}
//echo $username."<br/>";
if($user_datas = $this->user_model->user_exist(array('username'=>$username))){
//if user already exist then take the user_id
foreach($user_datas as $user_data){
$user_id=$user_data['id'];
}
//if the user is already in the project for this season
if($this->user_model->user_exist_in_project(array('project_id'=>$project_name,'student'=>$username,'season'=>$season))){
//check users first name and last name if exist
if($user_datas = $this->user_model->user_exist(array('first_name'=>$first_name,'last_name'=>$last_name))){
//if match found then reject this data
$rejected[]=array("error"=> $this->lang->line('student_already_in_project_in_season'),"line_number"=>$error_count);
}else{
$accepted[]=$file_data;
}
}
}else{
$accepted[]=$file_data;
}
}
$error_count++;
}
My answer is going to address the specific problem you had regarding:
I need a solution from which i generate a unique username with
available details also can check that a every student enters in
database only one time and have only one username.
Because you stated that you have "first name", "last name" and "birthday" (which might be null) for each student, and need to create a unique username, I'm going to suggest using a checksum.
The real problem is that the data you have cannot in itself guarantee uniqueness, so even the solution I will suggest is not going to work 100% without you implementing some sort of random salt in the user data.
Here is a code snippet to help you see what I'm thinking:
$fname = "John";
$lname = "Doe";
$bday = "1980-03-01";
$unique_user_string = strtolower($fname . $lname . $bday); // not actually unique if 2 people have same name and birthday
$username = ucfirst(substr($fname, 0, 1)) . ucfirst($lname) . crc32($unique_user_string);
From the above code, you should have a username like: JDoe4246458655
And the nice part is that you can always confirm an existing user by checking the checksum and creating a new one using the user data from your CSV. To get the checksum from the existing username, just do:
$crc = substr($username, -10, 10);
I hope this makes sense.
You can use this function simplly:
$uniqueid2 = md5(uniqid());
$uniqueid = substr($uniqueid2, 0, 8);
And add this $uniqueid variable at the end of their name, so this could lead you to a very unique login.

php unique random number that is not in mysql table- check and then generate

I have this script:
$rrezervim_id = rand(1, 5);
$result = mysql_query("SELECT rrezervim_id FROM pax_list WHERE rrezervim_id='$rrezervim_id'");
if(mysql_num_rows($result) == 1)
{
$rrezervim_id = rand(1, 5);
}
else(mysql_num_rows($result) > 1);
{
echo "$rrezervim_id";
}
What i am trying to do is To generate a Unique Random number using PHP and MySql
i have the value inside table( rrezervim_id)[Values:1,2,3,5] so the only Random number that have to be generated and is free is Number 4.
But with this script something is not working since i am getting even random that are already inserted in the table [Values:1,2,3,5].
Any one can help me, is very important to make a check in mysql before generating the unique number if already exist in table.
First of all, the direct error in your code is
if(mysql_num_rows($result) == 1)
{
$rrezervim_id = rand(1, 5);
}
fails, if you hit a taken number twice. You need a loop, such as
while (mysql_num_rows($result) == 1)
{
$rrezervim_id = rand(1, 5);
$result = mysql_query("SELECT rrezervim_id FROM pax_list WHERE rrezervim_id='$rrezervim_id'");
}
That said, I suspect, that there is more wrong with your code:
If you want to use this "free" random number to insert it into the database at a later point in time, you are wide open to a race condition: Both processes select the same (still free) number, but only on the first insert is it still unique.
This approach can have extremely bad performance, if your field of possible random numbers is nearly full: If you have 80% fill rate, such as in your example, you will on average have 4 "bad" hits, before getting a "good" hit.
I recommend you consider using a database built-in, such as the battle-proven AUTO_INCREMENT as a primary means, then use a formula to create the hard-to-guess pseudo-random from it. A linear feedback shift register can be one approach, while cryptographically combining the auto-generated ID and a (not necessarily unique) pseudo-random stored in the table might be another. Both methods give you linear performance and race-free usage.
you can create unique number in php
<?php
echo uniqid();
?>
But you should use AUTO INCREMENT. If you want to know by which number inserted item is saved use something like this:
function insertUser(){
Global $userName;
$sqlInsert="INSERT INTO person (e_mail)
VALUES ('".$userName."')";
if (!mysql_query($sqlInsert)){
die('Error: ' . mysql_error());
}
$userId = mysql_insert_id();
return $userId;
}
in $userId is last inserted value
Since you are not using AUTO_INCREMENT, a suggestion (which is slow) is to select all the numbers that are valid and pick 1 randomly.
If we have [1,2,3,5,7] and our allowed elements are 1..10, then we have 5 allowed elements(4,6,8,9,10). So we rand(1,5). If we get "1", our next number is 4, if we get "2", our next number is 6. To better explain the idea:
Rand(1,5) Our array Value(available)
1
2
3
1 - 4
5
2 - 6
7
3 8
4 9
5 10
Code example:
$max_num = 100;
$res = mysql_query("SELECT rrezervim_id FROM pax_list ORDER BY rrezervim_id ASC");
$nums = [];
while($row = mysql_fetch_assoc($res)){
$nums[] = $res['rrezervim_id'];
}
$numbers_allowed = $max_num - count($nums); // actual number of allowed elements
$new_num_idx = rand(1, $numbers_allowed); // The selected element's index
(skipping all existing elements)
// in the following loop: $j starts as our lowest options.
// when $new_num_idx reaches 0 - it means that we have skipped
// over $new_num_idx elements. The next available element is
// our choice. $new_num_idx is a countdown
for($i=0,$j=1, $n=count($nums); $i<$n && $new_num_idx > 0; $i++){
while ($nums[$i]>$i+$j){
$j++; $new_num_idx--;
}
}
return $i+$j;

Get a random number betwen 1-200 but leaves out numbers read from query

I need to get a random number between, lets say 1-200, but at the same time I need to prevent selecting a random number that has already been used for a particular REMOTE_ADDR (as stored in a table).
This is what I have so far (I have tried several different approaches):
$ip = $_SERVER['REMOTE_ADDR'];
$query7 = "
SELECT *
FROM IP
WHERE IP = '$ip'
";
$result7 = mysql_query($query7) or die(mysql_error());
$rows7 = mysql_num_rows($result7);
while ($row7 = mysql_fetch_array($result7)){
$id = $row7['ID'];
}
I'm using the random number to pick an image to display, but my users are complaining that the images selected for them is not random enough; ie, the same picture is getting "randomly" selected too often, sometimes showing the same image over and over.
It does not have to be in PHP, if there is another option.
Something like that
// all ids from 1 to 100
$all = array_fill(1, 200, 0);
// remove used
foreach ($used as $i) {
unset($all[$i]);
}
// get survived keys
$keys = array_keys($all);
// get random position, note that the array with keys is 0 based
$j = rand(0, count($all) - 1);
return $keys[$j];
Run your select and instead of using *, only select the id column. Then use:
while($row7[] = mysql_fetch_array($query7));
do{
$rand = rand(0,200);
}while(in_array($rand,$row7));
You can do it all in mysql. Have one table that has your list of images, and another table that has the list of IP addresses and the images that have already been shown to that IP. Then you select and join the tables and order the result randomly.
SELECT image_id FROM images
LEFT JOIN shown_images ON images.image_id=shown_images.image_id AND ip_addr=[#.#.#.#]
WHERE shown_images.image_id IS NULL
ORDER BY RAND() LIMIT 1;
After you show an image to an IP, just insert a record into the shown_images table with the IP and the image ID. That will work right up until that have seen all the images. Then you can delete the records and start over.
This answer assumes that you have 200 items, and collect the items which you do not want to show. Alternatively, you can query only id's of available items and choose from these, you would need to create a table with available items for that.
Create a map which maps consecutive numbers to (non-consecutive) available numbers. Suppose the numbers 1 and 3 are in use, you can map to 2 and 4 (and so on).
Actually, it is possible to use a simple array (not-associative) for this. You can do something like this:
$reserved = array(1, 3); // fill $reserved using your code
$available = array();
for ($i = 1; $i <= 200; $i++) {
if (!in_array($i, $reserved)) {
$available[] = $i;
}
}
if (count($available) > 0) {
$random_index = rand(0, count($available) - 1);
$r = $available[$random_index];
} else {
// Nothing available!
}
There will be nothing to choose when you run out of pictures that have not been displayed yet. In this case, count($available) will be zero. One way to solve this would be to clear your list of displayed images for the current IP and choose again; see also other answers for this.

Categories