Summerize all fields if exists from database - php

I have different fields in the database and im fetching their values.
Now what I would like to do is subract a number if certain field exists in database.
Here is my code:
<?php
$percent_profile_image = 40;
$percent_cover_image = 20;
$percent_profiletext = 10;
$percent_travelintext = 10;
$percent_sparetimetext = 10;
$percent_gouttext = 10;
$avatar_status_num;
$cover_status_num;
$profiletext = $display_profile['profile_text_approved'];
$sparetimetext = $display_profile['spare_time_text_approved'];
$travelintext = $display_profile['traveling_text_approved'];
$gouttext = $display_profile['go_out_text_approved'];
if($avatar_status_num == 2) { echo $percent_profile_image; } + if($avatar_status_num == 2) { echo $percent_profile_image; }
?>
Now I know my if code is wrong. What I would like to do if example $avatar_status_num = 2 i would like to print out 40. if $cover_status_num = 2 I would like to substract these to numbers so. 40 + 20. So it should only print out the number and substract it if the value from DB is nr2.
I hope you understand my question :)
Cheerz

Use an extra variable to sum your values.
$sum = 0;
if (isset($someValue) && $someValue == 2) {
$sum += 40;
}
if (isset($someOtherValue) && $someOtherValue == 2) {
$sum += 20;
}
Or if you wanna do this dynamically in your code:
$percent = array(
'profile_image' => 40,
'cover_image' => 20,
'profile_text_approved' => 10,
'traveling_text_approved' => 10,
'spare_time_text_approved' => 10,
'go_out_text_approved' => 10,
);
$sum = 0;
foreach ($display_profile as $key => $value) {
if (array_key_exists($key, $percent) && $value == 2) {
$sum += $percent[$key];
}
}
Note In this case the $percent key names should be the same as the $display_profile key names.

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)
*/

Place colliding elements next to each other

I'm creating some kind of calendar/agenda which shows the events for a specific day. Each event is displayed as an HTML element in a vertical hours grid. There could be multiple ("colliding") events at the same time, and in those cases the elements should be placed next to each other, horizontally, and have equal widths. E.g. four colliding events get the column value 4, in this way the width of 25%.
The tricky part is these colliding events. I thought I solved it, but some elements get the wrong number of columns.
There might be a better way to calculate the column count and placement - I'm open to suggestions.
Sample image for current (wrong) result:
Relevant code:
<?php
class Calendar {
const ROW_HEIGHT = 24;
public $events = array();
public $blocks = array();
public function calculate_blocks() {
foreach($this->events as $event) {
// Calculate the correct height and vertical placement
$top = $this->time_to_pixels($event->_event_start_time);
$bottom = $this->time_to_pixels($event->_event_end_time);
$height = $bottom - $top;
// Abort if there's no height
if(!$height) continue;
$this->blocks[] = array(
'id' => $event->ID,
'columns' => 1,
'placement' => 0, // Column order, 0 = first
'css' => array(
'top' => $top,
'bottom' => $bottom, // bottom = top + height
'height' => $height
)
);
}
$done = array();
// Compare all the blocks with each other
foreach($this->blocks as &$block) {
foreach($this->blocks as &$sub) {
// Only compare two blocks once, and never compare a block with itself
if($block['id'] == $sub['id'] || (isset($done[$block['id']]) && in_array($sub['id'], $done[$block['id']])) || (isset($done[$sub['id']]) && in_array($block['id'], $done[$sub['id']]))) continue;
$done[$block['id']][] = $sub['id'];
// If the blocks are colliding
if(($sub['css']['top'] >= $block['css']['top'] && $sub['css']['top'] < $block['css']['bottom'])
|| ($sub['css']['bottom'] >= $block['css']['top'] && $sub['css']['bottom'] < $block['css']['bottom'])
|| ($sub['css']['top'] <= $block['css']['top'] && $sub['css']['bottom'] >= $block['css']['bottom'])) {
// Increase both blocks' columns and sub-block's placement
$sub['columns'] = ++$block['columns'];
$sub['placement']++;
}
}
}
}
private function time_to_int($time) {
// H:i:s (24-hour format)
$hms = explode(':', $time);
return ($hms[0] + ($hms[1] / 60) + ($hms[2] / 3600));
}
private function time_to_pixels($time) {
$block = $this->time_to_int($time);
return (int)round($block * self::ROW_HEIGHT * 2);
}
}
?>
Try this:
public function calculate_blocks()
{
$n = count($events);
$collumns = array();
$placements = array();
// Set initial values.
for ($i = 0; $i < $n; $i++)
{
$collumns[$i] = 1;
$placements[$i] = 0;
}
// Loop over all events.
for ($i = 0; $i < $n; $i++)
{
$top1 = $this->time_to_pixels($events[$i]->_event_start_time);
$bottom1 = $this->time_to_pixels($events[$i]->_event_end_time);
// Check for collisions with events with higher indices.
for ($j = $i + 1; $j < $n; $j++)
{
$top2 = $this->time_to_pixels($events[$k]->_event_start_time);
$bottom2 = $this->time_to_pixels($events[$k]->_event_end_time);
$collides = $top1 < $bottom2 && $top2 < $bottom1;
// If there is a collision, increase the collumn count for both events and move the j'th event one place to the right.
if ($collides)
{
$collumns[$i]++;
$collumns[$j]++;
$placements[$j]++;
}
}
$this->blocks[] = array(
'id' => $events[$i]->ID,
'columns' => $collumns[$i],
'placement' => $placements[$i],
'css' => array(
'top' => $top1,
'bottom' => $bottom1,
'height' => $bottom1 - $top1;
)
);
}
}
I can't actually test it, but I think it should leave you with a correct blocks array.
Edit 1: Doesn't seem to yield the required result, see comments below.
Edit 2: I think this is the exact same problem: Visualization of calendar events. Algorithm to layout events with maximum width. Someone solved it with C#, but it should be relatively easy to port that answer to PHP to solve your problem.

