Is there another way to automatically increment student numbers? - php

I am trying to automatically create student IDs and the ID looks like this "MILE/001/5". The 'mile' is the school name and the '001' is the class number and the '5' is the ID. There can only be 40 students in one class and after 40 the next student will go to the second class e.g 'Mile/002/41'. I have done this using hard coded if stemements meaning i stopped somewhere but i want to automatically do this in a few lines of code without all the if statements. I am getting the $count variable from the database and i increment it after each registered student. Here is the code:
if ($count <= 40) {
$class = '001';
$student_id = "MILE/".$class."/".$count;
} elseif($count >= 41 && $count <= 80 ) {
$class = '002';
$student_id = "MILE/".$class."/".$count;
} elseif($count >= 81 && $count <= 120 ) {
$class = '003';
$student_id = "MILE/".$class."/".$count;
} elseif($count >= 121 && $count <= 160 ) {
$class = '004';
$student_id = "MILE/".$class."/".$count; } }

Check out intdiv https://www.php.net/manual/en/function.intdiv.php
It will perform an integer division (discards fractional part), i.e. 1/2 => 0, 3/2 => 1.
Here's an implementation using intdiv
function generateId($school, $capacity, $id) {
$classIndex = intdiv($id - 1, $capacity) + 1;
$class = sprintf("%03d", $classIndex);
return "$school/$class/$id";
}
$CLASS_CAPACITY = 40;
$SCHOOL = 'MILE';
for ($id=38; $id < 42; $id++) {
$studentId = generateId($SCHOOL, $CLASS_CAPACITY, $id);
var_dump($studentId);
}
output:
string(11) "MILE/001/38"
string(11) "MILE/001/39"
string(11) "MILE/001/40"
string(11) "MILE/002/41"

Related

How can I generate and validate random IDs using the Saudi ID format?

I need to generate random IDs that validate against the criteria for Saudi IDs shown in this question:
Saudi Iqama/National Identity number field validation
I've tried the following code:
$random_numbers = [];
while(count($random_numbers) < 1000000000){
do {
$random_number = mt_rand(1000000000,9000000000);
}
while (in_array($random_number, $random_numbers));{
$type = substr ( $random_number, 0, 1 );
if($type != 2 && $type != 1 ) break;
$sum = 0;
for( $i = 0 ; $i<10 ; $i++ ) {
if ( $i % 2 == 0){
$ZFOdd = str_pad ( ( substr($random_number, $i, 1) * 2 ), 2, "0", STR_PAD_LEFT );
$sum += substr ( $ZFOdd, 0, 1 ) + substr ( $ZFOdd, 1, 1 );
}else{
$sum += substr ( $random_number, $i, 1 );
}
}
return $sum%10 ? break : echo $random_number;
----------
echo "<br>";
$random_numbers[] = $random_number;}
}
Disclaimer: I'm not 100% sure on the validation required etc. for Saudi ID numbers and have only briefly looked at the answers supplied in the linked question
Okay, so, my understanding is that you need to generate a random id that:
Matches the pattern/format:
[12]\d{9}
Validates against the criteria show in the linked question:
Saudi Iqama/National Identity number field validation
To do this we need to create a couple of functions; one to generate IDs and one to validate the IDs against the given criteria.
Generate the ID
Simply generating an ID is simple enough. We can use the random_int function in PHP with a loop. If we enclose the code to generate the ID inside of a do...while... loop then we can execute the code and validate the ID repeatedly until we get a valid one.
function getRandomSaudiId() : int
{
do {
$saudiId = (string) random_int(1,2);
for($i = 0; $i < 9; $i++){
$saudiId .= random_int(0,9);
}
} while(validateSaudiId($saudiId) === false);
return (int) $saudiId;
}
Validate the ID
Note: we convert to string so that we can access the numbers based on their index.
function validateSaudiId(string $id) : bool
{
$sum = 0;
for($i = 0; $i < 9; $i++){
if( $i % 2 ){
// Even number
$sum += $id[$i];
}
else{
//Odd number
$increment = $id[$i] * 2;
while($increment > 9){
$increment = (string) $increment;
$increment = $increment[0] + $increment[1];
}
$sum += $increment;
}
}
$sum = (string) $sum;
return ($sum[1] == $id[9] || $id[9] == (10 - $sum[1])) ? true : false;
}
Example use
for($i = 0; $i < 10; $i++) var_dump(getRandomSaudiId());
/*
Output:
int(2933617506)
int(2409806096)
int(1072585118)
int(2891306413)
int(1810304558)
int(2591965856)
int(1363032527)
int(1031823269)
int(1265954048)
int(2498099472)
int(1134172537)
*/

Distribute array value in table column

