Read UTC timestamp from NTP time server
Fri, 12 November 2021
NtpServer.php
<?php /** * NtpServer * @example `$utcTimestamp = NtpServer::get();` */ class NtpServer { /** * @var string[] */ public static array $servers = [ 'time1.google.com', 'time2.google.com', 'time3.google.com', 'time4.google.com' ]; /** * Get the time from an NTP server. The timestamp returned is always in UTC. * * @link https://en.wikipedia.org/wiki/Network_Time_Protocol * @param array|null $servers * @param int $secondsTimeout * @param float $millisecondTimeout * @return int|null */ public static function get(?array $servers = null, int $secondsTimeout = 1, float $millisecondTimeout = 0): ?int { if (null === $servers) { $servers = self::$servers; } $time = null; foreach ($servers as $server) { $time = self::attempt($server, $secondsTimeout, $millisecondTimeout); if ($time !== null) { break; } } return $time; } /** * Attempt to get the time from an NTP server. * * @param string $server * @param int $secondsTimeout * @param float $millisecondTimeout * @return int|mixed|null */ protected static function attempt(string $server, int $secondsTimeout = 1, float $millisecondTimeout = 0) { $socket = @stream_socket_client( sprintf('udp://%s:123', $server), $errorCode, $errorMessage, $millisecondTimeout ); if (false === $socket || $errorCode !== 0) { return null; } @stream_set_timeout($socket, $secondsTimeout, $millisecondTimeout); if (false === @fwrite($socket, "\010\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0")) { return null; } if (false === $binary = @fread($socket, 48)) { return null; } if (false === @fclose($socket)) { return null; } if (false === $data = @unpack('N12', $binary)) { return null; } return $data[9] - 2208988800; } }