Incrementing through a MYSQL result set without stopping

I am trying to increment through a result set from my table.
I attempt to display the next three results using an increment. This is working fine.
For example;
current = 5.
It then displays the next three: 6,7,8
It can also display the previous three: 4,3,2
The problem comes when I reach the last couple or minimum couple of results. It will currently stop;
current = 23
next: 24, 25
I cannot figure out to loop through to the last or first few results.
E.g. I want it to do this:
current = 2
display previous three: 1, 25, 24
AND FOR next:
current = 23:
display next three: 24, 25, 1
I'm returning these as arrays. Code:
$test_array = array();
$no = 1;
while($results=mysql_fetch_assoc($test_query))
{
$test_array[] = array('test_id' => $results['id'],
'path' => $results['Path'],
'type' => $results['FileType']
'no' => $no);
$no++;
}
$current_no = 0;
if(is_array($test_array) && count($test_array)>0)
{
foreach($test_array as $key=>$array)
{
if($array['test_id']==intval($db_res['current_id']))
{
$current[] = $array;
$current_no = intval($key+1);
}
else
//error
if(intval($current_no)>0)
{
//Next 3
for($i=0;$i<3;$i++)
{
if(isset($test_array[intval($current_no+$i)]) && is_array($test_array[intval($current_no+$i)]))
{
$next[] = $test_array[intval($current_no+$i)];
}
else
break;
}
//Previous 3
for($i=2;$i<5;$i++)
{
if(isset($test_array[intval($current_no-$i)]) && is_array($test_array[intval($current_no-$i)]))
{
$previous[] = $test_array[intval($current_no-$i)];
}
else
break;
}
break;
}
else
//error
}
}
else
//error
If anyone has any ideas on how to help, that would be great!
Find $key for $current and set $next_key = $prev_key = $key;
Find last key $max = count($test_array) - 1;
Increase $next_key & decrease $prev_key 3 times (and check if
boundary is reached):
Loop might look like this.
for ($i = 1; $i <= 3; $i++)
{
$next_key = ($next_key == $max) ? 0 : $next_key + 1;
$prev_key = ($prev_key == 0) ? $max : $prev_key - 1;
$next[] = $test_array[$next_key];
$prev[] = $test_array[$prev_key];
}

Simple php string issue,

