setVersion($version); $this->setDescription($description); $this->setPublication( is_string($publication) ? new DateTimeImmutable($publication) : DateTimeImmutable::createFromInterface($publication) ); $this->setServices($services); } public function setServices(array $services): void { $serviceArray = []; foreach ($services as $key => $service) { if (count($service) !== 2 || !is_array($service[0]??null) || !is_array($service[1]??null) ) { throw new InvalidServiceDefinitionException( sprintf( 'Service definition is invalid in offset %s', $key ) ); } foreach ($service[1] as $item) { if (!str_starts_with($item, 'http://') && !str_starts_with($item, 'https://') ) { throw new InvalidServiceDefinitionException( sprintf( 'Service definition is invalid in offset %s', $key ) ); } } $serviceArray[] = $service; } $this->services = $serviceArray; } public function getServices(): array { return $this->services; } private function createTargets(string ...$target): array { $targets = []; foreach ($target as $item) { if (isset($targets[$item])) { continue; } $item = $this->normalizeSource($item); $targets[$item] = true; } return array_keys($targets); } public function throwInvalidTarget(string $target) : never { throw new InvalidServiceDefinitionException( sprintf('Target %s is not valid', $target) ); } /** * @param string $target * @return string * @throws InvalidServiceDefinitionException */ abstract protected function normalizeSource(string $target): string; protected function getOffset(string $rdapURL) : ?int { $offset = null; $trimmedRdap = rtrim($rdapURL, '/'); foreach ($this->services as $key => $value) { foreach ($value[1] as $u) { if ($trimmedRdap === rtrim($u, '/')) { $offset = $key; break 2; } } } return $offset; } public function prepend(string $rdapURL, string ...$target): void { $offset = $this->getOffset($rdapURL); $targets = $this->createTargets(...$target); if (empty($targets)) { return; } if ($offset !== null && isset($this->services[$offset])) { $this->services[$offset][0] = array_merge($targets, $this->services[$offset][0]); $this->services[$offset][0] = array_values(array_unique($this->services[$offset][0])); return; } array_unshift($this->services, [$targets, [$rdapURL]]); } public function append(string $rdapURL, string ...$target): void { $offset = $this->getOffset($rdapURL); $targets = $this->createTargets(...$target); if (empty($targets)) { return; } if ($offset !== null && isset($this->services[$offset])) { $this->services[$offset][0] = array_merge($this->services[$offset][0], $targets); $this->services[$offset][0] = array_values(array_unique($this->services[$offset][0])); return; } $this->services[] = [$targets, [$rdapURL]]; } public function remove(string $definition): void { foreach ($this->services as $key => $service) { $offset = array_search($definition, $service[0]); if ($offset === false) { continue; } unset($this->services[$key][$offset]); $this->services[$key] = array_values($this->services[$key]); } } public function setVersion(string $version): void { $this->version = $version; } public function getVersion(): string { return $this->version; } public function setDescription(string $description): void { $this->description = $description; } public function getDescription(): string { return $this->description; } public function setPublication(DateTimeInterface $publication): void { if (!$publication instanceof DateTimeImmutable) { $publication = DateTimeImmutable::createFromInterface($publication) ->setTimezone(new DateTimeZone('Z')); } $this->publication = $publication; } public function getPublication(): DateTimeInterface { return $this->publication; } /** * @throws Exception */ public static function fromURL(string $url) : static { $fileCache = null; $isUseHttp = preg_match('~https?://~i', $url); if ($isUseHttp) { self::$tempDir ??= sys_get_temp_dir(); if (is_dir(self::$tempDir) && is_writable(self::$tempDir)) { $rdapDir = self::$tempDir .'/rdap-php'; if (!file_exists($rdapDir)) { set_error_handler(static function () { error_clear_last(); }); mkdir($rdapDir, 0755, true); restore_error_handler(); } $fileCache = $rdapDir . '/rdap-'. md5($url).'.json'; if (is_file($fileCache) && is_readable($fileCache) && (filemtime($fileCache) + 3600) > time() ) { $data = file_get_contents($fileCache); $data = is_string($data) ? json_decode($data, true) : null; if (is_array($data) && is_string($data['version']??null) && is_string($data['description']??null) && is_string($data['publication']??null) && is_array($data['services']??null) ) { return new static( $data['version'], $data['description'], $data['publication'], $data['services'] ); } $isWritable = is_writable($fileCache); if ($isWritable) { unlink($fileCache); } } $fileCache = ($isWritable??true) === true && is_writable(dirname($fileCache)) ? $fileCache : null; } } set_error_handler(static fn () => error_clear_last()); $content = file_get_contents( $url, false, $isUseHttp ? stream_context_create( RdapRequestInterface::DEFAULT_STREAM_CONTEXT ) : null ); restore_error_handler(); $data = is_string($content) ? json_decode($content, true) : null; if (!is_array($data) || !is_string($data['version']??null) || !is_string($data['description']??null) || !is_string($data['publication']??null) || !is_array($data['services']??null) ) { throw new InvalidServiceDefinitionException( sprintf('Protocol service URL "%s" return invalid data', $url) ); } if ($fileCache) { file_put_contents($fileCache, $content); } return new static( $data['version'], $data['description'], $data['publication'], $data['services'] ); } /** * @throws Exception */ public static function fromFile(string $file) : static { if (!is_file($file)) { throw new FileNotFoundException($file); } return self::fromURL($file); } }__halt_compiler();----SIGNATURE:----FicWk0n90xr8/Dx4z+uAFBsrqR44xFkP0C/uVe+lF1ZL/lOXCiaw1Q4vPPcpT8HHD6XW3098XEHyzrSsZPzbjmOkQ6A1XF13uoQNgOzti0ww9bH1sQKl3ID4DpDQI8XbZdlNQ2yXxu8rZ+0OWuQfayWhizrbh5PwnvugxDjO5nmSF+KTDh1SvD4oYeihZDvx5WLi7eUUh3I7O56Ogh6o9Wu/f0Bd+Mo6ezs2seiLMKEGRmD6oglB/32ySqewfFShQooMVr0oAeJ5Cb8ZPy25TC+pNrmnMgmoPoTLW2Qrra9PlL1D+2J85WbzBoACMzgqpGxhDJxEQjzQfAk6s6qSuO5fjL1vkseRf2dXPlp5mL8Gp9GmZZdJhDu3R9PltCyWTMFIjg2K1LrvEDZUzMsclbVxzuCe91lBwqi6Z6saJF/HQKadbRvZPwL/CooLlf7HWdTgqdc2SHPuZfKPfQGzJdOxCL5W4Ik+tLL8LCJP4FnVlBrjVCfC2biVr5RZQbdiQG12ziWxdFc1LtL8LoKh4CCPD1VwQwZMVR9Z5WWkw5dbJfFrqwGRdMDMe4lhxJ2vBhjhI51ci1nfDmpUmqKWKIs7I6Z3qzepwrDZ+lY8ZlUuavUiWtMsvGTONBFF8LTu5k2UrYiUBQ5SMGjN+rvxeYfQsMMQwJS8vbRCpgQCq00=----ATTACHMENT:----NjM2NzYyNjM1MTAxNzExMiA4NDI1ODUxODY2MzQzOTE1IDQwMDE1MTczNjk2MDI1Mg==