botInfo === true || is_array($this->botInfo)) { if($this->botInfo === true) return 'a bot'; return $this->botInfo['name'] ?? 'an unknown bot'; } if(empty($this->clientInfo['name'])) return 'an unknown browser'; $string = $this->clientInfo['name']; if(!empty($this->clientInfo['version'])) $string .= ' ' . $this->clientInfo['version']; $hasOsInfo = !empty($this->osInfo['name']); $hasModelName = !empty($this->modelName); if($hasOsInfo || $hasModelName) $string .= ' on '; if($hasModelName) { $deviceName = trim($this->brandName . ' ' . $this->modelName); // most naive check in the world but it works well enough for this lol $firstCharIsVowel = in_array(strtolower($deviceName[0]), ['a', 'i', 'u', 'e', 'o']); $string .= ($firstCharIsVowel ? 'an' : 'a') . ' ' . $deviceName; } if($hasOsInfo) { if($hasModelName) $string .= ' running '; $string .= $this->osInfo['name']; if(!empty($this->osInfo['version'])) $string .= ' ' . $this->osInfo['version']; if(!empty($this->osInfo['platform'])) $string .= ' (' . $this->osInfo['platform'] . ')'; } return $string; } public function encode(): string { return json_encode($this); } public function jsonSerialize(): mixed { $data = new stdClass; $data->version = self::SERIALIZE_VERSION; if($this->botInfo === true || is_array($this->botInfo)) $data->bot = $this->botInfo; if($this->clientInfo !== null) $data->client = $this->clientInfo; if($this->osInfo !== null) $data->os = $this->osInfo; if($this->brandName !== '') $data->vendor = $this->brandName; if($this->modelName !== '') $data->model = $this->modelName; return $data; } public static function decode(string $encoded): self { $data = json_decode($encoded, true); $version = $data['version'] ?? 0; if($version < 0 || $version > self::SERIALIZE_VERSION) throw new RuntimeException('$data does not contain a valid version argument'); return new ClientInfo( $data['bot'] ?? null, $data['client'] ?? null, $data['os'] ?? null, $data['vendor'] ?? '', $data['model'] ?? '' ); } public static function parse(array|string $serverVarsOrUserAgent): self { static $dd = null; $dd ??= new DeviceDetector(); if(is_string($serverVarsOrUserAgent)) { $dd->setUserAgent($serverVarsOrUserAgent); } else { $dd->setUserAgent( array_key_exists('HTTP_USER_AGENT', $serverVarsOrUserAgent) ? $serverVarsOrUserAgent['HTTP_USER_AGENT'] : '' ); $dd->setClientHints(ClientHints::factory($serverVarsOrUserAgent)); } $dd->parse(); return new ClientInfo( $dd->getBot(), $dd->getClient(), $dd->getOs(), $dd->getBrandName(), $dd->getModel() ); } public static function fromRequest(): self { return self::parse($_SERVER); } }