PHP Auto Aging Task for MyBB - php

So, I was wondering if anybody would mind checking over this task and correcting it? I'm very sure I've muddled Python in with what little PHP I know, and that there are open tags.
Basically, there'll be a field where the nasty decimal age goes ($age, which will later be replaced by the appropriate field id). Our site works in months for juveniles and then years and seasons for adults. Using the nasty age, I'm trying to calculate the rounded age values and then store them as a string value which will then be set as the value of the field that will display the age ($displayagefid, will be replaced later with the appropriate field id). Only certain usergroups will be updated (the list is huge, so I left it out).
I also have no idea how to set a variable as a string using both string and the value of another variable.
Please know that I'm a complete newbie to PHP.
This is intended to run as a task on a self-hosted MyBB forum.
Thank you in advance!
<?php
function task_age($task)
{
global $mybb, $db;
$increment = 0.04167
$age = $age + $increment
floor($age*4) = $seasons
floor($age) = $years
floor($age*12) = $months
if ($year < 1) {
$display_age = $months, "mnths"
}
elseif ( ! filter_var($year, FILTER_VALIDATE_INT) ){
$display_age = $year, "yrs"
}
else {
$display age = $display_age = $years, "yrs", $seasons, "s"
};
$query = $db->query("
UPDATE mybb_userfields userfields
for ($usergroup = a || b || d || all that other crap) {
SET $dispalyagefid = $display_age;
};
");
add_task_log($task, "The age characters task successfully ran.");

I had a cursory look over your code and the first thing which sticks out is you have some of your variable assignments back to front:
$increment = 0.04167
$age = $age + $increment
floor($age*4) = $seasons
floor($age) = $years
floor($age*12) = $months
Whatever is on the left gets set to whatever is on the right, so your first two are OK but the last three need switching around.
Having said that it seems to me you are not approaching this correctly. I enter my decimal age into your site but how are you going to work out seasons? It might be my birthday tomorrow, it might have been my birthday yesterday.
You would be better off having the user enter a date of birth, from that calculate their age.
$birthday=date_create("2013-03-15");
$today=date_create('now');
$diff=date_diff($birthday,$today);
Now in the $diff variable you can check all the elements of a PHP date. So first check if they are under 18:
if ($diff->format("%y") < 18) {
$ageInMonths = ($diff->format("%y") * 12) + $diff->format("%m");
$age = "$ageInMonths months";
}
If they are over 18 you want age in years, then calculate seasons from the remaining months.
else {
$ageInYears = $diff->format("%y");
$ageInSeasons = floor($diff->format("%m") / 4);
if ($ageInSeasons > 0) {
$age = "$ageInYears years and $ageInSeasons seasons";
} else {
$age = "$ageInYears years";
}
}

Related

PHP function - output of function is the input of another function

I have the following function where certain inputs are given and then 4 outputs are given: -
function rsiNext($dailyGainAvgPrev, $dailyLossAvgPrev,$cpDailyNext){
if($cpDailyNext > 0){
$dailyGainAvgNext = (($dailyGainAvgPrev * 13) + $cpDailyNext)/14;
}else{
$dailyGainAvgNext = (($dailyGainAvgPrev * 13) + 0)/14;
}
if($cpDailyNext < 0){
$dailyLossAvgNext = (($dailyLossAvgPrev*13) + abs($cpDailyNext))/14;
}else{
$dailyLossAvgNext = (($dailyLossAvgPrev*13) + abs(0))/14;
}
$relStrNext = $dailyGainAvgNext/$dailyLossAvgNext;
if($dailyLossAvgNext == 0){
$relStrIndNext = 100;
}else{
$relStrIndNext = 100-(100/(1+$relStrNext));
}
return array($dailyGainAvgNext, $dailyLossAvgNext, $relStrNext, $relStrIndNext);
}
I output the values using the following line of code:
//Get value for day 15
list($dailyGainAvg02, $dailyLossAvg02, $relStr02, $relStrInd02) = rsiNext($averageGains14, $averageLosses14, $priceDifferences[15]);
echo '<tr><td>'.$dailyGainAvg02.'</td><td>'.$dailyLossAvg02.'</td><td>'.$relStr02.'</td><td>'.$relStrInd02.'</td></tr>';
Now when I want the value for day 16 I use the following line of code:
//Get value for day 16
list($dailyGainAvg03, $dailyLossAvg03, $relStr03, $relStrInd03) = rsiNext($dailyGainAvg02, $dailyLossAvg02, $priceDifferences[16]);
echo '<tr><td>'.$dailyGainAvg03.'</td><td>'.$dailyLossAvg03.'</td><td>'.$relStr03.'</td><td>'.$relStrInd03.'</td></tr>';
The output of day 15 is the input of day 16, the output of day 16 is the input of day 17. The output of day 17 is the input of day 18, etc...
I need to repeat the list for 100 days. How can I go about it without repeating the list line for another 100 days?
Thank you.
Assuming you have the $priceDifferences array fully populated, something like the following should do:
$cur_dailyGainAvg = 0; // you need to initialize this value appropriately
$cur_dailyLossAvg = 0; // you need to initialize this value appropriately
for ($idx = 1; $idx <= 100; $idx++) {
list($new_dailyGainAvg, $new_dailyLossAvg, $new_relStr, $new_relStrInd) = rsiNext($cur_dailyGainAvg, $cur_dailyLossAvg, $priceDifferences[$idx])
// print
echo '<tr><td>'.$new_dailyGainAvg.'</td><td>'.$new_dailyLossAvg.'</td><td>'.$new_relStr.'</td><td>'.$new_relStrInd.'</td></tr>';
// shift the new values onto the current, and repeat the calculation
$cur_dailyGainAvg = $new_dailyGainAvg;
$cur_dailyLossAvg = $new_dailyLossAvg;
}
Basically distinguish between your "current" values, which you feed into your function, and the "new" values that come out, then "shift" the new onto the current ones and repeat.
You may have to check the boundaries of the loop.

Calculating Vat Rates Based on some variables

The following function is working up to a point where I have to calculate the $vatamount based on some rules.
Ive got all my POST content from a script that fires my ajax request (code below is the code from the ajax URL).
The rules are - If the $bookingtype value is a "Corporate" booking or a "Groups" booking then the vat rate is calculated over the length of stay. 20% for anything up to 28 nights and 4% for anything over 28 nights.
However, if the $bookingtype value is a "Leisure" booking then the vat rate is 20% regardless of the length of stay.
I've got the function to return the right VAT percentage. But that last if statement just isn't working for me. Im a php newbish and i think I've done well to get this far with it. Just need some assistance completing this function. I think I've screwed my syntax in there somewhere lol
The last echo should echo the calculated vat amount.
Thanks in advance.
function implement_ajax_vat() {
if(isset($_POST['arrivaldate']))
{
//get the start and end dates
$startdate = ($_POST['arrivaldate']);
$enddate = ($_POST['leavingdate']);
$datetime1 = new DateTime($startdate);
$datetime2 = new DateTime($enddate);
$interval = $datetime1->diff($datetime2);
$numberofnights = $interval->format('%a nights');
//calculatge the VAT amount
$bookingtype = ($_POST['bookingtype']);
$rentalprice = ($_POST['rentalprice']);
//check numbr of nights
if($numberofnights >= 29){
$vatrate = "4";
} elseif ($numberofnights <= 28) {
$vatrate = "20";
}
//get the booking type and check if its a variable rate
if(($bookingtype = 'Corporate') || ($bookingtype = 'Groups')){
$vatamount = ($rentalprice / 100) * $vatrate;
} elseif ($bookingtype = 'Leisure') {
$vatamount = "20";
}
echo $vatamount;
die();
}
}
You are assigning values instead of comparing: use double equals sign ==:
if($bookingtype == 'Corporate' || $bookingtype == 'Groups'){
^ ^
$vatamount = ($rentalprice / 100) * $vatrate;
} elseif ($bookingtype == 'Leisure') {
^
$vatamount = 20;
}
That's why first statement yields true as you assign and return there non-empty string, so you never go to elseif section.

How to manage couple of combo box working together?

I'm having two comboboxes. One is like 'admin', 'city' , 'theatre' and the other one is daily and weekly. If user select one of item in first and daily in second it shows daily operations. If user select one of item in the first one select nothing in second one it shows daily and weekly operations. If user does not select anything in first and daily in second it brings all operations daily and son on.
Therefore I think there is 2^3 if conditions. Is there anyway to reduce this? I am using PHP language but I think core algorithm is same in all languages!
Following is what I have done so far for three conditions if it is admin and daily and weekly:
<?php
if(strlen($_POST['attribute'])>0)
{
echo "For admin: ";
echo "</br>";
//If admin
if($_POST['attribute'] == 'Admin'){
//If daily
if($_POST['date'] == 'Daily'){
echo "The only feature to show update is making a user admin\n";
echo "</br>";
$fh = fopen('back-up/makeadmin.txt','r');
$foo = true;
while ($line = fgets($fh)) {
if($foo){
//Current time
$now = new DateTimeImmutable();
//One week ago
$oneDayAgo = $now->sub(new DateInterval('P1D'));
echo "</br>";
echo "</br>";
$date = DateTime::createFromFormat('m/d/Y h:i:s a+', $line);
//Here you can compare your dates like any other variables
if ($date > $oneDayAgo) {
/* Nothing echo "Current date is less than 1 week old";
Break;
*/
break;
}
if ($date < $oneDayAgo) {
echo "$line";
}
var_dump($line);
}
$foo = (!$foo);
}
fclose($fh);
}
else { /*if($_POST['date'] == 'Weekly'){*/
echo "The only feature to show update is making a user admin\n";
echo "</br>";
$fh = fopen('back-up/makeadmin.txt','r');
$foo = true;
while ($line = fgets($fh)) {
if($foo){
//Current time
$now = new DateTimeImmutable();
//One week ago
$oneWeekAgo = $now->sub(new DateInterval('P1W'));
echo "</br>";
echo "</br>";
$date = DateTime::createFromFormat('m/d/Y h:i:s a+', $line);
//Here you can compare your dates like any other variables
if ($date > $oneWeekAgo) {
/* Nothing echo "Current date is less than 1 week old";
Break;
*/
}
if ($date < $oneWeekAgo) {
echo "Current date is more than 1 week old";
}
var_dump($line);
}
$foo = (!$foo);
}
fclose($fh);
}
//If not daily
else
{
echo "weekly";
}
}
}
else
{
echo "Not admin";
}
?>
I'm not familiar with PHP, but if your code has a lot of hard-coded if statements, it's a clear sign that you need a better data structure, or maybe any data structure at all.
For example, you duplicate a whole block of code that only differs in that the first uses $oneDayAgo and the second $oneWeekAgo?. You could easily make that into a variable someTimeAgo that is a time span of seven days or one day, depending on the value of your second list box.
I'm not sure what the selection of the first box is for, maybe the file to read from? You might be able to find some common behaviour fro these three cases, too, and try to express them in variables rather than code.
You could probably store the relevant data is an associative array whose keys are the values of the list boxes:
$span = array("Daily" => "P1D", "Weekly" => "P1W");
As a next step, you could even populate your list from PHP with the keys (the values left of the fat arrows) of the array and you could easily extens the list together with the time spans without adding any new code, just new data.
Lastly, an UI niggle: If you have only two values, you shouldn't use a drop-down list box. Use a group of two radio-buttons next to each other and the user will be able to see both options at one glance without having to click anything. (I also don't think these are combo boxes, because combo boxes allow to enter a value by either typing it in manually or selecting it from a drop-down list.)

Making an array out of variables and update its contents based on one of the variables

I have a question that pertains to gathering events from tables in a calendar program where they are separated into "events" or "repeated events". I can get all individual events perfectly well now (thanks to Chris on this site), but if they are repeating events I have to calculate it from what is given in this particular db. If I change the types or the data in the db, it will probably trash the calendar so I have to use what I have.
The variables I have sorted out so far are:
$quid2 = The IDs for today's events that are classified as repeating events (needed earlier)
$quname = The repeated event names
$qucls = The date UNIX time for the last sent reminder of events dated today
$qutype = One of these words - daily, weekly, monthly or yearly
$qudesc = A description of the event
These variables all have the same number of items and are ordered correctly between each other. (I Hope)
Below is the logic I am trying to accomplish. It are most assuredly not proper syntax but I think it is understandable; I need to figure out what the syntax and form is. I am utterly and completely new at this... so please be gentle...
It needs to be put in an array (I think)
$arr1 = some type of array($quname, $qucls, $qutype, $qudesc)
update the array...
IF $qutype($row2) = "daily", then + 1440 to it's $qucls($row[1])
IF $qutype($row2) = "weekly", then + 10080 to it's $qucls($row[1])
IF $qutype($row2) = "monthly, then + 1 month to it's $qucls($row[1])
IF $qutype($row2) = "yearly", then + 1 year to it's $qucls($row[1])
Then final product...
while ($row = mysql_fetch_array($arr1, MYSQL_NUM)) {
$UxTime = $row[1];
date_default_timezone_set('America/Denver');
$Time = date("H:i", $UxTime);
$qufinal = sprintf("Event: %s \nTime: %s \nDesc: %s \n\n", $row[0], $Time, $row[3);
}
...
This is a big learning project for me. I don't know enough PHP and mysql to make this work but I know just enough to get me in trouble. Thanks!
EDIT: adding the queries from which I made these variables:
$today = date("Ymd");
mysql_select_db($dbname);
$query1 = "SELECT cal_id, cal_name, cal_date, cal_time, cal_type, cal_description FROM webcal_entry WHERE cal_type = "M" AND cal_date != " . $today;
$wequ1 = mysql_query($query1)
while ($row = mysql_fetch_array($wequ1, MYSQL_NUM)) {
$quid1 = $row[0], $quname = $row[1], $qutime = $row[2], $qudesc = $row[3];
}
$query2 = "SELECT cal_id, cal_type, cal_ByDay FROM webcal_entry_repeats WHERE cal_id = " . $quid1;
$wer1 = mysql_query($query2)
while ($row = mysql_fetch_array($wer1, MYSQL_NUM)) {
$quid2 = $row[0] $qutype = $row[1], $qubdy = $row[2];
}
$query3 = "SELECT cal_id, cal_last_sent FROM webcal_reminders WHERE cal_id = " . $quid2;
$wer2 = mysql_query($query3)
while ($row = mysql_fetch_array($wer2, MYSQL_NUM)) {
$qucls = $row[1];
}
The syntax for arrays is as follows:
$arrayName = array($quname, $qucls, $qutype, $qudesc);
Then you can access the values by their index on the array variable:
$arrayName[0] == $quname
$arrayName[1] == $qucls
...
You can also define it as associative array:
$arrayName = array(
"quname" => $quname,
"qucls" => $qucls,
"qutype" => $qutype,
"qudesc" => $qudesc
);
Using this syntax you can access the elements by their name:
$arrayName["quname"] == $quname
$arrayName["qucls"] == $qucls
...
More reading on this: Arrays
However, you don't really need an array for what you plan to do here. Arrays are very useful if you want to store data that is structurally equal. This applies e.g. to rows in a database: They always have the same number of entries, and the columns are of the same type.
If you have just one dataset at that point of code (one event in this case), then you need no array. Of course you have several events, but as they are processed in a loop (I assume) you handle only one event at a time, and then head to the next.
So, you want to modify a variable depending on the value $qutype. To do that, you can use a switch statement:
$dateObj = date_create("#$qucls");
switch($qutype) {
case "daily":
date_add($dateObj, date_interval_create_from_date_string("1 day"));
break;
case "weekly":
date_add($dateObj, date_interval_create_from_date_string("1 week"));
break;
case "monthly":
date_add($dateObj, date_interval_create_from_date_string("1 month"));
break;
case "yearly":
date_add($dateObj, date_interval_create_from_date_string("1 year"));
break;
}
$qucls = date_format($dateObj, "U");
I don't add the number of seconds, because that would work for days and weeks- but not for months and years, as they don't have a fixed number of seconds.
If you have questions about the functions I used above you can look up their documentation on php.net.
In the code you show you must not use mysql_fetch_array.
That function is only meant for result rows you got from a call to mysql_query, but not for normal arrays.
You don't need the while loop either. All you have to do is formatting $qucls to a readable format and produce the final string:
date_default_timezone_set('America/Denver');
$Time = date("H:i", $qucls);
$qufinal = sprintf("Event: %s \nTime: %s \nDesc: %s \n\n", $quname, $Time, $qudesc);
Edit:
Like discussed in the comments here is the revised and commented code you edited in:
$today = date("Ymd");
mysql_select_db($dbname);
// You need to use single quotes at the 'M'. Using double quotes will
// end the string and thus leading to incorrect syntax
$query1 = "SELECT cal_id, cal_name, cal_date, cal_time, cal_type, cal_description FROM webcal_entry WHERE cal_type = 'M' AND cal_date != " . $today;
$wequ1 = mysql_query($query1);
// This is a counter variable which is incremented in the loop
$i = 0;
// This is the outer while loop used to gather and store the events
while ($row = mysql_fetch_array($wequ1, MYSQL_NUM)) {
// Store the results in arrays
// Statements must be seperated by a ;
$quid1[$i] = $row[0];
$quname[$i] = $row[1];
$qutime[$i] = $row[2];
$qudesc[$i] = $row[3];
$query2 = "SELECT cal_id, cal_type, cal_ByDay FROM webcal_entry_repeats WHERE cal_id = " . $quid1[$i];
$wer1 = mysql_query($query2);
// Assuming that IDs are unique this query can only return one entry. Therefore no while is
// needed, but an if statement tests if the ID actually matched a result
if ($row = mysql_fetch_array($wer1, MYSQL_NUM)) {
//$quid2[$i] = $row[0]; <- the query above ensures that $quid1[$i] == $quid2[$i]. No need to store it again
$qutype[$i] = $row[1];
$qubdy[$i] = $row[2];
}
$query3 = "SELECT cal_id, cal_last_sent FROM webcal_reminders WHERE cal_id = " . $quid1[$i];
$wer2 = mysql_query($query3);
// Same as above; If the IDs are unique then you need no loop
if ($row = mysql_fetch_array($wer2, MYSQL_NUM)) {
// The $i++ used here is the short form. As this is the last time $i is
// used in the loop it needs to be increased before the next round. You can do
// this like this or in an extra statement. This way it's evaluated and then increased
$qucls[$i++] = $row[1];
}
// End outer while loop
}
// Now go through the results. $i holds the number of entries in the arrays + 1
// Secondary counter variable and for-loop
for ($j = 0; $j < $i; $j++) {
// Adding the dates to $qucls, formatting the string, ...
// Access them like above: $qucls[$j]
// Do not increase $j manually though - the for loop does that for you already
}
Please note that this code is untested. It's syntactically correct though.
On a side note: You are currently using three different database queries to gather the data.
You can easily merge them into a single query using SQL JOINs. If you want somebody to show you how to do that, you can show them in a seperate question and ask for them to be joined into one.

Comparing missing numbers in an array. PHP

I got this script which looks up taken times in this table and then removes those times from these three arrays. The arrays are times 1-24.
The ultimate goal of this script is to compare all the missing times from these arrays and make one big array with only the available times.
The catch is it needs to check if a time is missing three times in a row. If it is, that time will not display in the final array.
For example:
<?php
include 'db-connect.php';
if (isset($_GET['month']) && isset($_GET['day']) && isset($_GET['year'])) {
$month = $_GET['month'];
$day = $_GET['day'];
$year = $_GET['year'];
//string together date
$date = $month."/".$day."/".$year;
//define the queries
$sql1 = mysql_query("SELECT start_time, server FROM classes WHERE date = '$date' AND server = '1'");
$sql2 = mysql_query("SELECT start_time, server FROM classes WHERE date = '$date' AND server = '2'");
$sql3 = mysql_query("SELECT start_time, server FROM classes WHERE date = '$date' AND server = '3'");
//define time lists for each server
$timelist1 = range(1, 24);
$timelist2 = range(1, 24);
$timelist3 = range(1, 24);
//unset the arrays with the taken times for server 1
while($query1 = mysql_fetch_array($sql1)) {
unset($timelist1[$query1['start_time'] - 1]);
}
//unset the arrays with the taken times for server 2
while($query2 = mysql_fetch_array($sql2)) {
unset($timelist2[$query2['start_time'] - 1]);
}
//unset the arrays with the taken times for server 3
while($query3 = mysql_fetch_array($sql3)) {
unset($timelist3[$query3['start_time'] - 1]);
}
//now see which times are missing three times in a row and make one final array of available times.
//code goes here...
}
?>
Instead of your current strategy you could just store the number of arrays each time is found in, like:
include 'db-connect.php';
if (isset($_GET['month']) && isset($_GET['day']) && isset($_GET['year'])) {
$month = $_GET['month'];
$day = $_GET['day'];
$year = $_GET['year'];
//string together date
$date = $month."/".$day."/".$year;
//define time list
$timelist = array_fill(1, 24, 0);
while($query1 = mysql_fetch_array($sql1)) {
$timelist[$query1['start_time']]++;
}
while($query2 = mysql_fetch_array($sql2)) {
$timelist[$query2['start_time']]++;
}
while($query3 = mysql_fetch_array($sql3)) {
$timelist[$query3['start_time']]++;
}
$timelist = array_keys(array_filter($timelist, 'equals3'));
function equals3($x){
return $x == 3;
}
Now $timelist is an array of times that were found in all three queries. If you want an array of times that were missing from at least one query use this instead of the last few lines:
$timelist = array_keys(array_filter($timelist, 'lessThan3'));
function lessThan3($x){
return $x < 3;
}
Edit for variable amount of servers.
// Here you can list the servers you want to include in the query
// In an array form so it can be filled easily
$servers = array(1,2,4,5);
$num_servers = count($servers);
// Convert servers into queryable format
$servers = '(\''.implode('\',\'', $servers).'\')';
$query = 'SELECT `start_time`, COUNT(*) as `count` FROM `classes`
WHERE `date` = \''.$date.'\' AND `server` IN '.$servers.'
GROUP BY `start_time`';
$result = mysql_query($query);
$timelist = array_fill(1, 24, 1);
while($row = mysql_fetch_row($result))
if($row[1] == $num_servers) // `start_time` is missing from at least one server
unset($timelist[$row[0]]);
$timelist = array_keys($timelist);
// Now $timelist is an array of times that are available on at least one server from the query
Please note that since your date variable comes from $_GET you should be very careful of MySQL Injection attacks. Someone could delete your whole database, or worse, if you don't have the right protection in place. Please read this: http://www.learnphponline.com/security/sql-injection-prevention-mysql-php

Categories