Author: Thomas Müller (t_mueller_stolzenhain@yahoo.de)
Esempio n. 1
0
 /**
  * Gets the settings for a given pattern (method calls itself to
  * get the data from the parent patterns)
  *
  * @param  string $pattern
  * @param  array  $settings
  * @return array
  */
 public function getSettings($pattern, array $settings = [])
 {
     // 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 (count($addedSettings) > 0) {
             $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 ($parentPattern !== null) {
         return $this->getSettings($this->quoter->pregQuote($parentPattern), $settings);
     }
     return $settings;
 }
Esempio n. 2
0
 /**
  * Creates new pattern cache files
  *
  * @param string $content
  *
  * @return \Generator
  */
 public function createPatterns($content)
 {
     // get all relevant patterns from the INI file
     // - containing "*" or "?"
     // - not containing "*" or "?", but not having a comment
     preg_match_all('/(?<=\\[)(?:[^\\r\\n]*[?*][^\\r\\n]*)(?=\\])|(?<=\\[)(?:[^\\r\\n*?]+)(?=\\])(?![^\\[]*Comment=)/m', $content, $matches);
     if (empty($matches[0]) || !is_array($matches[0])) {
         (yield []);
         return;
     }
     $quoterHelper = new Quoter();
     $matches = $matches[0];
     usort($matches, [$this, 'compareBcStrings']);
     // build an array to structure the data. this requires some memory, but we need this step to be able to
     // sort the data in the way we need it (see below).
     $data = [];
     foreach ($matches as $pattern) {
         if ('GJK_Browscap_Version' === $pattern) {
             continue;
         }
         $pattern = strtolower($pattern);
         $patternhash = Pattern::getHashForPattern($pattern, false);
         $tmpLength = Pattern::getPatternLength($pattern);
         // special handling of default entry
         if ($tmpLength === 0) {
             $patternhash = str_repeat('z', 32);
         }
         if (!isset($data[$patternhash])) {
             $data[$patternhash] = [];
         }
         if (!isset($data[$patternhash][$tmpLength])) {
             $data[$patternhash][$tmpLength] = [];
         }
         $pattern = $quoterHelper->pregQuote($pattern);
         // Check if the pattern contains digits - in this case we replace them with a digit regular expression,
         // so that very similar patterns (e.g. only with different browser version numbers) can be compressed.
         // This helps to speed up the first (and most expensive) part of the pattern search a lot.
         if (strpbrk($pattern, '0123456789') !== false) {
             $compressedPattern = preg_replace('/\\d/', '[\\d]', $pattern);
             if (!in_array($compressedPattern, $data[$patternhash][$tmpLength])) {
                 $data[$patternhash][$tmpLength][] = $compressedPattern;
             }
         } else {
             $data[$patternhash][$tmpLength][] = $pattern;
         }
     }
     unset($matches);
     // sorting of the data is important to check the patterns later in the correct order, because
     // we need to check the most specific (=longest) patterns first, and the least specific
     // (".*" for "Default Browser")  last.
     //
     // sort by pattern start to group them
     ksort($data);
     // and then by pattern length (longest first)
     foreach (array_keys($data) as $key) {
         krsort($data[$key]);
     }
     // write optimized file (grouped by the first character of the has, generated from the pattern
     // start) with multiple patterns joined by tabs. this is to speed up loading of the data (small
     // array with pattern strings instead of an large array with single patterns) and also enables
     // us to search for multiple patterns in one preg_match call for a fast first search
     // (3-10 faster), followed by a detailed search for each single pattern.
     $contents = [];
     foreach ($data as $patternhash => $tmpEntries) {
         if (empty($tmpEntries)) {
             continue;
         }
         $subkey = SubKey::getPatternCacheSubkey($patternhash);
         if (!isset($contents[$subkey])) {
             $contents[$subkey] = [];
         }
         foreach ($tmpEntries as $tmpLength => $tmpPatterns) {
             if (empty($tmpPatterns)) {
                 continue;
             }
             $chunks = array_chunk($tmpPatterns, self::COUNT_PATTERN);
             foreach ($chunks as $chunk) {
                 $contents[$subkey][] = $patternhash . "\t" . $tmpLength . "\t" . implode("\t", $chunk);
             }
         }
     }
     unset($data);
     $subkeys = SubKey::getAllPatternCacheSubkeys();
     foreach ($contents as $subkey => $content) {
         $subkey = (string) $subkey;
         (yield [$subkey => $content]);
         unset($subkeys[$subkey]);
     }
     foreach (array_keys($subkeys) as $subkey) {
         $subkey = (string) $subkey;
         (yield [$subkey => []]);
     }
 }
Esempio n. 3
0
 /**
  *
  */
 public function testPregQuote()
 {
     $expected = 'Mozilla\\/.\\.0 \\(compatible; Ask Jeeves\\/Teoma.*\\)';
     self::assertSame($expected, $this->quoter->pregQuote('Mozilla/?.0 (compatible; Ask Jeeves/Teoma*)'));
 }
Esempio n. 4
0
 /**
  * Parses the ini data to get the version of loaded ini file
  *
  * @param string $iniString The loaded ini data
  *
  * @return int
  */
 public function getIniVersion($iniString)
 {
     $quoterHelper = new Quoter();
     $key = $quoterHelper->pregQuote(self::BROWSCAP_VERSION_KEY);
     if (preg_match('/\\.*\\[' . $key . '\\][^\\[]*Version=(\\d+)\\D.*/', $iniString, $matches)) {
         if (isset($matches[1])) {
             $this->iniVersion = (int) $matches[1];
         }
     }
     return $this->iniVersion;
 }