Leap Indicator | rien |
Version Number | 3 |
Mode | serveur |
Strate | 2 |
Reference Clock Update | 1696469499 | 2023-10-05T03:31:39+02:00 |
Originate Time Stamp | 1696470061 | 2023-10-05T03:41:01+02:00 |
Receive Time Stamp | 1696470061 | 2023-10-05T03:41:01+02:00 |
Transmit Time Stamp | 1696470061 | 2023-10-05T03:41:01+02:00 |
Délai Aller Retour | 0 sec. |
Ecart | 0 sec. |
Date Locale | 2023-10-05T03:41:01+02:00 |
Date Corrigée | 2023-10-05T03:41:01+02:00 |
<?php
/**
* @file client_ntp.php
* @brief Client NTP en PHP
*
* @author hughes monget
* @see http://www.monget.com/
* @since 2012-02-14
* @date 2012-02-14
*/
###### PARAMETRES PHP ######
error_reporting(E_ALL | E_NOTICE | E_STRICT);
set_time_limit(0);
$arr_ini_set = array('log_errors' => 0, 'display_errors' => 1, 'error_log' => 0, 'html_errors' => 0, 'date.timezone' => 'Europe/Paris');
array_walk($arr_ini_set, create_function('$v, $k', 'ini_set($k, $v);'));
if (!setlocale(LC_ALL, 'french')) { echo 'locale not set'; }
###### CONSTANTES ######
// Calcul du nombre de secondes de 1900 jusqu'en 1970.
$int_nombre_seconde_1900_1970 = 0.0;
foreach (range(1900, 1969) as $int_annee)
{
$int_nombre_jour = est_bissextile($int_annee) ? 366.0 : 365.0;
$int_nombre_seconde_1900_1970 += $int_nombre_jour * 24.0 * 60.0 * 60.0;
}
define('NOMBRE_SECONDE_1900_1970', $int_nombre_seconde_1900_1970);
//define('NOMBRE_SECONDE_1900_1970', 2208988800.0);
define('LONGEUR_MESSAGE_EN_OCTET', 48);
// http://www.pool.ntp.org/zone/europe
define('NOM_SERVEUR_NTP', 'fr.pool.ntp.org');
define('PORT_SERVEUR_NTP', 123);
###### FONCTIONS ######
/**
* @param $int_annee - integer - une année
* @return boolean - TRUE si l'année est bisextile
*/
function est_bissextile($int_annee)
{
if ($int_annee % 400 == 0) { return TRUE; }
elseif ($int_annee % 100 == 0) { return FALSE; }
elseif ($int_annee % 4 == 0) { return TRUE; }
else { return FALSE; }
}
/**
* Cette fonction transforme 4 octets d'un message NTP en un timestamp unix.
* @param $arr_raw - array of octet
* @param $int_position - integer - la position de début du mot de 32 bits.
* @return integer - un timestamp unix.
*/
function extraire_seconde($arr_raw, $int_position)
{
$mix_return = $arr_raw[$int_position].$arr_raw[$int_position+1].$arr_raw[$int_position+2].$arr_raw[$int_position+3];
$mix_return = unpack('N', $mix_return);
$mix_return = reset($mix_return);
$mix_return = floatval($mix_return);
if ($mix_return < 0)
{
$mix_return += pow(2, 32);
}
if ($mix_return > NOMBRE_SECONDE_1900_1970)
{
$mix_return -= NOMBRE_SECONDE_1900_1970;
}
return intval($mix_return);
}
/**
* Cette fonction fait afficher un tableau d'octet sous sa forme binaire.
* @param $arr_octect - array of octet
*/
function afficher_message($arr_octect)
{
for ($ii = 0, $nn = count($arr_octect); $ii < $nn; $ii++)
{
$octet = $arr_octect[$ii];
printf('%08b ', ord($octet));
if (($ii + 1) % 4 == 0)
{
echo '<br />';
}
}
}
###### MAIN ######
function main()
{
// On envoie le début du html.
echo
'
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Client NTP</title>
<style type="text/css">
<!--
* { font: 14px monospace; }
table { border-collapse: collapse; }
table, td, th { border: 1px solid #000; }
td, th { padding: 5px; }
-->
</style>
</head>
<body>
';
// On prépare la requête à envoyer au serveur NTP.
$arr_octect = array_fill(0, LONGEUR_MESSAGE_EN_OCTET, "\x0");
// 1 octect => indicateur de saut Version du protocole Mode Client
// 00 011 011
// 00 011 011 == 0001 1011 == 0x1B
$arr_octect[0] = "\x1B";
// On remplit le Transmit Timestamp, il nous reviendra
// dans l'Originate Timestamp.
$mix_originate = floatval(time()) + NOMBRE_SECONDE_1900_1970;
$mix_originate = pack('N', $mix_originate);
$arr_octect[40] = $mix_originate[0];
$arr_octect[41] = $mix_originate[1];
$arr_octect[42] = $mix_originate[2];
$arr_octect[43] = $mix_originate[3];
/*
// On remplit les secondes de valeurs aléatoires.
foreach (range(44, 47) as $int_position)
{
$arr_octect[$int_position] = chr(mt_rand(0, 0xFF));
}
*/
// On affiche le message que l'on envoie.
echo '<hr />Requête envoyée: <br />';
afficher_message($arr_octect);
// On envoie la requête au serveur NTP.
$raw_octect = implode($arr_octect);
// On ouvre la socket.
ini_set('default_socket_timeout', 3);
$int_t1a = time();
$res_socket = fsockopen('udp://'.NOM_SERVEUR_NTP, PORT_SERVEUR_NTP);
if ($res_socket === FALSE)
{ exit('Problème de connexion au serveur NTP'); }
// On envoie la requête.
if (fwrite($res_socket, $raw_octect) === FALSE)
{ exit('Problème d\'envoi de données'); }
// On récupère la réponse.
$raw_octect = fread($res_socket, LONGEUR_MESSAGE_EN_OCTET);
$int_t2a = time();
if ($arr_octect === FALSE)
{ exit('Problème de lecture de données'); }
fclose($res_socket);
// On contrôle la réponse.
$arr_octect = str_split($raw_octect);
if (count($arr_octect) != LONGEUR_MESSAGE_EN_OCTET)
{ exit('Problème de taille de message'); }
// On affiche le message reçu en binaire.
echo '<hr />Réponse reçue: <br />';
afficher_message($arr_octect);
// On affiche les différentes informations issues du serveur.
// Saut de seconde
$arr_str_saut = array(0 => 'rien', 1 => 'ajouter une seconde', 2 => 'enlever une seconde', 3 => 'horloge non synchronisée');
$int_saut = (ord($arr_octect[0]) >> 6) & 0x3;
$str_saut = isset($arr_str_saut[$int_saut]) ? $arr_str_saut[$int_saut] : '-';
// Version
$int_version = (ord($arr_octect[0]) >> 3) & 0x7;
// Mode
$int_mode = ord($arr_octect[0]) & 0x7;
$arr_str_mode = array(1 => 'symétrique actif', 2 => 'symétrique passif', 3 => 'client', 4 => 'serveur', 5 => 'broadcast ', 6 => 'message de contrôle NTP');
$str_mode = isset($arr_str_mode[$int_mode]) ? $arr_str_mode[$int_mode] : '-';
// ID Serveur: sauf erreur de ma part, il n'envoie pas l'IP du serveur comme annoncé.
//$str_identifier = strval(ord($arr_octect[12])).'.'.strval(ord($arr_octect[13])).'.'.strval(ord($arr_octect[14])).'.'.strval(ord($arr_octect[15]));
//$str_identifier .= ' - '.$arr_octect[12].$arr_octect[13].$arr_octect[14].$arr_octect[15];
// Strate
$int_strate = ord($arr_octect[1]);
echo '<hr />';
echo '<table>';
echo "<tr><td>Leap Indicator</td><td>$str_saut</td></tr>";
echo "<tr><td>Version Number</td><td>$int_version</td></tr>";
echo "<tr><td>Mode</td><td>$str_mode</td></tr>";
//echo "<tr><td>Reference Clock Identifier</td><td>$str_identifier</td></tr>";
echo "<tr><td>Strate</td><td>$int_strate</td></tr>";
echo '</table>';
// On affiche les différents temps reçus.
echo '<hr />';
echo '<table>';
foreach (array('Reference Clock Update' => 16, 'Originate Time Stamp' => 24, 'Receive Time Stamp' => 32, 'Transmit Time Stamp' => 40) as $str_libelle => $int_position)
{
$int_date = extraire_seconde($arr_octect, $int_position);
$str_date = date('c', $int_date);
echo "<tr><td>$str_libelle</td><td>$int_date</td><td>$str_date</td></tr>";
}
echo '</table>';
// On affiche les différentes valeurs calculées.
echo '<hr />';
$int_t1b = extraire_seconde($arr_octect, 32);
$int_t2b = extraire_seconde($arr_octect, 40);
$int_delai_aller_retour = ($int_t2a - $int_t1a) - ($int_t2b - $int_t1b);
$int_ecart = intval(($int_t1b + $int_t2b) / 2.0 - ($int_t1a + $int_t2a) / 2.0);
$int_date_locale = time();
$str_date_locale = date('c', $int_date_locale);
$int_date_corrigee = $int_date_locale + $int_ecart;
$str_date_corrigee = date('c', $int_date_corrigee);
$str_info = ($int_ecart) ? (($int_ecart > 0) ? '(en retard)' : '(en avance)') : '';
echo '<table cellpadding="2x" border="1px">';
echo "<tr><td>Délai Aller Retour</td><td>$int_delai_aller_retour sec.</td></tr>";
echo "<tr><td>Ecart</td><td>$int_ecart sec. $str_info</td></tr>";
echo "<tr><td>Date Locale</td><td>$str_date_locale</td></tr>";
echo "<tr><td>Date Corrigée</td><td>$str_date_corrigee</td></tr>";
echo '</table>';
echo '<hr />';
highlight_file(__FILE__);
// Fin html
echo '</body></html>';
}
main();