Here is my function,
It is meant to get the user level an the amount of xp needed until the next level, it works but only through levels 1 to 2, then if the required xp for level 3 is entered it fails.
The XP doubles per level, so from level 1 to 2 is 10, 2 to 3 is 20, 3 to 4 is 40 etc;
$user['xp'] is an int to explain better, here are some examples of what the function returns with different values.
$user['xp'] == 1, level 1, xpGot 1, xpNeeded 9, 10%
$user['xp'] == 5, level 1, xpGot 5, xpNeeded 5, 50%
$user['xp'] == 9, level 1, xpGot 9, xpNeeded 1, 90%
$user['xp'] == 10, level 2, xpGot 0, xpNeeded 20, 0%
$user['xp'] == 15, level 2, xpGot 5, xpNeeded 15, 25%
$user['xp'] == 29, level 2, xpGot 19, xpNeeded 1, 95%
7. $user['xp'] == 30, level 2, xpGot 0, xpNeeded 0, 0%
It fails there on after.
function calculateLevel($xpGot) {
$level = 1;
$xpNeeded = 10;
while ($xpGot >= $xpNeeded) {
$level++;
$xpGot %= $xpNeeded;
$xpNeeded *= 2;
}
if ($xpGot < $xpNeeded) {
$xp = $xpGot / $xpNeeded * 100;
echo '<p>Level: ' . $level . '</p>';
echo '<div class="displayBarWrap" title="' . $xpGot . '/' . $xpNeeded . ' XP (' . $xp . '%)">
<p>XP:</p>
<div class="displayBar"><div style="width: ' . $xp . '%;"></div></div></div>';
}
}
calculateLevel($user['xp']);
I think you want following: replace %= with -=:
$xpGot -= $xpNeeded;
Take this line
$xpGot %= $xpNeeded;
There is no difference if the $xpGot is 15 or 45, % 10 will still return 5. The modulus operator divides the left operand by the right and returns the remainder.
Changing it to -= as #scessor suggested is probably what you're looking for.
With the fix the others mentioned and a possible mistake in the echo, this works for me:
<?php
function calculateLevel($xpGot) {
$level = 1;
$xpNeeded = 10;
if ($xpGot < $xpNeeded) /* NEW! */
return;
while ($xpGot >= $xpNeeded) {
$level++;
$xpGot -= $xpNeeded; /* FIXED (other answers!) */
$xpNeeded *= 2;
}
if ($xpGot < $xpNeeded) {
$xp = $xpGot / $xpNeeded * 100;
echo '<p>Level: ' . $level . '</p>';
/* FIXED ? */
echo '<div class="displayBarWrap" title="' . $xpGot . '/' . $xpNeeded . ' XP (' . $xp . '%)"> <p>XP:</p> <div class="displayBar"><div style="width: ' . $xp . '%;"></div></div></div>';
}
}
calculateLevel($user['xp']);
?>
Related
I have to validate an Estonian business ID (not a citizen ID). The ID is 9 numbers, but I think there might be a system of assigning them. For example, here is the Finnish validation with the last number as the checksum
if (preg_match('/^\d{7}-\d{1}$/', $user_input)) {
list($num, $control) = preg_split('[-]', $user_input);
// Add leading zeros if number is < 7
$num = str_pad($num, 7, 0, STR_PAD_LEFT);
$controlSum = 0;
$controlSum += (int)substr($num, 0, 1)*7;
$controlSum += (int)substr($num, 1, 1)*9;
$controlSum += (int)substr($num, 2, 1)*10;
$controlSum += (int)substr($num, 3, 1)*5;
$controlSum += (int)substr($num, 4, 1)*8;
$controlSum += (int)substr($num, 5, 1)*4;
$controlSum += (int)substr($num, 6, 1)*2;
$controlSum = $controlSum%11;
if ($controlSum == 0) {
return ($controlSum == $control) ? true : false;
} elseif ($controlSum >= 2 && $controlSum <= 10 ) {
return ((11 - $controlSum) == $control) ? true : false;
}
}
Usually there is a checksum for all of these types of IDs, so it's not just a matter of running a regex on it, but I can't find anything relating to Estonian businesses.
Any links to known libraries, examples would be appreciated. I'm working in PHP, but these could be in any language.
Thanks.
You can include a SOAP-Call from the European Commission https://ec.europa.eu/taxation_customs/vies/vatRequest.html
It should work like this (not 100% tested):
$vatId = "{{the vat id }}";
$client = new SoapClient("http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl");
if ($client) {
$cc = substr($vatId, 0, 2);
$vn = substr($vatId, 2);
$params = array('countryCode' => $cc, 'vatNumber' => $vn);
$result = $client->checkVat($params);
if ($result->valid == true) {
echo "VAT-ID ok";
}
} else {
die("connection failed");
}
I found this library, which answers my question
https://github.com/arthurdejong/python-stdnum/blob/master/stdnum/ee/registrikood.py
from stdnum.exceptions import *
from stdnum.util import clean, isdigits
def calc_check_digit(number):
"""Calculate the check digit."""
check = sum(((i % 9) + 1) * int(n)
for i, n in enumerate(number[:-1])) % 11
if check == 10:
check = sum((((i + 2) % 9) + 1) * int(n)
for i, n in enumerate(number[:-1])) % 11
return str(check % 10)
def compact(number):
"""Convert the number to the minimal representation. This strips the
number of any valid separators and removes surrounding whitespace."""
return clean(number, ' ').strip()
def validate(number):
"""Check if the number provided is valid. This checks the length and
check digit."""
number = compact(number)
if not isdigits(number):
raise InvalidFormat()
if len(number) != 8:
raise InvalidLength()
if number[0] not in '1789':
raise InvalidComponent()
if number[-1] != calc_check_digit(number):
raise InvalidChecksum()
return number
def is_valid(number):
"""Check if the number provided is valid. This checks the length and
check digit."""
try:
return bool(validate(number))
except ValidationError:
return False
How would you create a function (in PHP) to return a value for the appropriate rounded ranking group (e.g. "Top 5", "Top 10", "Top 15", ... "Top 1 million", "Top 5 million", "Top 10 million", "Top 15 million").
Note that it should round up to the nearest 1, 5 or 10 - e.g. "Top 15 million" rather than "Top 12 million".
Example:
Rank = Output
1-5 = 5 (Top 5 ranking)
6-10 = 10 (Top 10 ranking)
11-15 = 15 (Top 15 ranking)
This should work all the way up to trillions.
My current function works (sort of) however it would return a value for a ranking group of top 15 as top 20 instead.
private function format_number_iollions($amount,$style=null) {
$amount = (0 + str_replace(',', '', $amount));
if (!is_numeric($amount)){
return false;
}
$plusString = '';
switch ($style){
case 'plus':
$plusString = '+';
break;
}
if ($style==='rank' && $amount<=10){
return 10;
}
// filter and format it
if ($amount>1000000000000){
if ($style==='rank'){
$v = ceil(($amount/1000000000000));
} else {
$v = floor(($amount/1000000000000));
}
$v .= $plusString.' trillion';
} else if ($amount>1000000000){
if ($style==='rank'){
$v = ceil(($amount/1000000000));
} else {
$v = floor(($amount/1000000000));
}
$v .= $plusString.' billion';
} else if ($amount>1000000){
if ($style==='rank'){
$v = ceil(($amount/1000000));
} else {
$v = floor(($amount/1000000));
}
$v .= $plusString.' million';
} else if ($amount>100000){
if ($style==='rank'){
$v = ceil(($amount/100000));
} else {
$v = floor(($amount/100000));
}
$v .= '00,000'.$plusString;
} else if ($amount>10000){
if ($style==='rank'){
$v = ceil(($amount/10000));
} else {
$v = floor(($amount/10000));
}
$v .= '0,000'.$plusString;
} else if ($amount>1000){
if ($style==='rank'){
$v = ceil(($amount/1000));
} else {
$v = floor(($amount/1000));
}
$v .= ',000'.$plusString;
} else if ($amount>100){
if ($style==='rank'){
$v = ceil(($amount/100));
} else {
$v = floor(($amount/100));
}
$v .= '00'.$plusString;
} else if ($amount>10){
if ($style==='rank'){
$v = ceil(($amount/10));
} else {
$v = floor(($amount/10));
}
$v .= '0'.$plusString;
} else {
return number_format($amount);
}
return $v;
}
UPDATE - the final solution is this function (if anyone needs it):
private function get_rank_group($rawrank) {
// Divide by 1000 and count how many divisions were done
$rank_scale = 0;
while ($rawrank >= 1000) {
$rawrank /= 1000;
$rank_scale++;
}
// Determine which Top X can be
if ($rawrank >= 100) {
$lim_name = (floor(($rawrank-1) / 50) + 1) * 50;
} else {
$lim_name = (floor(($rawrank-1) / 5) + 1) * 5;
}
// if its in the next higher level
if ($lim_name >= 1000) {
$lim_name = '1';
$rank_scale++;
}
static $rank_scale_names = array('', ',000', ' Million', ' Billion', ' Trillion', ' Quadrillion', ' Quintillion', ' Sextillion', ' Septillion');
if (!isset($rank_scale_names[$rank_scale])){
return null; //too much - add higher word-numbers to $rank_scale_names
} else {
return "$lim_name{$rank_scale_names[$rank_scale]}";
}
}
<?php
function get_rank_group($rawrank) {
// Divide by 1000 and count how many divisions were done
$rank_scale = 0;
while ($rawrank >= 1000) {
$rawrank /= 1000;
$rank_scale++;
}
// Determine which Top X can be
static $rank_split = array(3, 5, 10, 15, 20, 30, 50, 100, 150, 200, 300, 500);
$lim_name = false;
// Look for a group, which is not less than the number
foreach ($rank_split as $lim) {
if ($rawrank <= $lim) {
$lim_name = $lim;
break;
}
}
// If nothing was found then it is a Top 1 of (next scaler) eg. 501 is Top 1 Thousand
if ($lim_name === false) {
$lim_name = '1';
$rank_scale++;
}
static $rank_scale_names = array('', ' Thousand', ' Million', ' Billion', ' Trillion', ' Quadrillion', ' Quintillion', ' Sextillion', ' Septillion'); // etc
if (!isset($rank_scale_names[$rank_scale])) return 'too much!'; // just check
return "Top $lim_name{$rank_scale_names[$rank_scale]}";
}
// Tests
$tests = array(1, 2, 3, 4, 16, 49, 50, 51, 299, 300, 301, 12345, 654321, 234567890, 1234567890123456789);
foreach ($tests as $test) {
print ("$test -> " . get_rank_group($test) . PHP_EOL);
}
The output:
1 -> Top 3
2 -> Top 3
3 -> Top 3
4 -> Top 5
16 -> Top 20
49 -> Top 50
50 -> Top 50
51 -> Top 100
299 -> Top 300
300 -> Top 300
301 -> Top 500
12345 -> Top 15 Thousand
654321 -> Top 1 Million
234567890 -> Top 300 Million
1234567890123456789 -> Top 3 Quintillion
As an improvement of AterLux's Solution
...
// Determine which Top X can be
if ($rawrank >= 100) {
$lim_name = (floor(($rawrank-1) / 50) + 1) * 50;
} else {
$lim_name = (floor(($rawrank-1) / 5) + 1) * 5;
}
// if its in the next higher level
if ($lim_name >= 1000) {
$lim_name = '1';
$rank_scale++;
}
static $rank_scale_names = array( ...
Output
1 -> Top 5
5 -> Top 5
9 -> Top 10
10 -> Top 10
12 -> Top 15
16 -> Top 20
49 -> Top 50
50 -> Top 50
51 -> Top 55
299 -> Top 300
300 -> Top 300
301 -> Top 350
995 -> Top 1 Thousand
12345 -> Top 15 Thousand
654321 -> Top 700 Thousand
234567890 -> Top 250 Million
1234567890123456789 -> Top 5 Quintillion
There's an array of pages,
$pages = array(
1,
2,
3,
...
100,
101
);
And there's a variable $current_page. All I'm trying to do is pagination in digg-like style, so that it would look like this,
< 4 5 6 7 .... 15 16 17 18 >
The first thing that comes to mind is to get last and previous array values from specific position that equals to $current_page.
So I started with a basic for loop, but the problem is that amount of pages could be very large, so I don't think that's an efficient thing to do. Is there any another proper way of doing this? (maybe via native array_* functions)?
The following function builds StackOverflow like pagination. The objectives are:
First and last links must be visible always
Previous and next links must be visible always
At most 4 links before/after the current page should be visible
While the following function displays the complete pager, we are primarily interested in how to calculate the surrounding pages a and b as a function of current page, pager size and page count.
function so_like_pager($current_page, $page_count, $pager_size = 4) {
if ($current_page <= $pager_size) {
// the pager for first 4 pages starts from 1
$a = 1;
$b = min(1 + $pager_size, $page_count);
} else {
// the pager for remaining pages ends at current page + 2
// and starts so that 4 links are shown
$b = min($current_page + ($pager_size >> 1), $page_count);
$a = $b - $pager_size;
}
// return array("show_from" => $a, "show_upto" => $b);
echo '<p>';
if ($current_page !== 1) {
echo '' . 1 . ' ';
} else {
echo '<b>' . 1 . '</b> ';
}
if ($a > 1 + 1) {
echo '<span>...</span> ';
}
for ($i = $a; $i <= $b; $i++) {
if ($i !== 1 && $i !== $page_count) {
if ($current_page !== $i) {
echo '' . $i . ' ';
} else {
echo '<b>' . $i . '</b> ';
}
}
}
if ($b < $page_count - 1) {
echo '<span>...</span> ';
}
if ($current_page !== $page_count) {
echo '' . $page_count . ' ';
} else {
echo '<b>' . $page_count . '</b> ';
}
echo '</p>';
}
function so_like_pager_page($page) {
return 'page-' . $page . '/';
}
Tests:
so_like_pager(1, 100);
so_like_pager(2, 100);
so_like_pager(3, 100);
so_like_pager(4, 100);
so_like_pager(5, 100);
so_like_pager(6, 100);
so_like_pager(50, 100);
so_like_pager(99, 100);
so_like_pager(100, 100);
Output:
PS: Note: I ported this function from ASP classic to PHP in a hurry and did not test against edge cases.
function get_surrounding_pages(array $pages, $current, $amount = 2) {
$pages_idx = array_flip($pages);
if (!isset($pages_idx[$current])) {
return false;
}
$offset = max(0, $pages_idx[$current] - $amount);
$limit = $amount + 1 + ($pages_idx[$current] - $offset);
return array_slice($pages, $offset, $limit);
}
$pages = range(1, 1000);
$current = 42;
get_surrounding_pages($pages, $current, 4);
// array(38, 39, 40, 41, 42, 43, 44, 45, 46)
// this will work even if your number of pages is not continuous (eg: 1, 2, 6).
$pages = array(1, 2, 5, 6, 42, 234, 1048);
$current = 6;
get_surrounding_pages($pages, $current, 2);
// array(2, 5, 6, 42, 234)
// also works if you reach the boundaries
$pages = range(1, 10);
$current = 2;
get_surrounding_pages($pages, $current, 2);
// array(1, 2, 3, 4)
$current = 9;
get_surrounding_pages($pages, $current, 2);
// array(7, 8, 9, 10)
// returns false if you ask a page that doesn't exists
$pages = range(1, 10);
$current = 42;
get_surrounding_pages($pages, $current, 2);
// false
You can use PHP's end function to get the last entry of an array.
<?php
$a = array( 1, 2, 3, 4, 5, 10 );
echo end($a);
You can also use array_slice, or array_splice to cut an array, or array_pop, which removes the last element and returns what was removed.
Maybe you can try end. Should be more efficient than looping.
Using for each I am dismantling a series of dates.
foreach( $ds as $d){
echo '<div class="bkback" onclick="bkdates(this);">'.date('M', strtotime("today + $d day")).'<br /><span class="bknum">'.date('d', strtotime("today + $d day")).'</span><br />
'.date('D', strtotime("today + $d day")).'</div>';
}
What I want to do is every put a marker <div class="marker"></div> after post 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, and 85 for the purposes of a jumping Jquery scroller.
So I need away of identifying which post we are at so far.
Any ideas?
Marvellous
Increment a variable each time through the loop - something like:
$i = 0;
foreach( $ds as $d) {
if ($i++ % 5 == 0) {
echo '<div class="marker"></div>';
}
}
I would just increment a counter and then check to see if it's divisible by 5.
$acounter = 0;
foreach( $ds as $d){
$acounter++;
if ( $acounter % 5 == 0 ) echo '<div class="marker"></div>';
echo '<div class="bkback" onclick="bkdates(this);">'.date('M', strtotime("today + $d day")).'<br /><span class="bknum">'.date('d', strtotime("today + $d day")).'</span><br />'.date('D', strtotime("today + $d day")).'</div>';
}
$counter = 0;
foreach( $ds as $d){
echo '<div class="bkback" onclick="bkdates(this);">'.date('M', strtotime("today + $d day")).'<br /><span class="bknum">'.date('d', strtotime("today + $d day")).'</span><br />
'.date('D', strtotime("today + $d day")).'</div>';
$counter++;
if ($counter % 5 == 0) { echo '<div class="marker"></div>'; }
}
generate list of hex colours?
Hi there,
Currently I am trying to generate a list of 50 hex colours that create a roughly smooth gradient from white to black, with all the colours in between.
How would I go about doing this in php?
Well,
Although The colours could prob be in a better order,
Here was my working.
<?php
function Gradient($HexFrom, $HexTo, $ColorSteps) {
$FromRGB['r'] = hexdec(substr($HexFrom, 0, 2));
$FromRGB['g'] = hexdec(substr($HexFrom, 2, 2));
$FromRGB['b'] = hexdec(substr($HexFrom, 4, 2));
$ToRGB['r'] = hexdec(substr($HexTo, 0, 2));
$ToRGB['g'] = hexdec(substr($HexTo, 2, 2));
$ToRGB['b'] = hexdec(substr($HexTo, 4, 2));
$StepRGB['r'] = ($FromRGB['r'] - $ToRGB['r']) / ($ColorSteps - 1);
$StepRGB['g'] = ($FromRGB['g'] - $ToRGB['g']) / ($ColorSteps - 1);
$StepRGB['b'] = ($FromRGB['b'] - $ToRGB['b']) / ($ColorSteps - 1);
$GradientColors = array();
for($i = 0; $i <= $ColorSteps; $i++) {
$RGB['r'] = floor($FromRGB['r'] - ($StepRGB['r'] * $i));
$RGB['g'] = floor($FromRGB['g'] - ($StepRGB['g'] * $i));
$RGB['b'] = floor($FromRGB['b'] - ($StepRGB['b'] * $i));
$HexRGB['r'] = sprintf('%02x', ($RGB['r']));
$HexRGB['g'] = sprintf('%02x', ($RGB['g']));
$HexRGB['b'] = sprintf('%02x', ($RGB['b']));
$GradientColors[] = implode(NULL, $HexRGB);
}
$GradientColors = array_filter($GradientColors, "len");
return $GradientColors;
}
function len($val){
return (strlen($val) == 6 ? true : false );
}
$count = 0;
$steps = 9;
$Gradients = Gradient("FFFFFF", "FF0000", $steps);
foreach($Gradients as $Gradient)
echo '<div style="background-color: #' . strtoupper($Gradient) . '">' . htmlentities('<option value="' . strtoupper($Gradient) . '">' . strtoupper($Gradient) . '</option>') . '</div>';
$count += count($Gradients);
$Gradients = Gradient("df1f00", "00FF00", $steps);
foreach($Gradients as $Gradient)
echo '<div style="background-color: #' . strtoupper($Gradient) . '">' . htmlentities('<option value="' . strtoupper($Gradient) . '">' . strtoupper($Gradient) . '</option>') . '</div>';
$count += count($Gradients);
$Gradients = Gradient("00df1f", "0000FF", $steps);
foreach($Gradients as $Gradient)
echo '<div style="background-color: #' . strtoupper($Gradient) . '">' . htmlentities('<option value="' . strtoupper($Gradient) . '">' . strtoupper($Gradient) . '</option>') . '</div>';
$count += count($Gradients);
$Gradients = Gradient("0000df", "000000", $steps);
foreach($Gradients as $Gradient)
echo '<div style="background-color: #' . $Gradient . '">' . htmlentities('<option value="' . $Gradient . '">' . $Gradient . '</option>') . '</div>';
$count += count($Gradients);
echo 'count: ' . $count;
with all the colours in between
You can find a path from white to black but you will have a difficult time including all colours - colour space is 3-dimensional, not linear.
You could look at this for some ideas:
http://www.exorithm.com/algorithm/view/create_gradient
Here is some customisation of the function, it's also handle case only 1 or 2 graduation needed, and also remove # on hexa before calculs and send back an array of color starting with #. so that can be directly applied to a content.
public function gradient($from_color, $to_color, $graduations = 10) {
$graduations--;
$startcol = str_replace("#", "", $from_color);
$endcol = str_replace("#", "", $to_color);
$RedOrigin = hexdec(substr($startcol, 0, 2));
$GrnOrigin = hexdec(substr($startcol, 2, 2));
$BluOrigin = hexdec(substr($startcol, 4, 2));
if ($graduations >= 2) { // for at least 3 colors
$GradientSizeRed = (hexdec(substr($endcol, 0, 2)) - $RedOrigin) / $graduations; //Graduation Size Red
$GradientSizeGrn = (hexdec(substr($endcol, 2, 2)) - $GrnOrigin) / $graduations;
$GradientSizeBlu = (hexdec(substr($endcol, 4, 2)) - $BluOrigin) / $graduations;
for ($i = 0; $i <= $graduations; $i++) {
$RetVal[$i] = strtoupper("#" . str_pad(dechex($RedOrigin + ($GradientSizeRed * $i)), 2, '0', STR_PAD_LEFT) .
str_pad(dechex($GrnOrigin + ($GradientSizeGrn * $i)), 2, '0', STR_PAD_LEFT) .
str_pad(dechex($BluOrigin + ($GradientSizeBlu * $i)), 2, '0', STR_PAD_LEFT));
}
} elseif ($graduations == 1) { // exactlly 2 colors
$RetVal[] = $from_color;
$RetVal[] = $to_color;
} else { // one color
$RetVal[] = $from_color;
}
return $RetVal;
}
Also could be helpful to take a look at my answer here.
It has the code to convert any number from any given range (let's say [0,20]) to particular color where 0 is red, 10 is yellow, 20 is green. You can use any colors and even use combination of 4 colors, so it's red - yellow - green - blue.
function rgb2hex($rgb) {
$hex = "#";
$hex .= str_pad(dechex($rgb[0]), 2, "0", STR_PAD_LEFT);
$hex .= str_pad(dechex($rgb[1]), 2, "0", STR_PAD_LEFT);
$hex .= str_pad(dechex($rgb[2]), 2, "0", STR_PAD_LEFT);
return $hex; // returns the hex value including the number sign (#)
}
function dif($c1, $c2, $percent) {
$array=array();
for($x=0;$x<3;$x++) {
$d=($c2[$x]-$c1[$x])*$percent+$c1[$x];
$array[]=(int)$d;
}
return $array;
}
for($x=0;$x<=255;$x++) {
echo rgb2hex( dif(array(255,255,255), array(0,0,0), $x/255 /*percent*/) );
echo "<br>";
}