如何在PHP中显示系统运行时间?

8

我还是个初学者,请多包涵...
我找到了一个关于系统运行时间的函数,并在学习php和web开发的过程中进行了一些尝试。
我的目标是让输出看起来像天:小时:分钟:秒,但是由于没有$seconds变量,所以我根据其他内容添加了这一行代码。 除了秒钟显示为0外,一切都很顺利。我不太确定自己做错了什么,或者这是否是最好的方法。

function Uptime() {

    $uptime = @file_get_contents( "/proc/uptime");

    $uptime = explode(" ",$uptime);
    $uptime = $uptime[0];
    $days = explode(".",(($uptime % 31556926) / 86400));
    $hours = explode(".",((($uptime % 31556926) % 86400) / 3600));
    $minutes = explode(".",(((($uptime % 31556926) % 86400) % 3600) / 60));
    $seconds = explode(".",((((($uptime % 31556926) % 86400) % 3600) / 60) / 60));

    $time = $days[0].":".$hours[0].":".$minutes[0].":".$seconds[0];

    return $time;

}

编辑:我以不同的方式使它工作了,新功能如下。 我仍然很好奇为什么上述方法没有像预期那样工作,如果下面的新方法是实现这一目标的最佳方法,是否有人能够回答。

function Uptime() {
    $ut = strtok( exec( "cat /proc/uptime" ), "." );
    $days = sprintf( "%2d", ($ut/(3600*24)) );
    $hours = sprintf( "%2d", ( ($ut % (3600*24)) / 3600) );
    $min = sprintf( "%2d", ($ut % (3600*24) % 3600)/60  );
    $sec = sprintf( "%2d", ($ut % (3600*24) % 3600)%60  );


    return array( $days, $hours, $min, $sec );
}
$ut = Uptime();
echo "Uptime: $ut[0]:$ut[1]:$ut[2]:$ut[3]";

编辑2:根据nwellnhof所给的答案,我认为这种方法是最好的。我稍微调整了一下,以便输出完全符合我的要求。谢谢大家。

function Uptime() {
        $str   = @file_get_contents('/proc/uptime');
        $num   = floatval($str);
        $secs  = $num % 60;
        $num   = (int)($num / 60);
        $mins  = $num % 60;
        $num   = (int)($num / 60);
        $hours = $num % 24;
        $num   = (int)($num / 24);
        $days  = $num;

        return array(
            "days"  => $days,
            "hours" => $hours,
            "mins"  => $mins,
            "secs"  => $secs
        );
    }

将60的模数除以60,结果始终小于1.0。 - tkausl
你从哪里得到了31556926这个数字? - Blake Connally
啊,是的,我之后尝试了那个,然后忘记改回来了。我会编辑我的帖子。 - Ethan Morris
查看 PHP 中的 DateTime 类。http://php.net/manual/zh/book.datetime.php - RiggsFolly
@BlakeConnally 那个数字31556926大约是一年的秒数。 - mweerden
5个回答

10

直接从/proc/uptime读取是Linux上最高效的解决方案。有多种方式将输出转换为天/小时/分钟/秒。尝试类似以下代码:

$str   = @file_get_contents('/proc/uptime');
$num   = floatval($str);
$secs  = fmod($num, 60); $num = (int)($num / 60);
$mins  = $num % 60;      $num = (int)($num / 60);
$hours = $num % 24;      $num = (int)($num / 24);
$days  = $num;

或者,使用intdiv(PHP7):

$str   = @file_get_contents('/proc/uptime');
$num   = floatval($str);
$secs  = fmod($num, 60); $num = intdiv($num, 60);
$mins  = $num % 60;      $num = intdiv($num, 60);
$hours = $num % 24;      $num = intdiv($num, 24);
$days  = $num;

只是出于好奇,为什么从/proc/uptime读取更有效? - Ethan Morris
3
执行 uptimecat /proc/cpuinfo 命令会生成一个新的进程(在 Unix 上进行 fork/exec 操作),这需要几毫秒的时间。然后,这个新的进程会读取 /proc/cpuinfo 并将输出通过管道返回给原始进程。直接读取 /proc/cpuinfo 可以避免所有的开销。 - nwellnhof

4

uptime支持-p命令行选项。你可以使用这个简单的代码:

echo shell_exec('uptime -p');

有趣的是... 当我尝试使用 -p 时,它给了我一个完全随机的日期,但当我尝试使用 -s 时,它给了我当前日期和一个完全随机的时间。 - Ethan Morris
啊,抱歉,我还是个新手。我的意思是时间不是我预期的(自上次启动以来的正常运行时间),它们与htop uptime的输出不匹配,所以我认为它是错误的。不过,这是一个不同的参数,这很有道理。 - Ethan Morris
1
没事,我刚才看错了,-p输出是正确的,只是在我的HTML中被截断了。 - Ethan Morris
在Unix上,uptime命令不存在-p参数。 - kenorb
取决于您安装 uptime 的来源。来自 procps 的版本支持它。 - hek2mgl
显示剩余4条评论

1
您的初始示例的变体,作为一个类:

class Uptime {
    private $uptime;

    private $modVals = array(31556926, 86400, 3600, 60, 60);

    public function __construct() {
        $this->read_uptime();
    }

    /**
     * actually trigger a read of the system clock and cache the value
     * @return string
     */
    private function read_uptime() {
        $uptime_raw = @file_get_contents("/proc/uptime");
        $this->uptime = floatval($uptime_raw);
        return $this->uptime;
    }

    private function get_uptime_cached() {
        if(is_null($this->uptime)) $this->read_uptime(); // only read if not yet stored or empty
        return $this->uptime;
    }

