Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Client and Devices Indexes #7821

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions DeviceDetector.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,18 @@ class DeviceDetector
*/
protected $cache = null;

/**
* Using indexes for faster client search (support browser and apps)
* @var bool
*/
protected $clientIndexes = false;

/**
* Using indexes for faster device search
* @var bool
*/
protected $deviceIndexes = false;

/**
* Holds the parser class used for parsing yml-Files
* @var YamlParser|null
Expand Down Expand Up @@ -631,22 +643,30 @@ public function parse(): void
*
* @param string $ua UserAgent to parse
* @param ?ClientHints $clientHints Client Hints to parse
* @param array $config Settings $deviceDetector
*
* @return array
*
* @deprecated
*
* @internal
*
*/
public static function getInfoFromUserAgent(string $ua, ?ClientHints $clientHints = null): array
public static function getInfoFromUserAgent(string $ua, ?ClientHints $clientHints = null, array $config = []): array
{
static $deviceDetector;

if (!($deviceDetector instanceof DeviceDetector)) {
$deviceDetector = new DeviceDetector();
}

if (\array_key_exists('clientIndexes', $config)) {
$deviceDetector->clientIndexes = $config['clientIndexes'];
}

if (\array_key_exists('deviceIndexes', $config)) {
$deviceDetector->deviceIndexes = $config['deviceIndexes'];
}

$deviceDetector->setUserAgent($ua);
$deviceDetector->setClientHints($clientHints);

Expand Down Expand Up @@ -869,6 +889,7 @@ protected function parseClient(): void
$parsers = $this->getClientParsers();

foreach ($parsers as $parser) {
$parser->setClientIndexer($this->clientIndexes);
$parser->setYamlParser($this->getYamlParser());
$parser->setCache($this->getCache());
$parser->setUserAgent($this->getUserAgent());
Expand All @@ -891,6 +912,7 @@ protected function parseDevice(): void
$parsers = $this->getDeviceParsers();

foreach ($parsers as $parser) {
$parser->setDeviceIndexer($this->deviceIndexes);
$parser->setYamlParser($this->getYamlParser());
$parser->setCache($this->getCache());
$parser->setUserAgent($this->getUserAgent());
Expand Down
28 changes: 22 additions & 6 deletions Parser/AbstractParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -253,9 +253,7 @@ protected function getRegexes(): array
}

if (empty($this->regexList)) {
$parsedContent = $this->getYamlParser()->parseFile(
$this->getRegexesDirectory() . DIRECTORY_SEPARATOR . $this->fixtureFile
);
$parsedContent = $this->getYamlParser()->parseFile($this->getRegexesFilePath());

if (!\is_array($parsedContent)) {
$parsedContent = [];
Expand Down Expand Up @@ -298,6 +296,14 @@ protected function getRegexesDirectory(): string
return \dirname(__DIR__);
}

/**
* @return string
*/
protected function getRegexesFilePath(): string
{
return $this->getRegexesDirectory() . DIRECTORY_SEPARATOR . $this->fixtureFile;
}

/**
* Matches the useragent against the given regex
*
Expand All @@ -310,9 +316,7 @@ protected function getRegexesDirectory(): string
protected function matchUserAgent(string $regex): ?array
{
$matches = [];

// only match if useragent begins with given regex or there is no letter before it
$regex = '/(?:^|[^A-Z0-9_-]|[^A-Z0-9-]_|sprd-|MZ-)(?:' . \str_replace('/', '\/', $regex) . ')/i';
$regex = $this->createUserAgentRegex($regex);

try {
if (\preg_match($regex, $this->userAgent, $matches)) {
Expand All @@ -329,6 +333,18 @@ protected function matchUserAgent(string $regex): ?array
return null;
}

/**
* Create base regex pattern
* @param string $regex
*
* @return string
*/
protected function createUserAgentRegex(string $regex): string
{
// only match if useragent begins with given regex or there is no letter before it
return '/(?:^|[^A-Z0-9_-]|[^A-Z0-9-]_|sprd-|MZ-)(?:' . \str_replace('/', '\/', $regex) . ')/i';
}

/**
* @param string $item
* @param array $matches
Expand Down
84 changes: 74 additions & 10 deletions Parser/Client/AbstractClientParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
namespace DeviceDetector\Parser\Client;

use DeviceDetector\Parser\AbstractParser;
use DeviceDetector\Parser\IndexerClient;

abstract class AbstractClientParser extends AbstractParser
{
Expand All @@ -26,6 +27,11 @@ abstract class AbstractClientParser extends AbstractParser
*/
protected $parserName = '';

/**
* @var bool
*/
protected $clientIndexes = false;

/**
* Parses the current UA and checks whether it contains any client information
*
Expand All @@ -45,25 +51,71 @@ public function parse(): ?array
{
$result = null;

if ($this->preMatchOverall()) {
foreach ($this->getRegexes() as $regex) {
$matches = $this->matchUserAgent($regex['regex']);
if ($this->clientIndexes) {
$result = $this->parseByPosition();
}

if ($matches) {
$result = [
'type' => $this->parserName,
'name' => $this->buildByMatch($regex['name'], $matches),
'version' => $this->buildVersion((string) $regex['version'], $matches),
];
if (null === $result && $this->preMatchOverall()) {
foreach ($this->getRegexes() as $regex) {
$result = $this->parseByRegex($regex);

break;
if (null !== $result) {
return $result;
}
}
}

return $result;
}

/**
* Parse the current UA by Indexes positions
* @return array|null
*/
public function parseByPosition(): ?array
{
$indexer = new IndexerClient($this->userAgent);
$dataId = $indexer->getDataId($this->parserName);
$dataIndex = $indexer->parse();

if (null !== $dataId && !empty($dataIndex['data'][$dataId])) {
$positions = $dataIndex['data'][$dataId];

foreach ($positions as $position) {
$regex = $this->regexList[$position] ?? null;
$result = null !== $regex ? $this->parseByRegex($regex) : null;

if (null !== $result) {
return $result;
}
}
}

return null;
}

/**
* Parse the current UA by regex data from $this->regexList
*
* @param array $regex
*
* @return array|null
*/
public function parseByRegex(array $regex): ?array
{
$matches = $this->matchUserAgent($regex['regex']);

if (!$matches) {
return null;
}

return [
'type' => $this->parserName,
'name' => $this->buildByMatch($regex['name'], $matches),
'version' => $this->buildVersion((string) $regex['version'], $matches),
];
}

/**
* Returns all names defined in the regexes
*
Expand All @@ -89,4 +141,16 @@ public static function getAvailableClients(): array

return \array_unique($names);
}

/**
* This method tells the class to use regex position indexes
*
* @param bool $stage
*
* @return void
*/
public function setClientIndexer(bool $stage): void
{
$this->clientIndexes = $stage;
}
}
57 changes: 52 additions & 5 deletions Parser/Device/AbstractDeviceParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
namespace DeviceDetector\Parser\Device;

use DeviceDetector\Parser\AbstractParser;
use DeviceDetector\Parser\IndexerDevice;

/**
* Class AbstractDeviceParser
Expand Down Expand Up @@ -51,6 +52,11 @@ abstract class AbstractDeviceParser extends AbstractParser
public const DEVICE_TYPE_WEARABLE = 12; // including set watches, headsets
public const DEVICE_TYPE_PERIPHERAL = 13; // including portable terminal, portable projector

/**
* @var bool
*/
protected $deviceIndexes = false;

/**
* Detectable device types
*
Expand Down Expand Up @@ -2144,6 +2150,18 @@ public function setUserAgent(string $userAgent): void
parent::setUserAgent($userAgent);
}

/**
* This method tells the class to use regex position indexes
*
* @param bool $stage
*
* @return void
*/
public function setDeviceIndexer(bool $stage): void
{
$this->deviceIndexes = $stage;
}

/**
* @inheritdoc
*/
Expand All @@ -2166,14 +2184,43 @@ public function parse(): ?array
return $this->getResult();
}

$brand = '';
$regexes = $this->getRegexes();
$matches = null;
$brand = '';

// is use device indexes
if ($this->deviceIndexes) {
$indexer = new IndexerDevice();
$indexer->setUserAgent($this->userAgent);
$indexer->setClientHints($this->clientHints);

foreach ($regexes as $brand => $regex) {
$matches = $this->matchUserAgent($regex['regex']);
$brands = $indexer->parse();

if ($matches) {
break;
foreach ($brands as $brandName) {
$regex = $regexes[$brandName] ?? null;

if (null === $regex) {
continue;
}

$matches = $this->matchUserAgent($regex['regex']);

if ($matches) {
$brand = $brandName;

break;
}
}
}

// is not use indexes
if ('' === $brand) {
foreach ($regexes as $brand => $regex) {
$matches = $this->matchUserAgent($regex['regex']);

if ($matches) {
break;
}
}
}

Expand Down
Loading
Loading