compatibility === null) { $compatibilityFile = __DIR__ . '/../include/compatibility.json'; if (!file_exists($compatibilityFile)) { throw new common_exception_FileSystemError('Unable to find the compatibility file'); } $this->compatibility = json_decode(file_get_contents($compatibilityFile), true); } return $this->compatibility; } /** * Fetch the support list * @throws common_exception_FileSystemError * @throws common_exception_InconsistentData * @throws common_exception_MissingParameter */ public function getSupportedList(): array { if ($this->supported == null) { /** @var SupportedListInterface $remoteSupportedListService */ $remoteSupportedListService = $this->getServiceLocator()->get(SupportedListInterface::SERVICE_ID); $supportedList = $remoteSupportedListService->getList(); if (!$supportedList) { throw new common_exception_InconsistentData('Unable to decode list of supported browsers'); } $this->supported = array_map(function ($entry) { $entry['compatible'] = self::COMPATIBILITY_SUPPORTED; $entry['versions'] = array_merge(...array_map(static function (string $version): array { return explode('-', $version); }, $entry['versions'])); return $entry; }, $supportedList); } return $this->supported; } protected function filterVersion($version): string { return preg_replace('#(\.0+)+($|-)#', '', $version); } /** * Standard version_compare threats that 5.2 < 5.2.0, 5.2 < 5.2.1, ... */ protected function versionCompare($ver1, $ver2): int { return version_compare($this->filterVersion($ver1), $this->filterVersion($ver2)); } /** * Check if a version is greater or equal to the listed ones */ protected function checkVersion($testedVersion, $versionList): bool { if (empty($versionList)) { return true; } foreach ($versionList as $version) { if ($this->versionCompare($testedVersion, $version) >= 0) { return true; } } return false; } /** * Checks if a version is excluded */ protected function isExcluded($name, $version, $exclusionsList): bool { $name = strtolower($name); if (count($exclusionsList) && array_key_exists($name, $exclusionsList)) { $explodedVersion = explode('.', $version); $excludedVersions = $exclusionsList[$name]; foreach ($excludedVersions as $excludedVersion) { if (empty($excludedVersion)) { // any version is excluded return true; } $explodedExcludedVersion = explode('.', $excludedVersion); if (array_slice($explodedVersion, 0, count($explodedExcludedVersion)) == $explodedExcludedVersion) { // greedy or exact version is excluded return true; } } } return false; } /** * Checks if a browser is excluded */ public function isBrowserExcluded($name, $version): bool { if ($this->excludedBrowsers === null) { $service = $this->getServiceLocator()->get(ExcludedBrowserService::SERVICE_ID); $this->excludedBrowsers = $service->getExclusionsList(); } return $this->isExcluded($name, $version, $this->excludedBrowsers); } /** * Checks if an OS is excluded */ public function isOsExcluded($name, $version): bool { if ($this->excludedOS === null) { $service = $this->getServiceLocator()->get(ExcludedOSService::SERVICE_ID); $this->excludedOS = $service->getExclusionsList(); } return $this->isExcluded($name, $version, $this->excludedOS); } /** * Checks if the client browser, and the OS, meet the requirements supplied in a validation list. * Returns a value corresponding to the COMPATIBILITY_* constants. * @throws common_exception_FileSystemError * @throws common_exception_InconsistentData * @throws common_exception_MissingParameter */ public function isCompatibleConfig(): int { $clientDevice = $this->getOsDetector()->isMobile() ? 'mobile' : 'desktop'; $clientOS = strtolower($this->getOsDetector()->getName()); $clientOSVersion = $this->getOsDetector()->getVersion(); $clientBrowser = strtolower($this->getBrowserDetector()->getName()); $clientBrowserVersion = $this->getBrowserDetector()->getVersion(); if ($this->isOsExcluded($clientOS, $clientOSVersion) || $this->isBrowserExcluded($clientBrowser, $clientBrowserVersion)) { return self::COMPATIBILITY_NOT_SUPPORTED; } $validationList = array_merge($this->getSupportedList(), $this->getCompatibilityList()); foreach ($validationList as $entry) { if ($clientDevice !== $entry['device']) { continue; } if ($entry['os']) { if (strtolower($entry['os']) !== $clientOS) { continue; } if ($entry['osVersion'] && $this->versionCompare($clientOSVersion, $entry['osVersion']) !== 0) { continue; } } if (strtolower($entry['browser']) !== $clientBrowser) { continue; } if ($this->checkVersion($clientBrowserVersion, $entry['versions'])) { if (isset($entry['compatible'])) { return $entry['compatible']; } return self::COMPATIBILITY_COMPATIBLE; } } return self::COMPATIBILITY_NOT_TESTED; } /** * Get the browser detector */ protected function getBrowserDetector(): Browser { return new Browser(); } /** * Get the operating system detector */ protected function getOsDetector(): Os { return new Os(); } }