diff --git a/src/Vies/HeartBeat.php b/src/Vies/HeartBeat.php index d063083..f12c1e0 100644 --- a/src/Vies/HeartBeat.php +++ b/src/Vies/HeartBeat.php @@ -28,6 +28,8 @@ */ class HeartBeat { + private const DEFAULT_TIMEOUT = 10; + /** * @var string The host you want to verify */ @@ -57,7 +59,7 @@ class HeartBeat * @param int $port * @param int $timeout */ - public function __construct(?string $host = null, int $port = 80, int $timeout = 10) + public function __construct(?string $host = null, int $port = Vies::VIES_PORT, int $timeout = self::DEFAULT_TIMEOUT) { if (null !== $host) { $this->setHost($host); @@ -150,23 +152,35 @@ public function isAlive(): bool */ private function reachOut(): bool { - $errno = 0; - $error = ''; - $hostname = $this->getHost(); - $portNumber = $this->getPort(); - $timeToLive = $this->getTimeout(); try { - if (false === ($handle = \fsockopen('tcp://' . $hostname, $portNumber, $errno, $error, $timeToLive))) { - return false; - } - } catch (\Exception $exception) { + $data = $this->getSecuredResponse(); + } catch (\RuntimeException $runtimeException) { return false; } + return ( + (0 === strcmp('HTTP/1.1 200 OK', $data[0])) || + (0 === strcmp('HTTP/1.1 307 Temporary Redirect', $data[0])) + ); + } + + /** + * This method will make a simple request inside a stream + * resource to retrieve its contents. Useful inside secured + * streams. + * + * @param resource $handle + * @return array + */ + private function readContents($handle): array + { + if (! is_resource($handle)) { + throw new \InvalidArgumentException('Expecting a resource to be provided'); + } $response = ''; - $uri = sprintf('%s://%s/', Vies::VIES_PROTO, Vies::VIES_DOMAIN); + $uri = sprintf('%s://%s/', Vies::VIES_PROTO, $this->host); $stream = [ 'GET ' . $uri . ' HTTP/1.0', - 'Host: ' . Vies::VIES_DOMAIN, + 'Host: ' . $this->host, 'Connection: close', ]; fwrite($handle, implode("\r\n", $stream) . "\r\n\r\n"); @@ -176,9 +190,48 @@ private function reachOut(): bool fclose($handle); $response = str_replace("\r\n", PHP_EOL, $response); $data = explode(PHP_EOL, $response); - return ( - (0 === strcmp('HTTP/1.1 200 OK', $data[0])) || - (0 === strcmp('HTTP/1.1 307 Temporary Redirect', $data[0])) + return $data; + } + + /** + * Will make a secured request over SSL/TLS where this + * method will first create a secured stream before + * making the request. + * + * @return array + * @throws \RuntimeException + * @see https://bytephunk.wordpress.com/2017/11/27/ssl-tls-stream-sockets-in-php-7/ + */ + private function getSecuredResponse(): array + { + $streamOptions = [ + 'ssl' => [ + 'verify_peer' => true, + 'verify_peer_name' => true, + 'allow_self_signed' => false, + ], + ]; + $streamContext = stream_context_create($streamOptions); + $socketAddress = sprintf( + 'tls://%s:%d', + $this->host, + $this->port + ); + $error = null; + $errno = null; + $stream = stream_socket_client( + $socketAddress, + $errno, + $error, + self::DEFAULT_TIMEOUT, + STREAM_CLIENT_CONNECT, + $streamContext ); + + if (! $stream) { + throw new \RuntimeException('Can not create socket stream: ' . $error); + } + + return $this->readContents($stream); } } diff --git a/src/Vies/Vies.php b/src/Vies/Vies.php index 1c8509e..83ef1d4 100644 --- a/src/Vies/Vies.php +++ b/src/Vies/Vies.php @@ -46,9 +46,9 @@ */ class Vies { - const VIES_PROTO = 'http'; + const VIES_PROTO = 'https'; const VIES_DOMAIN = 'ec.europa.eu'; - const VIES_PORT = 80; + const VIES_PORT = 443; const VIES_WSDL = '/taxation_customs/vies/checkVatService.wsdl'; const VIES_TEST_WSDL = '/taxation_customs/vies/checkVatTestService.wsdl'; const VIES_EU_COUNTRY_TOTAL = 29; diff --git a/tests/Vies/HeartBeatTest.php b/tests/Vies/HeartBeatTest.php index 4a285d5..2f9fc8a 100644 --- a/tests/Vies/HeartBeatTest.php +++ b/tests/Vies/HeartBeatTest.php @@ -32,7 +32,7 @@ public function testDefaultPortIsHttp() { $hb = new HeartBeat(); $port = $hb->getPort(); - $this->assertSame(80, $port); + $this->assertSame(443, $port); } /** @@ -113,7 +113,7 @@ public function socketProvider(): array { return [ 'Non-existing socket on localhost' => ['127.0.0.1', -1, 10, false], - 'Socket 80 on ec.europe.eu' => [Vies::VIES_DOMAIN, Vies::VIES_PORT, 10, true], + 'Socket 443 on ec.europe.eu' => [Vies::VIES_DOMAIN, Vies::VIES_PORT, 10, true], ]; } @@ -121,6 +121,8 @@ public function socketProvider(): array * @dataProvider socketProvider * @covers ::isAlive * @covers ::reachOut + * @covers ::getSecuredResponse + * @covers ::readContents */ public function testIsAliveUsingSockets($host, $port, $timeout, $expectedResult) {