I`m stucked on a php code and my question is:
I`m working with php if and elseif to show something like this below:
<?php
$test_a = 0 to 10; (My problem)
$test_b = 11 to 20; (My problem)
$test_c = 21 to 30; (My problem)
$test = 50; (random value)
$something = 12;
$something_b = 5;
$something_c = 15;
?>
<?php
if($test>=$test_a){
echo $something;
}elseif ($test=<$test_b) {
echo $something_b;
}elseif (test=<$test_c) {
echo $something_c;
}
?>
My question is how do I work with range using if/elseif.
Thanks!
That obviously is not valid syntax. This really is just a basic if/else statement:
if($test>=0 && $test <=10){
echo $something;
}elseif ($test>=11 && $test <=20) {
echo $something_b;
}elseif ($test>=21 && $test <=30) {
echo $something_c;
}
Just check of $test is greater than or equal to value 1 or less than or equal to value 2. If not, move on to your next if statement.
Set your variables to the top of each range:
$test_a = 10;
$test_b = 20;
$test_c = 30;
if ($test <= $test_a) {
echo $something;
} elseif ($test <= $test_b) {
echo $something_b;
} elseif ($test <= $test_c) {
echo $something_c;
}
If you have lots of cases, it may be better to create an array and use a loop:
$tests = array (array ('limit' => 10, 'message' => $something),
array ('limit' => 20, 'message' => $something_b),
array ('limit' => 30, 'message' => $something_c)
);
foreach ($tests as $curtest) {
if ($test <= $curtest['limit']) {
echo $curtest['message'];
break;
}
}

How do I get box plot key numbers from an array in PHP?

