国内流行的内容管理系统(CMS)多端全媒体解决方案 https://www.dedebiz.com
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

417 satır
11KB

  1. <?php
  2. if (!defined('DEDEINC')) exit('dedebiz');
  3. require_once(DEDEINC."/libraries/crawlerdetect.class.php");
  4. require_once(DEDEINC."/libraries/mobiledetect.class.php");
  5. // copyright https://github.com/jenssegers/agent
  6. use BadMethodCallException;
  7. class Agent extends Mobile_Detect
  8. {
  9. /**
  10. * List of desktop devices.
  11. * @var array
  12. */
  13. protected static $desktopDevices = [
  14. 'Macintosh' => 'Macintosh',
  15. ];
  16. /**
  17. * List of additional operating systems.
  18. * @var array
  19. */
  20. protected static $additionalOperatingSystems = [
  21. 'Windows' => 'Windows',
  22. 'Windows NT' => 'Windows NT',
  23. 'OS X' => 'Mac OS X',
  24. 'Debian' => 'Debian',
  25. 'Ubuntu' => 'Ubuntu',
  26. 'Macintosh' => 'PPC',
  27. 'OpenBSD' => 'OpenBSD',
  28. 'Linux' => 'Linux',
  29. 'ChromeOS' => 'CrOS',
  30. ];
  31. /**
  32. * List of additional browsers.
  33. * @var array
  34. */
  35. protected static $additionalBrowsers = [
  36. 'Opera Mini' => 'Opera Mini',
  37. 'Opera' => 'Opera|OPR',
  38. 'Edge' => 'Edge|Edg',
  39. 'Coc Coc' => 'coc_coc_browser',
  40. 'UCBrowser' => 'UCBrowser',
  41. 'Vivaldi' => 'Vivaldi',
  42. 'Chrome' => 'Chrome',
  43. 'Firefox' => 'Firefox',
  44. 'Safari' => 'Safari',
  45. 'IE' => 'MSIE|IEMobile|MSIEMobile|Trident/[.0-9]+',
  46. 'Netscape' => 'Netscape',
  47. 'Mozilla' => 'Mozilla',
  48. 'WeChat' => 'MicroMessenger',
  49. ];
  50. /**
  51. * List of additional properties.
  52. * @var array
  53. */
  54. protected static $additionalProperties = [
  55. // Operating systems
  56. 'Windows' => 'Windows NT [VER]',
  57. 'Windows NT' => 'Windows NT [VER]',
  58. 'OS X' => 'OS X [VER]',
  59. 'BlackBerryOS' => ['BlackBerry[\w]+/[VER]', 'BlackBerry.*Version/[VER]', 'Version/[VER]'],
  60. 'AndroidOS' => 'Android [VER]',
  61. 'ChromeOS' => 'CrOS x86_64 [VER]',
  62. // Browsers
  63. 'Opera Mini' => 'Opera Mini/[VER]',
  64. 'Opera' => [' OPR/[VER]', 'Opera Mini/[VER]', 'Version/[VER]', 'Opera [VER]'],
  65. 'Netscape' => 'Netscape/[VER]',
  66. 'Mozilla' => 'rv:[VER]',
  67. 'IE' => ['IEMobile/[VER];', 'IEMobile [VER]', 'MSIE [VER];', 'rv:[VER]'],
  68. 'Edge' => ['Edge/[VER]', 'Edg/[VER]'],
  69. 'Vivaldi' => 'Vivaldi/[VER]',
  70. 'Coc Coc' => 'coc_coc_browser/[VER]',
  71. ];
  72. /**
  73. * @var CrawlerDetect
  74. */
  75. protected static $crawlerDetect;
  76. /**
  77. * Get all detection rules. These rules include the additional
  78. * platforms and browsers and utilities.
  79. * @return array
  80. */
  81. public static function getDetectionRulesExtended()
  82. {
  83. static $rules;
  84. if (!$rules) {
  85. $rules = static::mergeRules(
  86. static::$desktopDevices, // NEW
  87. static::$phoneDevices,
  88. static::$tabletDevices,
  89. static::$operatingSystems,
  90. static::$additionalOperatingSystems, // NEW
  91. static::$browsers,
  92. static::$additionalBrowsers, // NEW
  93. static::$utilities
  94. );
  95. }
  96. return $rules;
  97. }
  98. public function getRules()
  99. {
  100. if ($this->detectionType === static::DETECTION_TYPE_EXTENDED) {
  101. return static::getDetectionRulesExtended();
  102. }
  103. return static::getMobileDetectionRules();
  104. }
  105. /**
  106. * @return CrawlerDetect
  107. */
  108. public function getCrawlerDetect()
  109. {
  110. if (static::$crawlerDetect === null) {
  111. static::$crawlerDetect = new CrawlerDetect();
  112. }
  113. return static::$crawlerDetect;
  114. }
  115. public static function getBrowsers()
  116. {
  117. return static::mergeRules(
  118. static::$additionalBrowsers,
  119. static::$browsers
  120. );
  121. }
  122. public static function getOperatingSystems()
  123. {
  124. return static::mergeRules(
  125. static::$operatingSystems,
  126. static::$additionalOperatingSystems
  127. );
  128. }
  129. public static function getPlatforms()
  130. {
  131. return static::mergeRules(
  132. static::$operatingSystems,
  133. static::$additionalOperatingSystems
  134. );
  135. }
  136. public static function getDesktopDevices()
  137. {
  138. return static::$desktopDevices;
  139. }
  140. public static function getProperties()
  141. {
  142. return static::mergeRules(
  143. static::$additionalProperties,
  144. static::$properties
  145. );
  146. }
  147. /**
  148. * Get accept languages.
  149. * @param string $acceptLanguage
  150. * @return array
  151. */
  152. public function languages($acceptLanguage = null)
  153. {
  154. if ($acceptLanguage === null) {
  155. $acceptLanguage = $this->getHttpHeader('HTTP_ACCEPT_LANGUAGE');
  156. }
  157. if (!$acceptLanguage) {
  158. return [];
  159. }
  160. $languages = [];
  161. // Parse accept language string.
  162. foreach (explode(',', $acceptLanguage) as $piece) {
  163. $parts = explode(';', $piece);
  164. $language = strtolower($parts[0]);
  165. $priority = empty($parts[1]) ? 1. : floatval(str_replace('q=', '', $parts[1]));
  166. $languages[$language] = $priority;
  167. }
  168. // Sort languages by priority.
  169. arsort($languages);
  170. return array_keys($languages);
  171. }
  172. /**
  173. * Match a detection rule and return the matched key.
  174. * @param array $rules
  175. * @param string|null $userAgent
  176. * @return string|bool
  177. */
  178. protected function findDetectionRulesAgainstUA(array $rules, $userAgent = null)
  179. {
  180. // Loop given rules
  181. foreach ($rules as $key => $regex) {
  182. if (empty($regex)) {
  183. continue;
  184. }
  185. // Check match
  186. if ($this->match($regex, $userAgent)) {
  187. return $key ?: reset((array)$this->matchesArray);
  188. }
  189. }
  190. return false;
  191. }
  192. /**
  193. * Get the browser name.
  194. * @param string|null $userAgent
  195. * @return string|bool
  196. */
  197. public function browser($userAgent = null)
  198. {
  199. return $this->findDetectionRulesAgainstUA(static::getBrowsers(), $userAgent);
  200. }
  201. /**
  202. * Get the platform name.
  203. * @param string|null $userAgent
  204. * @return string|bool
  205. */
  206. public function platform($userAgent = null)
  207. {
  208. return $this->findDetectionRulesAgainstUA(static::getPlatforms(), $userAgent);
  209. }
  210. /**
  211. * Get the device name.
  212. * @param string|null $userAgent
  213. * @return string|bool
  214. */
  215. public function device($userAgent = null)
  216. {
  217. $rules = static::mergeRules(
  218. static::getDesktopDevices(),
  219. static::getPhoneDevices(),
  220. static::getTabletDevices(),
  221. static::getUtilities()
  222. );
  223. return $this->findDetectionRulesAgainstUA($rules, $userAgent);
  224. }
  225. /**
  226. * Check if the device is a desktop computer.
  227. * @param string|null $userAgent deprecated
  228. * @param array $httpHeaders deprecated
  229. * @return bool
  230. */
  231. public function isDesktop($userAgent = null, $httpHeaders = null)
  232. {
  233. // Check specifically for cloudfront headers if the useragent === 'Amazon CloudFront'
  234. if ($this->getUserAgent() === 'Amazon CloudFront') {
  235. $cfHeaders = $this->getCfHeaders();
  236. if(array_key_exists('HTTP_CLOUDFRONT_IS_DESKTOP_VIEWER', $cfHeaders)) {
  237. return $cfHeaders['HTTP_CLOUDFRONT_IS_DESKTOP_VIEWER'] === 'true';
  238. }
  239. }
  240. return !$this->isMobile($userAgent, $httpHeaders) && !$this->isTablet($userAgent, $httpHeaders) && !$this->isRobot($userAgent);
  241. }
  242. /**
  243. * Check if the device is a mobile phone.
  244. * @param string|null $userAgent deprecated
  245. * @param array $httpHeaders deprecated
  246. * @return bool
  247. */
  248. public function isPhone($userAgent = null, $httpHeaders = null)
  249. {
  250. return $this->isMobile($userAgent, $httpHeaders) && !$this->isTablet($userAgent, $httpHeaders);
  251. }
  252. /**
  253. * Get the robot name.
  254. * @param string|null $userAgent
  255. * @return string|bool
  256. */
  257. public function robot($userAgent = null)
  258. {
  259. if ($this->getCrawlerDetect()->isCrawler($userAgent ?: $this->userAgent)) {
  260. return ucfirst($this->getCrawlerDetect()->getMatches());
  261. }
  262. return false;
  263. }
  264. /**
  265. * Check if device is a robot.
  266. * @param string|null $userAgent
  267. * @return bool
  268. */
  269. public function isRobot($userAgent = null)
  270. {
  271. return $this->getCrawlerDetect()->isCrawler($userAgent ?: $this->userAgent);
  272. }
  273. /**
  274. * Get the device type
  275. * @param null $userAgent
  276. * @param null $httpHeaders
  277. * @return string
  278. */
  279. public function deviceType($userAgent = null, $httpHeaders = null)
  280. {
  281. if ($this->isDesktop($userAgent, $httpHeaders)) {
  282. return "desktop";
  283. } elseif ($this->isPhone($userAgent, $httpHeaders)) {
  284. return "phone";
  285. } elseif ($this->isTablet($userAgent, $httpHeaders)) {
  286. return "tablet";
  287. } elseif ($this->isRobot($userAgent)) {
  288. return "robot";
  289. }
  290. return "other";
  291. }
  292. public function version($propertyName, $type = self::VERSION_TYPE_STRING)
  293. {
  294. if (empty($propertyName)) {
  295. return false;
  296. }
  297. // set the $type to the default if we don't recognize the type
  298. if ($type !== self::VERSION_TYPE_STRING && $type !== self::VERSION_TYPE_FLOAT) {
  299. $type = self::VERSION_TYPE_STRING;
  300. }
  301. $properties = self::getProperties();
  302. // Check if the property exists in the properties array.
  303. if (true === isset($properties[$propertyName])) {
  304. // Prepare the pattern to be matched.
  305. // Make sure we always deal with an array (string is converted).
  306. $properties[$propertyName] = (array) $properties[$propertyName];
  307. foreach ($properties[$propertyName] as $propertyMatchString) {
  308. if (is_array($propertyMatchString)) {
  309. $propertyMatchString = implode("|", $propertyMatchString);
  310. }
  311. $propertyPattern = str_replace('[VER]', self::VER, $propertyMatchString);
  312. // Identify and extract the version.
  313. preg_match(sprintf('#%s#is', $propertyPattern), $this->userAgent, $match);
  314. if (false === empty($match[1])) {
  315. $version = ($type === self::VERSION_TYPE_FLOAT ? $this->prepareVersionNo($match[1]) : $match[1]);
  316. return $version;
  317. }
  318. }
  319. }
  320. return false;
  321. }
  322. /**
  323. * Merge multiple rules into one array.
  324. * @param array $all
  325. * @return array
  326. */
  327. protected static function mergeRules(...$all)
  328. {
  329. $merged = [];
  330. foreach ($all as $rules) {
  331. foreach ($rules as $key => $value) {
  332. if (empty($merged[$key])) {
  333. $merged[$key] = $value;
  334. } elseif (is_array($merged[$key])) {
  335. $merged[$key][] = $value;
  336. } else {
  337. $merged[$key] .= '|' . $value;
  338. }
  339. }
  340. }
  341. return $merged;
  342. }
  343. /**
  344. * @inheritdoc
  345. */
  346. public function __call($name, $arguments)
  347. {
  348. // Make sure the name starts with 'is', otherwise
  349. if (strpos($name, 'is') !== 0) {
  350. throw new BadMethodCallException("No such method exists: $name");
  351. }
  352. $this->setDetectionType(self::DETECTION_TYPE_EXTENDED);
  353. $key = substr($name, 2);
  354. return $this->matchUAAgainstKey($key);
  355. }
  356. }