cache = $cache; $this->logger = $logger; $this->quoter = $quoter; } /** * Gets the settings for a given pattern (method calls itself to * get the data from the parent patterns) * * @param string[] $settings * * @return string[] * * @throws UnexpectedValueException */ public function getSettings(string $pattern, array $settings = []): array { // The pattern has been pre-quoted on generation to speed up the pattern search, // but for this check we need the unquoted version $unquotedPattern = $this->quoter->pregUnQuote($pattern); // Try to get settings for the pattern $addedSettings = $this->getIniPart($unquotedPattern); // set some additional data if (count($settings) === 0) { // The optimization with replaced digits get can now result in setting searches, for which we // won't find a result - so only add the pattern information, is settings have been found. // // If not an empty array will be returned and the calling function can easily check if a pattern // has been found. if (0 < count($addedSettings)) { $settings['browser_name_regex'] = '/^' . $pattern . '$/'; $settings['browser_name_pattern'] = $unquotedPattern; } } // check if parent pattern set, only keep the first one $parentPattern = null; if (isset($addedSettings['Parent'])) { $parentPattern = $addedSettings['Parent']; if (isset($settings['Parent'])) { unset($addedSettings['Parent']); } } // merge settings $settings += $addedSettings; if (is_string($parentPattern)) { return $this->getSettings($this->quoter->pregQuote($parentPattern), $settings); } return $settings; } /** * Gets the relevant part (array of settings) of the ini file for a given pattern. * * @return string[] * * @throws void */ private function getIniPart(string $pattern): array { $pattern = strtolower($pattern); $patternhash = Pattern::getHashForParts($pattern); $subkey = SubKey::getIniPartCacheSubKey($patternhash); try { if (!$this->cache->hasItem('browscap.iniparts.' . $subkey, true)) { $this->logger->debug(sprintf('cache key "browscap.iniparts.%s" for pattern "%s" not found', $subkey, $pattern)); return []; } } catch (InvalidArgumentException $e) { $this->logger->error(new \InvalidArgumentException(sprintf('an error occured while checking inipart "browscap.iniparts.%s" in the cache', $subkey), 0, $e)); return []; } $success = null; try { $file = $this->cache->getItem('browscap.iniparts.' . $subkey, true, $success); } catch (InvalidArgumentException $e) { $this->logger->error(new \InvalidArgumentException(sprintf('an error occured while reading inipart "browscap.iniparts.%s" from the cache', $subkey), 0, $e)); return []; } if (!$success) { $this->logger->debug(sprintf('cache key "browscap.iniparts.%s" for pattern "%s" not found', $subkey, $pattern)); return []; } if (!is_array($file) || !count($file)) { $this->logger->debug(sprintf('cache key "browscap.iniparts.%s" for pattern "%s" was empty', $subkey, $pattern)); return []; } $propertyFormatter = new PropertyFormatter(new PropertyHolder()); $return = []; foreach ($file as $buffer) { [$tmpBuffer, $patterns] = explode("\t", $buffer, 2); if ($tmpBuffer === $patternhash) { try { $return = json_decode($patterns, true, 512, JSON_THROW_ON_ERROR); } catch (JsonException $e) { $this->logger->error(sprintf('data for cache key "browscap.iniparts.%s" for pattern "%s" are not valid json', $subkey, $pattern)); return []; } assert(is_array($return)); foreach (array_keys($return) as $property) { $return[$property] = $propertyFormatter->formatPropertyValue($return[$property], (string) $property); } break; } } return $return; } }