Say I have an array with values like:
$values = array(48,30,97,61,34,40,51,33,1);
And I want the values to be able to plot a box plot like follows:
$box_plot_values = array(
'lower_outlier' => 1,
'min' => 8,
'q1' => 32,
'median' => 40,
'q3' => 56,
'max' => 80,
'higher_outlier' => 97,
);
How would I do this in PHP?
function box_plot_values($array)
{
$return = array(
'lower_outlier' => 0,
'min' => 0,
'q1' => 0,
'median' => 0,
'q3' => 0,
'max' => 0,
'higher_outlier' => 0,
);
$array_count = count($array);
sort($array, SORT_NUMERIC);
$return['min'] = $array[0];
$return['lower_outlier'] = $return['min'];
$return['max'] = $array[$array_count - 1];
$return['higher_outlier'] = $return['max'];
$middle_index = floor($array_count / 2);
$return['median'] = $array[$middle_index]; // Assume an odd # of items
$lower_values = array();
$higher_values = array();
// If we have an even number of values, we need some special rules
if ($array_count % 2 == 0)
{
// Handle the even case by averaging the middle 2 items
$return['median'] = round(($return['median'] + $array[$middle_index - 1]) / 2);
foreach ($array as $idx => $value)
{
if ($idx < ($middle_index - 1)) $lower_values[] = $value; // We need to remove both of the values we used for the median from the lower values
elseif ($idx > $middle_index) $higher_values[] = $value;
}
}
else
{
foreach ($array as $idx => $value)
{
if ($idx < $middle_index) $lower_values[] = $value;
elseif ($idx > $middle_index) $higher_values[] = $value;
}
}
$lower_values_count = count($lower_values);
$lower_middle_index = floor($lower_values_count / 2);
$return['q1'] = $lower_values[$lower_middle_index];
if ($lower_values_count % 2 == 0)
$return['q1'] = round(($return['q1'] + $lower_values[$lower_middle_index - 1]) / 2);
$higher_values_count = count($higher_values);
$higher_middle_index = floor($higher_values_count / 2);
$return['q3'] = $higher_values[$higher_middle_index];
if ($higher_values_count % 2 == 0)
$return['q3'] = round(($return['q3'] + $higher_values[$higher_middle_index - 1]) / 2);
// Check if min and max should be capped
$iqr = $return['q3'] - $return['q1']; // Calculate the Inner Quartile Range (iqr)
if ($return['q1'] > $iqr) $return['min'] = $return['q1'] - $iqr;
if ($return['max'] - $return['q3'] > $iqr) $return['max'] = $return['q3'] + $iqr;
return $return;
}
Lilleman's code is brilliant. I really appreciate his way to deal with median and q1/q3. If I were answering this first, I would be cope with odd and even amount of values in a harder but unnecessary way. I mean useing if 4 times for 4 different situationgs of mode( count( values ) , 4 ). But his way is just neat and tidy. I really admires his work.
I would like to make some improvemenets about max, min, higher_outliers and lower_outliers. Because q1 - 1.5*IQR is only the lower bound, we should find the least value that greater than this bound as the 'min'. This is the same for 'max'. Also, there might be more than one outliers. So I would like to make some changes based on Lilleman's work. Thanks.
function box_plot_values($array)
{
$return = array(
'lower_outlier' => 0,
'min' => 0,
'q1' => 0,
'median' => 0,
'q3' => 0,
'max' => 0,
'higher_outlier' => 0,
);
$array_count = count($array);
sort($array, SORT_NUMERIC);
$return['min'] = $array[0];
$return['lower_outlier'] = array();
$return['max'] = $array[$array_count - 1];
$return['higher_outlier'] = array();
$middle_index = floor($array_count / 2);
$return['median'] = $array[$middle_index]; // Assume an odd # of items
$lower_values = array();
$higher_values = array();
// If we have an even number of values, we need some special rules
if ($array_count % 2 == 0)
{
// Handle the even case by averaging the middle 2 items
$return['median'] = round(($return['median'] + $array[$middle_index - 1]) / 2);
foreach ($array as $idx => $value)
{
if ($idx < ($middle_index - 1)) $lower_values[] = $value; // We need to remove both of the values we used for the median from the lower values
elseif ($idx > $middle_index) $higher_values[] = $value;
}
}
else
{
foreach ($array as $idx => $value)
{
if ($idx < $middle_index) $lower_values[] = $value;
elseif ($idx > $middle_index) $higher_values[] = $value;
}
}
$lower_values_count = count($lower_values);
$lower_middle_index = floor($lower_values_count / 2);
$return['q1'] = $lower_values[$lower_middle_index];
if ($lower_values_count % 2 == 0)
$return['q1'] = round(($return['q1'] + $lower_values[$lower_middle_index - 1]) / 2);
$higher_values_count = count($higher_values);
$higher_middle_index = floor($higher_values_count / 2);
$return['q3'] = $higher_values[$higher_middle_index];
if ($higher_values_count % 2 == 0)
$return['q3'] = round(($return['q3'] + $higher_values[$higher_middle_index - 1]) / 2);
// Check if min and max should be capped
$iqr = $return['q3'] - $return['q1']; // Calculate the Inner Quartile Range (iqr)
$return['min'] = $return['q1'] - 1.5*$iqr; // This ( q1 - 1.5*IQR ) is actually the lower bound,
// We must compare every value in the lower half to this.
// Those less than the bound are outliers, whereas
// The least one that greater than this bound is the 'min'
// for the boxplot.
foreach( $lower_values as $idx => $value )
{
if( $value < $return['min'] ) // when values are less than the bound
{
$return['lower_outlier'][$idx] = $value ; // keep the index here seems unnecessary
// but those who are interested in which values are outliers
// can take advantage of this and asort to identify the outliers
}else
{
$return['min'] = $value; // when values that greater than the bound
break; // we should break the loop to keep the 'min' as the least that greater than the bound
}
}
$return['max'] = $return['q3'] + 1.5*$iqr; // This ( q3 + 1.5*IQR ) is the same as previous.
foreach( array_reverse($higher_values) as $idx => $value )
{
if( $value > $return['max'] )
{
$return['higher_outlier'][$idx] = $value ;
}else
{
$return['max'] = $value;
break;
}
}
return $return;
}
I wish this could be helpful for those who would be interested in this issue. And Pls add comment to me if there is a better way to know which values are the outliers. Thanks!
I have a different solution for calculating the lower and higher whiskers. Like ShaoE's solution it finds the least value greater or equal than the lower bound (Q1 - 1.5 * IQR) and vice versa for the higher bound.
I use array_filter which iterates over an array, passing values to a callback function and returns an array with only the values for which the callback gives true (see php.net's array_filter manual). In this case values greater than the lower bound are returned and used as input for min which itself returns the least value.
// get lower whisker
$whiskerMin = min(array_filter($array, function($value) use($quartile1, $iqr) {
return $value >= $quartile1 - 1.5 * $iqr;
} ));
// get higher whisker vice versa
$whiskerMax = max(array_filter($array, function($value) use($quartile3, $iqr) {
return $value <= $quartile3 + 1.5 * $iqr;
} ));
Note that it ignores outliers and I only tested it with positive values.

Categories