HttpTimeProvider.php 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. <?php
  2. namespace RobThree\Auth\Providers\Time;
  3. use DateTime;
  4. /**
  5. * Takes the time from any webserver by doing a HEAD request on the specified URL and extracting the 'Date:' header
  6. */
  7. class HttpTimeProvider implements ITimeProvider {
  8. /** @var string */
  9. public $url;
  10. /** @var string */
  11. public $expectedtimeformat;
  12. /** @var array */
  13. public $options;
  14. /**
  15. * @param string $url
  16. * @param string $expectedtimeformat
  17. * @param array $options
  18. */
  19. public function __construct(
  20. $url = "https://google.com",
  21. $expectedtimeformat = "D, d M Y H:i:s O+",
  22. array $options = null,
  23. ) {
  24. $this->url = $url;
  25. $this->expectedtimeformat = $expectedtimeformat;
  26. if ($options === null) {
  27. $options = [
  28. "http" => [
  29. "method" => "HEAD",
  30. "follow_location" => false,
  31. "ignore_errors" => true,
  32. "max_redirects" => 0,
  33. "request_fulluri" => true,
  34. "header" => [
  35. "Connection: close",
  36. "User-agent: TwoFactorAuth HttpTimeProvider (https://github.com/RobThree/TwoFactorAuth)",
  37. "Cache-Control: no-cache",
  38. ],
  39. ],
  40. ];
  41. }
  42. $this->options = $options;
  43. }
  44. /**
  45. * {@inheritdoc}
  46. */
  47. public function getTime() {
  48. try {
  49. $context = stream_context_create($this->options);
  50. $fd = fopen($this->url, "rb", false, $context);
  51. $headers = stream_get_meta_data($fd);
  52. fclose($fd);
  53. foreach ($headers["wrapper_data"] as $h) {
  54. if (strcasecmp(substr($h, 0, 5), "Date:") === 0) {
  55. return DateTime::createFromFormat(
  56. $this->expectedtimeformat,
  57. trim(substr($h, 5)),
  58. )->getTimestamp();
  59. }
  60. }
  61. throw new \Exception('Invalid or no "Date:" header found');
  62. } catch (\Exception $ex) {
  63. throw new TimeException(
  64. sprintf("Unable to retrieve time from %s (%s)", $this->url, $ex->getMessage()),
  65. );
  66. }
  67. }
  68. }