PHP Session Timer Works Initially but Gone Wrong - php

So I have a php session timer that works but somehow gets bugged out after awhile... this is the code and the console log I got. I'm looking for a fix to this problem, or possibly a different set of code to achieve the same timer effect (as I'm not sure if using session is the best method for a timer)
session_start();
function timer($time) {
//Set the countdown to 120 seconds.
$_SESSION['countdown'] = $time*60;
//Store the timestamp of when the countdown began.
$_SESSION['time_started'] = time();
$now = time();
$timeSince = $now - $_SESSION['time_started'];
$remainingSeconds = abs($_SESSION['countdown'] - $timeSince);
$counter = 0;
$minutes = $remainingSeconds/60;
echo "$minutes minutes countdown starts.".PHP_EOL;
while($remainingSeconds >= 1) {
$now = time();
$timeSince = $now - $_SESSION['time_started'];
if (($timeSince-$counter) >= 60) {
$remainingSeconds = abs($_SESSION['countdown'] - $timeSince);
$counter = $timeSince;
$minutes = $remainingSeconds/60;
echo "$minutes minutes has passed.".PHP_EOL;
}
}
if($remainingSeconds < 1){
session_abort();
return true;
}
}
if($this->timer(30)) {
// do whatever
echo "$time has passed";
}
Here's what happens in the console:
30 minutes countdown starts.
29 minutes has passed.
.... (continue as per pattern)
16 minutes has passed.
15 minutes has passed. (problem occurs here)
8.7166666666667 minutes has passed.
7.7166666666667 minutes has passed.
6.7166666666667 minutes has passed.
.... (continue as per pattern)
0.71666666666667 minutes has passed.
0.28333333333333 minutes has passed.
1.2833333333333 minutes has passed.
2.2833333333333 minutes has passed.
.... (continue as per pattern all the way)
Extra notes: The session timer doesn't always recur this same pattern, there have been times when it ran through the entire 30minutes and managed to echo "$time has passed"; while the bug only occured later on

I haven't run your, but just from reading it I think there are a few things very wrong with it.
Sessions. You're not using them right.
Session values should only be set once, meaning before you do $_SESSION['countdown'] = $time*60; and $_SESSION['time_started'] = time();, you should check if they already exist or not, and only assign if nonexistent. Your current code resets the clock every time the page is refreshed, which defeats the purpose of sessions.
abs. I think you're not using them right either.
You shouldn't abs the remaining seconds all the time. $remainingSeconds = abs($_SESSION['countdown'] - $timeSince); should be allowed to go into negative. Negative remaining seconds mean your timeout has expired / you've missed it! Calling abs means you're effectively letting it go forever if you by any chance miss the exact time of your event. This is the answer to your main problem. Fix this and your counter will stop going to zero and back up again.
You're relying on your code correctly checking every single second. But it doesn't.
The nasty decimals you're getting happen when for some reason your code gets delayed and doesn't correctly check the 60th second, which means your division by 60 is not perfectly round and you get 8.7166666 minutes.
If you start by removing the abs calls and generally try to simplify your code a bit, I believe you'll quickly get it to work as intended.
// Edit 1
This is a very naive, but simplified approach to your problem. I left two different outputs in there for you to pick one.
function timer($time) {
echo "$time minutes countdown starts." . PHP_EOL;
// Save the date in future when the timer should stop
$endTime = time() + $time * 60;
// Keeps track of last full minute to simplify logs
$lastFullMinute = $time;
while(true) {
$timeRemaining = $endTime - time();
if ($timeRemaining <= 0) {
// Time remaining is less than zero, which means we've gone beyond the end date.
// End the loop
return;
}
// Round up!
$minutesRemaining = ceil($timeRemaining / 60);
if ($minutesRemaining != $lastFullMinute) {
// Current "minute" is different than the previous one, so display a nice message
// If you want to show how many minutes are remainig, use this:
echo "$minutesRemaining minutes remaining." . PHP_EOL;
// If you want to show how many minutes have passed, you have to take mintutesRemaining away from the original time
$minutesPassed = $time - $minutesRemaining;
echo "$minutesPassed minutes passed." . PHP_EOL;
$lastFullMinute = $minutesRemaining;
}
}
}
The main way for you to improve it further would be to use the sleep function http://php.net/manual/en/function.sleep.php. Currently the while loop will hog all the CPU by constantly checking if the timer happened, so you should sleep for a few seconds inside.

