我的虚拟机 (VMWare/Ubuntu) 出现时间不同步的问题。我们决定最好的办法是直接从 NTP 服务器获取时间,所以我开始研究一个脚本来做到这一点,但到目前为止没有任何效果,这就是为什么我决定来这里看看是否有人能指出我的正确方向方向。
澄清一下,我正在寻找一种通过 PHP 连接到时间服务器的方法,以直接检索时间并在我需要生成的时间戳上重用它,而不是同步服务器。
这是一个完整的工作代码:
<?php
error_reporting(E_ALL ^ E_NOTICE);
ini_set("display_errors", 1);
date_default_timezone_set("America/Argentina/Buenos_Aires");
/* Query a time server (C) 1999-09-29, Ralf D. Kloth (QRQ.software) <ralf at qrq.de> */
function query_time_server ($timeserver, $socket)
{
$fp = fsockopen($timeserver,$socket,$err,$errstr,5);
# parameters: server, socket, error code, error text, timeout
if($fp)
{
fputs($fp, "\n");
$timevalue = fread($fp, 49);
fclose($fp); # close the connection
}
else
{
$timevalue = " ";
}
$ret = array();
$ret[] = $timevalue;
$ret[] = $err; # error code
$ret[] = $errstr; # error text
return($ret);
} # function query_time_server
$timeserver = "ntp.pads.ufrj.br";
$timercvd = query_time_server($timeserver, 37);
//if no error from query_time_server
if(!$timercvd[1])
{
$timevalue = bin2hex($timercvd[0]);
$timevalue = abs(HexDec('7fffffff') - HexDec($timevalue) - HexDec('7fffffff'));
$tmestamp = $timevalue - 2208988800; # convert to UNIX epoch time stamp
$datum = date("Y-m-d (D) H:i:s",$tmestamp - date("Z",$tmestamp)); /* incl time zone offset */
$doy = (date("z",$tmestamp)+1);
echo "Time check from time server ",$timeserver," : [<font color=\"red\">",$timevalue,"</font>]";
echo " (seconds since 1900-01-01 00:00.00).<br>\n";
echo "The current date and universal time is ",$datum," UTC. ";
echo "It is day ",$doy," of this year.<br>\n";
echo "The unix epoch time stamp is $tmestamp.<br>\n";
echo date("d/m/Y H:i:s", $tmestamp);
}
else
{
echo "Unfortunately, the time server $timeserver could not be reached at this time. ";
echo "$timercvd[1] $timercvd[2].<br>\n";
}
?>
此链接中的更多信息
我想从监听端口 123 UDP rfc5905的 ntp 服务器检索时间。我在这里找到了解决方案。在我的工作页面 php 下:
<!doctype html>
<?php
session_start();
$please_wait = '';
$last = time();
if(isset($_SESSION['last'])) {
$last = $_SESSION['last'];
}
else {
$_SESSION['last'] = $last;
}
//wrap the whole thing in a test for the last hit-time on the page, to avoid abusing NTP servers
if (time() - $last < 15) {
$wait = time() - $last;
$please_wait = 'Request limit exceeded, please wait ' . (15 - $wait) . ' s.';
$server = $vn_response = $mode_response = $stratum_response = $remote_originate = $remote_received
= $remote_received = $remote_transmitted = $delay_ms = $ntp_time_formatted = $server_time_formatted = $please_wait;
}
else {
$_SESSION['last'] = time();
$bit_max = 4294967296;
$epoch_convert = 2208988800;
$vn = 3;
$servers = array('0.uk.pool.ntp.org','1.uk.pool.ntp.org','2.uk.pool.ntp.org','3.uk.pool.ntp.org');
$server_count = count($servers);
//see rfc5905, page 20
//first byte
//LI (leap indicator), a 2-bit integer. 00 for 'no warning'
$header = '00';
//VN (version number), a 3-bit integer. 011 for version 3
$header .= sprintf('%03d',decbin($vn));
//Mode (association mode), a 3-bit integer. 011 for 'client'
$header .= '011';
//echo bindec($header);
//construct the packet header, byte 1
$request_packet = chr(bindec($header));
//we'll use a for loop to try additional servers should one fail to respond
$i = 0;
for($i; $i < $server_count; $i++) {
$socket = @fsockopen('udp://'.$servers[$i], 123, $err_no, $err_str,1);
if ($socket) {
//add nulls to position 11 (the transmit timestamp, later to be returned as originate)
//10 lots of 32 bits
for ($j=1; $j<40; $j++) {
$request_packet .= chr(0x0);
}
//the time our packet is sent from our server (returns a string in the form 'msec sec')
$local_sent_explode = explode(' ',microtime());
$local_sent = $local_sent_explode[1] + $local_sent_explode[0];
//add 70 years to convert unix to ntp epoch
$originate_seconds = $local_sent_explode[1] + $epoch_convert;
//convert the float given by microtime to a fraction of 32 bits
$originate_fractional = round($local_sent_explode[0] * $bit_max);
//pad fractional seconds to 32-bit length
$originate_fractional = sprintf('%010d',$originate_fractional);
//pack to big endian binary string
$packed_seconds = pack('N', $originate_seconds);
$packed_fractional = pack("N", $originate_fractional);
//add the packed transmit timestamp
$request_packet .= $packed_seconds;
$request_packet .= $packed_fractional;
if (fwrite($socket, $request_packet)) {
$data = NULL;
stream_set_timeout($socket, 1);
$response = fread($socket, 48);
//the time the response was received
$local_received = microtime(true);
//echo 'response was: '.strlen($response).$response;
}
fclose($socket);
if (strlen($response) == 48) {
//the response was of the right length, assume it's valid and break out of the loop
break;
}
else {
if ($i == $server_count-1) {
//this was the last server on the list, so give up
die('unable to establish a connection');
}
}
}
else {
if ($i == $server_count-1) {
//this was the last server on the list, so give up
die('unable to establish a connection');
}
}
}
//unpack the response to unsiged lonng for calculations
$unpack0 = unpack("N12", $response);
//print_r($unpack0);
//present as a decimal number
$remote_originate_seconds = sprintf('%u', $unpack0[7])-$epoch_convert;
$remote_received_seconds = sprintf('%u', $unpack0[9])-$epoch_convert;
$remote_transmitted_seconds = sprintf('%u', $unpack0[11])-$epoch_convert;
$remote_originate_fraction = sprintf('%u', $unpack0[8]) / $bit_max;
$remote_received_fraction = sprintf('%u', $unpack0[10]) / $bit_max;
$remote_transmitted_fraction = sprintf('%u', $unpack0[12]) / $bit_max;
$remote_originate = $remote_originate_seconds + $remote_originate_fraction;
$remote_received = $remote_received_seconds + $remote_received_fraction;
$remote_transmitted = $remote_transmitted_seconds + $remote_transmitted_fraction;
//unpack to ascii characters for the header response
$unpack1 = unpack("C12", $response);
//print_r($unpack1);
//echo 'byte 1: ' . $unpack1[1] . ' | ';
//the header response in binary (base 2)
$header_response = base_convert($unpack1[1], 10, 2);
//pad with zeros to 1 byte (8 bits)
$header_response = sprintf('%08d',$header_response);
//Mode (the last 3 bits of the first byte), converting to decimal for humans;
$mode_response = bindec(substr($header_response, -3));
//VN
$vn_response = bindec(substr($header_response, -6, 3));
//the header stratum response in binary (base 2)
$stratum_response = base_convert($unpack1[2], 10, 2);
$stratum_response = bindec($stratum_response);
//echo 'stratum: ' . bindec($stratum_response);
//calculations assume a symmetrical delay, fixed point would give more accuracy
$delay = (($local_received - $local_sent) / 2) - ($remote_transmitted - $remote_received);
$delay_ms = round($delay * 1000) . ' ms';
//echo 'delay: ' . $delay * 1000 . 'ms';
$server = $servers[$i];
$ntp_time = $remote_transmitted - $delay;
$ntp_time_explode = explode('.',$ntp_time);
$ntp_time_formatted = date('Y-m-d H:i:s', $ntp_time_explode[0]).'.'.$ntp_time_explode[1];
//compare with the current server time
$server_time = microtime();
$server_time_explode = explode(' ', $server_time);
$server_time_micro = round($server_time_explode[0],4);
$server_time_formatted = date('Y-m-d H:i:s', time()) .'.'. substr($server_time_micro,2);
}
?>
<html lang="en">
<head>
<meta charset="utf-8">
<title></title>
<meta name="description" content="">
<meta name="author" content="">
<style type="text/css">
td{
width: 160px; height: 20px;
padding: 4px;
border: 1px solid #000;
font-size: 12px;
}
.ntp_response{
width: 240px;
}
</style>
</head>
<body>
<table border="0">
<tr>
<td>Server:
<td class="ntp_response"><?php echo $server;?></td>
</tr>
<tr>
<td>VN (version number):</td>
<td class="ntp_response"><?php echo $vn_response;?></td>
</tr>
<tr>
<td>Mode:</td>
<td class="ntp_response"><?php echo $mode_response;?></td>
</tr>
<tr>
<td>Stratum:</td>
<td class="ntp_response"><?php echo $stratum_response;?></td>
</tr>
<tr>
<td>Origin time:</td>
<td class="ntp_response"><?php echo $remote_originate;?></td>
</tr>
<td>Received:</td>
<td class="ntp_response"><?php echo $remote_received;?></td>
</tr>
<td>Transmitted:</td>
<td class="ntp_response"><?php echo $remote_transmitted;?></td>
</tr>
<td>Delay:</td>
<td class="ntp_response"><?php echo $delay_ms;?></td>
</tr>
<td>NTP time:</td>
<td class="ntp_response"><?php echo $ntp_time_explode[0];?></td>
</tr>
<td>Server time:</td>
<td class="ntp_response"><?php echo $server_time_formatted;?></td>
</tr>
</table>
</body>
</html>