    /**
     * recursively run mods on time value up to given depth
     * @param int $d
     * @return int
     **/
    private function doModDep($d) {
        $start = $this->get_uptime_cached();
        for($i=0;$i<$d;$i++) {
            $start = $start % $this->modVals[$i];
        }
        return intval($start / $this->modVals[$d]);
    }

    public function getDays()
    {
        return $this->doModDep(1);
    }

    public function getHours() {
        return $this->doModDep(2);
    }

    public function getMinutes()
    {
        return $this->doModDep(3);
    }

    public function getSeconds()
    {
        return $this->doModDep(4);
    }

    public function getTime($cached=false) {
        if($cached != false) $this->read_uptime(); // resample cached system clock value
        return sprintf("%03d:%02d:%02d:%02d", $this->getDays(), $this->getHours(), $this->getMinutes(), $this->getSeconds());
    }
}

顺便说一下,现在这个是我的一个自己的类库 - 感谢你的帮助! - Scott

0

如果你仔细观察你的语句中的模式,你会发现秒钟的模式是不同的。它有两个部分。此外,你使用的数字代表每个时间单位的秒数。每秒的秒数应该是1,而不是60。简而言之:

$seconds = explode(".",((((($uptime % 31556926) % 86400) % 3600) / 60) / 60));

应该是:

$seconds = explode(".",((((($uptime % 31556926) % 86400) % 3600) % 60) / 1));

现在这种做事的方式有点奇怪。例如,(x % (n*m)) % m 就是 x % m

更好的方法是:

$uptime  = (int) $uptime;
$seconds =  $uptime               % 60;
$minutes = ($uptime /  60       ) % 60;
$hours   = ($uptime / (60*60)   ) % 24;
$days    =  $uptime / (60*60*24); # % 365, if you want

永远不要进行这样的计算,因为当夏令时更改发生时,它们将是错误的。使用PHP的日期/时间函数来处理。 - hek2mgl
@hek2mgl,"从来没有"是一个很强烈的说法;它取决于一个人想要什么以及如何使用它。此外,这应该是对原帖的评论。这只是以更友好的方式书写已经发布的内容。 - mweerden
我只是想诚实地学习,到目前为止每个答案都很有帮助。虽然@hek2mgl提到了夏令时问题,确实有道理。 - Ethan Morris
@hek2mgl 如果你只想将时间转换为人类可读的格式,把一天定义为24小时(86,400秒)是完全可以接受的。 GNU coreutils 的 uptime 命令也是这样做的 - nwellnhof
有趣。我使用的是procps中的uptime而不是coreutils。那个版本使用了localtime(),它能够识别夏令时。 - hek2mgl
显示剩余3条评论

0
在Unix/BSD上,使用/proc不可靠,因为它默认未挂载,在某些Linux发行版上也可能被卸载,因此最好使用uptimesysctl命令进行解析,例如:

sysctl

<?php
preg_match('/sec = (\d+)/', shell_exec('sysctl -n kern.boottime'), $secs)
echo $secs[1];

或者:

$s = explode( " ", exec("/sbin/sysctl -n kern.boottime") );
$a = str_replace( ",", "", $s[3]);
$uptime = time() - $a;  

或如来自 m0n0wall 的示例:

<?php
exec("/sbin/sysctl -n kern.boottime", $boottime);
preg_match("/sec = (\d+)/", $boottime[0], $matches);
$boottime = $matches[1];
$uptime = time() - $boottime;

if ($uptime > 60)
    $uptime += 30;
$updays = (int)($uptime / 86400);
$uptime %= 86400;
$uphours = (int)($uptime / 3600);
$uptime %= 3600;
$upmins = (int)($uptime / 60);

$uptimestr = "";
if ($updays > 1)
    $uptimestr .= "$updays days, ";
else if ($updays > 0)
    $uptimestr .= "1 day, ";
$uptimestr .= sprintf("%02d:%02d", $uphours, $upmins);
echo htmlspecialchars($uptimestr);

uptime

示例来自4webhelp

<?php
$data = shell_exec('uptime');
$uptime = explode(' up ', $data);
$uptime = explode(',', $uptime[1]);
$uptime = $uptime[0].', '.$uptime[1];
echo ('Current server uptime: '.$uptime.'

或者(在FreeBSD上测试过):

$uptime = exec("uptime");
$uptime = split(" ",$uptime);
$days = $uptime[3]; # NetBSD: $days = $uptime[4];
$time = split(",",$uptime[5]); # NetBSD: $time = split(",",$uptime[7]);
if (sizeof($hourmin = split(":",$time[0])) < 2){ ;
  $hours = "0";
  $mins = $hourmin[0];
} else {
  $hourmin=split(":",$time[0]);
  $hours = $hourmin[0];
  $mins = $hourmin[1];
}
$calcuptime =  "Uptime: ".$days." days ".$hours." hours ".$mins." mins" ;
echo $calcuptime;

这是适用于Windows的版本:

<?php
$uptime = `c:\windows\system32\uptime2.bat $server`;
$uptime = explode(": ", $uptime);
$uptime = explode(", ", $uptime[1]);

$uptime_days = preg_replace($pattern, '', $uptime[0]);
$uptime_hours = preg_replace($pattern, '', $uptime[1]);
$uptime_minutes = preg_replace($pattern, '', $uptime[2]);
$uptime_seconds = preg_replace($pattern, '', $uptime[3]);

echo '<b>Uptime:</b><br><br>';

echo 'Days: '.$uptime_days.'<br>';
echo 'Hours: '.$uptime_hours.'<br>';
echo 'Minutes: '.$uptime_minutes.'<br>';
echo 'Seconds: '.$uptime_seconds.'<br>';

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接