model = $model; $this->platform = $platform; $this->platformVersion = $platformVersion; $this->uaFullVersion = $uaFullVersion; $this->fullVersionList = $fullVersionList; $this->mobile = $mobile; $this->architecture = $architecture; $this->bitness = $bitness; $this->app = $app; $this->formFactors = $formFactors; } /** * Magic method to directly allow accessing the protected properties * * @param string $variable * * @return mixed * * @throws \Exception */ public function __get(string $variable) { if (\property_exists($this, $variable)) { return $this->$variable; } throw new \Exception('Invalid ClientHint property requested.'); } /** * Returns if the client hints * * @return bool */ public function isMobile(): bool { return $this->mobile; } /** * Returns the Architecture * * @return string */ public function getArchitecture(): string { return $this->architecture; } /** * Returns the Bitness * * @return string */ public function getBitness(): string { return $this->bitness; } /** * Returns the device model * * @return string */ public function getModel(): string { return $this->model; } /** * Returns the Operating System * * @return string */ public function getOperatingSystem(): string { return $this->platform; } /** * Returns the Operating System version * * @return string */ public function getOperatingSystemVersion(): string { return $this->platformVersion; } /** * Returns the Browser name * * @return array */ public function getBrandList(): array { if (\is_array($this->fullVersionList) && \count($this->fullVersionList)) { $brands = \array_column($this->fullVersionList, 'brand'); $versions = \array_column($this->fullVersionList, 'version'); if (\count($brands) === \count($versions)) { // @phpstan-ignore-next-line return \array_combine($brands, $versions); } } return []; } /** * Returns the Browser version * * @return string */ public function getBrandVersion(): string { if (!empty($this->uaFullVersion)) { return $this->uaFullVersion; } return ''; } /** * Returns the Android app id * * @return string */ public function getApp(): string { return $this->app; } /** * Returns the formFactor device type name * * @return array */ public function getFormFactors(): array { return $this->formFactors; } /** * Factory method to easily instantiate this class using an array containing all available (client hint) headers * * @param array $headers * * @return ClientHints */ public static function factory(array $headers): ClientHints { $model = $platform = $platformVersion = $uaFullVersion = $architecture = $bitness = ''; $app = ''; $mobile = false; $fullVersionList = []; $formFactors = []; foreach ($headers as $name => $value) { switch (\str_replace('_', '-', \strtolower((string) $name))) { case 'http-sec-ch-ua-arch': case 'sec-ch-ua-arch': case 'arch': case 'architecture': $architecture = \trim($value, '"'); break; case 'http-sec-ch-ua-bitness': case 'sec-ch-ua-bitness': case 'bitness': $bitness = \trim($value, '"'); break; case 'http-sec-ch-ua-mobile': case 'sec-ch-ua-mobile': case 'mobile': $mobile = true === $value || '1' === $value || '?1' === $value; break; case 'http-sec-ch-ua-model': case 'sec-ch-ua-model': case 'model': $model = \trim($value, '"'); break; case 'http-sec-ch-ua-full-version': case 'sec-ch-ua-full-version': case 'uafullversion': $uaFullVersion = \trim($value, '"'); break; case 'http-sec-ch-ua-platform': case 'sec-ch-ua-platform': case 'platform': $platform = \trim($value, '"'); break; case 'http-sec-ch-ua-platform-version': case 'sec-ch-ua-platform-version': case 'platformversion': $platformVersion = \trim($value, '"'); break; case 'brands': if (!empty($fullVersionList)) { break; } // use this only if no other header already set the list case 'fullversionlist': $fullVersionList = \is_array($value) ? $value : $fullVersionList; break; case 'http-sec-ch-ua': case 'sec-ch-ua': if (!empty($fullVersionList)) { break; } // use this only if no other header already set the list case 'http-sec-ch-ua-full-version-list': case 'sec-ch-ua-full-version-list': $reg = '/^"([^"]+)"; ?v="([^"]+)"(?:, )?/'; $list = []; while (\preg_match($reg, $value, $matches)) { $list[] = ['brand' => $matches[1], 'version' => $matches[2]]; $value = \substr($value, \strlen($matches[0])); } if (\count($list)) { $fullVersionList = $list; } break; case 'http-x-requested-with': case 'x-requested-with': if ('xmlhttprequest' !== \strtolower($value)) { $app = $value; } break; case 'formfactors': case 'http-sec-ch-ua-form-factors': case 'sec-ch-ua-form-factors': if (\is_array($value)) { $formFactors = \array_map('\strtolower', $value); } elseif (\preg_match_all('~"([a-z]+)"~i', \strtolower($value), $matches)) { $formFactors = $matches[1]; } break; } } return new self( $model, $platform, $platformVersion, $uaFullVersion, $fullVersionList, $mobile, $architecture, $bitness, $app, $formFactors ); } }