2013-05-16 3 views
7

У меня проблема с виртуальной машиной (VMWare/Ubuntu), которая выходит из синхронизации времени. Мы решили, что самое лучшее, что нужно сделать, - это получить время непосредственно с сервера NTP, поэтому я начал исследовать сценарий, чтобы сделать это, но ничего не работает до сих пор, поэтому я решил приехать сюда и посмотреть, может ли кто-нибудь указать мне вправо направление.Получить время с сервера NTP через PHP

Чтобы уточнить, я ищу способ подключения к серверу времени через PHP, чтобы получить время напрямую и повторно использовать его на метке времени, которую мне нужно создать, чтобы не синхронизировать сервер.

+0

Попробуйте один http://www.xenocafe.com/tutorials/php/ntp_time_synchronization/index.php –

ответ

9

Вот полный рабочий код:

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

Более подробная информация в этом link

5

Я хотел, чтобы получить время с NTP-сервер прослушивает порт 123 UDP rfc5905. Я нашел решение here. Под моей рабочей страницы 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>