What do you think of this solution? referenced from above
function timer($time) {
echo "$time minutes countdown starts." . PHP_EOL;
// Save the date in future when the timer should stop
$endTime = time() + $time*60;
while(true) {
sleep(20);
$secondsRemaining = $endTime - time();
if ($secondsRemaining <= 0) {
echo 'Finished';
return true;
}
}
}

Related

How to subtract a DateTime by a changing time

I've seen various posts asking how to subtract a specific number of hours, days, etc from a DateTime - but my question is a bit different.
Say I have a user log in, and the system records the date/time. Every second, a timer increases based on the difference between the current date/time and the recorded date/time - effectively creating a log-in timer. Then, the user decides to pause the timer, so the system records pause start and pause end (for when they resume). What I would like to do is make the displayed time subtracted by the pause time - such that the timer doesn't 'increase' while paused. Because I'm not using an actual counter adding up every second, in which case I could just not count up during lunch, I am unaware how to calculate the proper value on the timer.
Here is the code on displaying the timer (part of incriment.php):
date_default_timezone_set('America/Chicago');
$date = new DateTime(date('m/d/Y H:i'));
$date2 = new DateTime(date($_SESSION['date_in'] . ' ' .
$_SESSION['time_in']));
$interval = $date->diff($date2);
$interval = $interval->format('%H:%I');
$_SESSION['current_timer'] = $interval;
echo $_SESSION['current_timer'];
And here is the code on being paused
if(isset($_SESSION['paused']) && $_SESSION['paused'] === true) {
echo '<div class="info">';
echo '<img src="images/information-button" style="max-width:3em">';
if(isset($_SESSION['pause_start'])) {
date_default_timezone_set('America/Chicago');
if(isset($_SESSION['pause_end'])) {
$time = $_SESSION['pause_end']->diff($_SESSION['pause_start']);
echo '<br>Current pause time: ' . $time->format('%H:%I');
} else {
$time = new DateTime(date('H:i'));
$time = $time->diff(new DateTime($_SESSION['date_pause_start'] . ' ' . $_SESSION['pause_start']));
$_SESSION['pause_timer'] = $time->format('%h hours, %i minutes');
echo '<br>Pause timer: ' . $time->format('%h hours, %i minutes');
}
echo '</div>';
}
}
TLDR; How can I subtract a DateTime by an object returned by diff when I don't know if that diff will return minutes (say 30 minutes) or hours (say 1 hour, 30 minutes). I can't do this as a result of not knowing that, nor can I do something like $date->modify("+30 minutes") because I don't know if it's minutes or hours or what. I feel like it should be easy because in my lunch calculations, $time is displaying the time paused (ex: 30 minutes) and by using that into a string I could use the$date->modify strategy - but that's not working (See below what I tried in my incriment.php I showed earlier)
$interval = $interval->format('H:i');
if(isset($_SESSION['pause_timer'])) {
$interval = new DateTime(date($interval));
$interval = $interval->modify("-". $_SESSION['pause_timer']);
echo '-' . $_SESSION['pause_timer'];
}
But that echo's out -0 hours, 40 minutes if the user was paused for 40 minutes - and changes the time from 01:48 to 14:18 which is really confusing as it should be 1:08 obviously. That means to me that I'm improperly using the DateTime for my situation, is there a better solution
Thank you!
Edit: The user can only pause once per session for simplicities sake
I appreciate the replies in comments [even those they deleted ;) ], I managed to get it working by changing the paused code at the $_SESSION['pause_timer'] = $time->format('%h hours, %i minutes') into $_SESSION['pause_timer'] = $time->format('-%h hours, -%i minutes'). My problem was that I was subtracting only the hours, so when my time was only in minutes it added the minutes and subtracted the 0 hours!

