NTPTimeProvider.php 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. <?php
  2. namespace RobThree\Auth\Providers\Time;
  3. /**
  4. * Takes the time from any NTP server
  5. */
  6. class NTPTimeProvider implements ITimeProvider
  7. {
  8. /** @var string */
  9. public $host;
  10. /** @var int */
  11. public $port;
  12. /** @var int */
  13. public $timeout;
  14. /**
  15. * @param string $host
  16. * @param int $port
  17. * @param int $timeout
  18. */
  19. public function __construct($host = 'time.google.com', $port = 123, $timeout = 1)
  20. {
  21. $this->host = $host;
  22. if (!is_int($port) || $port <= 0 || $port > 65535) {
  23. throw new TimeException('Port must be 0 < port < 65535');
  24. }
  25. $this->port = $port;
  26. if (!is_int($timeout) || $timeout < 0) {
  27. throw new TimeException('Timeout must be >= 0');
  28. }
  29. $this->timeout = $timeout;
  30. }
  31. /**
  32. * {@inheritdoc}
  33. */
  34. public function getTime()
  35. {
  36. try {
  37. /* Create a socket and connect to NTP server */
  38. $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
  39. socket_set_option($sock, SOL_SOCKET, SO_RCVTIMEO, ['sec' => $this->timeout, 'usec' => 0]);
  40. socket_connect($sock, $this->host, $this->port);
  41. /* Send request */
  42. $msg = "\010" . str_repeat("\0", 47);
  43. socket_send($sock, $msg, strlen($msg), 0);
  44. /* Receive response and close socket */
  45. if (socket_recv($sock, $recv, 48, MSG_WAITALL) === false) {
  46. throw new \Exception(socket_strerror(socket_last_error($sock)));
  47. }
  48. socket_close($sock);
  49. /* Interpret response */
  50. $data = unpack('N12', $recv);
  51. $timestamp = (int) sprintf('%u', $data[9]);
  52. /* NTP is number of seconds since 0000 UT on 1 January 1900 Unix time is seconds since 0000 UT on 1 January 1970 */
  53. return $timestamp - 2208988800;
  54. } catch (\Exception $ex) {
  55. throw new TimeException(sprintf('Unable to retrieve time from %s (%s)', $this->host, $ex->getMessage()));
  56. }
  57. }
  58. }