I am trying to count how many hits I have on my site each hour, but am not sure how to approach this.
Here is what i have now:
if($cacheAvailable == true){ // WE GOT A CACHE
date_default_timezone_set("UTC");
$thisHour = date("H", time());
$moveStats = $memcache->get('moveStats');
if(!$moveStats){
$todayStats = array(array(hour => $thisHour, hits => 1, executetime => $total_time));
$memcache->set('moveStats', $todayStats);
}
foreach ($moveStats as $k => $v) {
if($v['hour'] == $thisHour){
$moveStats[$k]['hits']=$moveStats[$k]['hits']+1;
}
}
$memcache->set('moveStats', $moveStats);
echo '<pre>';
print_r($moveStats);
echo '</pre>';
}
This makes an array like this:
Array
(
[0] => Array
(
[hour] => 18
[hits] => 6
[executetime] => 0
)
)
//##### EDIT ######//
I am able to add to the current hour but I don't know how to add a new hour when the clock turns into the new hour?
Hoping for help and thanks in advance.
You just have to check if that index already exists, if not create a new one, and always increase the old value:
$todayStats = $moveStats;
if (!isset($todayStats [$thisHour])) {
$todayStats[$thisHour] = 0;
}
$todayStats[$thisHour]['hits']++;
$todayStats[$thisHour]['executetime'] = $total_time;
But you have some other problems in your implementation:
- Don't use string without quotes. That will try to call a constant with that name and only as fallback return the string itself. It also raises a notice.
- $thisHour won't contain the current hour. If you really want to have the hour try: date('H') only.
Related
Okay I am trying to create a boss kill log for a game that I play(Runescape). I found on the internet that the developers were gracious enough to have an api with an adventure's log that logs different activities you do in game, bossing is one of em. So I got the info into a multidimensional array structured as so:
Array
(
[magic] => 5379429
[questsstarted] => 5
[totalskill] => 2333
[questscomplete] => 134
[questsnotstarted] => 95
[totalxp] => 163169890
[ranged] => 18656921
[activities] => Array
(
[0] => Array
(
[date] => 17-Dec-2017 21:51
[details] => I killed 8 graceful followers of Armadyl, all called Kree'arra. The gods have little imagination for names.
[text] => I killed 8 Kree'arras.
etc
.
.
)
The above array isn't the whole array I shortened it to not make this too long because it is a big array. What I am trying to do is only get the values that say "I killed x boss", in this case the boss would be Kree'arra. What's got me stumped is that the string contains a number that changes, like so:
"I killed 5 kree'arras"
"I killed 3 kree'arras"
so I cant use an if statement because I would never know the exact string to use the comparison operator. I tried using array_search('I killed', array_column($runemetrics, 'text')), but got a blank screen. I tried a bunch of answers that I found on stackoverflow, but either I got a blank screen or it was partially what I wanted. I am thinking this is a simple solution. Here is my code:
$get_runemetrics = file_get_contents("https://apps.runescape.com/runemetrics/profile/profile?user=Thee_Newb&activities=20");
$runemetrics = json_decode($get_runemetrics, true);
if(isset($runemetrics["activities"]) === TRUE){
for($i = 0; $i < count($runemetrics["activities"]); $i++){
echo $runemetrics["activities"][$i]["text"];
}
}
EDIT: I forgot to mention that the boss changes too
You can use strpos() to check if text has 'I killed' string
for($i = 0; $i < count($runemetrics["activities"]); $i++){
$text = $runemetrics["activities"][$i]["text"];
if (strpos($text, 'I killed') > -1) {
echo $text . '<br>';
}
}
I have the following array which contains a set of periods:
Array
(
Array
(
[period_start] => 1
[period_end] => 12
)
Array
(
[period_start] => 4
[period_end] => 8
)
)
I want to split the periods that overlap other periods. For example, because the second period is overlapping the first, it should split the first period into two periods so that it looks something like this:
Array
(
Array
(
[period_start] => 1
[period_end] => 3
)
Array
(
[period_start] => 4
[period_end] => 8
)
Array
(
[period_start] => 9
[period_end] => 12
)
)
So that no two periods contain a start and end value within the range of another period. But I have no idea how best to achieve this in an efficient manner. Any help would be appreciated.
EDIT: To the comments, this post was more a plea for rubber ducking, not for getting someone else to do my work for me. I've got a solution to my problem (brace yourselves):
// Sort the collection by period_start in ascending order.
function sortByPeriod(&$collection) {
usort($collection, function ($value1, $value2) {
if (!array_key_exists('period_start', $value1) || !array_key_exists('period_start', $value2)) {
return 0;
}
if ($value1['period_start'] == $value2['period_start']) {
return 0;
}
return $value1['period_start'] < $value2['period_start'] ? -1 : 1;
});
}
$periods = array();
$products = array(
array(
'period_start' => 4,
'period_end' => 8
),
array(
'period_start' => 1,
'period_end' => 12
)
);
sortByPeriod($products);
foreach ($products as $product) {
// Store them in $periods using a key, so that if an identical period comes along on a future iteration, it doesn't get counted. The keys aren't required.
if (array_key_exists('period_start', $product) && !is_null($product['period_start'])) {
if (!array_key_exists($product['period_start'] . '-' . $product['period_end'], $periods)) {
$productStart = $product['period_start'];
$productEnd = $product['period_end'];
// Go through each period already inserted
foreach ($periods as &$period) {
$periodStart = $period['period_start'];
$periodEnd = $period['period_end'];
If the product's start overlaps the period's end
if ($productStart <= $periodEnd) {
// Set that period's end to the product's start - 1
$period['period_end'] = $productStart - 1;
// If the overlapping product is entirely within the period (e.g. period is 1-12, product is 4-8, like the example provided earlier)
if ($productEnd <= $periodEnd) {
// Add a new period, whose start is the product's end + 1 and the end is the initial period's end.
$periods[($productEnd + 1) . '-' . $periodEnd] = array(
'period_start' => $productEnd + 1,
'period_end' => $periodEnd
);
// The product's period isn't entirely within the period (e.g. period is 1-6, product is 4-8)
} else {
// Add a new period from product start to period end (e.g. following the example above, the period becomes 1-3, insert 4-6)
$periods[$productStart . '-' . $periodEnd] = array(
'period_start' => $productStart,
'period_end' => $periodEnd
);
// Set the product's start to the period's end + 1 (e.g. 7)
$productStart = $periodEnd + 1;
}
}
}
// Add the period (following the example iteration above, product start = 7, end = 8)
$periods[$productStart . '-' . $productEnd] = array(
'period_start' => $productStart,
'period_end' => $productEnd
);
}
}
// After one iteration, we have 1-3, 4-6 and 7-8
}
sortByPeriod($periods);
$periods = array_values($periods);
print_r($periods);
Which works and yields the expected output as shown above. However, as you can see, it isn't very well organised and I feel as if there would be a better way to approach this.
Thank you.
I realised that I was going about this in a bit of a strange way. My thinking was that if I had a period range (let's say 1-8) and another (4-12), it should split these ranges up and leave it with 1-3, 4-8, 9-12. While the output is indeed the output that I desire, getting to it by splitting it up and adding new periods to compensate for the missing ranges in between was too complicated. I was thinking of it like this (and I had it working this way):
I have three loaves of bread, each a different size. I need to split them all up so that I have several slices of the loaf, enough to equal the content of the largest loaf. Okay, let's take a piece out of this loaf, a piece out of that loaf, and put it all together.
It's all a mess. Really, the best way to go about it is to use the largest loaf and cut in the exact places that the other loaves would fit, so instead of using three loaves, i'm just using one.
I put the theory into practice (using JavaScript. I can port it to PHP). First I need a way for each period to be indistinguishable, so that if my initial periods are something along the lines of 1-3, 1-12 and 4-8, it will count the 1-3 and 4-8 as two separate periods. Luckily, all of my items are products that have a normal price and a discounted price. The discounted price takes effect during the discount period.
Next, I need to identify the largest period and note it's start and end:
var range = {};
this.products.forEach(product => {
if (!range.start) {
range.start = product.start;
}
if (!range.end) {
range.end = product.end;
}
if (product.start < range.start) {
range.start = product.start
}
if (product.end > range.end) {
range.end = product.end;
}
});
Now, for each product, I iterate from start to end by 1 each iteration, storing the product's discount price if it's period is within the current iteration, or otherwise it's normal price:
var periodCounter = [];
this.products.forEach(product => {
for (i = range.start; i <= range.end; i ++) {
if (!periodCounter[i]) {
periodCounter[i] = 0;
}
if (i >= product.start && i <= product.end) {
periodCounter[i] += product.def_amount;
} else {
periodCounter[i] += product.amount;
}
}
});
Great. Now I have an array filled with prices for all products during each single one month period. Now I need to identify the actual periods. This is really easy - iterate through the array, check to see if the current price is equal to the previous price. If it is, we're still in a period. If it isn't, we've reached the end of that period and started a new one:
var periods = [];
var periodStart = 0;
var periodEnd = 0;
for (i = range.start; i <= range.end; i ++) {
if (i == range.start) {
periodStart = i;
} else {
if (periodCounter[i] != periodCounter[i-1]) {
periodEnd = i-1;
periods.push({
start: periodStart,
end: periodEnd,
amount: periodCounter[i-1]
});
periodStart = i;
}
if (i == range.end) {
periods.push({
start: periodStart,
end: i,
amount: periodCounter[i]
});
}
}
}
If by any chance the totals of two "logical" periods equal the same price, it doesn't really matter. The end user just needs to know what the price is for these periods, they gain no information in knowing that two periods equal the same price, so in essence, you might as well just concatenate those periods into one large period, which is what would happen. If it's absolutely necessary to display the true "logical" periods, instead of storing the price in the counter, use a byte value (1, 2, 4, 8, etc).
I made a codepen for this project, using Vue.js and Bulma to display the products and the correct periods. Of course, I'm open to better ways that I might be able to go about this.
I have a form where users have to enter timecodes or time values 00:00:00, which at the end must fulfill the condition that each timestamp must be larger than the previous. I know it can be achieved by processing the $_POST['timecode']. However can't make it work. This is what I've been working around. Sorry for my ignorance, but being sure this is the way and not getting the result drove me to ask here.
$q_tc=count($_POST['timecode']);
for ($w = 0; $w < $q_tc; $w++) {
if ($_POST['id_ts'][$w] > $_POST['id_ts'][$w+1]) {
echo "error: should be smaller than next timecode";
} else {
// ...
}
}
What I get after running this code is that everytime an error message is deployed, even without the condition being placed.
I'm running PHP 5.4 on a apache server. This is what the $_POST['timecode'] contains:
Array ( [0] => 00:00:30 [1] => 10:00:00 [2] => 12:00:00 )
And as it can be seen, no error should be generated, but the code does not check accurately the requested condition.
You end up comparing the last one to a null value, because you look at 0 and 1, then 1 and 2, then 2 and 3, but key 3 doesn't exist.
Try this fix. Skip the first one, compare each to the previous.
$arr = array('00:00:30', '10:00:00', '12:00:00');
$q_tc=count($arr);
for ($w = 1; $w < $q_tc; $w++) {
if ($arr[$w-1] > $arr[$w]) {
echo "error: should be smaller than next timecode";
}
}
I am experiencing an issue with a wordpress site that I've not encountered before. Allow me to provide some quick details...
Background:
The site I am working on is for a University Radio Station. The station is setup with 9 2 hour blocks of "Show Time" which is split up between various student shows. These blocks of time start at 8AM and end at 2AM, with 2 hour intervals. So 8AM to 10AM and 10AM to 12PM Noon etc... What we need to do is display the show that is "Now Playing" and the show that comes right after "Playing Next".
That said... I have written the below code and it is confirmed working on a test site... That site is http://khill.mhostiuckproductions.com/siteNowplaying/ The code works exactly as I need it to with no faults.
Now when I switch this over to wordpress I get the following error: Warning: Invalid argument supplied for foreach() in [directory to file and line #]
What I have determined/know with the assistance of a gentleman in chat yesterday:
The above error is occurring because the array $showBlocks in the foreach is empty. I know this by doing a var_dump on that array on the wordpress site in which the var dump outputs NULL. This has something to do with my variables being global (global variables can get nasty from what I understand which makes sense).
Said gentleman provided a possible solution which I was not able to get fully working before I had to call it quits for the day, I'll go over that proposed solution below...
The code:
Now I realize this code is terrible and I need to be using classes, and ultimately a database, my code looks like this right now as I do not have a ton of PHP or SQL experience, and I have a deadline that's quickly approaching. I need to get this knocked out and working so I can move on and finish the rest of the site. I plan to develop this further in the background once the new theme launches, ultimately it will tie into the wordpress CMS as a plugin/widget.
That said... I realize what I am doing is very brute force and I am ok with brute forced solutions. As I've said above, my code works perfectly on a standalone test site, it is only when it is moved into wordpress that it breaks.
I have simplified my code to provide only what is needed for a single day (lots of duplicate stuff for each day of the week, you'll understand as you continue further down).
I have the following variables at the top of my file...
$day = date(D); // Textual representation of day in the format of "Mon, Tue, Wed" etc.
date_default_timezone_set('America/New_York'); // Set the default time zone (EST)
I have the following arrays... The first one establishes my "blocks" of time as per their starting and ending times, the second one brings in variables which store my "outputs". These outputs are in a separate file which is included above the file that has all of the code I am showing here. The second array is suplicated for each day of the week, and the variable names change accordingly.
// $showBlocks Array
$showBlocks = array ( // Define available blocks of show time | starts at 8AM ends at 2AM with 2 hour increments
'a' => array ('00:00:01', '02:00:00'), // MIDNIGHT TO 2AM
'b' => array ('02:00:00', '08:00:00'), // OFF AIR TIME
'c' => array ('08:00:00', '10:00:00'),
'd' => array ('10:00:00', '12:00:00'),
'e' => array ('12:00:00', '14:00:00'), // NOON to 2PM
'f' => array ('14:00:00', '16:00:00'),
'g' => array ('16:00:00', '18:00:00'),
'h' => array ('18:00:00', '20:00:00'),
'i' => array ('20:00:00', '22:00:00'),
'j' => array ('22:00:00', '23:59:59'),
);
$mondayShows = array (
'a' => $sunday12a_2a, // MIDNIGHT TO 2AM
'b' => $offAirTime, // OFF AIR TIME
'c' => $monday8a_10a,
'd' => $monday10a_12,
'e' => $mondayy12_2, // NOON to 2PM
'f' => $monday2_4,
'g' => $monday4_6,
'h' => $monday6_8,
'i' => $monday8_10,
'j' => $monday10_12a,
);
The first function... This just checks what day it is, and echo's the appropriate function for that day which is the next bit of code I'll show you. I echo the nowPlaying() function in my site where I want my output to appear.
function nowPlaying() {
global $day;
if ($day == "Sun") { //IF DAY IS TRUE THEN PERFORM AN ACTION
echo sundayShow();
} else if ($day == "Mon") {
echo mondayShow();
} else if ($day == "Tue") {
echo tuesdayShow();
} else if ($day == "Wed") {
echo wednesdayShow();
} else if ($day == "Thu") {
echo thursdayShow();
} else if ($day == "Fri") {
echo fridayShow();
} else if ($day == "Sat") {
echo saturdayShow();
}
}
For the sake of simplicity I am going to show you only one of the functions that appear inside the above function, we'll use Monday since it's Monday.
This function uses the two arrays seen above as inputs, the $mondayShows array variable changes to $tuesdayShows for the tuesdayShow() function. (basically exactly the same code with different variable name for the array input) The foreach here is the line where the error code says there is a problem. Again, as someone from the php chat guided me to, is because when I put this code into wordpress, suddenly my array becomes empty.
function mondayShow() {
global $mondayShows, $showBlocks; // GLOBALIZE THESE VARIABLES
foreach ($showBlocks as $name => $range) {
if (time() > strtotime($range[0]) && strtotime($range[1]) > time()) { // checks if time() is between defined ranges from $showBlocks array
echo($mondayShows[$name]);
}
}
}
Earlier I mentioned also displaying what is "Playing Next". This is handled by duplicating all of the above code with new names, for example the name of the equivalent code for the above function becomes mondayNextShow(). To make the code display the actual next show I add 7200 (number of seconds in 2 hours) to time() so... time + 7200. This addition is inside the if statement of the above code... so it now looks like this...
if (time() + 7200 > strtotime($range[0]) && strtotime($range[1]) > time() + 7200) {
What was suggested to me in chat but I was unable to get working:
In chat, it was suggested I get rid of the global variables, and include my array directly into the function via a separate file... I tried this by moving the above $showBlocks array to a separate file "now-playing-array.php" for instance. The array code was changed from the above to instead return the array so it now looks like this:
return array (
'a' => array ('00:00:01', '02:00:00'), // 12AM MIDNIGHT TO 2AM
'b' => array ('02:00:00', '08:00:00'), // OFF AIR TIME
'c' => array ('08:00:00', '10:00:00'),
....................
);
I then remove $showBlocks from global variables of the above function, and I include said file into the function using the __DIR__ magic constant.
The above function now looks like this:
function mondayShow() {
global $mondayShows; // GLOBALIZE THESE VARIABLES
$showBlocks = include __DIR__."/now-playing-arrays.php";
foreach ($showBlocks as $name => $range) {
if (time() > strtotime($range[0]) && strtotime($range[1]) > time()) { // checks if time() is between defined ranges from $showBlocks array
echo($mondayShows[$name]);
}
}
}
A var_dump on $showBlocks now produced: bool(false)
Now the questions...
Please keep in mind this code is very brute forced and I know and realize that, but that's what I want for now. I am going to be using this project to expand my PHP into using classes and databases and such but I don't have the time for that now. I am not looking for, your code is terrible you should just start over and do it the right way answers... I know that already.
First, if you understand the route this gentleman from chat was trying to take me, is it the best route to take?
If it is the best route to take then, how do I go about finishing it off? From what I gather the bool(false) thing means it can't find my file? The files are all in the same folder.
You could put your return arrays into functions, and then simply call the function and assign it to a variable from within your mondayShow() function:
function showBlocks(){
return array (
'a' => array ('00:00:01', '02:00:00'), // MIDNIGHT TO 2AM
'b' => array ('02:00:00', '08:00:00'), // OFF AIR TIME
'c' => array ('08:00:00', '10:00:00'),
'd' => array ('10:00:00', '12:00:00'),
'e' => array ('12:00:00', '14:00:00'), // NOON to 2PM
'f' => array ('14:00:00', '16:00:00'),
'g' => array ('16:00:00', '18:00:00'),
'h' => array ('18:00:00', '20:00:00'),
'i' => array ('20:00:00', '22:00:00'),
'j' => array ('22:00:00', '23:59:59'),
);
}
function mondayShows(){
return array (
'a' => "a", // MIDNIGHT TO 2AM
'b' => "b", // OFF AIR TIME
'c' => "c",
'd' => "d",
'e' => "e", // NOON to 2PM
'f' => "f",
'g' => "g",
'h' => "h",
'i' => "i",
'j' => "j",
);
}
function mondayShow() {
$showBlocks = showBlocks();
$mondayShows = mondayShows();
foreach ($showBlocks as $name => $range) {
if (time() > strtotime($range[0]) && strtotime($range[1]) > time()) {
echo($mondayShows[$name]);
}
}
}
mondayShow();
This way, you don't need to explicitly globalize anything, and you don't need to worry about having extra files. Simply make a function for each show listing array, and have it return.
One small thing: In the code above, I changed the $mondayShows array values to something that was defined (just letters), so make sure you're actually assigning those to something.
I have to create an automatic weather including rain, snow, clouds, fog and sunny.
Depending on the season I need to set a percentage for all weather: the forecast will be updated 3 or 4 times during a day.
Example:
Winter | Rain: 30% Snow: 30% Sunny: 10% Cloudy: 10%, Fog: 20%
I do not know how to implement a random condition based on percentages. Some help?
Many thanks and sorry for my bad English.
Well, you can use:
$location = 'Rome';
$document = file_get_contents(str_replace(" ", "+", "http://api.wunderground.com/auto/wui/geo/WXCurrentObXML/index.xml?query=".$location));
$xml = new SimpleXMLElement($document);
echo "$location: ".$xml->temp_c."° C";
Just take a look on the XML and see what data you have available.
EDIT
I didn't understand what the OP wanted the first time. Basically, it's even easier.
$weather = mt_rand(0,100);
$season = 'winter';
switch($season) {
case 'winter': {
if ($weather < 30) {
$output = 'Rainy';
} else if ($weather >=30 && $weather < 60) {
$output = 'Snowy';
}
// goes on on the same ideea of testing the value of $weather
break;
}
// other seasons
}
echo $output;
What I suggest tough, is to keep your values in arrays (for example the seasons) as well as the values for chances to have one type of weather or another.
array (
[winter] => array (
[30] => 'Rainy',
[60] => 'Snowy',
... // the other chances of weather
),
[spring] => array (
...
),
... // and so on
)
Use mt_rand(0,100) to get a random value and the array above to determine the weather.
Please let me know if this works for you.
Great answer by Claudiu but if you want to view with Fahrenheit (F) that possible example Below:
<?php
$location = 'Washington';
$document = file_get_contents(str_replace(" ", "+", "http://api.wunderground.com/auto/wui/geo/WXCurrentObXML/index.xml?query=" . $location));
$xml = new SimpleXMLElement($document);
echo $xml->temp_f . "° F";
?>