WebOrbiton
v1.0.3

PriviMetrics 2

480 lines · 14.6 KB
  1. <?php
  2. ​
  3. if (!function_exists('pm_fetch_location')) {
  4. ​
  5. function pm_fetch_location(string $ip): array
  6. {
  7. $timezone = $_GET['tz'] ?? null;
  8. $navLang = $_GET['lang'] ?? null;
  9. $langHeader = $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '';
  10. ​
  11. $code = 'XX';
  12. $method = 'Unknown';
  13. ​
  14. $timezoneMap = pm_timezone_country_map();
  15. ​
  16. if ($timezone && isset($timezoneMap[$timezone])) {
  17. $code = $timezoneMap[$timezone];
  18. $method = 'Timezone';
  19. } elseif ($navLang && preg_match('/^([a-z]{2})-([A-Z]{2})$/i', $navLang, $m)) {
  20. $code = strtoupper($m[2]);
  21. $method = 'Browser-Language';
  22. } elseif (preg_match('/([a-z]{2})-([A-Z]{2})/i', $langHeader, $matches)) {
  23. $code = strtoupper($matches[2]);
  24. $method = 'Accept-Language-Region';
  25. } else {
  26. $code = pm_detect_from_accept_language($langHeader);
  27. $method = $code !== 'XX' ? 'Accept-Language' : 'Fallback';
  28. }
  29. ​
  30. $countries = pm_country_list();
  31. if (!isset($countries[$code])) {
  32. $code = 'XX';
  33. }
  34. ​
  35. return [
  36. 'country' => $countries[$code] ?? 'Unknown',
  37. 'code' => $code,
  38. 'method' => 'Privacy-First (' . $method . ')',
  39. ];
  40. }
  41. ​
  42. function pm_detect_from_accept_language(string $header): string
  43. {
  44. if ($header === '') return 'XX';
  45. ​
  46. $langToCountry = [
  47. 'pl' => 'PL',
  48. 'cs' => 'CZ',
  49. 'sk' => 'SK',
  50. 'hu' => 'HU',
  51. 'ro' => 'RO',
  52. 'bg' => 'BG',
  53. 'uk' => 'UA',
  54. 'be' => 'BY',
  55. 'lt' => 'LT',
  56. 'lv' => 'LV',
  57. 'et' => 'EE',
  58. 'fi' => 'FI',
  59. 'sv' => 'SE',
  60. 'no' => 'NO',
  61. 'nb' => 'NO',
  62. 'nn' => 'NO',
  63. 'da' => 'DK',
  64. 'is' => 'IS',
  65. 'el' => 'GR',
  66. 'tr' => 'TR',
  67. 'he' => 'IL',
  68. 'iw' => 'IL',
  69. 'ja' => 'JP',
  70. 'ko' => 'KR',
  71. 'th' => 'TH',
  72. 'vi' => 'VN',
  73. 'id' => 'ID',
  74. 'ms' => 'MY',
  75. 'tl' => 'PH',
  76. 'fil' => 'PH',
  77. 'hi' => 'IN',
  78. 'bn' => 'BD',
  79. 'ur' => 'PK',
  80. 'fa' => 'IR',
  81. 'ar' => 'SA',
  82. 'ka' => 'GE',
  83. 'hy' => 'AM',
  84. 'az' => 'AZ',
  85. 'kk' => 'KZ',
  86. 'uz' => 'UZ',
  87. 'sl' => 'SI',
  88. 'hr' => 'HR',
  89. 'sr' => 'RS',
  90. 'bs' => 'BA',
  91. 'mk' => 'MK',
  92. 'sq' => 'AL',
  93. 'mt' => 'MT',
  94. 'ga' => 'IE',
  95. 'zh' => 'CN',
  96. 'ru' => 'RU',
  97. 'pt' => 'BR',
  98. 'de' => 'DE',
  99. 'fr' => 'FR',
  100. 'it' => 'IT',
  101. 'es' => 'ES',
  102. 'nl' => 'NL',
  103. 'en' => 'US',
  104. 'af' => 'ZA',
  105. 'sw' => 'KE',
  106. 'am' => 'ET',
  107. 'ti' => 'ER',
  108. 'so' => 'SO',
  109. 'mg' => 'MG',
  110. 'ny' => 'MW',
  111. 'sn' => 'ZW',
  112. 'nso' => 'ZA',
  113. 'st' => 'ZA',
  114. 'ts' => 'ZA',
  115. 'ss' => 'SZ',
  116. 'tn' => 'ZA',
  117. 've' => 'ZA',
  118. 'xh' => 'ZA',
  119. 'zu' => 'ZA',
  120. 'ca' => 'ES',
  121. 'eu' => 'ES',
  122. 'gl' => 'ES',
  123. 'cy' => 'GB',
  124. 'gd' => 'GB',
  125. 'lb' => 'LU',
  126. 'rm' => 'CH',
  127. 'fo' => 'FO',
  128. 'kl' => 'GL',
  129. 'mn' => 'MN',
  130. 'my' => 'MM',
  131. 'lo' => 'LA',
  132. 'km' => 'KH',
  133. 'ta' => 'IN',
  134. 'te' => 'IN',
  135. 'ml' => 'IN',
  136. 'kn' => 'IN',
  137. 'mr' => 'IN',
  138. 'gu' => 'IN',
  139. 'pa' => 'IN',
  140. 'or' => 'IN',
  141. 'as' => 'IN',
  142. 'ne' => 'NP',
  143. 'dz' => 'BT',
  144. 'dv' => 'MV',
  145. 'ps' => 'AF',
  146. 'ku' => 'IQ',
  147. 'tg' => 'TJ',
  148. 'ky' => 'KG',
  149. ];
  150. ​
  151. $langs = [];
  152. foreach (explode(',', $header) as $part) {
  153. $part = trim($part);
  154. if ($part === '') continue;
  155. $q = 1.0;
  156. if (preg_match('/;q=([0-9.]+)/', $part, $qm)) {
  157. $q = (float) $qm[1];
  158. $part = preg_replace('/;q=[0-9.]+/', '', $part);
  159. }
  160. $langs[] = ['lang' => trim($part), 'q' => $q];
  161. }
  162. ​
  163. usort($langs, fn($a, $b) => $b['q'] <=> $a['q']);
  164. ​
  165. foreach ($langs as $item) {
  166. $lang = strtolower($item['lang']);
  167. if (preg_match('/^([a-z]{2})-([a-z]{2})$/i', $lang, $m)) {
  168. return strtoupper($m[2]);
  169. }
  170. $short = substr($lang, 0, 2);
  171. if ($short === 'en' && count($langs) > 1 && $item['q'] < 1.0) continue;
  172. if (isset($langToCountry[$short])) return $langToCountry[$short];
  173. }
  174. ​
  175. return 'XX';
  176. }
  177. ​
  178. function pm_timezone_country_map(): array
  179. {
  180. return [
  181. 'Europe/Warsaw' => 'PL',
  182. 'Europe/Berlin' => 'DE',
  183. 'Europe/Paris' => 'FR',
  184. 'Europe/London' => 'GB',
  185. 'Europe/Rome' => 'IT',
  186. 'Europe/Madrid' => 'ES',
  187. 'Europe/Kiev' => 'UA',
  188. 'Europe/Kyiv' => 'UA',
  189. 'Europe/Bucharest' => 'RO',
  190. 'Europe/Budapest' => 'HU',
  191. 'Europe/Prague' => 'CZ',
  192. 'Europe/Vienna' => 'AT',
  193. 'Europe/Stockholm' => 'SE',
  194. 'Europe/Oslo' => 'NO',
  195. 'Europe/Helsinki' => 'FI',
  196. 'Europe/Copenhagen' => 'DK',
  197. 'Europe/Dublin' => 'IE',
  198. 'Europe/Brussels' => 'BE',
  199. 'Europe/Amsterdam' => 'NL',
  200. 'Europe/Zurich' => 'CH',
  201. 'Europe/Athens' => 'GR',
  202. 'Europe/Lisbon' => 'PT',
  203. 'Europe/Tallinn' => 'EE',
  204. 'Europe/Riga' => 'LV',
  205. 'Europe/Vilnius' => 'LT',
  206. 'Europe/Sofia' => 'BG',
  207. 'Europe/Bratislava' => 'SK',
  208. 'Europe/Ljubljana' => 'SI',
  209. 'Europe/Zagreb' => 'HR',
  210. 'Europe/Belgrade' => 'RS',
  211. 'Europe/Sarajevo' => 'BA',
  212. 'Europe/Skopje' => 'MK',
  213. 'Europe/Tirane' => 'AL',
  214. 'Europe/Luxembourg' => 'LU',
  215. 'Europe/Monaco' => 'MC',
  216. 'Europe/Malta' => 'MT',
  217. 'Europe/Chisinau' => 'MD',
  218. 'Europe/Istanbul' => 'TR',
  219. 'Europe/Moscow' => 'RU',
  220. 'Europe/Minsk' => 'BY',
  221. 'Asia/Shanghai' => 'CN',
  222. 'Asia/Hong_Kong' => 'HK',
  223. 'Asia/Tokyo' => 'JP',
  224. 'Asia/Seoul' => 'KR',
  225. 'Asia/Singapore' => 'SG',
  226. 'Asia/Bangkok' => 'TH',
  227. 'Asia/Jakarta' => 'ID',
  228. 'Asia/Kolkata' => 'IN',
  229. 'Asia/Dubai' => 'AE',
  230. 'Asia/Riyadh' => 'SA',
  231. 'Asia/Tehran' => 'IR',
  232. 'Asia/Jerusalem' => 'IL',
  233. 'Asia/Taipei' => 'TW',
  234. 'Asia/Ho_Chi_Minh' => 'VN',
  235. 'Asia/Kuala_Lumpur' => 'MY',
  236. 'Asia/Manila' => 'PH',
  237. 'Asia/Karachi' => 'PK',
  238. 'Asia/Tashkent' => 'UZ',
  239. 'Asia/Almaty' => 'KZ',
  240. 'Asia/Amman' => 'JO',
  241. 'Asia/Baghdad' => 'IQ',
  242. 'Asia/Dhaka' => 'BD',
  243. 'Asia/Colombo' => 'LK',
  244. 'Asia/Kathmandu' => 'NP',
  245. 'Asia/Tbilisi' => 'GE',
  246. 'Asia/Yerevan' => 'AM',
  247. 'Asia/Baku' => 'AZ',
  248. 'America/New_York' => 'US',
  249. 'America/Chicago' => 'US',
  250. 'America/Denver' => 'US',
  251. 'America/Los_Angeles' => 'US',
  252. 'America/Anchorage' => 'US',
  253. 'America/Honolulu' => 'US',
  254. 'America/Toronto' => 'CA',
  255. 'America/Vancouver' => 'CA',
  256. 'America/Montreal' => 'CA',
  257. 'America/Mexico_City' => 'MX',
  258. 'America/Sao_Paulo' => 'BR',
  259. 'America/Buenos_Aires' => 'AR',
  260. 'America/Santiago' => 'CL',
  261. 'America/Bogota' => 'CO',
  262. 'America/Lima' => 'PE',
  263. 'America/Caracas' => 'VE',
  264. 'Africa/Lagos' => 'NG',
  265. 'Africa/Cairo' => 'EG',
  266. 'Africa/Johannesburg' => 'ZA',
  267. 'Africa/Nairobi' => 'KE',
  268. 'Africa/Casablanca' => 'MA',
  269. 'Africa/Tunis' => 'TN',
  270. 'Africa/Accra' => 'GH',
  271. 'Australia/Sydney' => 'AU',
  272. 'Australia/Melbourne' => 'AU',
  273. 'Australia/Perth' => 'AU',
  274. 'Australia/Brisbane' => 'AU',
  275. 'Pacific/Auckland' => 'NZ',
  276. 'Pacific/Fiji' => 'FJ',
  277. ];
  278. }
  279. ​
  280. function pm_country_list(): array
  281. {
  282. return [
  283. 'AF' => 'Afghanistan',
  284. 'AL' => 'Albania',
  285. 'DZ' => 'Algeria',
  286. 'AD' => 'Andorra',
  287. 'AO' => 'Angola',
  288. 'AR' => 'Argentina',
  289. 'AM' => 'Armenia',
  290. 'AU' => 'Australia',
  291. 'AT' => 'Austria',
  292. 'AZ' => 'Azerbaijan',
  293. 'BS' => 'Bahamas',
  294. 'BH' => 'Bahrain',
  295. 'BD' => 'Bangladesh',
  296. 'BY' => 'Belarus',
  297. 'BE' => 'Belgium',
  298. 'BZ' => 'Belize',
  299. 'BO' => 'Bolivia',
  300. 'BA' => 'Bosnia and Herzegovina',
  301. 'BW' => 'Botswana',
  302. 'BR' => 'Brazil',
  303. 'BN' => 'Brunei',
  304. 'BG' => 'Bulgaria',
  305. 'KH' => 'Cambodia',
  306. 'CM' => 'Cameroon',
  307. 'CA' => 'Canada',
  308. 'CL' => 'Chile',
  309. 'CN' => 'China',
  310. 'CO' => 'Colombia',
  311. 'CR' => 'Costa Rica',
  312. 'HR' => 'Croatia',
  313. 'CU' => 'Cuba',
  314. 'CY' => 'Cyprus',
  315. 'CZ' => 'Czech Republic',
  316. 'DK' => 'Denmark',
  317. 'DO' => 'Dominican Republic',
  318. 'EC' => 'Ecuador',
  319. 'EG' => 'Egypt',
  320. 'SV' => 'El Salvador',
  321. 'EE' => 'Estonia',
  322. 'ET' => 'Ethiopia',
  323. 'FI' => 'Finland',
  324. 'FR' => 'France',
  325. 'GE' => 'Georgia',
  326. 'DE' => 'Germany',
  327. 'GH' => 'Ghana',
  328. 'GR' => 'Greece',
  329. 'GT' => 'Guatemala',
  330. 'HN' => 'Honduras',
  331. 'HK' => 'Hong Kong',
  332. 'HU' => 'Hungary',
  333. 'IS' => 'Iceland',
  334. 'IN' => 'India',
  335. 'ID' => 'Indonesia',
  336. 'IR' => 'Iran',
  337. 'IQ' => 'Iraq',
  338. 'IE' => 'Ireland',
  339. 'IL' => 'Israel',
  340. 'IT' => 'Italy',
  341. 'JM' => 'Jamaica',
  342. 'JP' => 'Japan',
  343. 'JO' => 'Jordan',
  344. 'KZ' => 'Kazakhstan',
  345. 'KE' => 'Kenya',
  346. 'KR' => 'South Korea',
  347. 'KW' => 'Kuwait',
  348. 'LA' => 'Laos',
  349. 'LV' => 'Latvia',
  350. 'LB' => 'Lebanon',
  351. 'LY' => 'Libya',
  352. 'LT' => 'Lithuania',
  353. 'LU' => 'Luxembourg',
  354. 'MO' => 'Macao',
  355. 'MK' => 'North Macedonia',
  356. 'MY' => 'Malaysia',
  357. 'MT' => 'Malta',
  358. 'MX' => 'Mexico',
  359. 'MD' => 'Moldova',
  360. 'MC' => 'Monaco',
  361. 'MA' => 'Morocco',
  362. 'MZ' => 'Mozambique',
  363. 'MM' => 'Myanmar',
  364. 'NA' => 'Namibia',
  365. 'NP' => 'Nepal',
  366. 'NL' => 'Netherlands',
  367. 'NZ' => 'New Zealand',
  368. 'NI' => 'Nicaragua',
  369. 'NG' => 'Nigeria',
  370. 'NO' => 'Norway',
  371. 'OM' => 'Oman',
  372. 'PK' => 'Pakistan',
  373. 'PA' => 'Panama',
  374. 'PY' => 'Paraguay',
  375. 'PE' => 'Peru',
  376. 'PH' => 'Philippines',
  377. 'PL' => 'Poland',
  378. 'PT' => 'Portugal',
  379. 'QA' => 'Qatar',
  380. 'RO' => 'Romania',
  381. 'RU' => 'Russia',
  382. 'SA' => 'Saudi Arabia',
  383. 'RS' => 'Serbia',
  384. 'SG' => 'Singapore',
  385. 'SK' => 'Slovakia',
  386. 'SI' => 'Slovenia',
  387. 'ZA' => 'South Africa',
  388. 'ES' => 'Spain',
  389. 'LK' => 'Sri Lanka',
  390. 'SE' => 'Sweden',
  391. 'CH' => 'Switzerland',
  392. 'SY' => 'Syria',
  393. 'TW' => 'Taiwan',
  394. 'TH' => 'Thailand',
  395. 'TN' => 'Tunisia',
  396. 'TR' => 'Turkey',
  397. 'UA' => 'Ukraine',
  398. 'AE' => 'United Arab Emirates',
  399. 'GB' => 'United Kingdom',
  400. 'US' => 'United States',
  401. 'UY' => 'Uruguay',
  402. 'UZ' => 'Uzbekistan',
  403. 'VE' => 'Venezuela',
  404. 'VN' => 'Vietnam',
  405. 'YE' => 'Yemen',
  406. 'ZM' => 'Zambia',
  407. 'ZW' => 'Zimbabwe',
  408. 'DZ' => 'Algeria',
  409. 'AO' => 'Angola',
  410. 'BO' => 'Bolivia',
  411. 'BT' => 'Bhutan',
  412. 'BZ' => 'Belize',
  413. 'BN' => 'Brunei',
  414. 'BW' => 'Botswana',
  415. 'CM' => 'Cameroon',
  416. 'CR' => 'Costa Rica',
  417. 'CU' => 'Cuba',
  418. 'DO' => 'Dominican Republic',
  419. 'EC' => 'Ecuador',
  420. 'ER' => 'Eritrea',
  421. 'ET' => 'Ethiopia',
  422. 'FO' => 'Faroe Islands',
  423. 'GF' => 'French Guiana',
  424. 'GH' => 'Ghana',
  425. 'GL' => 'Greenland',
  426. 'GT' => 'Guatemala',
  427. 'HN' => 'Honduras',
  428. 'HT' => 'Haiti',
  429. 'IQ' => 'Iraq',
  430. 'JM' => 'Jamaica',
  431. 'JO' => 'Jordan',
  432. 'KE' => 'Kenya',
  433. 'KG' => 'Kyrgyzstan',
  434. 'KP' => 'North Korea',
  435. 'KW' => 'Kuwait',
  436. 'LA' => 'Laos',
  437. 'LY' => 'Libya',
  438. 'MG' => 'Madagascar',
  439. 'MN' => 'Mongolia',
  440. 'MO' => 'Macao',
  441. 'MW' => 'Malawi',
  442. 'MV' => 'Maldives',
  443. 'MZ' => 'Mozambique',
  444. 'NA' => 'Namibia',
  445. 'NC' => 'New Caledonia',
  446. 'NI' => 'Nicaragua',
  447. 'OM' => 'Oman',
  448. 'PA' => 'Panama',
  449. 'PG' => 'Papua New Guinea',
  450. 'PY' => 'Paraguay',
  451. 'QA' => 'Qatar',
  452. 'RW' => 'Rwanda',
  453. 'SB' => 'Solomon Islands',
  454. 'SD' => 'Sudan',
  455. 'SN' => 'Senegal',
  456. 'SO' => 'Somalia',
  457. 'SR' => 'Suriname',
  458. 'SV' => 'El Salvador',
  459. 'SY' => 'Syria',
  460. 'SZ' => 'Eswatini',
  461. 'TJ' => 'Tajikistan',
  462. 'TL' => 'Timor-Leste',
  463. 'TO' => 'Tonga',
  464. 'TT' => 'Trinidad and Tobago',
  465. 'TZ' => 'Tanzania',
  466. 'UG' => 'Uganda',
  467. 'UY' => 'Uruguay',
  468. 'WS' => 'Samoa',
  469. 'YE' => 'Yemen',
  470. 'ZM' => 'Zambia',
  471. 'ZW' => 'Zimbabwe',
  472. 'AS' => 'American Samoa',
  473. 'BM' => 'Bermuda',
  474. 'BS' => 'Bahamas',
  475. 'GU' => 'Guam',
  476. 'XX' => 'Unknown',
  477. ];
  478. }
  479. }
  480. ​