5 if(isset($_SESSION['last'])) {
6 $last = $_SESSION['last'];
9 $_SESSION['last'] = $last;
11 //wrap the whole thing in a test for the last hit-time on the page, to avoid abusing NTP servers
12 #if (time() - $last < 1) {
13 # $wait = time() - $last;
14 # $please_wait = 'Request limit exceeded, please wait ' . (15 - $wait) . ' s.';
15 # $server = $vn_response = $mode_response = $stratum_response = $remote_originate = $remote_received
16 # = $remote_received = $remote_transmitted = $delay_ms = $ntp_time_formatted = $server_time_formatted = $please_wait;
19 $_SESSION['last'] = time();
21 $bit_max = 4294967296;
22 $epoch_convert = 2208988800;
25 $servers = array('localhost');
26 $server_count = count($servers);
28 //see rfc5905, page 20
30 //LI (leap indicator), a 2-bit integer. 00 for 'no warning'
32 //VN (version number), a 3-bit integer. 011 for version 3
33 $header .= sprintf('%03d',decbin($vn));
34 //Mode (association mode), a 3-bit integer. 011 for 'client'
37 //echo bindec($header);
39 //construct the packet header, byte 1
40 $request_packet = chr(bindec($header));
42 //we'll use a for loop to try additional servers should one fail to respond
44 for($i; $i < $server_count; $i++) {
45 $socket = @fsockopen('udp://'.$servers[$i], 123, $err_no, $err_str,1);
48 //add nulls to position 11 (the transmit timestamp, later to be returned as originate)
50 for ($j=1; $j<40; $j++) {
51 $request_packet .= chr(0x0);
54 //the time our packet is sent from our server (returns a string in the form 'msec sec')
55 $local_sent_explode = explode(' ',microtime());
56 $local_sent = $local_sent_explode[1] + $local_sent_explode[0];
58 //add 70 years to convert unix to ntp epoch
59 $originate_seconds = $local_sent_explode[1] + $epoch_convert;
61 //convert the float given by microtime to a fraction of 32 bits
62 $originate_fractional = round($local_sent_explode[0] * $bit_max);
64 //pad fractional seconds to 32-bit length
65 $originate_fractional = sprintf('%010d',$originate_fractional);
67 //pack to big endian binary string
68 $packed_seconds = pack('N', $originate_seconds);
69 $packed_fractional = pack("N", $originate_fractional);
71 //add the packed transmit timestamp
72 $request_packet .= $packed_seconds;
73 $request_packet .= $packed_fractional;
75 if (fwrite($socket, $request_packet)) {
77 stream_set_timeout($socket, 1);
79 $response = fread($socket, 48);
81 //the time the response was received
82 $local_received = microtime(true);
84 //echo 'response was: '.strlen($response).$response;
88 if (strlen($response) == 48) {
89 //the response was of the right length, assume it's valid and break out of the loop
93 if ($i == $server_count-1) {
94 //this was the last server on the list, so give up
95 die('unable to establish a connection');
100 if ($i == $server_count-1) {
101 //this was the last server on the list, so give up
102 die('unable to establish a connection');
107 //unpack the response to unsiged lonng for calculations
108 $unpack0 = unpack("N12", $response);
111 //present as a decimal number
112 $remote_originate_seconds = sprintf('%u', $unpack0[7])-$epoch_convert;
113 $remote_received_seconds = sprintf('%u', $unpack0[9])-$epoch_convert;
114 $remote_transmitted_seconds = sprintf('%u', $unpack0[11])-$epoch_convert;
116 $remote_originate_fraction = sprintf('%u', $unpack0[8]) / $bit_max;
117 $remote_received_fraction = sprintf('%u', $unpack0[10]) / $bit_max;
118 $remote_transmitted_fraction = sprintf('%u', $unpack0[12]) / $bit_max;
120 $remote_originate = $remote_originate_seconds + $remote_originate_fraction;
121 $remote_received = $remote_received_seconds + $remote_received_fraction;
122 $remote_transmitted = $remote_transmitted_seconds + $remote_transmitted_fraction;
124 //unpack to ascii characters for the header response
125 $unpack1 = unpack("C12", $response);
128 //echo 'byte 1: ' . $unpack1[1] . ' | ';
130 //the header response in binary (base 2)
131 $header_response = base_convert($unpack1[1], 10, 2);
133 //pad with zeros to 1 byte (8 bits)
134 $header_response = sprintf('%08d',$header_response);
136 //Mode (the last 3 bits of the first byte), converting to decimal for humans;
137 $mode_response = bindec(substr($header_response, -3));
140 $vn_response = bindec(substr($header_response, -6, 3));
142 //the header stratum response in binary (base 2)
143 $stratum_response = base_convert($unpack1[2], 10, 2);
144 $stratum_response = bindec($stratum_response);
145 //echo 'stratum: ' . bindec($stratum_response);
147 //calculations assume a symmetrical delay, fixed point would give more accuracy
148 $delay = (($local_received - $local_sent) / 2) - ($remote_transmitted - $remote_received);
149 $delay_ms = round($delay * 1000) . ' ms';
150 //echo 'delay: ' . $delay * 1000 . 'ms';
152 $server = $servers[$i];
154 $ntp_time = $remote_transmitted - $delay;
155 $ntp_time_explode = explode('.',$ntp_time);
157 $ntp_time_formatted = date('Y-m-d H:i:s', $ntp_time_explode[0]).'.'.$ntp_time_explode[1];
159 //compare with the current server time
160 $server_time = microtime();
161 $server_time_explode = explode(' ', $server_time);
162 $server_time_micro = round($server_time_explode[0],4);
164 $server_time_formatted = date('Y-m-d H:i:s', time()) .'.'. substr($server_time_micro,2);
169 <?php echo $remote_received;?>