I have three column having limit of certain percentage of total.i want to distribute an array of values to three columns in such a manner first check customer 1 then 2 then 3 and start from customer 3,2,1 and again from 1,2,3 etc. And also check each value not crossing column limit.Remaining array value should be distribute in column having large percentage assigned.
Array : $stone_doll_inner_arr = array(1=>'67212','37256','32909','29847','28529','27643','25356','25274','23604','23058','18581');
I tried like
Table
for($m=1;$m<=1;$m++){
for($n=1;$n<=count($stone_doll_inner_arr);$n++){
if ($n % 2 == 0) {
$asc_desc = 'asc';
}else{
$asc_desc = 'desc';
}
//Query
$sql_main_table = "select * from create_nemix_tbl where create_id = '".$getid."' order by percentage ".$asc_desc."";
$qry_main_table = $con->query($sql_main_table);
$num_main_table = $qry_main_table->num_rows;
if ($n % 2 == 0) {
$l = $num_main_table-1;
}else{
$l = 0;
}
while($row_main_table = $qry_main_table->fetch_array()){
$stone_doll_val = $stone_doll_arr[$m];
$stone_doll_val_perc = ($stone_doll_val * $row_main_table['percentage']) / 100;
$pre_existing = isset($customer[$l]) ? array_sum($customer[$l]) : 0;
$first_value = $pre_existing+$stone_doll_inner_arr[$n];
$var = 0;
if ($first_value <= $stone_doll_val_perc){
$customer[$l][] = $stone_doll_inner_arr[$n];
unset($stone_doll_inner_arr[$n]);
$var =1;
}
if($var == 1){
break;
}
}
if ($n % 2 == 0) {
$l--;
}else{
$l++;
}
}
}
echo "<pre>";
print_r($customer);
Table Structure and output of script i wanted

leveling up PHP algorithm

I want some algorithm to make a PHP level up system I already made a system to level up people but what if people gained a huge amount of exp so they need to level up multiple times example of my code:
if(isset($_POST['id']) && isset($_POST['amount'])) {
$amount = $_POST['amount'];
$user = $_POST['id'];
$exp;$etnl;$newExp;$level;
`//select exp and etnl from DB
$result = DB::getInstance() ->query("SELECT exp,etnl,level FROM exp WHERE id = $user");
$result->setFetchMode(PDO::FETCH_ASSOC);
$row = $result->fetch();
$exp = $row['exp'];
$etnl = $row['etnl'];
$level = $row['level']
//c where to level up user or to add exp to his ep bar
if($amount + $exp > $etnl) {
$etnl = $etnl * 2;
$leftOvers = ($amount + $exp) - $etnl;
$newExp = $leftOvers;
$level = $level + 1;`
$result = DB::getInstance()->prepare("UPDATE exp SET exp=?,level=?,etnl=? WHERE id=?");
$result->execute(array($amount,$level,$etnl,$user));
} else {
$result = DB::getInstance()->prepare("UPDATE exp SET exp=? WHERE id=?");
$result->execute(array($amount,$user));
}
}`
`
but this system fails if the exp could level up a person 2 times any help or any new code? BTW etnl stands for exp till next level thank you
If you don't want to manually type out a level table like the other answer suggets you can also try doing your process with a recursive function:
$current_exp = 0;
$current_level = 1;
$to_next_level = 1000;
function did_level( $amount = 0 ) {
global $current_exp;
global $curent_level;
global $to_next_level;
$tmp_amount = $amount + $current_exp;
$tmp_amount_remainder = $tmp_amount - $to_next_level;
if ($tmp_amount >= $to_next_level) {
$current_level++;
$to_next_level *= 2;
$current_exp = $tmp_amount;
if ($tmp_amount_remainder > 0) {
// Level us up again.
did_level( $tmp_amount_remainder );
} else {
// Store the new level, to next level, and current exp
}
} else {
// Store the new exp amount
}
}
You have to get a table of levels which is basically a list of [exp, level] pairs. For example,
$level_list = [
['exp' => 0, 'level' => 1],
['exp' => 100, 'level' => 2],
['exp' => 1000, 'level' => 3],
// etc.
];
Then, you iterate the table starting from the end:
$i = count($level_list);
while($i > 0) {
$i--;
if ($user_exp >= $level_list[i]['exp']) {
// this is the level we need
break;
}
}
$target_level = $level_list[$i]['level'];
$target_exp = $level_list[$i]['exp'];

Split total into 5 different numbers

