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