calculating time remaining using php time()

I have a php script where I need to make sure a pre-set "future" time has not passed.
When the time is originally logged (or passed and needs relogged), I am taking:
$newTime = time() + 15000; // 2.5 minutes from "now"
The system is tossing this in the DB no problem and the numbers appear to be correct.
Now, when the page is loaded, it pulls the number from the DB and loads it into the .php file:
error_reporting(E_ALL);
ini_set('display_errors',1);
$tname = $_SESSION['username']."Data";
$results = $conn->query("SELECT val FROM $tname where pri='pettyTimer'") or die(mysqli_error($conn));
//$conn declared elsewhere for connection and does work properly
$row = $results->fetch_assoc();
$timer = $row['val'];
I am then comparing the times:
$now = time();
if ($timer > time()) { //script below
} else {
//more script that seems to be working fine
}
When the original conditional $timer > time() is true I am trying to break down the minutes and seconds of the time remaining and echoing them in a basic format that is readable to the user:
$raw = ($timer - $now);
$minutesLeft = floor($raw / 60000);
$totalMinutes2Mils = $minutesLeft * 60000;
$totalRemainingSecs = round(($raw - $totalMinutes2Mils) / (1000));
echo "You are still laying low from the last job you ran. You still have ".$minutesLeft." Minutes and ".$totalRemainingSecs." Seconds left.";
My problem is, the time does not appear to be shifting when I refresh/reload the page.
I echoed both time() and $timer and they are 15000 milliseconds apart when I first loaded it, so this should only exist (conditional be true) for about 2.5 minutes, but I've been working at least 5 minutes since my last set and it's still at 14 seconds.
Can someone please double check my math to make sure I'm calculating this correctly? Thanks!
The time() function returns the current time in the number of seconds since the Unix Epoch (January 1 1970 00:00:00 GMT).
http://www.w3schools.com/php/func_date_time.asp
You are treating it as milliseconds, but should be treating it as straight seconds. take about /1000 and you should be ok.
$minutesLeft = floor($raw / 60);
$totalMinutes2Mils = $minutesLeft * 60;
$newTime = time() + (60*2.5); // 2.5 minutes from "now"
time() returns seconds, not milliseconds, so you should add 150 instead of 15000 to get 2:30 minutes.

Store time in DB and resume after log in PHP