Ok what i'm wanting to do is split a number ($row['count']) into 5, this is easy enough if you want equal numbers:
$sum = ($row['count'] / 5);
$fsum = floor($sum);
but I want each number to be different and still add up to total ie $row['count'] how can this be achieved?
Update:
If this helps its to be used to update 5 rows in a database:
$query = "SELECT * FROM foo";
$result = mysql_query($query);
while ($row = mysql_fetch_array($result)) {
$sum = ($row['count'] / 5);
$fsum = floor($sum);
$id = $row['id'];
$update = "UPDATE foo SET foo1='$fsum', foo2='$fsum', foo3='$fsum', foo4='$fsum', foo5='$fsum' WHERE id='$id'";
mysql_query($update);
}// while
so ideally the $update query would be something like:
$update = "UPDATE foo SET foo1='$fsum1', foo2='$fsum2', foo3='$fsum3', foo4='$fsum4', foo5='$fsum5' WHERE id='$id'";
This is my take:
function randomize($sum, $parts) {
$part_no = count($parts);
$continnue_counter = 0;
while (count(array_unique($parts)) != $part_no) {
$changing = array_rand($parts, 2);
if (($parts[$changing[0]] - 1) == 0 || ($parts[$changing[1]] - 1) == 0) { // don't let them go under 1
++$continnue_counter;
// sometime one element get everything and others even out on 1
// just throw away everything you got so far and start over
if ($continnue_counter > 10) {
$parts = setup($sum, $part_no);
$continnue_counter = 0;
}
continue;
}
$continnue_counter = 0;
$signum = mt_rand(0, 100) % 2 ? 1 : -1;
$delta = $signum * mt_rand(1, min($parts[$changing[0]] - 1, $parts[$changing[1]] - 1)); // -1 to make sure they don't go under 0
$parts[$changing[0]] += $delta;
$parts[$changing[1]] -= $delta;
}
return $parts;
}
function setup($sum, $part_no) {
$parts = array_fill(0, $part_no, (int)($sum / $part_no));
// acount for the reminder of (int) cast
$reminder = $sum - array_sum($parts);
while ($reminder) {
$parts[array_rand($parts)] += 1;
--$reminder;
}
return $parts;
}
$part_no = 5;
$sum = 42;
$parts = randomize($sum, setup($sum, $part_no));
var_export($parts);
print array_sum($parts)
Update:
I've added a version that introduces a little more entropy.
Update2:
The more random one had a tendency to decrement everything to 1 except one part, added an explicit detection to deal with this. Still the algorithm behind it has unknown termination time.

Returning a default grade from a score value

Here is my problem. I upload a csv file containing two columns (student Number and Score). But when i form an HTML table from the data, i'll like to have a column display a grade according to the score uploaded... Also all the courses that have a score >40 should all be put into another table. Below is the loop i'm trying to make work, but it's not getting me anywhere near it.
Thanks for the help. I most appreciate it. Thanks
while ($row4 = mysql_fetch_assoc($query4)) {
if ($row4['score'] >= 70) {
$grade = A;
}
elseif ($row4['score'] >= 60) {
$grade = B;
}
elseif ($row4['score'] >= 50) {
$grade = C;
}
elseif ($row4['score'] >= 45) {
$grade = D;
}
elseif($row4['score'] >= 40) {
$grade = E;
}
elseif($row4['score'] >= 40) {
$grade = F;
}else {
$grade = AR;
}
}
If I understand correctly, the following should do what you are looking for. I assume that your Course ID and Student ID are in the database row, but you will need to update those if not.
<?php
define('GRADE_A_MIN', 70);
define('GRADE_B_MIN', 60);
define('GRADE_C_MIN', 50);
define('GRADE_D_MIN', 45);
define('GRADE_E_MIN', 40);
define('GRADE_F_MIN', 35);
$table_one_values = array(); // Used to create table for students with scores 40+
$table_two_values = array();
while ($row4 = mysql_fetch_assoc($query4)) {
$score = $row4['score'];
$destination_table = 'two';
if ( $score >= GRADE_A_MIN ) {
$grade = 'A';
$destination_table = 'one';
} elseif ( $score >= GRADE_B_MIN ) {
$grade = 'B';
$destination_table = 'one';
} elseif ( $score >= GRADE_C_MIN ) {
$grade = 'C';
$destination_table = 'one';
} elseif ( $score >= GRADE_D_MIN ) {
$grade = 'D';
$destination_table = 'one';
} elseif ( $score >= GRADE_E_MIN ) {
$grade = 'E';
$destination_table = 'one';
} elseif ( $score >= GRADE_F_MIN ) {
$grade = 'F';
} else {
$grade = 'AR';
}
$table = 'table_'.$destination_table.'_values';
$$table[] = array(
'course_id' => $row4['course_id'],
'student_id' => $row4['student_id'],
'score' => $score,
'grade' => $grade
);
}
Some problems:
Your $grade variable gets overwritten in the loop so you only will have the last value at the end. As your row contains a student number as well, you could do something like: $grade[$row4['number']] = 'A'; to link that specific grade to a specific student number. Note that you would set your array before the loop: $grade = array();
Your assignment is wrong, unless A, B, etc. are constants. It should probably be 'A' instead of A, etc. So: $grade[$row4['number']] = 'C';, etc.

Categories