1*d5ef99ddSAndreas Gohr<?php 2*d5ef99ddSAndreas Gohr 3*d5ef99ddSAndreas Gohr/** 4*d5ef99ddSAndreas Gohr * Device Detector - The Universal Device Detection library for parsing User Agents 5*d5ef99ddSAndreas Gohr * 6*d5ef99ddSAndreas Gohr * @link https://matomo.org 7*d5ef99ddSAndreas Gohr * 8*d5ef99ddSAndreas Gohr * @license http://www.gnu.org/licenses/lgpl.html LGPL v3 or later 9*d5ef99ddSAndreas Gohr */ 10*d5ef99ddSAndreas Gohr 11*d5ef99ddSAndreas Gohrdeclare(strict_types=1); 12*d5ef99ddSAndreas Gohr 13*d5ef99ddSAndreas Gohrnamespace DeviceDetector\Parser\Client; 14*d5ef99ddSAndreas Gohr 15*d5ef99ddSAndreas Gohruse DeviceDetector\Parser\AbstractParser; 16*d5ef99ddSAndreas Gohr 17*d5ef99ddSAndreas Gohrabstract class AbstractClientParser extends AbstractParser 18*d5ef99ddSAndreas Gohr{ 19*d5ef99ddSAndreas Gohr /** 20*d5ef99ddSAndreas Gohr * @var string 21*d5ef99ddSAndreas Gohr */ 22*d5ef99ddSAndreas Gohr protected $fixtureFile = ''; 23*d5ef99ddSAndreas Gohr 24*d5ef99ddSAndreas Gohr /** 25*d5ef99ddSAndreas Gohr * @var string 26*d5ef99ddSAndreas Gohr */ 27*d5ef99ddSAndreas Gohr protected $parserName = ''; 28*d5ef99ddSAndreas Gohr 29*d5ef99ddSAndreas Gohr /** 30*d5ef99ddSAndreas Gohr * Parses the current UA and checks whether it contains any client information 31*d5ef99ddSAndreas Gohr * 32*d5ef99ddSAndreas Gohr * @see $fixtureFile for file with list of detected clients 33*d5ef99ddSAndreas Gohr * 34*d5ef99ddSAndreas Gohr * Step 1: Build a big regex containing all regexes and match UA against it 35*d5ef99ddSAndreas Gohr * -> If no matches found: return 36*d5ef99ddSAndreas Gohr * -> Otherwise: 37*d5ef99ddSAndreas Gohr * Step 2: Walk through the list of regexes in feed_readers.yml and try to match every one 38*d5ef99ddSAndreas Gohr * -> Return the matched feed reader 39*d5ef99ddSAndreas Gohr * 40*d5ef99ddSAndreas Gohr * NOTE: Doing the big match before matching every single regex speeds up the detection 41*d5ef99ddSAndreas Gohr * 42*d5ef99ddSAndreas Gohr * @return array|null 43*d5ef99ddSAndreas Gohr */ 44*d5ef99ddSAndreas Gohr public function parse(): ?array 45*d5ef99ddSAndreas Gohr { 46*d5ef99ddSAndreas Gohr $result = null; 47*d5ef99ddSAndreas Gohr 48*d5ef99ddSAndreas Gohr if ($this->preMatchOverall()) { 49*d5ef99ddSAndreas Gohr foreach ($this->getRegexes() as $regex) { 50*d5ef99ddSAndreas Gohr $matches = $this->matchUserAgent($regex['regex']); 51*d5ef99ddSAndreas Gohr 52*d5ef99ddSAndreas Gohr if ($matches) { 53*d5ef99ddSAndreas Gohr $result = [ 54*d5ef99ddSAndreas Gohr 'type' => $this->parserName, 55*d5ef99ddSAndreas Gohr 'name' => $this->buildByMatch($regex['name'], $matches), 56*d5ef99ddSAndreas Gohr 'version' => $this->buildVersion((string) $regex['version'], $matches), 57*d5ef99ddSAndreas Gohr ]; 58*d5ef99ddSAndreas Gohr 59*d5ef99ddSAndreas Gohr break; 60*d5ef99ddSAndreas Gohr } 61*d5ef99ddSAndreas Gohr } 62*d5ef99ddSAndreas Gohr } 63*d5ef99ddSAndreas Gohr 64*d5ef99ddSAndreas Gohr return $result; 65*d5ef99ddSAndreas Gohr } 66*d5ef99ddSAndreas Gohr 67*d5ef99ddSAndreas Gohr /** 68*d5ef99ddSAndreas Gohr * Returns all names defined in the regexes 69*d5ef99ddSAndreas Gohr * 70*d5ef99ddSAndreas Gohr * Attention: This method might not return all names of detected clients 71*d5ef99ddSAndreas Gohr * 72*d5ef99ddSAndreas Gohr * @return array 73*d5ef99ddSAndreas Gohr */ 74*d5ef99ddSAndreas Gohr public static function getAvailableClients(): array 75*d5ef99ddSAndreas Gohr { 76*d5ef99ddSAndreas Gohr $instance = new static(); // @phpstan-ignore-line 77*d5ef99ddSAndreas Gohr $regexes = $instance->getRegexes(); 78*d5ef99ddSAndreas Gohr $names = []; 79*d5ef99ddSAndreas Gohr 80*d5ef99ddSAndreas Gohr foreach ($regexes as $regex) { 81*d5ef99ddSAndreas Gohr if (false !== \strpos($regex['name'], '$1')) { 82*d5ef99ddSAndreas Gohr continue; 83*d5ef99ddSAndreas Gohr } 84*d5ef99ddSAndreas Gohr 85*d5ef99ddSAndreas Gohr $names[] = $regex['name']; 86*d5ef99ddSAndreas Gohr } 87*d5ef99ddSAndreas Gohr 88*d5ef99ddSAndreas Gohr if (static::class === MobileApp::class) { 89*d5ef99ddSAndreas Gohr $names = \array_merge($names, [ 90*d5ef99ddSAndreas Gohr // Microsoft Office $1 91*d5ef99ddSAndreas Gohr 'Microsoft Office Access', 'Microsoft Office Excel', 'Microsoft Office OneDrive for Business', 92*d5ef99ddSAndreas Gohr 'Microsoft Office OneNote', 'Microsoft Office PowerPoint', 'Microsoft Office Project', 93*d5ef99ddSAndreas Gohr 'Microsoft Office Publisher', 'Microsoft Office Visio', 'Microsoft Office Word', 94*d5ef99ddSAndreas Gohr // Podkicker$1 95*d5ef99ddSAndreas Gohr 'Podkicker', 'Podkicker Pro', 'Podkicker Classic', 96*d5ef99ddSAndreas Gohr // radio.$1 97*d5ef99ddSAndreas Gohr 'radio.at', 'radio.de', 'radio.dk', 'radio.es', 'radio.fr', 98*d5ef99ddSAndreas Gohr 'radio.it', 'radio.pl', 'radio.pt', 'radio.se', 'radio.net', 99*d5ef99ddSAndreas Gohr ]); 100*d5ef99ddSAndreas Gohr } 101*d5ef99ddSAndreas Gohr 102*d5ef99ddSAndreas Gohr \natcasesort($names); 103*d5ef99ddSAndreas Gohr 104*d5ef99ddSAndreas Gohr return \array_unique($names); 105*d5ef99ddSAndreas Gohr } 106*d5ef99ddSAndreas Gohr} 107