We already know that the following code in PHP will log the user out after 5 mins of inactivity.
$timeout = 5*60; // Set timeout minutes
$logout_redirect_url = "index.php"; // Set logout URL
if (isset($_SESSION['start_time'])) {
$elapsed_time = time() - $_SESSION['start_time'];
if ($elapsed_time >= $timeout) {
session_unset();
session_destroy();
header("Location: $logout_redirect_url");
}
}
$_SESSION['start_time'] = time();
I want to implement a modification of the current code and do something like this:
Assume the user logs out when he had 3 minutes left before automatic logout(assuming the time doesn't restart for him after his inactivity for 2 minutes), we keep track of the time he has left by storing it in a DB (MySQL) and later on start reducing from the same 3 minutes after he logs back in. How can i do this?
Track by the time used, not the currentTime/storedTime. Just use those to figure out the time remaining. This is a quick example. There may be some small errors and improvements that can be made. It should be plenty to help you implement a solution.
User visits page:
if (empty($_SESSION['start_time'])) {
$_SESSION['start-time'] = time();
}
$timeLeft = //get time from db
//if there is a value in the db, that is the time left, otherwise, use the max time allowed (new timer)
$timeLeft = (!empty($timeLeft)) ? $timeLeft : $timeAllowed
$timePassed = time() - $_SESSION['start_time'];
if ($timePassed > $timeAllowed) {
//logout
}
Then, when the user leaves:
$timeLeft = $timeAllowed - (time() - $_SESSION['start_time']);
//Store $timeLeft in the database - should be a value like 180 (3 minutes)

countdown php jquery post ajax

I'm designing a website where there is a little game going on. Each user that participates has 99 minutes to complete it otherwise we display a game over state. Here is what I managed to do so far using jQuery post.
I've been able to display the timer. In the PHP I've set the target time to 99*60 seconds but I cant set the starting time to 0 as I'll do the difference beteen those to values for the countdown.
Furthermore, as each user is able to quit the page I want to be able to store the time when they left. All I am able to do is store the countdown value, let's say 5845, in the DB when they log off. Though I tried updating the table with each call to the jQuery post, it just makes it worse.
Here is my jQuery:
function countdown() {
var i = (new Date().getTime() / 1000) + (99 * 60);
setTimeout(function () {
$.post(\'countdown.php\',{target:i},function(data){
$('#countdown').html(data);
});
countdown();
},1000);
}
countdown();
Here is the PHP:
if (!empty($resm['Countdown']) || $resm['Countdown'] >= 0) {
$target = (99 * 60);
$countdown = ($target - $current);
$_SESSION['currenttime'] = $countdown;
$hours = floor($countdown / 3600);
$min = floor($countdown / 60);
$r_min = floor(($countdown - ($hours * 3600)) / 60);
$sec = floor($countdown - ($min * 60));
if ($min == 0) {
echo $target.' '.$current.' '.$countdown;
echo '<br/>'.$min.' minutes '.$sec.' seconds left';
} else {
echo 'Time Over';
$sql = "UPDATE bs10000099 SET Upgradedlevel='2',Activated='2',Countdown='5940' WHERE MemberID='$memberid'";
mysql_query($sql);
}
}
I cant figure out how to set the starting time or how to prevent countdown() restart on refresh page.
I'm not sure what kind of security you want, but getting time from Javascript is not really secure since JS gets the time from the computer instead of the server.
With your example, I would be able to play the game, wait until there's 10 minute left, and just roll back time on my desktop and it will reset. Or roll back a year and have 100000 minutes left!
I suggest you use server time.
Here is what I would do:
When the test starts, get the UNIX time + 90 minutes. This will give you the final time.
PHP
if (!isset($_SESSION['end'])) {
$_SESSION['end'] = strtotime("+90 minutes");
}
$remaining = $_SESSION['end'] - time();
if ($remaining > 0) {
echo json_encode(array(
"remaining" => $remaining
));
} else {
// finished! write code here.
}
You can then do a simple $.getJSON() to get the remaining seconds and display it.
Since you kept the "end" time, even if the users leave, the timer will continue.

Time in a variable, decrease a delay

I have a time() value saved in a variable like this:
$latest_attempt = 1337980678;
I am trying to calculate some delay.
$remaining_delay = time() - $latest_attempt - $delay;
However the result of $remaining_delay is increasing when I update the browser, and not the way around.
"You must wait 95 seconds before your next login attempt"
If I update some seconds later "You must wait 102 seconds before your next login attempt"
It's doing the opposite what it should doing, instead it would rather decrease than increase. What have I done wrong? I believe I need to do something with latest_attempt variable, but I could not find anything i the php manual.
I'd say, something like this:
$remaining_delay = $latest_attempt + $delay - time();
$time_since_last = time() - $last_attempt;
if ($time_since_last <= $delay) {
$remaining = $delay - $time_since_last;
} else {
... good to go ... delay's expired
}
The remaining delay is the difference between that moment in time when the blockage expires ($last_attempt + $delay because from $last_attempt on, the user is blocked for a period of $delay) and the current time (time()) - therefore the correct formula is:
$remaining_delay = ($latest_attempt + $delay) - time();
if ($remaining_delay > 0) {
die('Access denied, you need to wait another '. $remaining_delay .' seconds');
}

Categories