first show lad
[rb-clock.git] / php / time-ajax.php
1 <?php
2 session_start();
3 $please_wait = '';
4 $last = time();
5 if(isset($_SESSION['last'])) {
6 $last = $_SESSION['last'];
7 }
8 else {
9 $_SESSION['last'] = $last;
10 }
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;
17 #}
18 #else {
19   $_SESSION['last'] = time();
20
21   $bit_max = 4294967296;
22   $epoch_convert = 2208988800;
23   $vn = 3;
24   
25   $servers = array('localhost');
26   $server_count = count($servers);
27   
28   //see rfc5905, page 20
29   //first byte
30   //LI (leap indicator), a 2-bit integer. 00 for 'no warning'
31   $header = '00';
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'
35   $header .= '011';
36   
37   //echo bindec($header);    
38       
39   //construct the packet header, byte 1
40   $request_packet = chr(bindec($header));
41   
42   //we'll use a for loop to try additional servers should one fail to respond
43   $i = 0;
44   for($i; $i < $server_count; $i++) {
45     $socket = @fsockopen('udp://'.$servers[$i], 123, $err_no, $err_str,1);
46     if ($socket) {
47       
48       //add nulls to position 11 (the transmit timestamp, later to be returned as originate)
49       //10 lots of 32 bits
50       for ($j=1; $j<40; $j++) {
51         $request_packet .= chr(0x0);
52       }
53       
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];
57       
58       //add 70 years to convert unix to ntp epoch
59       $originate_seconds = $local_sent_explode[1] + $epoch_convert;
60         
61       //convert the float given by microtime to a fraction of 32 bits
62       $originate_fractional = round($local_sent_explode[0] * $bit_max);
63         
64       //pad fractional seconds to 32-bit length
65       $originate_fractional = sprintf('%010d',$originate_fractional);
66         
67       //pack to big endian binary string
68       $packed_seconds = pack('N', $originate_seconds);
69       $packed_fractional = pack("N", $originate_fractional);
70   
71       //add the packed transmit timestamp
72       $request_packet .= $packed_seconds;
73       $request_packet .= $packed_fractional;
74       
75       if (fwrite($socket, $request_packet)) {
76         $data = NULL;
77         stream_set_timeout($socket, 1);
78         
79         $response = fread($socket, 48);
80         
81         //the time the response was received
82         $local_received = microtime(true);
83         
84         //echo 'response was: '.strlen($response).$response;
85       }
86       fclose($socket);
87       
88       if (strlen($response) == 48) {
89         //the response was of the right length, assume it's valid and break out of the loop
90         break;
91       }
92       else {
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');
96         }
97       }
98     }
99     else {
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');
103       }
104     }
105   }
106   
107   //unpack the response to unsiged lonng for calculations
108   $unpack0 = unpack("N12", $response);
109   //print_r($unpack0);
110   
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;
115   
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;
119   
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;
123   
124   //unpack to ascii characters for the header response
125   $unpack1 = unpack("C12", $response);
126   //print_r($unpack1);
127   
128   //echo 'byte 1: ' . $unpack1[1] . ' | ';
129   
130   //the header response in binary (base 2)
131   $header_response =  base_convert($unpack1[1], 10, 2);
132   
133   //pad with zeros to 1 byte (8 bits)
134   $header_response = sprintf('%08d',$header_response);
135   
136   //Mode (the last 3 bits of the first byte), converting to decimal for humans;
137   $mode_response = bindec(substr($header_response, -3));
138   
139   //VN
140   $vn_response = bindec(substr($header_response, -6, 3));
141   
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);
146   
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';
151   
152   $server = $servers[$i];
153   
154   $ntp_time =  $remote_transmitted - $delay;
155   $ntp_time_explode = explode('.',$ntp_time);
156   
157   $ntp_time_formatted = date('Y-m-d H:i:s', $ntp_time_explode[0]).'.'.$ntp_time_explode[1];
158   
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);
163   
164   $server_time_formatted = date('Y-m-d H:i:s', time()) .'.'. substr($server_time_micro,2);
165
166 #}
167 ?>
168
169 <?php echo $remote_received;?>