v1.0.3
PriviMetrics 2
- <?php
-
- if (!function_exists('pm_fetch_location')) {
-
- function pm_fetch_location(string $ip): array
- {
- $timezone = $_GET['tz'] ?? null;
- $navLang = $_GET['lang'] ?? null;
- $langHeader = $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '';
-
- $code = 'XX';
- $method = 'Unknown';
-
- $timezoneMap = pm_timezone_country_map();
-
- if ($timezone && isset($timezoneMap[$timezone])) {
- $code = $timezoneMap[$timezone];
- $method = 'Timezone';
- } elseif ($navLang && preg_match('/^([a-z]{2})-([A-Z]{2})$/i', $navLang, $m)) {
- $code = strtoupper($m[2]);
- $method = 'Browser-Language';
- } elseif (preg_match('/([a-z]{2})-([A-Z]{2})/i', $langHeader, $matches)) {
- $code = strtoupper($matches[2]);
- $method = 'Accept-Language-Region';
- } else {
- $code = pm_detect_from_accept_language($langHeader);
- $method = $code !== 'XX' ? 'Accept-Language' : 'Fallback';
- }
-
- $countries = pm_country_list();
- if (!isset($countries[$code])) {
- $code = 'XX';
- }
-
- return [
- 'country' => $countries[$code] ?? 'Unknown',
- 'code' => $code,
- 'method' => 'Privacy-First (' . $method . ')',
- ];
- }
-
- function pm_detect_from_accept_language(string $header): string
- {
- if ($header === '') return 'XX';
-
- $langToCountry = [
- 'pl' => 'PL',
- 'cs' => 'CZ',
- 'sk' => 'SK',
- 'hu' => 'HU',
- 'ro' => 'RO',
- 'bg' => 'BG',
- 'uk' => 'UA',
- 'be' => 'BY',
- 'lt' => 'LT',
- 'lv' => 'LV',
- 'et' => 'EE',
- 'fi' => 'FI',
- 'sv' => 'SE',
- 'no' => 'NO',
- 'nb' => 'NO',
- 'nn' => 'NO',
- 'da' => 'DK',
- 'is' => 'IS',
- 'el' => 'GR',
- 'tr' => 'TR',
- 'he' => 'IL',
- 'iw' => 'IL',
- 'ja' => 'JP',
- 'ko' => 'KR',
- 'th' => 'TH',
- 'vi' => 'VN',
- 'id' => 'ID',
- 'ms' => 'MY',
- 'tl' => 'PH',
- 'fil' => 'PH',
- 'hi' => 'IN',
- 'bn' => 'BD',
- 'ur' => 'PK',
- 'fa' => 'IR',
- 'ar' => 'SA',
- 'ka' => 'GE',
- 'hy' => 'AM',
- 'az' => 'AZ',
- 'kk' => 'KZ',
- 'uz' => 'UZ',
- 'sl' => 'SI',
- 'hr' => 'HR',
- 'sr' => 'RS',
- 'bs' => 'BA',
- 'mk' => 'MK',
- 'sq' => 'AL',
- 'mt' => 'MT',
- 'ga' => 'IE',
- 'zh' => 'CN',
- 'ru' => 'RU',
- 'pt' => 'BR',
- 'de' => 'DE',
- 'fr' => 'FR',
- 'it' => 'IT',
- 'es' => 'ES',
- 'nl' => 'NL',
- 'en' => 'US',
- 'af' => 'ZA',
- 'sw' => 'KE',
- 'am' => 'ET',
- 'ti' => 'ER',
- 'so' => 'SO',
- 'mg' => 'MG',
- 'ny' => 'MW',
- 'sn' => 'ZW',
- 'nso' => 'ZA',
- 'st' => 'ZA',
- 'ts' => 'ZA',
- 'ss' => 'SZ',
- 'tn' => 'ZA',
- 've' => 'ZA',
- 'xh' => 'ZA',
- 'zu' => 'ZA',
- 'ca' => 'ES',
- 'eu' => 'ES',
- 'gl' => 'ES',
- 'cy' => 'GB',
- 'gd' => 'GB',
- 'lb' => 'LU',
- 'rm' => 'CH',
- 'fo' => 'FO',
- 'kl' => 'GL',
- 'mn' => 'MN',
- 'my' => 'MM',
- 'lo' => 'LA',
- 'km' => 'KH',
- 'ta' => 'IN',
- 'te' => 'IN',
- 'ml' => 'IN',
- 'kn' => 'IN',
- 'mr' => 'IN',
- 'gu' => 'IN',
- 'pa' => 'IN',
- 'or' => 'IN',
- 'as' => 'IN',
- 'ne' => 'NP',
- 'dz' => 'BT',
- 'dv' => 'MV',
- 'ps' => 'AF',
- 'ku' => 'IQ',
- 'tg' => 'TJ',
- 'ky' => 'KG',
- ];
-
- $langs = [];
- foreach (explode(',', $header) as $part) {
- $part = trim($part);
- if ($part === '') continue;
- $q = 1.0;
- if (preg_match('/;q=([0-9.]+)/', $part, $qm)) {
- $q = (float) $qm[1];
- $part = preg_replace('/;q=[0-9.]+/', '', $part);
- }
- $langs[] = ['lang' => trim($part), 'q' => $q];
- }
-
- usort($langs, fn($a, $b) => $b['q'] <=> $a['q']);
-
- foreach ($langs as $item) {
- $lang = strtolower($item['lang']);
- if (preg_match('/^([a-z]{2})-([a-z]{2})$/i', $lang, $m)) {
- return strtoupper($m[2]);
- }
- $short = substr($lang, 0, 2);
- if ($short === 'en' && count($langs) > 1 && $item['q'] < 1.0) continue;
- if (isset($langToCountry[$short])) return $langToCountry[$short];
- }
-
- return 'XX';
- }
-
- function pm_timezone_country_map(): array
- {
- return [
- 'Europe/Warsaw' => 'PL',
- 'Europe/Berlin' => 'DE',
- 'Europe/Paris' => 'FR',
- 'Europe/London' => 'GB',
- 'Europe/Rome' => 'IT',
- 'Europe/Madrid' => 'ES',
- 'Europe/Kiev' => 'UA',
- 'Europe/Kyiv' => 'UA',
- 'Europe/Bucharest' => 'RO',
- 'Europe/Budapest' => 'HU',
- 'Europe/Prague' => 'CZ',
- 'Europe/Vienna' => 'AT',
- 'Europe/Stockholm' => 'SE',
- 'Europe/Oslo' => 'NO',
- 'Europe/Helsinki' => 'FI',
- 'Europe/Copenhagen' => 'DK',
- 'Europe/Dublin' => 'IE',
- 'Europe/Brussels' => 'BE',
- 'Europe/Amsterdam' => 'NL',
- 'Europe/Zurich' => 'CH',
- 'Europe/Athens' => 'GR',
- 'Europe/Lisbon' => 'PT',
- 'Europe/Tallinn' => 'EE',
- 'Europe/Riga' => 'LV',
- 'Europe/Vilnius' => 'LT',
- 'Europe/Sofia' => 'BG',
- 'Europe/Bratislava' => 'SK',
- 'Europe/Ljubljana' => 'SI',
- 'Europe/Zagreb' => 'HR',
- 'Europe/Belgrade' => 'RS',
- 'Europe/Sarajevo' => 'BA',
- 'Europe/Skopje' => 'MK',
- 'Europe/Tirane' => 'AL',
- 'Europe/Luxembourg' => 'LU',
- 'Europe/Monaco' => 'MC',
- 'Europe/Malta' => 'MT',
- 'Europe/Chisinau' => 'MD',
- 'Europe/Istanbul' => 'TR',
- 'Europe/Moscow' => 'RU',
- 'Europe/Minsk' => 'BY',
- 'Asia/Shanghai' => 'CN',
- 'Asia/Hong_Kong' => 'HK',
- 'Asia/Tokyo' => 'JP',
- 'Asia/Seoul' => 'KR',
- 'Asia/Singapore' => 'SG',
- 'Asia/Bangkok' => 'TH',
- 'Asia/Jakarta' => 'ID',
- 'Asia/Kolkata' => 'IN',
- 'Asia/Dubai' => 'AE',
- 'Asia/Riyadh' => 'SA',
- 'Asia/Tehran' => 'IR',
- 'Asia/Jerusalem' => 'IL',
- 'Asia/Taipei' => 'TW',
- 'Asia/Ho_Chi_Minh' => 'VN',
- 'Asia/Kuala_Lumpur' => 'MY',
- 'Asia/Manila' => 'PH',
- 'Asia/Karachi' => 'PK',
- 'Asia/Tashkent' => 'UZ',
- 'Asia/Almaty' => 'KZ',
- 'Asia/Amman' => 'JO',
- 'Asia/Baghdad' => 'IQ',
- 'Asia/Dhaka' => 'BD',
- 'Asia/Colombo' => 'LK',
- 'Asia/Kathmandu' => 'NP',
- 'Asia/Tbilisi' => 'GE',
- 'Asia/Yerevan' => 'AM',
- 'Asia/Baku' => 'AZ',
- 'America/New_York' => 'US',
- 'America/Chicago' => 'US',
- 'America/Denver' => 'US',
- 'America/Los_Angeles' => 'US',
- 'America/Anchorage' => 'US',
- 'America/Honolulu' => 'US',
- 'America/Toronto' => 'CA',
- 'America/Vancouver' => 'CA',
- 'America/Montreal' => 'CA',
- 'America/Mexico_City' => 'MX',
- 'America/Sao_Paulo' => 'BR',
- 'America/Buenos_Aires' => 'AR',
- 'America/Santiago' => 'CL',
- 'America/Bogota' => 'CO',
- 'America/Lima' => 'PE',
- 'America/Caracas' => 'VE',
- 'Africa/Lagos' => 'NG',
- 'Africa/Cairo' => 'EG',
- 'Africa/Johannesburg' => 'ZA',
- 'Africa/Nairobi' => 'KE',
- 'Africa/Casablanca' => 'MA',
- 'Africa/Tunis' => 'TN',
- 'Africa/Accra' => 'GH',
- 'Australia/Sydney' => 'AU',
- 'Australia/Melbourne' => 'AU',
- 'Australia/Perth' => 'AU',
- 'Australia/Brisbane' => 'AU',
- 'Pacific/Auckland' => 'NZ',
- 'Pacific/Fiji' => 'FJ',
- ];
- }
-
- function pm_country_list(): array
- {
- return [
- 'AF' => 'Afghanistan',
- 'AL' => 'Albania',
- 'DZ' => 'Algeria',
- 'AD' => 'Andorra',
- 'AO' => 'Angola',
- 'AR' => 'Argentina',
- 'AM' => 'Armenia',
- 'AU' => 'Australia',
- 'AT' => 'Austria',
- 'AZ' => 'Azerbaijan',
- 'BS' => 'Bahamas',
- 'BH' => 'Bahrain',
- 'BD' => 'Bangladesh',
- 'BY' => 'Belarus',
- 'BE' => 'Belgium',
- 'BZ' => 'Belize',
- 'BO' => 'Bolivia',
- 'BA' => 'Bosnia and Herzegovina',
- 'BW' => 'Botswana',
- 'BR' => 'Brazil',
- 'BN' => 'Brunei',
- 'BG' => 'Bulgaria',
- 'KH' => 'Cambodia',
- 'CM' => 'Cameroon',
- 'CA' => 'Canada',
- 'CL' => 'Chile',
- 'CN' => 'China',
- 'CO' => 'Colombia',
- 'CR' => 'Costa Rica',
- 'HR' => 'Croatia',
- 'CU' => 'Cuba',
- 'CY' => 'Cyprus',
- 'CZ' => 'Czech Republic',
- 'DK' => 'Denmark',
- 'DO' => 'Dominican Republic',
- 'EC' => 'Ecuador',
- 'EG' => 'Egypt',
- 'SV' => 'El Salvador',
- 'EE' => 'Estonia',
- 'ET' => 'Ethiopia',
- 'FI' => 'Finland',
- 'FR' => 'France',
- 'GE' => 'Georgia',
- 'DE' => 'Germany',
- 'GH' => 'Ghana',
- 'GR' => 'Greece',
- 'GT' => 'Guatemala',
- 'HN' => 'Honduras',
- 'HK' => 'Hong Kong',
- 'HU' => 'Hungary',
- 'IS' => 'Iceland',
- 'IN' => 'India',
- 'ID' => 'Indonesia',
- 'IR' => 'Iran',
- 'IQ' => 'Iraq',
- 'IE' => 'Ireland',
- 'IL' => 'Israel',
- 'IT' => 'Italy',
- 'JM' => 'Jamaica',
- 'JP' => 'Japan',
- 'JO' => 'Jordan',
- 'KZ' => 'Kazakhstan',
- 'KE' => 'Kenya',
- 'KR' => 'South Korea',
- 'KW' => 'Kuwait',
- 'LA' => 'Laos',
- 'LV' => 'Latvia',
- 'LB' => 'Lebanon',
- 'LY' => 'Libya',
- 'LT' => 'Lithuania',
- 'LU' => 'Luxembourg',
- 'MO' => 'Macao',
- 'MK' => 'North Macedonia',
- 'MY' => 'Malaysia',
- 'MT' => 'Malta',
- 'MX' => 'Mexico',
- 'MD' => 'Moldova',
- 'MC' => 'Monaco',
- 'MA' => 'Morocco',
- 'MZ' => 'Mozambique',
- 'MM' => 'Myanmar',
- 'NA' => 'Namibia',
- 'NP' => 'Nepal',
- 'NL' => 'Netherlands',
- 'NZ' => 'New Zealand',
- 'NI' => 'Nicaragua',
- 'NG' => 'Nigeria',
- 'NO' => 'Norway',
- 'OM' => 'Oman',
- 'PK' => 'Pakistan',
- 'PA' => 'Panama',
- 'PY' => 'Paraguay',
- 'PE' => 'Peru',
- 'PH' => 'Philippines',
- 'PL' => 'Poland',
- 'PT' => 'Portugal',
- 'QA' => 'Qatar',
- 'RO' => 'Romania',
- 'RU' => 'Russia',
- 'SA' => 'Saudi Arabia',
- 'RS' => 'Serbia',
- 'SG' => 'Singapore',
- 'SK' => 'Slovakia',
- 'SI' => 'Slovenia',
- 'ZA' => 'South Africa',
- 'ES' => 'Spain',
- 'LK' => 'Sri Lanka',
- 'SE' => 'Sweden',
- 'CH' => 'Switzerland',
- 'SY' => 'Syria',
- 'TW' => 'Taiwan',
- 'TH' => 'Thailand',
- 'TN' => 'Tunisia',
- 'TR' => 'Turkey',
- 'UA' => 'Ukraine',
- 'AE' => 'United Arab Emirates',
- 'GB' => 'United Kingdom',
- 'US' => 'United States',
- 'UY' => 'Uruguay',
- 'UZ' => 'Uzbekistan',
- 'VE' => 'Venezuela',
- 'VN' => 'Vietnam',
- 'YE' => 'Yemen',
- 'ZM' => 'Zambia',
- 'ZW' => 'Zimbabwe',
- 'DZ' => 'Algeria',
- 'AO' => 'Angola',
- 'BO' => 'Bolivia',
- 'BT' => 'Bhutan',
- 'BZ' => 'Belize',
- 'BN' => 'Brunei',
- 'BW' => 'Botswana',
- 'CM' => 'Cameroon',
- 'CR' => 'Costa Rica',
- 'CU' => 'Cuba',
- 'DO' => 'Dominican Republic',
- 'EC' => 'Ecuador',
- 'ER' => 'Eritrea',
- 'ET' => 'Ethiopia',
- 'FO' => 'Faroe Islands',
- 'GF' => 'French Guiana',
- 'GH' => 'Ghana',
- 'GL' => 'Greenland',
- 'GT' => 'Guatemala',
- 'HN' => 'Honduras',
- 'HT' => 'Haiti',
- 'IQ' => 'Iraq',
- 'JM' => 'Jamaica',
- 'JO' => 'Jordan',
- 'KE' => 'Kenya',
- 'KG' => 'Kyrgyzstan',
- 'KP' => 'North Korea',
- 'KW' => 'Kuwait',
- 'LA' => 'Laos',
- 'LY' => 'Libya',
- 'MG' => 'Madagascar',
- 'MN' => 'Mongolia',
- 'MO' => 'Macao',
- 'MW' => 'Malawi',
- 'MV' => 'Maldives',
- 'MZ' => 'Mozambique',
- 'NA' => 'Namibia',
- 'NC' => 'New Caledonia',
- 'NI' => 'Nicaragua',
- 'OM' => 'Oman',
- 'PA' => 'Panama',
- 'PG' => 'Papua New Guinea',
- 'PY' => 'Paraguay',
- 'QA' => 'Qatar',
- 'RW' => 'Rwanda',
- 'SB' => 'Solomon Islands',
- 'SD' => 'Sudan',
- 'SN' => 'Senegal',
- 'SO' => 'Somalia',
- 'SR' => 'Suriname',
- 'SV' => 'El Salvador',
- 'SY' => 'Syria',
- 'SZ' => 'Eswatini',
- 'TJ' => 'Tajikistan',
- 'TL' => 'Timor-Leste',
- 'TO' => 'Tonga',
- 'TT' => 'Trinidad and Tobago',
- 'TZ' => 'Tanzania',
- 'UG' => 'Uganda',
- 'UY' => 'Uruguay',
- 'WS' => 'Samoa',
- 'YE' => 'Yemen',
- 'ZM' => 'Zambia',
- 'ZW' => 'Zimbabwe',
- 'AS' => 'American Samoa',
- 'BM' => 'Bermuda',
- 'BS' => 'Bahamas',
- 'GU' => 'Guam',
- 'XX' => 'Unknown',
- ];
- }
- }
-