1
0
mirror of https://github.com/nextcloud/ocsms.git synced 2026-08-23 14:22:54 +00:00

Updated phone formatter (#241)

* Add locale and libphonenumber libraries.

* Update country code information

Updated existing country codes, fixed incorrect NANP codes for member countries (as well as several UK based ones).

Also added in Country Name to ISO country code mapping array for use with libphonenumber.

* Convert phone number formatting to use libphonenumber

libphonenumber parses phone number more consistantly than the old regex's that mismatched number on a regular basis.
This commit is contained in:
Greg Ross
2018-06-26 03:49:22 -04:00
committed by Loïc Blot
parent d29e2b1f7f
commit 6e86c48486
1371 changed files with 636043 additions and 284 deletions
@@ -0,0 +1,50 @@
<?php
namespace libphonenumber\prefixmapper;
/**
* A utility which knows the data files that are available for the phone prefix mappers to use.
* The data files contain mappings from phone number prefixes to text descriptions, and are
* organized by country calling code and language that the text descriptions are in.
*
* Class MappingFileProvider
* @package libphonenumber\prefixmapper
* @internal
*/
class MappingFileProvider
{
protected $map;
public function __construct($map)
{
$this->map = $map;
}
public function getFileName($countryCallingCode, $language, $script, $region)
{
if (strlen($language) == 0) {
return "";
}
if ($language === 'zh' && ($region == 'TW' || $region == 'HK' || $region == 'MO')) {
$language = 'zh_Hant';
}
// Loop through the $countryCallingCode and load the prefix
$prefixLength = strlen($countryCallingCode);
for ($i = $prefixLength; $i > 0; $i--) {
$prefix = substr($countryCallingCode, 0, $i);
if ($this->inMap($language, $prefix)) {
return $language . DIRECTORY_SEPARATOR . $prefix . '.php';
}
}
return "";
}
protected function inMap($language, $countryCallingCode)
{
return (array_key_exists($language, $this->map) && in_array($countryCallingCode, $this->map[$language]));
}
}
@@ -0,0 +1,61 @@
<?php
namespace libphonenumber\prefixmapper;
use libphonenumber\PhoneNumber;
use libphonenumber\PhoneNumberUtil;
/**
* A utility that maps phone number prefixes to a description string,
* which may be, for example, the geographical area the prefix covers.
*
* Class PhonePrefixMap
* @package libphonenumber\prefixmapper
*/
class PhonePrefixMap
{
protected $phonePrefixMapStorage = array();
/**
* @var PhoneNumberUtil
*/
protected $phoneUtil;
public function __construct($map)
{
$this->phonePrefixMapStorage = $map;
$this->phoneUtil = PhoneNumberUtil::getInstance();
}
/**
* Returns the description of the {@code $number}. This method distinguishes the case of an invalid
* prefix and a prefix for which the name is not available in the current language. If the
* description is not available in the current language an empty string is returned. If no
* description was found for the provided number, null is returned.
*
* @param PhoneNumber $number The phone number to look up
* @return string|null the description of the number
*/
public function lookup(PhoneNumber $number)
{
$phonePrefix = $number->getCountryCode() . $this->phoneUtil->getNationalSignificantNumber($number);
return $this->lookupKey($phonePrefix);
}
public function lookupKey($key)
{
if (count($this->phonePrefixMapStorage) == 0) {
return null;
}
while (strlen($key) > 0) {
if (array_key_exists($key, $this->phonePrefixMapStorage)) {
return $this->phonePrefixMapStorage[$key];
}
$key = substr($key, 0, -1);
}
return null;
}
}
@@ -0,0 +1,120 @@
<?php
namespace libphonenumber\prefixmapper;
use libphonenumber\PhoneNumber;
use libphonenumber\PhoneNumberUtil;
/**
* A helper class doing file handling and lookup of phone number prefix mappings.
*
* @package libphonenumber\prefixmapper
*/
class PrefixFileReader
{
protected $phonePrefixDataDirectory;
/**
* The mappingFileProvider knows for which combination of countryCallingCode and language a phone
* prefix mapping file is available in the file system, so that a file can be loaded when needed.
* @var MappingFileProvider
*/
protected $mappingFileProvider;
/**
* A mapping from countryCallingCode_lang to the corresponding phone prefix map that has been
* loaded.
* @var array
*/
protected $availablePhonePrefixMaps = array();
public function __construct($phonePrefixDataDirectory)
{
$this->phonePrefixDataDirectory = $phonePrefixDataDirectory;
$this->loadMappingFileProvider();
}
protected function loadMappingFileProvider()
{
$mapPath = $this->phonePrefixDataDirectory . DIRECTORY_SEPARATOR . "Map.php";
if (!file_exists($mapPath)) {
throw new \InvalidArgumentException("Invalid data directory: $mapPath");
}
$map = require $mapPath;
$this->mappingFileProvider = new MappingFileProvider($map);
}
/**
* @param $prefixMapKey
* @param $language
* @param $script
* @param $region
* @return PhonePrefixMap|null
*/
public function getPhonePrefixDescriptions($prefixMapKey, $language, $script, $region)
{
$fileName = $this->mappingFileProvider->getFileName($prefixMapKey, $language, $script, $region);
if (strlen($fileName) == 0) {
return null;
}
if (!isset($this->availablePhonePrefixMaps[$fileName])) {
$this->loadPhonePrefixMapFromFile($fileName);
}
return $this->availablePhonePrefixMaps[$fileName];
}
protected function loadPhonePrefixMapFromFile($fileName)
{
$path = $this->phonePrefixDataDirectory . DIRECTORY_SEPARATOR . $fileName;
if (!file_exists($path)) {
throw new \InvalidArgumentException("Data does not exist");
}
$map = require $path;
$areaCodeMap = new PhonePrefixMap($map);
$this->availablePhonePrefixMaps[$fileName] = $areaCodeMap;
}
public function mayFallBackToEnglish($language)
{
// Don't fall back to English if the requested language is among the following:
// - Chinese
// - Japanese
// - Korean
return ($language != 'zh' && $language != 'ja' && $language != 'ko');
}
/**
* Returns a text description in the given language for the given phone number.
*
* @param PhoneNumber $number the phone number for which we want to get a text description
* @param string $language two or three-letter lowercase ISO language as defined by ISO 639
* @param string $script four-letter titlecase (the first letter is uppercase and the rest of the letters
* are lowercase) ISO script code as defined in ISO 15924
* @param string $region two-letter uppercase ISO country code as defined by ISO 3166-1
* @return string a text description for the given language code for the given phone number, or empty
* string if the number passed in is invalid or could belong to multiple countries
*/
public function getDescriptionForNumber(PhoneNumber $number, $language, $script, $region)
{
$phonePrefix = $number->getCountryCode() . PhoneNumberUtil::getInstance()->getNationalSignificantNumber($number);
$phonePrefixDescriptions = $this->getPhonePrefixDescriptions($phonePrefix, $language, $script, $region);
$description = ($phonePrefixDescriptions !== null) ? $phonePrefixDescriptions->lookup($number) : null;
// When a location is not available in the requested language, fall back to English.
if (($description === null || strlen($description) === 0) && $this->mayFallBackToEnglish($language)) {
$defaultMap = $this->getPhonePrefixDescriptions($phonePrefix, "en", "", "");
if ($defaultMap === null) {
return "";
}
$description = $defaultMap->lookup($number);
}
return ($description !== null) ? $description : "";
}
}
@@ -0,0 +1,84 @@
<?php
namespace libphonenumber\prefixmapper;
use libphonenumber\PhoneNumber;
use libphonenumber\PhoneNumberUtil;
class PrefixTimeZonesMap
{
/*
protected final PhonePrefixMap phonePrefixMap = new PhonePrefixMap();
protected static final String RAW_STRING_TIMEZONES_SEPARATOR = "&";
*/
const RAW_STRING_TIMEZONES_SEPARATOR = "&";
protected $phonePrefixMap;
public function __construct($map)
{
$this->phonePrefixMap = new PhonePrefixMap($map);
}
/**
* As per {@link #lookupTimeZonesForNumber(long)}, but receives the number as a PhoneNumber
* instead of a long.
*
* @param $number PhoneNumber the phone number to look up
* @return array the list of corresponding time zones
*/
public function lookupTimeZonesForNumber(PhoneNumber $number)
{
$phonePrefix = $number->getCountryCode() . PhoneNumberUtil::getInstance()->getNationalSignificantNumber(
$number
);
return $this->lookupTimeZonesForNumberKey($phonePrefix);
}
/**
* Returns the list of time zones {@code key} corresponds to.
*
* <p>{@code key} could be the calling country code and the full significant number of a
* certain number, or it could be just a phone-number prefix.
* For example, the full number 16502530000 (from the phone-number +1 650 253 0000) is a valid
* input. Also, any of its prefixes, such as 16502, is also valid.
*
* @param $key int the key to look up
* @return array the list of corresponding time zones
*/
protected function lookupTimeZonesForNumberKey($key)
{
// Lookup in the map data. The returned String may consist of several time zones, so it must be
// split.
$timezonesString = $this->phonePrefixMap->lookupKey($key);
if ($timezonesString === null) {
return array();
}
return $this->tokenizeRawOutputString($timezonesString);
}
/**
* Split {@code timezonesString} into all the time zones that are part of it.
*
* @param $timezonesString String
* @return array
*/
protected function tokenizeRawOutputString($timezonesString)
{
return explode(static::RAW_STRING_TIMEZONES_SEPARATOR, $timezonesString);
}
/**
* Returns the list of time zones {@code number}'s calling country code corresponds to.
*
* @param $number PhoneNumber the phone number to look up
* @return array the list of corresponding time zones
*/
public function lookupCountryLevelTimeZonesForNumber(PhoneNumber $number)
{
return $this->lookupTimeZonesForNumberKey($number->getCountryCode());
}
}