PHP 会话计时器最初工作但出错了

PHP Session Timer Works Initially but Gone Wrong

所以我有一个可以工作的 php 会话计时器,但不知何故在一段时间后被窃听...这是我得到的代码和控制台日志。我正在寻找解决此问题的方法,或者可能是一组不同的代码来实现相同的计时器效果(因为我不确定使用会话是否是计时器的最佳方法)

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";
    }

这是控制台中发生的事情:

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)

额外说明:会话计时器并不总是重复相同的模式,有时它会 运行 整个 30 分钟并设法 回显“$time has passed” ; 而该错误仅在稍后出现

我还没有 运行 你的,但仅仅通过阅读我认为它有一些非常错误的地方。

  1. 会话。你没有正确使用它们。

会话值应该只设置一次,这意味着在你做$_SESSION['countdown'] = $time*60;$_SESSION['time_started'] = time();之前,你应该检查它们是否已经存在,并且只有在不存在时才分配。每次刷新页面时,您当前的代码都会重置时钟,这违背了会话的目的。

  1. abs。我认为您也没有正确使用它们。

你不应该一直放弃剩余的秒数。 $remainingSeconds = abs($_SESSION['countdown'] - $timeSince); 应该被允许变成负数。负剩余秒数意味着您的超时已过期/您已经错过了!调用 abs 意味着如果您有任何机会错过活动的确切时间,您实际上就是让它永远消失。 这是您主要问题的答案。修复此问题,您的计数器将停止归零并再次备份。

  1. 您依赖于您的代码每一秒都正确检查。但事实并非如此。

当你的代码由于某种原因被延迟并且没有正确检查第 60 秒时,你会遇到讨厌的小数,这意味着你除以 60 不是完美的整数,你得到 8.7166666 分钟。

如果您从删除 abs 调用开始并通常尝试稍微简化您的代码,我相信您会很快让它按预期工作。

// 编辑 1

对于您的问题,这是一种非常幼稚但简化的方法。我在那里留下了两个不同的输出供你选择一个。

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;
        }
    }
}

进一步改进它的主要方法是使用 sleep 函数 http://php.net/manual/en/function.sleep.php。目前 while loop 将通过不断检查计时器是否发生来占用所有 CPU,所以你应该在里面睡几秒钟。

您如何看待这个解决方案?以上引用

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;
        }
    }
}