"Afghanistan" , "AX" => "Åland Islands", "AL" => "Albania", "DZ" => "Algeria", "AS" => "American Samoa", "AD" => "Andorra", "AO" => "Angola", "AI" => "Anguilla", "AQ" => "Antarctica", "AG" => "Antigua and Barbuda", "AR" => "Argentina", "AM" => "Armenia", "AW" => "Aruba", "AU" => "Australia", "AT" => "Austria", "AZ" => "Azerbaijan", "BS" => "Bahamas", "BH" => "Bahrain", "BD" => "Bangladesh", "BB" => "Barbados", "BY" => "Belarus", "BE" => "Belgium", "BZ" => "Belize", "BJ" => "Benin", "BM" => "Bermuda", "BT" => "Bhutan", "BO" => "Bolivia, Plurinational State of", "BQ" => "Bonaire, Sint Eustatius and Saba", "BA" => "Bosnia and Herzegovina", "BW" => "Botswana", "BV" => "Bouvet Island", "BR" => "Brazil", "IO" => "British Indian Ocean Territory", "BN" => "Brunei Darussalam", "BG" => "Bulgaria", "BF" => "Burkina Faso", "BI" => "Burundi", "KH" => "Cambodia", "CM" => "Cameroon", "CA" => "Canada", "CV" => "Cape Verde", "KY" => "Cayman Islands", "CF" => "Central African Republic", "TD" => "Chad", "CL" => "Chile", "CN" => "China", "CX" => "Christmas Island", "CC" => "Cocos (Keeling) Islands", "CO" => "Colombia", "KM" => "Comoros", "CG" => "Congo", "CD" => "Congo, the Democratic Republic of the", "CK" => "Cook Islands", "CR" => "Costa Rica", "CI" => "Côte d'Ivoire", "HR" => "Croatia", "CU" => "Cuba", "CW" => "Curaçao", "CY" => "Cyprus", "CZ" => "Czech Republic", "DK" => "Denmark", "DJ" => "Djibouti", "DM" => "Dominica", "DO" => "Dominican Republic", "EC" => "Ecuador", "EG" => "Egypt", "SV" => "El Salvador", "GQ" => "Equatorial Guinea", "ER" => "Eritrea", "EE" => "Estonia", "ET" => "Ethiopia", "FK" => "Falkland Islands (Malvinas)", "FO" => "Faroe Islands", "FJ" => "Fiji", "FI" => "Finland", "FR" => "France", "GF" => "French Guiana", "PF" => "French Polynesia", "TF" => "French Southern Territories", "GA" => "Gabon", "GM" => "Gambia", "GE" => "Georgia", "DE" => "Germany", "GH" => "Ghana", "GI" => "Gibraltar", "GR" => "Greece", "GL" => "Greenland", "GD" => "Grenada", "GP" => "Guadeloupe", "GU" => "Guam", "GT" => "Guatemala", "GG" => "Guernsey", "GN" => "Guinea", "GW" => "Guinea-Bissau", "GY" => "Guyana", "HT" => "Haiti", "HM" => "Heard Island and McDonald Islands", "VA" => "Holy See (Vatican City State)", "HN" => "Honduras", "HK" => "Hong Kong, China", "HU" => "Hungary", "IS" => "Iceland", "IN" => "India", "ID" => "Indonesia", "IR" => "Iran, Islamic Republic of", "IQ" => "Iraq", "IE" => "Ireland", "IM" => "Isle of Man", "IL" => "Israel", "IT" => "Italy", "JM" => "Jamaica", "JP" => "Japan", "JE" => "Jersey", "JO" => "Jordan", "KZ" => "Kazakhstan", "KE" => "Kenya", "KI" => "Kiribati", "KP" => "Korea, Democratic People's Republic of", "KR" => "Korea, Republic of", "KW" => "Kuwait", "KG" => "Kyrgyzstan", "LA" => "Lao People's Democratic Republic", "LV" => "Latvia", "LB" => "Lebanon", "LS" => "Lesotho", "LR" => "Liberia", "LY" => "Libya", "LI" => "Liechtenstein", "LT" => "Lithuania", "LU" => "Luxembourg", "MO" => "Macao, China", "MK" => "Macedonia, the former Yugoslav Republic of", "MG" => "Madagascar", "MW" => "Malawi", "MY" => "Malaysia", "MV" => "Maldives", "ML" => "Mali", "MT" => "Malta", "MH" => "Marshall Islands", "MQ" => "Martinique", "MR" => "Mauritania", "MU" => "Mauritius", "YT" => "Mayotte", "MX" => "Mexico", "FM" => "Micronesia, Federated States of", "MD" => "Moldova, Republic of", "MC" => "Monaco", "MN" => "Mongolia", "ME" => "Montenegro", "MS" => "Montserrat", "MA" => "Morocco", "MZ" => "Mozambique", "MM" => "Myanmar", "NA" => "Namibia", "NR" => "Nauru", "NP" => "Nepal", "NL" => "Netherlands", "NC" => "New Caledonia", "NZ" => "New Zealand", "NI" => "Nicaragua", "NE" => "Niger", "NG" => "Nigeria", "NU" => "Niue", "NF" => "Norfolk Island", "MP" => "Northern Mariana Islands", "NO" => "Norway", "OM" => "Oman", "PK" => "Pakistan", "PW" => "Palau", "PS" => "Palestinian Territory, Occupied", "PA" => "Panama", "PG" => "Papua New Guinea", "PY" => "Paraguay", "PE" => "Peru", "PH" => "Philippines", "PN" => "Pitcairn", "PL" => "Poland", "PT" => "Portugal", "PR" => "Puerto Rico", "QA" => "Qatar", "RE" => "Réunion", "RO" => "Romania", "RU" => "Russian Federation", "RW" => "Rwanda", "BL" => "Saint Barthélemy", "SH" => "Saint Helena, Ascension and Tristan da Cunha", "KN" => "Saint Kitts and Nevis", "LC" => "Saint Lucia", "MF" => "Saint Martin (French part)", "PM" => "Saint Pierre and Miquelon", "VC" => "Saint Vincent and the Grenadines", "WS" => "Samoa", "SM" => "San Marino", "ST" => "Sao Tome and Principe", "SA" => "Saudi Arabia", "SN" => "Senegal", "RS" => "Serbia", "SC" => "Seychelles", "SL" => "Sierra Leone", "SG" => "Singapore", "SX" => "Sint Maarten (Dutch part)", "SK" => "Slovakia", "SI" => "Slovenia", "SB" => "Solomon Islands", "SO" => "Somalia", "ZA" => "South Africa", "GS" => "South Georgia and the South Sandwich Islands", "SS" => "South Sudan", "ES" => "Spain", "LK" => "Sri Lanka", "SD" => "Sudan", "SR" => "Suriname", "SJ" => "Svalbard and Jan Mayen", "SZ" => "Swaziland", "SE" => "Sweden", "CH" => "Switzerland", "SY" => "Syrian Arab Republic", "TW" => "Taiwan, Province of China", "TJ" => "Tajikistan", "TZ" => "Tanzania, United Republic of", "TH" => "Thailand", "TL" => "Timor-Leste", "TG" => "Togo", "TK" => "Tokelau", "TO" => "Tonga", "TT" => "Trinidad and Tobago", "TN" => "Tunisia", "TR" => "Turkey", "TM" => "Turkmenistan", "TC" => "Turks and Caicos Islands", "TV" => "Tuvalu", "UG" => "Uganda", "UA" => "Ukraine", "AE" => "United Arab Emirates", "GB" => "United Kingdom", "US" => "United States", "UM" => "United States Minor Outlying Islands", "UY" => "Uruguay", "UZ" => "Uzbekistan", "VU" => "Vanuatu", "VE" => "Venezuela, Bolivarian Republic of", "VN" => "Viet Nam", "VG" => "Virgin Islands, British", "VI" => "Virgin Islands, U.S.", "WF" => "Wallis and Futuna", "EH" => "Western Sahara", "YE" => "Yemen", "ZM" => "Zambia", "ZW" => "Zimbabwe" ]; return isset($list[$code]) ? $list[$code] : $code; } public static function phonePrefixList() { return [ "AF" => "93", "AX" => "358", "AL" => "355", "DZ" => "213", "AS" => "1", "AD" => "376", "AO" => "244", "AI" => "1", "AQ" => "672", "AG" => "1", "AR" => "54", "AM" => "374", "AW" => "297", "AU" => "61", "AT" => "43", "AZ" => "994", "BS" => "1", "BH" => "973", "BD" => "880", "BB" => "1", "BY" => "375", "BE" => "32", "BZ" => "501", "BJ" => "229", "BM" => "1", "BT" => "975", "BO" => "591", "BQ" => "599", "BA" => "387", "BW" => "267", "BV" => "47", "BR" => "55", "IO" => "246", "BN" => "673", "BG" => "359", "BF" => "226", "BI" => "257", "KH" => "855", "CM" => "237", "CA" => "1", "CV" => "238", "KY" => "1", "CF" => "236", "TD" => "235", "CL" => "56", "CN" => "86", "CX" => "61", "CC" => "61", "CO" => "57", "KM" => "269", "CG" => "242", "CD" => "243", "CK" => "682", "CR" => "506", "CI" => "225", "HR" => "385", "CU" => "53", "CW" => "599", "CY" => "357", "CZ" => "420", "DK" => "45", "DJ" => "253", "DM" => "1", "DO" => "1", "EC" => "593", "EG" => "20", "SV" => "503", "GQ" => "240", "ER" => "291", "EE" => "372", "ET" => "251", "FK" => "500", "FO" => "298", "FJ" => "679", "FI" => "358", "FR" => "33", "GF" => "594", "PF" => "689", "TF" => "262", "GA" => "241", "GM" => "220", "GE" => "995", "DE" => "49", "GH" => "233", "GI" => "350", "GR" => "30", "GL" => "299", "GD" => "1", "GP" => "590", "GU" => "1", "GT" => "502", "GG" => "44", "GN" => "224", "GW" => "245", "GY" => "592", "HT" => "509", "HM" => "672", "VA" => "39", "HN" => "504", "HK" => "852", "HU" => "36", "IS" => "354", "IN" => "91", "ID" => "62", "IR" => "98", "IQ" => "964", "IE" => "353", "IM" => "44", "IL" => "972", "IT" => "39", "JM" => "1", "JP" => "81", "JE" => "44", "JO" => "962", "KZ" => "7", "KE" => "254", "KI" => "686", "KP" => "850", "KR" => "82", "KW" => "965", "KG" => "996", "LA" => "856", "LV" => "371", "LB" => "961", "LS" => "266", "LR" => "231", "LY" => "218", "LI" => "423", "LT" => "370", "LU" => "352", "MO" => "853", "MK" => "389", "MG" => "261", "MW" => "265", "MY" => "60", "MV" => "960", "ML" => "223", "MT" => "356", "MH" => "692", "MQ" => "596", "MR" => "222", "MU" => "230", "YT" => "262", "MX" => "52", "FM" => "691", "MD" => "373", "MC" => "377", "MN" => "976", "ME" => "382", "MS" => "1", "MA" => "212", "MZ" => "258", "MM" => "95", "NA" => "264", "NR" => "674", "NP" => "977", "NL" => "31", "NC" => "687", "NZ" => "64", "NI" => "505", "NE" => "227", "NG" => "234", "NU" => "683", "NF" => "672", "MP" => "1", "NO" => "47", "OM" => "968", "PK" => "92", "PW" => "680", "PS" => "970", "PA" => "507", "PG" => "675", "PY" => "595", "PE" => "51", "PH" => "63", "PN" => "64", "PL" => "48", "PT" => "351", "PR" => "1", "QA" => "974", "RE" => "262", "RO" => "40", "RU" => "7", "RW" => "250", "BL" => "590", "SH" => "290", "KN" => "1", "LC" => "1", "MF" => "590", "PM" => "508", "VC" => "1", "WS" => "685", "SM" => "378", "ST" => "239", "SA" => "966", "SN" => "221", "RS" => "381", "SC" => "248", "SL" => "232", "SG" => "65", "SX" => "1", "SK" => "421", "SI" => "386", "SB" => "677", "SO" => "252", "ZA" => "27", "GS" => "500", "SS" => "211", "ES" => "34", "LK" => "94", "SD" => "249", "SR" => "597", "SJ" => "47", "SZ" => "268", "SE" => "46", "CH" => "41", "SY" => "963", "TW" => "886", "TJ" => "992", "TZ" => "255", "TH" => "66", "TL" => "670", "TG" => "228", "TK" => "690", "TO" => "676", "TT" => "1", "TN" => "216", "TR" => "90", "TM" => "993", "TC" => "1", "TV" => "688", "UG" => "256", "UA" => "380", "AE" => "971", "GB" => "44", "US" => "1", "UM" => "1", "UY" => "598", "UZ" => "998", "VU" => "678", "VE" => "58", "VN" => "84", "VG" => "1", "VI" => "1", "WF" => "681", "EH" => "212", "YE" => "967", "ZM" => "260", "ZW" => "263" ]; } public static function phonePrefix($code) { $list = self::phonePrefixList(); return isset($list[$code]) ? $list[$code] : null; } public static function countryByPrefix($prefix) { // Si es 1, siempre devolver US if ($prefix === "1" || $prefix === 1) { return "US"; } // Invertir el array y buscar $list = array_flip(self::phonePrefixList()); return isset($list[$prefix]) ? $list[$prefix] : null; } /** * Decompose a full phone number into dial_code, local_phone, and country. * Matches against known dial codes from longest to shortest to avoid ambiguity. * Example: "+447387472724" → ['dial_code' => '44', 'phone' => '7387472724', 'country' => 'GB'] * "+34612345678" → ['dial_code' => '34', 'phone' => '612345678', 'country' => 'ES'] * * @param string $phone Full phone number (with or without +) * @return array ['dial_code' => string|null, 'phone' => string, 'country' => string|null] */ public static function decomposePhone($phone) { // Clean: remove spaces, dashes, dots, parentheses $clean = preg_replace('/[\s\-\.\(\)]/', '', $phone); // Remove leading + if (strpos($clean, '+') === 0) { $clean = substr($clean, 1); } // Only digits from here $digits = preg_replace('/[^0-9]/', '', $clean); if (empty($digits)) { return ['dial_code' => null, 'phone' => '', 'country' => null]; } // Build unique list of dial codes sorted by length descending (longest first) // This ensures "44" matches before "4", "1868" matches before "1", etc. $prefixes = array_unique(array_values(self::phonePrefixList())); usort($prefixes, function($a, $b) { return strlen($b) - strlen($a); }); // Try to match from longest prefix to shortest foreach ($prefixes as $prefix) { if (strpos($digits, $prefix) === 0 && strlen($digits) > strlen($prefix)) { $localPhone = substr($digits, strlen($prefix)); $country = self::countryByPrefix($prefix); return [ 'dial_code' => $prefix, 'phone' => $localPhone, 'country' => $country ]; } } // No match found — return everything as local phone return ['dial_code' => null, 'phone' => $digits, 'country' => null]; } }