-
-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #66 from andreaselia/fix-l11
Revert "Revert "Copy over Agent functionality to allow Laravel 11 Sup…
- Loading branch information
Showing
7 changed files
with
683 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
/vendor | ||
/.phpunit.cache | ||
composer.lock | ||
.phpunit.result.cache | ||
.phpunit.cache/test-results |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,382 @@ | ||
<?php | ||
|
||
namespace AndreasElia\Analytics; | ||
|
||
use BadMethodCallException; | ||
use Jaybizzle\CrawlerDetect\CrawlerDetect; | ||
use Mobile_Detect; | ||
|
||
class Agent extends Mobile_Detect | ||
{ | ||
/** @var array */ | ||
protected static $desktopDevices = [ | ||
'Macintosh' => 'Macintosh', | ||
]; | ||
|
||
/** @var array */ | ||
protected static $additionalOperatingSystems = [ | ||
'Windows' => 'Windows', | ||
'Windows NT' => 'Windows NT', | ||
'OS X' => 'Mac OS X', | ||
'Debian' => 'Debian', | ||
'Ubuntu' => 'Ubuntu', | ||
'Macintosh' => 'PPC', | ||
'OpenBSD' => 'OpenBSD', | ||
'Linux' => 'Linux', | ||
'ChromeOS' => 'CrOS', | ||
]; | ||
|
||
/** @var array */ | ||
protected static $additionalBrowsers = [ | ||
'Opera Mini' => 'Opera Mini', | ||
'Opera' => 'Opera|OPR', | ||
'Edge' => 'Edge|Edg', | ||
'Coc Coc' => 'coc_coc_browser', | ||
'UCBrowser' => 'UCBrowser', | ||
'Vivaldi' => 'Vivaldi', | ||
'Chrome' => 'Chrome', | ||
'Firefox' => 'Firefox', | ||
'Safari' => 'Safari', | ||
'IE' => 'MSIE|IEMobile|MSIEMobile|Trident/[.0-9]+', | ||
'Netscape' => 'Netscape', | ||
'Mozilla' => 'Mozilla', | ||
'WeChat' => 'MicroMessenger', | ||
]; | ||
|
||
/** @var array */ | ||
protected static $additionalProperties = [ | ||
// Operating systems | ||
'Windows' => 'Windows NT [VER]', | ||
'Windows NT' => 'Windows NT [VER]', | ||
'OS X' => 'OS X [VER]', | ||
'BlackBerryOS' => ['BlackBerry[\w]+/[VER]', 'BlackBerry.*Version/[VER]', 'Version/[VER]'], | ||
'AndroidOS' => 'Android [VER]', | ||
'ChromeOS' => 'CrOS x86_64 [VER]', | ||
|
||
// Browsers | ||
'Opera Mini' => 'Opera Mini/[VER]', | ||
'Opera' => [' OPR/[VER]', 'Opera Mini/[VER]', 'Version/[VER]', 'Opera [VER]'], | ||
'Netscape' => 'Netscape/[VER]', | ||
'Mozilla' => 'rv:[VER]', | ||
'IE' => ['IEMobile/[VER];', 'IEMobile [VER]', 'MSIE [VER];', 'rv:[VER]'], | ||
'Edge' => ['Edge/[VER]', 'Edg/[VER]'], | ||
'Vivaldi' => 'Vivaldi/[VER]', | ||
'Coc Coc' => 'coc_coc_browser/[VER]', | ||
]; | ||
|
||
/** @var CrawlerDetect */ | ||
protected static $crawlerDetect; | ||
|
||
/** @return array */ | ||
public static function getDetectionRulesExtended() | ||
{ | ||
static $rules; | ||
|
||
if (! $rules) { | ||
$rules = static::mergeRules( | ||
static::$desktopDevices, // NEW | ||
static::$phoneDevices, | ||
static::$tabletDevices, | ||
static::$operatingSystems, | ||
static::$additionalOperatingSystems, // NEW | ||
static::$browsers, | ||
static::$additionalBrowsers, // NEW | ||
static::$utilities | ||
); | ||
} | ||
|
||
return $rules; | ||
} | ||
|
||
public function getRules() | ||
{ | ||
if ($this->detectionType === static::DETECTION_TYPE_EXTENDED) { | ||
return static::getDetectionRulesExtended(); | ||
} | ||
|
||
return static::getMobileDetectionRules(); | ||
} | ||
|
||
/** @return CrawlerDetect */ | ||
public function getCrawlerDetect() | ||
{ | ||
if (static::$crawlerDetect === null) { | ||
static::$crawlerDetect = new CrawlerDetect(); | ||
} | ||
|
||
return static::$crawlerDetect; | ||
} | ||
|
||
public static function getBrowsers() | ||
{ | ||
return static::mergeRules( | ||
static::$additionalBrowsers, | ||
static::$browsers | ||
); | ||
} | ||
|
||
public static function getOperatingSystems() | ||
{ | ||
return static::mergeRules( | ||
static::$operatingSystems, | ||
static::$additionalOperatingSystems | ||
); | ||
} | ||
|
||
public static function getPlatforms() | ||
{ | ||
return static::mergeRules( | ||
static::$operatingSystems, | ||
static::$additionalOperatingSystems | ||
); | ||
} | ||
|
||
public static function getDesktopDevices() | ||
{ | ||
return static::$desktopDevices; | ||
} | ||
|
||
public static function getProperties() | ||
{ | ||
return static::mergeRules( | ||
static::$additionalProperties, | ||
static::$properties | ||
); | ||
} | ||
|
||
/** | ||
* @param string $acceptLanguage | ||
* @return array | ||
*/ | ||
public function languages($acceptLanguage = null) | ||
{ | ||
if ($acceptLanguage === null) { | ||
$acceptLanguage = $this->getHttpHeader('HTTP_ACCEPT_LANGUAGE'); | ||
} | ||
|
||
if (! $acceptLanguage) { | ||
return []; | ||
} | ||
|
||
$languages = []; | ||
|
||
// Parse accept language string. | ||
foreach (explode(',', $acceptLanguage) as $piece) { | ||
$parts = explode(';', $piece); | ||
$language = strtolower($parts[0]); | ||
$priority = empty($parts[1]) ? 1. : floatval(str_replace('q=', '', $parts[1])); | ||
|
||
$languages[$language] = $priority; | ||
} | ||
|
||
// Sort languages by priority. | ||
arsort($languages); | ||
|
||
return array_keys($languages); | ||
} | ||
|
||
/** | ||
* @param array $rules | ||
* @param string|null $userAgent | ||
* @return string|bool | ||
*/ | ||
protected function findDetectionRulesAgainstUA(array $rules, $userAgent = null) | ||
{ | ||
// Loop given rules | ||
foreach ($rules as $key => $regex) { | ||
if (empty($regex)) { | ||
continue; | ||
} | ||
|
||
// Check match | ||
if ($this->match($regex, $userAgent)) { | ||
return $key ?: reset($this->matchesArray); | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
/** | ||
* @param string|null $userAgent | ||
* @return string|bool | ||
*/ | ||
public function browser($userAgent = null) | ||
{ | ||
return $this->findDetectionRulesAgainstUA(static::getBrowsers(), $userAgent); | ||
} | ||
|
||
/** | ||
* @param string|null $userAgent | ||
* @return string|bool | ||
*/ | ||
public function platform($userAgent = null) | ||
{ | ||
return $this->findDetectionRulesAgainstUA(static::getPlatforms(), $userAgent); | ||
} | ||
|
||
/** | ||
* @param string|null $userAgent | ||
* @return string|bool | ||
*/ | ||
public function device($userAgent = null) | ||
{ | ||
$rules = static::mergeRules( | ||
static::getDesktopDevices(), | ||
static::getPhoneDevices(), | ||
static::getTabletDevices(), | ||
static::getUtilities() | ||
); | ||
|
||
return $this->findDetectionRulesAgainstUA($rules, $userAgent); | ||
} | ||
|
||
/** | ||
* @param string|null $userAgent deprecated | ||
* @param array $httpHeaders deprecated | ||
* @return bool | ||
*/ | ||
public function isDesktop($userAgent = null, $httpHeaders = null) | ||
{ | ||
// Check specifically for cloudfront headers if the useragent === 'Amazon CloudFront' | ||
if ($this->getUserAgent() === 'Amazon CloudFront') { | ||
$cfHeaders = $this->getCfHeaders(); | ||
|
||
if (array_key_exists('HTTP_CLOUDFRONT_IS_DESKTOP_VIEWER', $cfHeaders)) { | ||
return $cfHeaders['HTTP_CLOUDFRONT_IS_DESKTOP_VIEWER'] === 'true'; | ||
} | ||
} | ||
|
||
return ! $this->isMobile($userAgent, $httpHeaders) && ! $this->isTablet($userAgent, $httpHeaders) && ! $this->isRobot($userAgent); | ||
} | ||
|
||
/** | ||
* @param string|null $userAgent deprecated | ||
* @param array $httpHeaders deprecated | ||
* @return bool | ||
*/ | ||
public function isPhone($userAgent = null, $httpHeaders = null) | ||
{ | ||
return $this->isMobile($userAgent, $httpHeaders) && ! $this->isTablet($userAgent, $httpHeaders); | ||
} | ||
|
||
/** | ||
* @param string|null $userAgent | ||
* @return string|bool | ||
*/ | ||
public function robot($userAgent = null) | ||
{ | ||
if ($this->getCrawlerDetect()->isCrawler($userAgent ?: $this->userAgent)) { | ||
return ucfirst($this->getCrawlerDetect()->getMatches()); | ||
} | ||
|
||
return false; | ||
} | ||
|
||
/** | ||
* @param string|null $userAgent | ||
* @return bool | ||
*/ | ||
public function isRobot($userAgent = null) | ||
{ | ||
return $this->getCrawlerDetect()->isCrawler($userAgent ?: $this->userAgent); | ||
} | ||
|
||
/** | ||
* @param null $userAgent | ||
* @param null $httpHeaders | ||
* @return string | ||
*/ | ||
public function deviceType($userAgent = null, $httpHeaders = null) | ||
{ | ||
if ($this->isDesktop($userAgent, $httpHeaders)) { | ||
return 'desktop'; | ||
} elseif ($this->isPhone($userAgent, $httpHeaders)) { | ||
return 'phone'; | ||
} elseif ($this->isTablet($userAgent, $httpHeaders)) { | ||
return 'tablet'; | ||
} elseif ($this->isRobot($userAgent)) { | ||
return 'robot'; | ||
} | ||
|
||
return 'other'; | ||
} | ||
|
||
public function version($propertyName, $type = self::VERSION_TYPE_STRING) | ||
{ | ||
if (empty($propertyName)) { | ||
return false; | ||
} | ||
|
||
// set the $type to the default if we don't recognize the type | ||
if ($type !== self::VERSION_TYPE_STRING && $type !== self::VERSION_TYPE_FLOAT) { | ||
$type = self::VERSION_TYPE_STRING; | ||
} | ||
|
||
$properties = self::getProperties(); | ||
|
||
// Check if the property exists in the properties array. | ||
if (true === isset($properties[$propertyName])) { | ||
// Prepare the pattern to be matched. | ||
// Make sure we always deal with an array (string is converted). | ||
$properties[$propertyName] = (array) $properties[$propertyName]; | ||
|
||
foreach ($properties[$propertyName] as $propertyMatchString) { | ||
if (is_array($propertyMatchString)) { | ||
$propertyMatchString = implode('|', $propertyMatchString); | ||
} | ||
|
||
$propertyPattern = str_replace('[VER]', self::VER, $propertyMatchString); | ||
|
||
// Identify and extract the version. | ||
preg_match(sprintf('#%s#is', $propertyPattern), $this->userAgent, $match); | ||
|
||
if (false === empty($match[1])) { | ||
$version = ($type === self::VERSION_TYPE_FLOAT ? $this->prepareVersionNo($match[1]) : $match[1]); | ||
|
||
return $version; | ||
} | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
/** | ||
* @param array $all | ||
* @return array | ||
*/ | ||
protected static function mergeRules(...$all) | ||
{ | ||
$merged = []; | ||
|
||
foreach ($all as $rules) { | ||
foreach ($rules as $key => $value) { | ||
if (empty($merged[$key])) { | ||
$merged[$key] = $value; | ||
} elseif (is_array($merged[$key])) { | ||
$merged[$key][] = $value; | ||
} else { | ||
$merged[$key] .= '|'.$value; | ||
} | ||
} | ||
} | ||
|
||
return $merged; | ||
} | ||
|
||
/** @inheritdoc */ | ||
public function __call($name, $arguments) | ||
{ | ||
// Make sure the name starts with 'is', otherwise | ||
if (strpos($name, 'is') !== 0) { | ||
throw new BadMethodCallException("No such method exists: $name"); | ||
} | ||
|
||
$this->setDetectionType(self::DETECTION_TYPE_EXTENDED); | ||
|
||
$key = substr($name, 2); | ||
|
||
return $this->matchUAAgainstKey($key); | ||
} | ||
} |
Oops, something went wrong.