1<?php
2
3namespace libphonenumber;
4
5use libphonenumber\Leniency\AbstractLeniency;
6
7/**
8 * Utility for international phone numbers. Functionality includes formatting, parsing and
9 * validation.
10 *
11 * <p>If you use this library, and want to be notified about important changes, please sign up to
12 * our <a href="http://groups.google.com/group/libphonenumber-discuss/about">mailing list</a>.
13 *
14 * NOTE: A lot of methods in this class require Region Code strings. These must be provided using
15 * CLDR two-letter region-code format. These should be in upper-case. The list of the codes
16 * can be found here:
17 * http://www.unicode.org/cldr/charts/30/supplemental/territory_information.html
18 *
19 * @author Shaopeng Jia
20 * @see https://github.com/google/libphonenumber
21 */
22class PhoneNumberUtil
23{
24    /** Flags to use when compiling regular expressions for phone numbers */
25    const REGEX_FLAGS = 'ui'; //Unicode and case insensitive
26    // The minimum and maximum length of the national significant number.
27    const MIN_LENGTH_FOR_NSN = 2;
28    // The ITU says the maximum length should be 15, but we have found longer numbers in Germany.
29    const MAX_LENGTH_FOR_NSN = 17;
30
31    // We don't allow input strings for parsing to be longer than 250 chars. This prevents malicious
32    // input from overflowing the regular-expression engine.
33    const MAX_INPUT_STRING_LENGTH = 250;
34
35    // The maximum length of the country calling code.
36    const MAX_LENGTH_COUNTRY_CODE = 3;
37
38    const REGION_CODE_FOR_NON_GEO_ENTITY = '001';
39    const META_DATA_FILE_PREFIX = 'PhoneNumberMetadata';
40    const TEST_META_DATA_FILE_PREFIX = 'PhoneNumberMetadataForTesting';
41
42    // Region-code for the unknown region.
43    const UNKNOWN_REGION = 'ZZ';
44
45    const NANPA_COUNTRY_CODE = 1;
46    /*
47     * The prefix that needs to be inserted in front of a Colombian landline number when dialed from
48     * a mobile number in Colombia.
49     */
50    const COLOMBIA_MOBILE_TO_FIXED_LINE_PREFIX = '3';
51    // The PLUS_SIGN signifies the international prefix.
52    const PLUS_SIGN = '+';
53    const PLUS_CHARS = '++';
54    const STAR_SIGN = '*';
55
56    const RFC3966_EXTN_PREFIX = ';ext=';
57    const RFC3966_PREFIX = 'tel:';
58    const RFC3966_PHONE_CONTEXT = ';phone-context=';
59    const RFC3966_ISDN_SUBADDRESS = ';isub=';
60
61    // We use this pattern to check if the phone number has at least three letters in it - if so, then
62    // we treat it as a number where some phone-number digits are represented by letters.
63    const VALID_ALPHA_PHONE_PATTERN = '(?:.*?[A-Za-z]){3}.*';
64    // We accept alpha characters in phone numbers, ASCII only, upper and lower case.
65    const VALID_ALPHA = 'A-Za-z';
66
67
68    // Default extension prefix to use when formatting. This will be put in front of any extension
69    // component of the number, after the main national number is formatted. For example, if you wish
70    // the default extension formatting to be " extn: 3456", then you should specify " extn: " here
71    // as the default extension prefix. This can be overridden by region-specific preferences.
72    const DEFAULT_EXTN_PREFIX = ' ext. ';
73
74    // Regular expression of acceptable punctuation found in phone numbers, used to find numbers in
75    // text and to decide what is a viable phone number. This excludes diallable characters.
76    // This consists of dash characters, white space characters, full stops, slashes,
77    // square brackets, parentheses and tildes. It also includes the letter 'x' as that is found as a
78    // placeholder for carrier information in some phone numbers. Full-width variants are also
79    // present.
80    const VALID_PUNCTUATION = "-x\xE2\x80\x90-\xE2\x80\x95\xE2\x88\x92\xE3\x83\xBC\xEF\xBC\x8D-\xEF\xBC\x8F \xC2\xA0\xC2\xAD\xE2\x80\x8B\xE2\x81\xA0\xE3\x80\x80()\xEF\xBC\x88\xEF\xBC\x89\xEF\xBC\xBB\xEF\xBC\xBD.\\[\\]/~\xE2\x81\x93\xE2\x88\xBC";
81    const DIGITS = "\\p{Nd}";
82
83    // Pattern that makes it easy to distinguish whether a region has a single international dialing
84    // prefix or not. If a region has a single international prefix (e.g. 011 in USA), it will be
85    // represented as a string that contains a sequence of ASCII digits, and possible a tilde, which
86    // signals waiting for the tone. If there are multiple available international prefixes in a
87    // region, they will be represented as a regex string that always contains one or more characters
88    // that are not ASCII digits or a tilde.
89    const SINGLE_INTERNATIONAL_PREFIX = "[\\d]+(?:[~\xE2\x81\x93\xE2\x88\xBC\xEF\xBD\x9E][\\d]+)?";
90    const NON_DIGITS_PATTERN = "(\\D+)";
91
92    // The FIRST_GROUP_PATTERN was originally set to $1 but there are some countries for which the
93    // first group is not used in the national pattern (e.g. Argentina) so the $1 group does not match
94    // correctly. Therefore, we use \d, so that the first group actually used in the pattern will be
95    // matched.
96    const FIRST_GROUP_PATTERN = "(\\$\\d)";
97    // Constants used in the formatting rules to represent the national prefix, first group and
98    // carrier code respectively.
99    const NP_STRING = '$NP';
100    const FG_STRING = '$FG';
101    const CC_STRING = '$CC';
102
103    // A pattern that is used to determine if the national prefix formatting rule has the first group
104    // only, i.e, does not start with the national prefix. Note that the pattern explicitly allows
105    // for unbalanced parentheses.
106    const FIRST_GROUP_ONLY_PREFIX_PATTERN = '\\(?\\$1\\)?';
107    public static $PLUS_CHARS_PATTERN;
108    protected static $SEPARATOR_PATTERN;
109    protected static $CAPTURING_DIGIT_PATTERN;
110    protected static $VALID_START_CHAR_PATTERN;
111    public static $SECOND_NUMBER_START_PATTERN = '[\\\\/] *x';
112    public static $UNWANTED_END_CHAR_PATTERN = "[[\\P{N}&&\\P{L}]&&[^#]]+$";
113    protected static $DIALLABLE_CHAR_MAPPINGS = array();
114    protected static $CAPTURING_EXTN_DIGITS;
115
116    /**
117     * @var PhoneNumberUtil
118     */
119    protected static $instance;
120
121    /**
122     * Only upper-case variants of alpha characters are stored.
123     *
124     * @var array
125     */
126    protected static $ALPHA_MAPPINGS = array(
127        'A' => '2',
128        'B' => '2',
129        'C' => '2',
130        'D' => '3',
131        'E' => '3',
132        'F' => '3',
133        'G' => '4',
134        'H' => '4',
135        'I' => '4',
136        'J' => '5',
137        'K' => '5',
138        'L' => '5',
139        'M' => '6',
140        'N' => '6',
141        'O' => '6',
142        'P' => '7',
143        'Q' => '7',
144        'R' => '7',
145        'S' => '7',
146        'T' => '8',
147        'U' => '8',
148        'V' => '8',
149        'W' => '9',
150        'X' => '9',
151        'Y' => '9',
152        'Z' => '9',
153    );
154
155    /**
156     * Map of country calling codes that use a mobile token before the area code. One example of when
157     * this is relevant is when determining the length of the national destination code, which should
158     * be the length of the area code plus the length of the mobile token.
159     *
160     * @var array
161     */
162    protected static $MOBILE_TOKEN_MAPPINGS = array();
163
164    /**
165     * Set of country codes that have geographically assigned mobile numbers (see GEO_MOBILE_COUNTRIES
166     * below) which are not based on *area codes*. For example, in China mobile numbers start with a
167     * carrier indicator, and beyond that are geographically assigned: this carrier indicator is not
168     * considered to be an area code.
169     *
170     * @var array
171     */
172    protected static $GEO_MOBILE_COUNTRIES_WITHOUT_MOBILE_AREA_CODES;
173
174    /**
175     * Set of country calling codes that have geographically assigned mobile numbers. This may not be
176     * complete; we add calling codes case by case, as we find geographical mobile numbers or hear
177     * from user reports. Note that countries like the US, where we can't distinguish between
178     * fixed-line or mobile numbers, are not listed here, since we consider FIXED_LINE_OR_MOBILE to be
179     * a possibly geographically-related type anyway (like FIXED_LINE).
180     *
181     * @var array
182     */
183    protected static $GEO_MOBILE_COUNTRIES;
184
185    /**
186     * For performance reasons, amalgamate both into one map.
187     *
188     * @var array
189     */
190    protected static $ALPHA_PHONE_MAPPINGS;
191
192    /**
193     * Separate map of all symbols that we wish to retain when formatting alpha numbers. This
194     * includes digits, ASCII letters and number grouping symbols such as "-" and " ".
195     *
196     * @var array
197     */
198    protected static $ALL_PLUS_NUMBER_GROUPING_SYMBOLS;
199
200    /**
201     * Simple ASCII digits map used to populate ALPHA_PHONE_MAPPINGS and
202     * ALL_PLUS_NUMBER_GROUPING_SYMBOLS.
203     *
204     * @var array
205     */
206    protected static $asciiDigitMappings = array(
207        '0' => '0',
208        '1' => '1',
209        '2' => '2',
210        '3' => '3',
211        '4' => '4',
212        '5' => '5',
213        '6' => '6',
214        '7' => '7',
215        '8' => '8',
216        '9' => '9',
217    );
218
219    /**
220     * Regexp of all possible ways to write extensions, for use when parsing. This will be run as a
221     * case-insensitive regexp match. Wide character versions are also provided after each ASCII
222     * version.
223     *
224     * @var String
225     */
226    protected static $EXTN_PATTERNS_FOR_PARSING;
227    /**
228     * @var string
229     * @internal
230     */
231    public static $EXTN_PATTERNS_FOR_MATCHING;
232    protected static $EXTN_PATTERN;
233    protected static $VALID_PHONE_NUMBER_PATTERN;
234    protected static $MIN_LENGTH_PHONE_NUMBER_PATTERN;
235    /**
236     *  Regular expression of viable phone numbers. This is location independent. Checks we have at
237     * least three leading digits, and only valid punctuation, alpha characters and
238     * digits in the phone number. Does not include extension data.
239     * The symbol 'x' is allowed here as valid punctuation since it is often used as a placeholder for
240     * carrier codes, for example in Brazilian phone numbers. We also allow multiple "+" characters at
241     * the start.
242     * Corresponds to the following:
243     * [digits]{minLengthNsn}|
244     * plus_sign*(([punctuation]|[star])*[digits]){3,}([punctuation]|[star]|[digits]|[alpha])*
245     *
246     * The first reg-ex is to allow short numbers (two digits long) to be parsed if they are entered
247     * as "15" etc, but only if there is no punctuation in them. The second expression restricts the
248     * number of digits to three or more, but then allows them to be in international form, and to
249     * have alpha-characters and punctuation.
250     *
251     * Note VALID_PUNCTUATION starts with a -, so must be the first in the range.
252     *
253     * @var string
254     */
255    protected static $VALID_PHONE_NUMBER;
256    protected static $numericCharacters = array(
257        "\xef\xbc\x90" => 0,
258        "\xef\xbc\x91" => 1,
259        "\xef\xbc\x92" => 2,
260        "\xef\xbc\x93" => 3,
261        "\xef\xbc\x94" => 4,
262        "\xef\xbc\x95" => 5,
263        "\xef\xbc\x96" => 6,
264        "\xef\xbc\x97" => 7,
265        "\xef\xbc\x98" => 8,
266        "\xef\xbc\x99" => 9,
267
268        "\xd9\xa0" => 0,
269        "\xd9\xa1" => 1,
270        "\xd9\xa2" => 2,
271        "\xd9\xa3" => 3,
272        "\xd9\xa4" => 4,
273        "\xd9\xa5" => 5,
274        "\xd9\xa6" => 6,
275        "\xd9\xa7" => 7,
276        "\xd9\xa8" => 8,
277        "\xd9\xa9" => 9,
278
279        "\xdb\xb0" => 0,
280        "\xdb\xb1" => 1,
281        "\xdb\xb2" => 2,
282        "\xdb\xb3" => 3,
283        "\xdb\xb4" => 4,
284        "\xdb\xb5" => 5,
285        "\xdb\xb6" => 6,
286        "\xdb\xb7" => 7,
287        "\xdb\xb8" => 8,
288        "\xdb\xb9" => 9,
289
290        "\xe1\xa0\x90" => 0,
291        "\xe1\xa0\x91" => 1,
292        "\xe1\xa0\x92" => 2,
293        "\xe1\xa0\x93" => 3,
294        "\xe1\xa0\x94" => 4,
295        "\xe1\xa0\x95" => 5,
296        "\xe1\xa0\x96" => 6,
297        "\xe1\xa0\x97" => 7,
298        "\xe1\xa0\x98" => 8,
299        "\xe1\xa0\x99" => 9,
300    );
301
302    /**
303     * The set of county calling codes that map to the non-geo entity region ("001").
304     *
305     * @var array
306     */
307    protected $countryCodesForNonGeographicalRegion = array();
308    /**
309     * The set of regions the library supports.
310     *
311     * @var array
312     */
313    protected $supportedRegions = array();
314
315    /**
316     * A mapping from a country calling code to the region codes which denote the region represented
317     * by that country calling code. In the case of multiple regions sharing a calling code, such as
318     * the NANPA regions, the one indicated with "isMainCountryForCode" in the metadata should be
319     * first.
320     *
321     * @var array
322     */
323    protected $countryCallingCodeToRegionCodeMap = array();
324    /**
325     * The set of regions that share country calling code 1.
326     *
327     * @var array
328     */
329    protected $nanpaRegions = array();
330
331    /**
332     * @var MetadataSourceInterface
333     */
334    protected $metadataSource;
335
336    /**
337     * @var MatcherAPIInterface
338     */
339    protected $matcherAPI;
340
341    /**
342     * This class implements a singleton, so the only constructor is protected.
343     * @param MetadataSourceInterface $metadataSource
344     * @param $countryCallingCodeToRegionCodeMap
345     */
346    protected function __construct(MetadataSourceInterface $metadataSource, $countryCallingCodeToRegionCodeMap)
347    {
348        $this->metadataSource = $metadataSource;
349        $this->countryCallingCodeToRegionCodeMap = $countryCallingCodeToRegionCodeMap;
350        $this->init();
351        $this->matcherAPI = RegexBasedMatcher::create();
352        static::initExtnPatterns();
353        static::initExtnPattern();
354        static::$PLUS_CHARS_PATTERN = '[' . static::PLUS_CHARS . ']+';
355        static::$SEPARATOR_PATTERN = '[' . static::VALID_PUNCTUATION . ']+';
356        static::$CAPTURING_DIGIT_PATTERN = '(' . static::DIGITS . ')';
357        static::initValidStartCharPattern();
358        static::initAlphaPhoneMappings();
359        static::initDiallableCharMappings();
360
361        static::$ALL_PLUS_NUMBER_GROUPING_SYMBOLS = array();
362        // Put (lower letter -> upper letter) and (upper letter -> upper letter) mappings.
363        foreach (static::$ALPHA_MAPPINGS as $c => $value) {
364            static::$ALL_PLUS_NUMBER_GROUPING_SYMBOLS[strtolower($c)] = $c;
365            static::$ALL_PLUS_NUMBER_GROUPING_SYMBOLS[$c] = $c;
366        }
367        static::$ALL_PLUS_NUMBER_GROUPING_SYMBOLS += static::$asciiDigitMappings;
368        static::$ALL_PLUS_NUMBER_GROUPING_SYMBOLS['-'] = '-';
369        static::$ALL_PLUS_NUMBER_GROUPING_SYMBOLS["\xEF\xBC\x8D"] = '-';
370        static::$ALL_PLUS_NUMBER_GROUPING_SYMBOLS["\xE2\x80\x90"] = '-';
371        static::$ALL_PLUS_NUMBER_GROUPING_SYMBOLS["\xE2\x80\x91"] = '-';
372        static::$ALL_PLUS_NUMBER_GROUPING_SYMBOLS["\xE2\x80\x92"] = '-';
373        static::$ALL_PLUS_NUMBER_GROUPING_SYMBOLS["\xE2\x80\x93"] = '-';
374        static::$ALL_PLUS_NUMBER_GROUPING_SYMBOLS["\xE2\x80\x94"] = '-';
375        static::$ALL_PLUS_NUMBER_GROUPING_SYMBOLS["\xE2\x80\x95"] = '-';
376        static::$ALL_PLUS_NUMBER_GROUPING_SYMBOLS["\xE2\x88\x92"] = '-';
377        static::$ALL_PLUS_NUMBER_GROUPING_SYMBOLS['/'] = '/';
378        static::$ALL_PLUS_NUMBER_GROUPING_SYMBOLS["\xEF\xBC\x8F"] = '/';
379        static::$ALL_PLUS_NUMBER_GROUPING_SYMBOLS[' '] = ' ';
380        static::$ALL_PLUS_NUMBER_GROUPING_SYMBOLS["\xE3\x80\x80"] = ' ';
381        static::$ALL_PLUS_NUMBER_GROUPING_SYMBOLS["\xE2\x81\xA0"] = ' ';
382        static::$ALL_PLUS_NUMBER_GROUPING_SYMBOLS['.'] = '.';
383        static::$ALL_PLUS_NUMBER_GROUPING_SYMBOLS["\xEF\xBC\x8E"] = '.';
384
385
386        static::initValidPhoneNumberPatterns();
387
388        static::$UNWANTED_END_CHAR_PATTERN = '[^' . static::DIGITS . static::VALID_ALPHA . '#]+$';
389
390        static::initMobileTokenMappings();
391
392        static::$GEO_MOBILE_COUNTRIES_WITHOUT_MOBILE_AREA_CODES = array();
393        static::$GEO_MOBILE_COUNTRIES_WITHOUT_MOBILE_AREA_CODES[] = 86; // China
394
395        static::$GEO_MOBILE_COUNTRIES = array();
396        static::$GEO_MOBILE_COUNTRIES[] = 52; // Mexico
397        static::$GEO_MOBILE_COUNTRIES[] = 54; // Argentina
398        static::$GEO_MOBILE_COUNTRIES[] = 55; // Brazil
399        static::$GEO_MOBILE_COUNTRIES[] = 62; // Indonesia: some prefixes only (fixed CMDA wireless)
400
401        static::$GEO_MOBILE_COUNTRIES = array_merge(static::$GEO_MOBILE_COUNTRIES, static::$GEO_MOBILE_COUNTRIES_WITHOUT_MOBILE_AREA_CODES);
402    }
403
404    /**
405     * Gets a {@link PhoneNumberUtil} instance to carry out international phone number formatting,
406     * parsing or validation. The instance is loaded with phone number metadata for a number of most
407     * commonly used regions.
408     *
409     * <p>The {@link PhoneNumberUtil} is implemented as a singleton. Therefore calling getInstance
410     * multiple times will only result in one instance being created.
411     *
412     * @param string $baseFileLocation
413     * @param array|null $countryCallingCodeToRegionCodeMap
414     * @param MetadataLoaderInterface|null $metadataLoader
415     * @param MetadataSourceInterface|null $metadataSource
416     * @return PhoneNumberUtil instance
417     */
418    public static function getInstance($baseFileLocation = self::META_DATA_FILE_PREFIX, array $countryCallingCodeToRegionCodeMap = null, MetadataLoaderInterface $metadataLoader = null, MetadataSourceInterface $metadataSource = null)
419    {
420        if (static::$instance === null) {
421            if ($countryCallingCodeToRegionCodeMap === null) {
422                $countryCallingCodeToRegionCodeMap = CountryCodeToRegionCodeMap::$countryCodeToRegionCodeMap;
423            }
424
425            if ($metadataLoader === null) {
426                $metadataLoader = new DefaultMetadataLoader();
427            }
428
429            if ($metadataSource === null) {
430                $metadataSource = new MultiFileMetadataSourceImpl($metadataLoader, __DIR__ . '/data/' . $baseFileLocation);
431            }
432
433            static::$instance = new static($metadataSource, $countryCallingCodeToRegionCodeMap);
434        }
435        return static::$instance;
436    }
437
438    protected function init()
439    {
440        $supportedRegions = array(array());
441
442        foreach ($this->countryCallingCodeToRegionCodeMap as $countryCode => $regionCodes) {
443            // We can assume that if the country calling code maps to the non-geo entity region code then
444            // that's the only region code it maps to.
445            if (count($regionCodes) === 1 && static::REGION_CODE_FOR_NON_GEO_ENTITY === $regionCodes[0]) {
446                // This is the subset of all country codes that map to the non-geo entity region code.
447                $this->countryCodesForNonGeographicalRegion[] = $countryCode;
448            } else {
449                // The supported regions set does not include the "001" non-geo entity region code.
450                $supportedRegions[] = $regionCodes;
451            }
452        }
453
454        $this->supportedRegions = call_user_func_array('array_merge', $supportedRegions);
455
456
457        // If the non-geo entity still got added to the set of supported regions it must be because
458        // there are entries that list the non-geo entity alongside normal regions (which is wrong).
459        // If we discover this, remove the non-geo entity from the set of supported regions and log.
460        $idx_region_code_non_geo_entity = array_search(static::REGION_CODE_FOR_NON_GEO_ENTITY, $this->supportedRegions);
461        if ($idx_region_code_non_geo_entity !== false) {
462            unset($this->supportedRegions[$idx_region_code_non_geo_entity]);
463        }
464        $this->nanpaRegions = $this->countryCallingCodeToRegionCodeMap[static::NANPA_COUNTRY_CODE];
465    }
466
467    /**
468     * @internal
469     */
470    public static function initExtnPatterns()
471    {
472        static::$EXTN_PATTERNS_FOR_PARSING = static::createExtnPattern(true);
473        static::$EXTN_PATTERNS_FOR_MATCHING = static::createExtnPattern(false);
474    }
475
476    /**
477     * Helper method for constructing regular expressions for parsing. Creates an expression that
478     * captures up to maxLength digits.
479     * @param int $maxLength
480     * @return string
481     */
482    private static function extnDigits($maxLength)
483    {
484        return '(' . self::DIGITS . '{1,' . $maxLength . '})';
485    }
486
487    /**
488     * Helper initialiser method to create the regular-expression pattern to match extensions.
489     * Note that there are currently six capturing groups for the extension itself. If this number is
490     * changed, MaybeStripExtension needs to be updated.
491     *
492     * @param boolean $forParsing
493     * @return string
494     */
495    protected static function createExtnPattern($forParsing)
496    {
497        // We cap the maximum length of an extension based on the ambiguity of the way the extension is
498        // prefixed. As per ITU, the officially allowed length for extensions is actually 40, but we
499        // don't support this since we haven't seen real examples and this introduces many false
500        // interpretations as the extension labels are not standardized.
501        $extLimitAfterExplicitLabel = 20;
502        $extLimitAfterLikelyLabel = 15;
503        $extLimitAfterAmbiguousChar = 9;
504        $extLimitWhenNotSure = 6;
505
506
507
508        $possibleSeparatorsBetweenNumberAndExtLabel = "[ \xC2\xA0\\t,]*";
509        // Optional full stop (.) or colon, followed by zero or more spaces/tabs/commas.
510        $possibleCharsAfterExtLabel = "[:\\.\xEf\xBC\x8E]?[ \xC2\xA0\\t,-]*";
511        $optionalExtnSuffix = "#?";
512
513        // Here the extension is called out in more explicit way, i.e mentioning it obvious patterns
514        // like "ext.". Canonical-equivalence doesn't seem to be an option with Android java, so we
515        // allow two options for representing the accented o - the character itself, and one in the
516        // unicode decomposed form with the combining acute accent.
517        $explicitExtLabels = "(?:e?xt(?:ensi(?:o\xCC\x81?|\xC3\xB3))?n?|\xEF\xBD\x85?\xEF\xBD\x98\xEF\xBD\x94\xEF\xBD\x8E?|\xD0\xB4\xD0\xBE\xD0\xB1|anexo)";
518        // One-character symbols that can be used to indicate an extension, and less commonly used
519        // or more ambiguous extension labels.
520        $ambiguousExtLabels = "(?:[x\xEF\xBD\x98#\xEF\xBC\x83~\xEF\xBD\x9E]|int|\xEF\xBD\x89\xEF\xBD\x8E\xEF\xBD\x94)";
521        // When extension is not separated clearly.
522        $ambiguousSeparator = "[- ]+";
523
524        $rfcExtn = static::RFC3966_EXTN_PREFIX . static::extnDigits($extLimitAfterExplicitLabel);
525        $explicitExtn = $possibleSeparatorsBetweenNumberAndExtLabel . $explicitExtLabels
526            . $possibleCharsAfterExtLabel . static::extnDigits($extLimitAfterExplicitLabel)
527            . $optionalExtnSuffix;
528        $ambiguousExtn = $possibleSeparatorsBetweenNumberAndExtLabel . $ambiguousExtLabels
529            . $possibleCharsAfterExtLabel . static::extnDigits($extLimitAfterAmbiguousChar) . $optionalExtnSuffix;
530        $americanStyleExtnWithSuffix = $ambiguousSeparator . static::extnDigits($extLimitWhenNotSure) . "#";
531
532        // The first regular expression covers RFC 3966 format, where the extension is added using
533        // ";ext=". The second more generic where extension is mentioned with explicit labels like
534        // "ext:". In both the above cases we allow more numbers in extension than any other extension
535        // labels. The third one captures when single character extension labels or less commonly used
536        // labels are used. In such cases we capture fewer extension digits in order to reduce the
537        // chance of falsely interpreting two numbers beside each other as a number + extension. The
538        // fourth one covers the special case of American numbers where the extension is written with a
539        // hash at the end, such as "- 503#".
540        $extensionPattern =
541            $rfcExtn . "|"
542            . $explicitExtn . "|"
543            . $ambiguousExtn . "|"
544            . $americanStyleExtnWithSuffix;
545        // Additional pattern that is supported when parsing extensions, not when matching.
546        if ($forParsing) {
547            // This is same as possibleSeparatorsBetweenNumberAndExtLabel, but not matching comma as
548            // extension label may have it.
549            $possibleSeparatorsNumberExtLabelNoComma = "[ \xC2\xA0\\t]*";
550            // ",," is commonly used for auto dialling the extension when connected. First comma is matched
551            // through possibleSeparatorsBetweenNumberAndExtLabel, so we do not repeat it here. Semi-colon
552            // works in Iphone and Android also to pop up a button with the extension number following.
553            $autoDiallingAndExtLabelsFound = "(?:,{2}|;)";
554
555            $autoDiallingExtn = $possibleSeparatorsNumberExtLabelNoComma
556                . $autoDiallingAndExtLabelsFound . $possibleCharsAfterExtLabel
557                . static::extnDigits($extLimitAfterLikelyLabel) . $optionalExtnSuffix;
558            $onlyCommasExtn = $possibleSeparatorsNumberExtLabelNoComma
559                . '(?:,)+' . $possibleCharsAfterExtLabel . static::extnDigits($extLimitAfterAmbiguousChar)
560                . $optionalExtnSuffix;
561            // Here the first pattern is exclusively for extension autodialling formats which are used
562            // when dialling and in this case we accept longer extensions. However, the second pattern
563            // is more liberal on the number of commas that acts as extension labels, so we have a strict
564            // cap on the number of digits in such extensions.
565            return $extensionPattern . "|"
566                . $autoDiallingExtn . "|"
567                . $onlyCommasExtn;
568        }
569        return $extensionPattern;
570    }
571
572    protected static function initExtnPattern()
573    {
574        static::$EXTN_PATTERN = '/(?:' . static::$EXTN_PATTERNS_FOR_PARSING . ')$/' . static::REGEX_FLAGS;
575    }
576
577    protected static function initValidPhoneNumberPatterns()
578    {
579        static::initExtnPatterns();
580        static::$MIN_LENGTH_PHONE_NUMBER_PATTERN = '[' . static::DIGITS . ']{' . static::MIN_LENGTH_FOR_NSN . '}';
581        static::$VALID_PHONE_NUMBER = '[' . static::PLUS_CHARS . ']*(?:[' . static::VALID_PUNCTUATION . static::STAR_SIGN . ']*[' . static::DIGITS . ']){3,}[' . static::VALID_PUNCTUATION . static::STAR_SIGN . static::VALID_ALPHA . static::DIGITS . ']*';
582        static::$VALID_PHONE_NUMBER_PATTERN = '%^' . static::$MIN_LENGTH_PHONE_NUMBER_PATTERN . '$|^' . static::$VALID_PHONE_NUMBER . '(?:' . static::$EXTN_PATTERNS_FOR_PARSING . ')?$%' . static::REGEX_FLAGS;
583    }
584
585    protected static function initAlphaPhoneMappings()
586    {
587        static::$ALPHA_PHONE_MAPPINGS = static::$ALPHA_MAPPINGS + static::$asciiDigitMappings;
588    }
589
590    protected static function initValidStartCharPattern()
591    {
592        static::$VALID_START_CHAR_PATTERN = '[' . static::PLUS_CHARS . static::DIGITS . ']';
593    }
594
595    protected static function initMobileTokenMappings()
596    {
597        static::$MOBILE_TOKEN_MAPPINGS = array();
598        static::$MOBILE_TOKEN_MAPPINGS['54'] = '9';
599    }
600
601    protected static function initDiallableCharMappings()
602    {
603        static::$DIALLABLE_CHAR_MAPPINGS = static::$asciiDigitMappings;
604        static::$DIALLABLE_CHAR_MAPPINGS[static::PLUS_SIGN] = static::PLUS_SIGN;
605        static::$DIALLABLE_CHAR_MAPPINGS['*'] = '*';
606        static::$DIALLABLE_CHAR_MAPPINGS['#'] = '#';
607    }
608
609    /**
610     * Used for testing purposes only to reset the PhoneNumberUtil singleton to null.
611     */
612    public static function resetInstance()
613    {
614        static::$instance = null;
615    }
616
617    /**
618     * Converts all alpha characters in a number to their respective digits on a keypad, but retains
619     * existing formatting.
620     *
621     * @param string $number
622     * @return string
623     */
624    public static function convertAlphaCharactersInNumber($number)
625    {
626        if (static::$ALPHA_PHONE_MAPPINGS === null) {
627            static::initAlphaPhoneMappings();
628        }
629
630        return static::normalizeHelper($number, static::$ALPHA_PHONE_MAPPINGS, false);
631    }
632
633    /**
634     * Normalizes a string of characters representing a phone number by replacing all characters found
635     * in the accompanying map with the values therein, and stripping all other characters if
636     * removeNonMatches is true.
637     *
638     * @param string $number a string of characters representing a phone number
639     * @param array $normalizationReplacements a mapping of characters to what they should be replaced by in
640     * the normalized version of the phone number.
641     * @param bool $removeNonMatches indicates whether characters that are not able to be replaced.
642     * should be stripped from the number. If this is false, they will be left unchanged in the number.
643     * @return string the normalized string version of the phone number.
644     */
645    protected static function normalizeHelper($number, array $normalizationReplacements, $removeNonMatches)
646    {
647        $normalizedNumber = '';
648        $strLength = mb_strlen($number, 'UTF-8');
649        for ($i = 0; $i < $strLength; $i++) {
650            $character = mb_substr($number, $i, 1, 'UTF-8');
651            if (isset($normalizationReplacements[mb_strtoupper($character, 'UTF-8')])) {
652                $normalizedNumber .= $normalizationReplacements[mb_strtoupper($character, 'UTF-8')];
653            } elseif (!$removeNonMatches) {
654                $normalizedNumber .= $character;
655            }
656            // If neither of the above are true, we remove this character.
657        }
658        return $normalizedNumber;
659    }
660
661    /**
662     * Helper function to check if the national prefix formatting rule has the first group only, i.e.,
663     * does not start with the national prefix.
664     *
665     * @param string $nationalPrefixFormattingRule
666     * @return bool
667     */
668    public static function formattingRuleHasFirstGroupOnly($nationalPrefixFormattingRule)
669    {
670        $firstGroupOnlyPrefixPatternMatcher = new Matcher(
671            static::FIRST_GROUP_ONLY_PREFIX_PATTERN,
672            $nationalPrefixFormattingRule
673        );
674
675        return mb_strlen($nationalPrefixFormattingRule) === 0
676            || $firstGroupOnlyPrefixPatternMatcher->matches();
677    }
678
679    /**
680     * Returns all regions the library has metadata for.
681     *
682     * @return array An unordered array of the two-letter region codes for every geographical region the
683     *  library supports
684     */
685    public function getSupportedRegions()
686    {
687        return $this->supportedRegions;
688    }
689
690    /**
691     * Returns all global network calling codes the library has metadata for.
692     *
693     * @return array An unordered array of the country calling codes for every non-geographical entity
694     *  the library supports
695     */
696    public function getSupportedGlobalNetworkCallingCodes()
697    {
698        return $this->countryCodesForNonGeographicalRegion;
699    }
700
701    /**
702     * Returns all country calling codes the library has metadata for, covering both non-geographical
703     * entities (global network calling codes) and those used for geographical entities. The could be
704     * used to populate a drop-down box of country calling codes for a phone-number widget, for
705     * instance.
706     *
707     * @return array An unordered array of the country calling codes for every geographical and
708     *      non-geographical entity the library supports
709     */
710    public function getSupportedCallingCodes()
711    {
712        return array_keys($this->countryCallingCodeToRegionCodeMap);
713    }
714
715    /**
716     * Returns true if there is any possible number data set for a particular PhoneNumberDesc.
717     *
718     * @param PhoneNumberDesc $desc
719     * @return bool
720     */
721    protected static function descHasPossibleNumberData(PhoneNumberDesc $desc)
722    {
723        // If this is empty, it means numbers of this type inherit from the "general desc" -> the value
724        // '-1' means that no numbers exist for this type.
725        $possibleLength = $desc->getPossibleLength();
726        return count($possibleLength) != 1 || $possibleLength[0] != -1;
727    }
728
729    /**
730     * Returns true if there is any data set for a particular PhoneNumberDesc.
731     *
732     * @param PhoneNumberDesc $desc
733     * @return bool
734     */
735    protected static function descHasData(PhoneNumberDesc $desc)
736    {
737        // Checking most properties since we don't know what's present, since a custom build may have
738        // stripped just one of them (e.g. liteBuild strips exampleNumber). We don't bother checking the
739        // possibleLengthsLocalOnly, since if this is the only thing that's present we don't really
740        // support the type at all: no type-specific methods will work with only this data.
741        return $desc->hasExampleNumber()
742            || static::descHasPossibleNumberData($desc)
743            || $desc->hasNationalNumberPattern();
744    }
745
746    /**
747     * Returns the types we have metadata for based on the PhoneMetadata object passed in.
748     *
749     * @param PhoneMetadata $metadata
750     * @return array
751     */
752    private function getSupportedTypesForMetadata(PhoneMetadata $metadata)
753    {
754        $types = array();
755        foreach (array_keys(PhoneNumberType::values()) as $type) {
756            if ($type === PhoneNumberType::FIXED_LINE_OR_MOBILE || $type === PhoneNumberType::UNKNOWN) {
757                // Never return FIXED_LINE_OR_MOBILE (it is a convenience type, and represents that a
758                // particular number type can't be determined) or UNKNOWN (the non-type).
759                continue;
760            }
761
762            if (self::descHasData($this->getNumberDescByType($metadata, $type))) {
763                $types[] = $type;
764            }
765        }
766
767        return $types;
768    }
769
770    /**
771     * Returns the types for a given region which the library has metadata for. Will not include
772     * FIXED_LINE_OR_MOBILE (if the numbers in this region could be classified as FIXED_LINE_OR_MOBILE,
773     * both FIXED_LINE and MOBILE would be present) and UNKNOWN.
774     *
775     * No types will be returned for invalid or unknown region codes.
776     *
777     * @param string $regionCode
778     * @return array
779     */
780    public function getSupportedTypesForRegion($regionCode)
781    {
782        if (!$this->isValidRegionCode($regionCode)) {
783            return array();
784        }
785        $metadata = $this->getMetadataForRegion($regionCode);
786        return $this->getSupportedTypesForMetadata($metadata);
787    }
788
789    /**
790     * Returns the types for a country-code belonging to a non-geographical entity which the library
791     * has metadata for. Will not include FIXED_LINE_OR_MOBILE (if numbers for this non-geographical
792     * entity could be classified as FIXED_LINE_OR_MOBILE, both FIXED_LINE and MOBILE would be
793     * present) and UNKNOWN.
794     *
795     * @param int $countryCallingCode
796     * @return array
797     */
798    public function getSupportedTypesForNonGeoEntity($countryCallingCode)
799    {
800        $metadata = $this->getMetadataForNonGeographicalRegion($countryCallingCode);
801        if ($metadata === null) {
802            return array();
803        }
804
805        return $this->getSupportedTypesForMetadata($metadata);
806    }
807
808    /**
809     * Gets the length of the geographical area code from the {@code nationalNumber} field of the
810     * PhoneNumber object passed in, so that clients could use it to split a national significant
811     * number into geographical area code and subscriber number. It works in such a way that the
812     * resultant subscriber number should be diallable, at least on some devices. An example of how
813     * this could be used:
814     *
815     * <code>
816     * $phoneUtil = PhoneNumberUtil::getInstance();
817     * $number = $phoneUtil->parse("16502530000", "US");
818     * $nationalSignificantNumber = $phoneUtil->getNationalSignificantNumber($number);
819     *
820     * $areaCodeLength = $phoneUtil->getLengthOfGeographicalAreaCode($number);
821     * if ($areaCodeLength > 0)
822     * {
823     *     $areaCode = substr($nationalSignificantNumber, 0,$areaCodeLength);
824     *     $subscriberNumber = substr($nationalSignificantNumber, $areaCodeLength);
825     * } else {
826     *     $areaCode = "";
827     *     $subscriberNumber = $nationalSignificantNumber;
828     * }
829     * </code>
830     *
831     * N.B.: area code is a very ambiguous concept, so the I18N team generally recommends against
832     * using it for most purposes, but recommends using the more general {@code nationalNumber}
833     * instead. Read the following carefully before deciding to use this method:
834     * <ul>
835     *  <li> geographical area codes change over time, and this method honors those changes;
836     *    therefore, it doesn't guarantee the stability of the result it produces.
837     *  <li> subscriber numbers may not be diallable from all devices (notably mobile devices, which
838     *    typically requires the full national_number to be dialled in most regions).
839     *  <li> most non-geographical numbers have no area codes, including numbers from non-geographical
840     *    entities
841     *  <li> some geographical numbers have no area codes.
842     * </ul>
843     *
844     * @param PhoneNumber $number PhoneNumber object for which clients want to know the length of the area code.
845     * @return int the length of area code of the PhoneNumber object passed in.
846     */
847    public function getLengthOfGeographicalAreaCode(PhoneNumber $number)
848    {
849        $metadata = $this->getMetadataForRegion($this->getRegionCodeForNumber($number));
850        if ($metadata === null) {
851            return 0;
852        }
853        // If a country doesn't use a national prefix, and this number doesn't have an Italian leading
854        // zero, we assume it is a closed dialling plan with no area codes.
855        if (!$metadata->hasNationalPrefix() && !$number->isItalianLeadingZero()) {
856            return 0;
857        }
858
859        $type = $this->getNumberType($number);
860        $countryCallingCode = $number->getCountryCode();
861
862        if ($type === PhoneNumberType::MOBILE
863            // Note this is a rough heuristic; it doesn't cover Indonesia well, for example, where area
864            // codes are present for some mobile phones but not for others. We have no better way of
865            // representing this in the metadata at this point.
866            && in_array($countryCallingCode, self::$GEO_MOBILE_COUNTRIES_WITHOUT_MOBILE_AREA_CODES)
867        ) {
868            return 0;
869        }
870
871        if (!$this->isNumberGeographical($type, $countryCallingCode)) {
872            return 0;
873        }
874
875        return $this->getLengthOfNationalDestinationCode($number);
876    }
877
878    /**
879     * Returns the metadata for the given region code or {@code null} if the region code is invalid
880     * or unknown.
881     *
882     * @param string $regionCode
883     * @return null|PhoneMetadata
884     */
885    public function getMetadataForRegion($regionCode)
886    {
887        if (!$this->isValidRegionCode($regionCode)) {
888            return null;
889        }
890
891        return $this->metadataSource->getMetadataForRegion($regionCode);
892    }
893
894    /**
895     * Helper function to check region code is not unknown or null.
896     *
897     * @param string $regionCode
898     * @return bool
899     */
900    protected function isValidRegionCode($regionCode)
901    {
902        return $regionCode !== null && in_array($regionCode, $this->supportedRegions);
903    }
904
905    /**
906     * Returns the region where a phone number is from. This could be used for geocoding at the region
907     * level. Only guarantees correct results for valid, full numbers (not short-codes, or invalid
908     * numbers).
909     *
910     * @param PhoneNumber $number the phone number whose origin we want to know
911     * @return null|string  the region where the phone number is from, or null if no region matches this calling
912     * code
913     */
914    public function getRegionCodeForNumber(PhoneNumber $number)
915    {
916        $countryCode = $number->getCountryCode();
917        if (!isset($this->countryCallingCodeToRegionCodeMap[$countryCode])) {
918            return null;
919        }
920        $regions = $this->countryCallingCodeToRegionCodeMap[$countryCode];
921        if (count($regions) == 1) {
922            return $regions[0];
923        }
924
925        return $this->getRegionCodeForNumberFromRegionList($number, $regions);
926    }
927
928    /**
929     * Returns the region code for a number from the list of region codes passing in.
930     *
931     * @param PhoneNumber $number
932     * @param array $regionCodes
933     * @return null|string
934     */
935    protected function getRegionCodeForNumberFromRegionList(PhoneNumber $number, array $regionCodes)
936    {
937        $nationalNumber = $this->getNationalSignificantNumber($number);
938        foreach ($regionCodes as $regionCode) {
939            // If leadingDigits is present, use this. Otherwise, do full validation.
940            // Metadata cannot be null because the region codes come from the country calling code map.
941            $metadata = $this->getMetadataForRegion($regionCode);
942            if ($metadata->hasLeadingDigits()) {
943                $nbMatches = preg_match(
944                    '/' . $metadata->getLeadingDigits() . '/',
945                    $nationalNumber,
946                    $matches,
947                    PREG_OFFSET_CAPTURE
948                );
949                if ($nbMatches > 0 && $matches[0][1] === 0) {
950                    return $regionCode;
951                }
952            } elseif ($this->getNumberTypeHelper($nationalNumber, $metadata) != PhoneNumberType::UNKNOWN) {
953                return $regionCode;
954            }
955        }
956        return null;
957    }
958
959    /**
960     * Gets the national significant number of the a phone number. Note a national significant number
961     * doesn't contain a national prefix or any formatting.
962     *
963     * @param PhoneNumber $number the phone number for which the national significant number is needed
964     * @return string the national significant number of the PhoneNumber object passed in
965     */
966    public function getNationalSignificantNumber(PhoneNumber $number)
967    {
968        // If leading zero(s) have been set, we prefix this now. Note this is not a national prefix.
969        $nationalNumber = '';
970        if ($number->isItalianLeadingZero() && $number->getNumberOfLeadingZeros() > 0) {
971            $zeros = str_repeat('0', $number->getNumberOfLeadingZeros());
972            $nationalNumber .= $zeros;
973        }
974        $nationalNumber .= $number->getNationalNumber();
975        return $nationalNumber;
976    }
977
978    /**
979     * Returns the type of number passed in i.e Toll free, premium.
980     *
981     * @param string $nationalNumber
982     * @param PhoneMetadata $metadata
983     * @return int PhoneNumberType constant
984     */
985    protected function getNumberTypeHelper($nationalNumber, PhoneMetadata $metadata)
986    {
987        if (!$this->isNumberMatchingDesc($nationalNumber, $metadata->getGeneralDesc())) {
988            return PhoneNumberType::UNKNOWN;
989        }
990        if ($this->isNumberMatchingDesc($nationalNumber, $metadata->getPremiumRate())) {
991            return PhoneNumberType::PREMIUM_RATE;
992        }
993        if ($this->isNumberMatchingDesc($nationalNumber, $metadata->getTollFree())) {
994            return PhoneNumberType::TOLL_FREE;
995        }
996
997
998        if ($this->isNumberMatchingDesc($nationalNumber, $metadata->getSharedCost())) {
999            return PhoneNumberType::SHARED_COST;
1000        }
1001        if ($this->isNumberMatchingDesc($nationalNumber, $metadata->getVoip())) {
1002            return PhoneNumberType::VOIP;
1003        }
1004        if ($this->isNumberMatchingDesc($nationalNumber, $metadata->getPersonalNumber())) {
1005            return PhoneNumberType::PERSONAL_NUMBER;
1006        }
1007        if ($this->isNumberMatchingDesc($nationalNumber, $metadata->getPager())) {
1008            return PhoneNumberType::PAGER;
1009        }
1010        if ($this->isNumberMatchingDesc($nationalNumber, $metadata->getUan())) {
1011            return PhoneNumberType::UAN;
1012        }
1013        if ($this->isNumberMatchingDesc($nationalNumber, $metadata->getVoicemail())) {
1014            return PhoneNumberType::VOICEMAIL;
1015        }
1016        $isFixedLine = $this->isNumberMatchingDesc($nationalNumber, $metadata->getFixedLine());
1017        if ($isFixedLine) {
1018            if ($metadata->getSameMobileAndFixedLinePattern()) {
1019                return PhoneNumberType::FIXED_LINE_OR_MOBILE;
1020            }
1021
1022            if ($this->isNumberMatchingDesc($nationalNumber, $metadata->getMobile())) {
1023                return PhoneNumberType::FIXED_LINE_OR_MOBILE;
1024            }
1025            return PhoneNumberType::FIXED_LINE;
1026        }
1027        // Otherwise, test to see if the number is mobile. Only do this if certain that the patterns for
1028        // mobile and fixed line aren't the same.
1029        if (!$metadata->getSameMobileAndFixedLinePattern() &&
1030            $this->isNumberMatchingDesc($nationalNumber, $metadata->getMobile())
1031        ) {
1032            return PhoneNumberType::MOBILE;
1033        }
1034        return PhoneNumberType::UNKNOWN;
1035    }
1036
1037    /**
1038     * @param string $nationalNumber
1039     * @param PhoneNumberDesc $numberDesc
1040     * @return bool
1041     */
1042    public function isNumberMatchingDesc($nationalNumber, PhoneNumberDesc $numberDesc)
1043    {
1044        // Check if any possible number lengths are present; if so, we use them to avoid checking the
1045        // validation pattern if they don't match. If they are absent, this means they match the general
1046        // description, which we have already checked before checking a specific number type.
1047        $actualLength = mb_strlen($nationalNumber);
1048        $possibleLengths = $numberDesc->getPossibleLength();
1049        if (count($possibleLengths) > 0 && !in_array($actualLength, $possibleLengths)) {
1050            return false;
1051        }
1052
1053        return $this->matcherAPI->matchNationalNumber($nationalNumber, $numberDesc, false);
1054    }
1055
1056    /**
1057     * isNumberGeographical(PhoneNumber)
1058     *
1059     * Tests whether a phone number has a geographical association. It checks if the number is
1060     * associated with a certain region in the country to which it belongs. Note that this doesn't
1061     * verify if the number is actually in use.
1062     *
1063     * isNumberGeographical(PhoneNumberType, $countryCallingCode)
1064     *
1065     * Tests whether a phone number has a geographical association, as represented by its type and the
1066     * country it belongs to.
1067     *
1068     * This version exists since calculating the phone number type is expensive; if we have already
1069     * done this, we don't want to do it again.
1070     *
1071     * @param PhoneNumber|int $phoneNumberObjOrType A PhoneNumber object, or a PhoneNumberType integer
1072     * @param int|null $countryCallingCode Used when passing a PhoneNumberType
1073     * @return bool
1074     */
1075    public function isNumberGeographical($phoneNumberObjOrType, $countryCallingCode = null)
1076    {
1077        if ($phoneNumberObjOrType instanceof PhoneNumber) {
1078            return $this->isNumberGeographical($this->getNumberType($phoneNumberObjOrType), $phoneNumberObjOrType->getCountryCode());
1079        }
1080
1081        return $phoneNumberObjOrType == PhoneNumberType::FIXED_LINE
1082        || $phoneNumberObjOrType == PhoneNumberType::FIXED_LINE_OR_MOBILE
1083        || (in_array($countryCallingCode, static::$GEO_MOBILE_COUNTRIES)
1084            && $phoneNumberObjOrType == PhoneNumberType::MOBILE);
1085    }
1086
1087    /**
1088     * Gets the type of a valid phone number.
1089     *
1090     * @param PhoneNumber $number the number the phone number that we want to know the type
1091     * @return int PhoneNumberType the type of the phone number, or UNKNOWN if it is invalid
1092     */
1093    public function getNumberType(PhoneNumber $number)
1094    {
1095        $regionCode = $this->getRegionCodeForNumber($number);
1096        $metadata = $this->getMetadataForRegionOrCallingCode($number->getCountryCode(), $regionCode);
1097        if ($metadata === null) {
1098            return PhoneNumberType::UNKNOWN;
1099        }
1100        $nationalSignificantNumber = $this->getNationalSignificantNumber($number);
1101        return $this->getNumberTypeHelper($nationalSignificantNumber, $metadata);
1102    }
1103
1104    /**
1105     * @param int $countryCallingCode
1106     * @param string $regionCode
1107     * @return null|PhoneMetadata
1108     */
1109    protected function getMetadataForRegionOrCallingCode($countryCallingCode, $regionCode)
1110    {
1111        return static::REGION_CODE_FOR_NON_GEO_ENTITY === $regionCode ?
1112            $this->getMetadataForNonGeographicalRegion($countryCallingCode) : $this->getMetadataForRegion($regionCode);
1113    }
1114
1115    /**
1116     * @param int $countryCallingCode
1117     * @return null|PhoneMetadata
1118     */
1119    public function getMetadataForNonGeographicalRegion($countryCallingCode)
1120    {
1121        if (!isset($this->countryCallingCodeToRegionCodeMap[$countryCallingCode])) {
1122            return null;
1123        }
1124        return $this->metadataSource->getMetadataForNonGeographicalRegion($countryCallingCode);
1125    }
1126
1127    /**
1128     * Gets the length of the national destination code (NDC) from the PhoneNumber object passed in,
1129     * so that clients could use it to split a national significant number into NDC and subscriber
1130     * number. The NDC of a phone number is normally the first group of digit(s) right after the
1131     * country calling code when the number is formatted in the international format, if there is a
1132     * subscriber number part that follows.
1133     *
1134     * follows.
1135     *
1136     * N.B.: similar to an area code, not all numbers have an NDC!
1137     *
1138     * An example of how this could be used:
1139     *
1140     * <code>
1141     * $phoneUtil = PhoneNumberUtil::getInstance();
1142     * $number = $phoneUtil->parse("18002530000", "US");
1143     * $nationalSignificantNumber = $phoneUtil->getNationalSignificantNumber($number);
1144     *
1145     * $nationalDestinationCodeLength = $phoneUtil->getLengthOfNationalDestinationCode($number);
1146     * if ($nationalDestinationCodeLength > 0) {
1147     *     $nationalDestinationCode = substr($nationalSignificantNumber, 0, $nationalDestinationCodeLength);
1148     *     $subscriberNumber = substr($nationalSignificantNumber, $nationalDestinationCodeLength);
1149     * } else {
1150     *     $nationalDestinationCode = "";
1151     *     $subscriberNumber = $nationalSignificantNumber;
1152     * }
1153     * </code>
1154     *
1155     * Refer to the unit tests to see the difference between this function and
1156     * {@link #getLengthOfGeographicalAreaCode}.
1157     *
1158     * @param PhoneNumber $number the PhoneNumber object for which clients want to know the length of the NDC.
1159     * @return int the length of NDC of the PhoneNumber object passed in, which could be zero
1160     */
1161    public function getLengthOfNationalDestinationCode(PhoneNumber $number)
1162    {
1163        if ($number->hasExtension()) {
1164            // We don't want to alter the proto given to us, but we don't want to include the extension
1165            // when we format it, so we copy it and clear the extension here.
1166            $copiedProto = new PhoneNumber();
1167            $copiedProto->mergeFrom($number);
1168            $copiedProto->clearExtension();
1169        } else {
1170            $copiedProto = clone $number;
1171        }
1172
1173        $nationalSignificantNumber = $this->format($copiedProto, PhoneNumberFormat::INTERNATIONAL);
1174
1175        $numberGroups = preg_split('/' . static::NON_DIGITS_PATTERN . '/', $nationalSignificantNumber);
1176
1177        // The pattern will start with "+COUNTRY_CODE " so the first group will always be the empty
1178        // string (before the + symbol) and the second group will be the country calling code. The third
1179        // group will be area code if it is not the last group.
1180        if (count($numberGroups) <= 3) {
1181            return 0;
1182        }
1183
1184        if ($this->getNumberType($number) == PhoneNumberType::MOBILE) {
1185            // For example Argentinian mobile numbers, when formatted in the international format, are in
1186            // the form of +54 9 NDC XXXX.... As a result, we take the length of the third group (NDC) and
1187            // add the length of the second group (which is the mobile token), which also forms part of
1188            // the national significant number. This assumes that the mobile token is always formatted
1189            // separately from the rest of the phone number.
1190
1191            $mobileToken = static::getCountryMobileToken($number->getCountryCode());
1192            if ($mobileToken !== '') {
1193                return mb_strlen($numberGroups[2]) + mb_strlen($numberGroups[3]);
1194            }
1195        }
1196        return mb_strlen($numberGroups[2]);
1197    }
1198
1199    /**
1200     * Formats a phone number in the specified format using default rules. Note that this does not
1201     * promise to produce a phone number that the user can dial from where they are - although we do
1202     * format in either 'national' or 'international' format depending on what the client asks for, we
1203     * do not currently support a more abbreviated format, such as for users in the same "area" who
1204     * could potentially dial the number without area code. Note that if the phone number has a
1205     * country calling code of 0 or an otherwise invalid country calling code, we cannot work out
1206     * which formatting rules to apply so we return the national significant number with no formatting
1207     * applied.
1208     *
1209     * @param PhoneNumber $number the phone number to be formatted
1210     * @param int $numberFormat the PhoneNumberFormat the phone number should be formatted into
1211     * @return string the formatted phone number
1212     */
1213    public function format(PhoneNumber $number, $numberFormat)
1214    {
1215        if ($number->getNationalNumber() == 0 && $number->hasRawInput()) {
1216            // Unparseable numbers that kept their raw input just use that.
1217            // This is the only case where a number can be formatted as E164 without a
1218            // leading '+' symbol (but the original number wasn't parseable anyway).
1219            // TODO: Consider removing the 'if' above so that unparseable
1220            // strings without raw input format to the empty string instead of "+00"
1221            $rawInput = $number->getRawInput();
1222            if (mb_strlen($rawInput) > 0) {
1223                return $rawInput;
1224            }
1225        }
1226
1227        $formattedNumber = '';
1228        $countryCallingCode = $number->getCountryCode();
1229        $nationalSignificantNumber = $this->getNationalSignificantNumber($number);
1230
1231        if ($numberFormat == PhoneNumberFormat::E164) {
1232            // Early exit for E164 case (even if the country calling code is invalid) since no formatting
1233            // of the national number needs to be applied. Extensions are not formatted.
1234            $formattedNumber .= $nationalSignificantNumber;
1235            $this->prefixNumberWithCountryCallingCode($countryCallingCode, PhoneNumberFormat::E164, $formattedNumber);
1236            return $formattedNumber;
1237        }
1238
1239        if (!$this->hasValidCountryCallingCode($countryCallingCode)) {
1240            $formattedNumber .= $nationalSignificantNumber;
1241            return $formattedNumber;
1242        }
1243
1244        // Note getRegionCodeForCountryCode() is used because formatting information for regions which
1245        // share a country calling code is contained by only one region for performance reasons. For
1246        // example, for NANPA regions it will be contained in the metadata for US.
1247        $regionCode = $this->getRegionCodeForCountryCode($countryCallingCode);
1248        // Metadata cannot be null because the country calling code is valid (which means that the
1249        // region code cannot be ZZ and must be one of our supported region codes).
1250        $metadata = $this->getMetadataForRegionOrCallingCode($countryCallingCode, $regionCode);
1251        $formattedNumber .= $this->formatNsn($nationalSignificantNumber, $metadata, $numberFormat);
1252        $this->maybeAppendFormattedExtension($number, $metadata, $numberFormat, $formattedNumber);
1253        $this->prefixNumberWithCountryCallingCode($countryCallingCode, $numberFormat, $formattedNumber);
1254        return $formattedNumber;
1255    }
1256
1257    /**
1258     * A helper function that is used by format and formatByPattern.
1259     * @param int $countryCallingCode
1260     * @param int $numberFormat PhoneNumberFormat
1261     * @param string $formattedNumber
1262     */
1263    protected function prefixNumberWithCountryCallingCode($countryCallingCode, $numberFormat, &$formattedNumber)
1264    {
1265        switch ($numberFormat) {
1266            case PhoneNumberFormat::E164:
1267                $formattedNumber = static::PLUS_SIGN . $countryCallingCode . $formattedNumber;
1268                return;
1269            case PhoneNumberFormat::INTERNATIONAL:
1270                $formattedNumber = static::PLUS_SIGN . $countryCallingCode . ' ' . $formattedNumber;
1271                return;
1272            case PhoneNumberFormat::RFC3966:
1273                $formattedNumber = static::RFC3966_PREFIX . static::PLUS_SIGN . $countryCallingCode . '-' . $formattedNumber;
1274                return;
1275            case PhoneNumberFormat::NATIONAL:
1276            default:
1277                return;
1278        }
1279    }
1280
1281    /**
1282     * Helper function to check the country calling code is valid.
1283     * @param int $countryCallingCode
1284     * @return bool
1285     */
1286    protected function hasValidCountryCallingCode($countryCallingCode)
1287    {
1288        return isset($this->countryCallingCodeToRegionCodeMap[$countryCallingCode]);
1289    }
1290
1291    /**
1292     * Returns the region code that matches the specific country calling code. In the case of no
1293     * region code being found, ZZ will be returned. In the case of multiple regions, the one
1294     * designated in the metadata as the "main" region for this calling code will be returned. If the
1295     * countryCallingCode entered is valid but doesn't match a specific region (such as in the case of
1296     * non-geographical calling codes like 800) the value "001" will be returned (corresponding to
1297     * the value for World in the UN M.49 schema).
1298     *
1299     * @param int $countryCallingCode
1300     * @return string
1301     */
1302    public function getRegionCodeForCountryCode($countryCallingCode)
1303    {
1304        $regionCodes = isset($this->countryCallingCodeToRegionCodeMap[$countryCallingCode]) ? $this->countryCallingCodeToRegionCodeMap[$countryCallingCode] : null;
1305        return $regionCodes === null ? static::UNKNOWN_REGION : $regionCodes[0];
1306    }
1307
1308    /**
1309     * Note in some regions, the national number can be written in two completely different ways
1310     * depending on whether it forms part of the NATIONAL format or INTERNATIONAL format. The
1311     * numberFormat parameter here is used to specify which format to use for those cases. If a
1312     * carrierCode is specified, this will be inserted into the formatted string to replace $CC.
1313     * @param string $number
1314     * @param PhoneMetadata $metadata
1315     * @param int $numberFormat PhoneNumberFormat
1316     * @param null|string $carrierCode
1317     * @return string
1318     */
1319    protected function formatNsn($number, PhoneMetadata $metadata, $numberFormat, $carrierCode = null)
1320    {
1321        $intlNumberFormats = $metadata->intlNumberFormats();
1322        // When the intlNumberFormats exists, we use that to format national number for the
1323        // INTERNATIONAL format instead of using the numberDesc.numberFormats.
1324        $availableFormats = (count($intlNumberFormats) == 0 || $numberFormat == PhoneNumberFormat::NATIONAL)
1325            ? $metadata->numberFormats()
1326            : $metadata->intlNumberFormats();
1327        $formattingPattern = $this->chooseFormattingPatternForNumber($availableFormats, $number);
1328        return ($formattingPattern === null)
1329            ? $number
1330            : $this->formatNsnUsingPattern($number, $formattingPattern, $numberFormat, $carrierCode);
1331    }
1332
1333    /**
1334     * @param NumberFormat[] $availableFormats
1335     * @param string $nationalNumber
1336     * @return NumberFormat|null
1337     */
1338    public function chooseFormattingPatternForNumber(array $availableFormats, $nationalNumber)
1339    {
1340        foreach ($availableFormats as $numFormat) {
1341            $leadingDigitsPatternMatcher = null;
1342            $size = $numFormat->leadingDigitsPatternSize();
1343            // We always use the last leading_digits_pattern, as it is the most detailed.
1344            if ($size > 0) {
1345                $leadingDigitsPatternMatcher = new Matcher(
1346                    $numFormat->getLeadingDigitsPattern($size - 1),
1347                    $nationalNumber
1348                );
1349            }
1350            if ($size == 0 || $leadingDigitsPatternMatcher->lookingAt()) {
1351                $m = new Matcher($numFormat->getPattern(), $nationalNumber);
1352                if ($m->matches() > 0) {
1353                    return $numFormat;
1354                }
1355            }
1356        }
1357        return null;
1358    }
1359
1360    /**
1361     * Note that carrierCode is optional - if null or an empty string, no carrier code replacement
1362     * will take place.
1363     * @param string $nationalNumber
1364     * @param NumberFormat $formattingPattern
1365     * @param int $numberFormat PhoneNumberFormat
1366     * @param null|string $carrierCode
1367     * @return string
1368     */
1369    public function formatNsnUsingPattern(
1370        $nationalNumber,
1371        NumberFormat $formattingPattern,
1372        $numberFormat,
1373        $carrierCode = null
1374    ) {
1375        $numberFormatRule = $formattingPattern->getFormat();
1376        $m = new Matcher($formattingPattern->getPattern(), $nationalNumber);
1377        if ($numberFormat === PhoneNumberFormat::NATIONAL &&
1378            $carrierCode !== null && mb_strlen($carrierCode) > 0 &&
1379            mb_strlen($formattingPattern->getDomesticCarrierCodeFormattingRule()) > 0
1380        ) {
1381            // Replace the $CC in the formatting rule with the desired carrier code.
1382            $carrierCodeFormattingRule = $formattingPattern->getDomesticCarrierCodeFormattingRule();
1383            $carrierCodeFormattingRule = str_replace(static::CC_STRING, $carrierCode, $carrierCodeFormattingRule);
1384            // Now replace the $FG in the formatting rule with the first group and the carrier code
1385            // combined in the appropriate way.
1386            $firstGroupMatcher = new Matcher(static::FIRST_GROUP_PATTERN, $numberFormatRule);
1387            $numberFormatRule = $firstGroupMatcher->replaceFirst($carrierCodeFormattingRule);
1388            $formattedNationalNumber = $m->replaceAll($numberFormatRule);
1389        } else {
1390            // Use the national prefix formatting rule instead.
1391            $nationalPrefixFormattingRule = $formattingPattern->getNationalPrefixFormattingRule();
1392            if ($numberFormat == PhoneNumberFormat::NATIONAL &&
1393                $nationalPrefixFormattingRule !== null &&
1394                mb_strlen($nationalPrefixFormattingRule) > 0
1395            ) {
1396                $firstGroupMatcher = new Matcher(static::FIRST_GROUP_PATTERN, $numberFormatRule);
1397                $formattedNationalNumber = $m->replaceAll(
1398                    $firstGroupMatcher->replaceFirst($nationalPrefixFormattingRule)
1399                );
1400            } else {
1401                $formattedNationalNumber = $m->replaceAll($numberFormatRule);
1402            }
1403        }
1404        if ($numberFormat == PhoneNumberFormat::RFC3966) {
1405            // Strip any leading punctuation.
1406            $matcher = new Matcher(static::$SEPARATOR_PATTERN, $formattedNationalNumber);
1407            if ($matcher->lookingAt()) {
1408                $formattedNationalNumber = $matcher->replaceFirst('');
1409            }
1410            // Replace the rest with a dash between each number group.
1411            $formattedNationalNumber = $matcher->reset($formattedNationalNumber)->replaceAll('-');
1412        }
1413        return $formattedNationalNumber;
1414    }
1415
1416    /**
1417     * Appends the formatted extension of a phone number to formattedNumber, if the phone number had
1418     * an extension specified.
1419     *
1420     * @param PhoneNumber $number
1421     * @param PhoneMetadata|null $metadata
1422     * @param int $numberFormat PhoneNumberFormat
1423     * @param string $formattedNumber
1424     */
1425    protected function maybeAppendFormattedExtension(PhoneNumber $number, $metadata, $numberFormat, &$formattedNumber)
1426    {
1427        if ($number->hasExtension() && mb_strlen($number->getExtension()) > 0) {
1428            if ($numberFormat === PhoneNumberFormat::RFC3966) {
1429                $formattedNumber .= static::RFC3966_EXTN_PREFIX . $number->getExtension();
1430            } elseif (!empty($metadata) && $metadata->hasPreferredExtnPrefix()) {
1431                $formattedNumber .= $metadata->getPreferredExtnPrefix() . $number->getExtension();
1432            } else {
1433                $formattedNumber .= static::DEFAULT_EXTN_PREFIX . $number->getExtension();
1434            }
1435        }
1436    }
1437
1438    /**
1439     * Returns the mobile token for the provided country calling code if it has one, otherwise
1440     * returns an empty string. A mobile token is a number inserted before the area code when dialing
1441     * a mobile number from that country from abroad.
1442     *
1443     * @param int $countryCallingCode the country calling code for which we want the mobile token
1444     * @return string the mobile token, as a string, for the given country calling code
1445     */
1446    public static function getCountryMobileToken($countryCallingCode)
1447    {
1448        if (count(static::$MOBILE_TOKEN_MAPPINGS) === 0) {
1449            static::initMobileTokenMappings();
1450        }
1451
1452        if (array_key_exists($countryCallingCode, static::$MOBILE_TOKEN_MAPPINGS)) {
1453            return static::$MOBILE_TOKEN_MAPPINGS[$countryCallingCode];
1454        }
1455        return '';
1456    }
1457
1458    /**
1459     * Checks if the number is a valid vanity (alpha) number such as 800 MICROSOFT. A valid vanity
1460     * number will start with at least 3 digits and will have three or more alpha characters. This
1461     * does not do region-specific checks - to work out if this number is actually valid for a region,
1462     * it should be parsed and methods such as {@link #isPossibleNumberWithReason} and
1463     * {@link #isValidNumber} should be used.
1464     *
1465     * @param string $number the number that needs to be checked
1466     * @return bool true if the number is a valid vanity number
1467     */
1468    public function isAlphaNumber($number)
1469    {
1470        if (!static::isViablePhoneNumber($number)) {
1471            // Number is too short, or doesn't match the basic phone number pattern.
1472            return false;
1473        }
1474        $this->maybeStripExtension($number);
1475        return (bool)preg_match('/' . static::VALID_ALPHA_PHONE_PATTERN . '/' . static::REGEX_FLAGS, $number);
1476    }
1477
1478    /**
1479     * Checks to see if the string of characters could possibly be a phone number at all. At the
1480     * moment, checks to see that the string begins with at least 2 digits, ignoring any punctuation
1481     * commonly found in phone numbers.
1482     * This method does not require the number to be normalized in advance - but does assume that
1483     * leading non-number symbols have been removed, such as by the method extractPossibleNumber.
1484     *
1485     * @param string $number to be checked for viability as a phone number
1486     * @return boolean true if the number could be a phone number of some sort, otherwise false
1487     */
1488    public static function isViablePhoneNumber($number)
1489    {
1490        if (static::$VALID_PHONE_NUMBER_PATTERN === null) {
1491            static::initValidPhoneNumberPatterns();
1492        }
1493
1494        if (mb_strlen($number) < static::MIN_LENGTH_FOR_NSN) {
1495            return false;
1496        }
1497
1498        $validPhoneNumberPattern = static::getValidPhoneNumberPattern();
1499
1500        $m = preg_match($validPhoneNumberPattern, $number);
1501        return $m > 0;
1502    }
1503
1504    /**
1505     * We append optionally the extension pattern to the end here, as a valid phone number may
1506     * have an extension prefix appended, followed by 1 or more digits.
1507     * @return string
1508     */
1509    protected static function getValidPhoneNumberPattern()
1510    {
1511        return static::$VALID_PHONE_NUMBER_PATTERN;
1512    }
1513
1514    /**
1515     * Strips any extension (as in, the part of the number dialled after the call is connected,
1516     * usually indicated with extn, ext, x or similar) from the end of the number, and returns it.
1517     *
1518     * @param string $number the non-normalized telephone number that we wish to strip the extension from
1519     * @return string the phone extension
1520     */
1521    protected function maybeStripExtension(&$number)
1522    {
1523        $matches = array();
1524        $find = preg_match(static::$EXTN_PATTERN, $number, $matches, PREG_OFFSET_CAPTURE);
1525        // If we find a potential extension, and the number preceding this is a viable number, we assume
1526        // it is an extension.
1527        if ($find > 0 && static::isViablePhoneNumber(substr($number, 0, $matches[0][1]))) {
1528            // The numbers are captured into groups in the regular expression.
1529
1530            for ($i = 1, $length = count($matches); $i <= $length; $i++) {
1531                if ($matches[$i][0] != '') {
1532                    // We go through the capturing groups until we find one that captured some digits. If none
1533                    // did, then we will return the empty string.
1534                    $extension = $matches[$i][0];
1535                    $number = substr($number, 0, $matches[0][1]);
1536                    return $extension;
1537                }
1538            }
1539        }
1540        return '';
1541    }
1542
1543    /**
1544     * Parses a string and returns it in proto buffer format. This method differs from {@link #parse}
1545     * in that it always populates the raw_input field of the protocol buffer with numberToParse as
1546     * well as the country_code_source field.
1547     *
1548     * @param string $numberToParse number that we are attempting to parse. This can contain formatting
1549     *                                  such as +, ( and -, as well as a phone number extension. It can also
1550     *                                  be provided in RFC3966 format.
1551     * @param string $defaultRegion region that we are expecting the number to be from. This is only used
1552     *                                  if the number being parsed is not written in international format.
1553     *                                  The country calling code for the number in this case would be stored
1554     *                                  as that of the default region supplied.
1555     * @param PhoneNumber $phoneNumber
1556     * @return PhoneNumber              a phone number proto buffer filled with the parsed number
1557     */
1558    public function parseAndKeepRawInput($numberToParse, $defaultRegion, PhoneNumber $phoneNumber = null)
1559    {
1560        if ($phoneNumber === null) {
1561            $phoneNumber = new PhoneNumber();
1562        }
1563        $this->parseHelper($numberToParse, $defaultRegion, true, true, $phoneNumber);
1564        return $phoneNumber;
1565    }
1566
1567    /**
1568     * Returns an iterable over all PhoneNumberMatches in $text
1569     *
1570     * @param string $text
1571     * @param string $defaultRegion
1572     * @param AbstractLeniency $leniency Defaults to Leniency::VALID()
1573     * @param int $maxTries Defaults to PHP_INT_MAX
1574     * @return PhoneNumberMatcher
1575     */
1576    public function findNumbers($text, $defaultRegion, AbstractLeniency $leniency = null, $maxTries = PHP_INT_MAX)
1577    {
1578        if ($leniency === null) {
1579            $leniency = Leniency::VALID();
1580        }
1581
1582        return new PhoneNumberMatcher($this, $text, $defaultRegion, $leniency, $maxTries);
1583    }
1584
1585    /**
1586     * Gets an AsYouTypeFormatter for the specific region.
1587     *
1588     * @param string $regionCode The region where the phone number is being entered.
1589     * @return AsYouTypeFormatter
1590     */
1591    public function getAsYouTypeFormatter($regionCode)
1592    {
1593        return new AsYouTypeFormatter($regionCode);
1594    }
1595
1596    /**
1597     * A helper function to set the values related to leading zeros in a PhoneNumber.
1598     * @param string $nationalNumber
1599     * @param PhoneNumber $phoneNumber
1600     */
1601    public static function setItalianLeadingZerosForPhoneNumber($nationalNumber, PhoneNumber $phoneNumber)
1602    {
1603        if (strlen($nationalNumber) > 1 && substr($nationalNumber, 0, 1) == '0') {
1604            $phoneNumber->setItalianLeadingZero(true);
1605            $numberOfLeadingZeros = 1;
1606            // Note that if the national number is all "0"s, the last "0" is not counted as a leading
1607            // zero.
1608            while ($numberOfLeadingZeros < (strlen($nationalNumber) - 1) &&
1609                substr($nationalNumber, $numberOfLeadingZeros, 1) == '0') {
1610                $numberOfLeadingZeros++;
1611            }
1612
1613            if ($numberOfLeadingZeros != 1) {
1614                $phoneNumber->setNumberOfLeadingZeros($numberOfLeadingZeros);
1615            }
1616        }
1617    }
1618
1619    /**
1620     * Parses a string and fills up the phoneNumber. This method is the same as the public
1621     * parse() method, with the exception that it allows the default region to be null, for use by
1622     * isNumberMatch(). checkRegion should be set to false if it is permitted for the default region
1623     * to be null or unknown ("ZZ").
1624     * @param string $numberToParse
1625     * @param string $defaultRegion
1626     * @param bool $keepRawInput
1627     * @param bool $checkRegion
1628     * @param PhoneNumber $phoneNumber
1629     * @throws NumberParseException
1630     */
1631    protected function parseHelper($numberToParse, $defaultRegion, $keepRawInput, $checkRegion, PhoneNumber $phoneNumber)
1632    {
1633        if ($numberToParse === null) {
1634            throw new NumberParseException(NumberParseException::NOT_A_NUMBER, 'The phone number supplied was null.');
1635        }
1636
1637        $numberToParse = trim($numberToParse);
1638
1639        if (mb_strlen($numberToParse) > static::MAX_INPUT_STRING_LENGTH) {
1640            throw new NumberParseException(
1641                NumberParseException::TOO_LONG,
1642                'The string supplied was too long to parse.'
1643            );
1644        }
1645
1646        $nationalNumber = '';
1647        $this->buildNationalNumberForParsing($numberToParse, $nationalNumber);
1648
1649        if (!static::isViablePhoneNumber($nationalNumber)) {
1650            throw new NumberParseException(
1651                NumberParseException::NOT_A_NUMBER,
1652                'The string supplied did not seem to be a phone number.'
1653            );
1654        }
1655
1656        // Check the region supplied is valid, or that the extracted number starts with some sort of +
1657        // sign so the number's region can be determined.
1658        if ($checkRegion && !$this->checkRegionForParsing($nationalNumber, $defaultRegion)) {
1659            throw new NumberParseException(
1660                NumberParseException::INVALID_COUNTRY_CODE,
1661                'Missing or invalid default region.'
1662            );
1663        }
1664
1665        if ($keepRawInput) {
1666            $phoneNumber->setRawInput($numberToParse);
1667        }
1668        // Attempt to parse extension first, since it doesn't require region-specific data and we want
1669        // to have the non-normalised number here.
1670        $extension = $this->maybeStripExtension($nationalNumber);
1671        if (mb_strlen($extension) > 0) {
1672            $phoneNumber->setExtension($extension);
1673        }
1674
1675        $regionMetadata = $this->getMetadataForRegion($defaultRegion);
1676        // Check to see if the number is given in international format so we know whether this number is
1677        // from the default region or not.
1678        $normalizedNationalNumber = '';
1679        try {
1680            // TODO: This method should really just take in the string buffer that has already
1681            // been created, and just remove the prefix, rather than taking in a string and then
1682            // outputting a string buffer.
1683            $countryCode = $this->maybeExtractCountryCode(
1684                $nationalNumber,
1685                $regionMetadata,
1686                $normalizedNationalNumber,
1687                $keepRawInput,
1688                $phoneNumber
1689            );
1690        } catch (NumberParseException $e) {
1691            $matcher = new Matcher(static::$PLUS_CHARS_PATTERN, $nationalNumber);
1692            if ($e->getErrorType() == NumberParseException::INVALID_COUNTRY_CODE && $matcher->lookingAt()) {
1693                // Strip the plus-char, and try again.
1694                $countryCode = $this->maybeExtractCountryCode(
1695                    substr($nationalNumber, $matcher->end()),
1696                    $regionMetadata,
1697                    $normalizedNationalNumber,
1698                    $keepRawInput,
1699                    $phoneNumber
1700                );
1701                if ($countryCode == 0) {
1702                    throw new NumberParseException(
1703                        NumberParseException::INVALID_COUNTRY_CODE,
1704                        'Could not interpret numbers after plus-sign.'
1705                    );
1706                }
1707            } else {
1708                throw new NumberParseException($e->getErrorType(), $e->getMessage(), $e);
1709            }
1710        }
1711        if ($countryCode !== 0) {
1712            $phoneNumberRegion = $this->getRegionCodeForCountryCode($countryCode);
1713            if ($phoneNumberRegion != $defaultRegion) {
1714                // Metadata cannot be null because the country calling code is valid.
1715                $regionMetadata = $this->getMetadataForRegionOrCallingCode($countryCode, $phoneNumberRegion);
1716            }
1717        } else {
1718            // If no extracted country calling code, use the region supplied instead. The national number
1719            // is just the normalized version of the number we were given to parse.
1720
1721            $normalizedNationalNumber .= static::normalize($nationalNumber);
1722            if ($defaultRegion !== null) {
1723                $countryCode = $regionMetadata->getCountryCode();
1724                $phoneNumber->setCountryCode($countryCode);
1725            } elseif ($keepRawInput) {
1726                $phoneNumber->clearCountryCodeSource();
1727            }
1728        }
1729        if (mb_strlen($normalizedNationalNumber) < static::MIN_LENGTH_FOR_NSN) {
1730            throw new NumberParseException(
1731                NumberParseException::TOO_SHORT_NSN,
1732                'The string supplied is too short to be a phone number.'
1733            );
1734        }
1735        if ($regionMetadata !== null) {
1736            $carrierCode = '';
1737            $potentialNationalNumber = $normalizedNationalNumber;
1738            $this->maybeStripNationalPrefixAndCarrierCode($potentialNationalNumber, $regionMetadata, $carrierCode);
1739            // We require that the NSN remaining after stripping the national prefix and carrier code be
1740            // long enough to be a possible length for the region. Otherwise, we don't do the stripping,
1741            // since the original number could be a valid short number.
1742            $validationResult = $this->testNumberLength($potentialNationalNumber, $regionMetadata);
1743            if ($validationResult !== ValidationResult::TOO_SHORT
1744                && $validationResult !== ValidationResult::IS_POSSIBLE_LOCAL_ONLY
1745                && $validationResult !== ValidationResult::INVALID_LENGTH) {
1746                $normalizedNationalNumber = $potentialNationalNumber;
1747                if ($keepRawInput && mb_strlen($carrierCode) > 0) {
1748                    $phoneNumber->setPreferredDomesticCarrierCode($carrierCode);
1749                }
1750            }
1751        }
1752        $lengthOfNationalNumber = mb_strlen($normalizedNationalNumber);
1753        if ($lengthOfNationalNumber < static::MIN_LENGTH_FOR_NSN) {
1754            throw new NumberParseException(
1755                NumberParseException::TOO_SHORT_NSN,
1756                'The string supplied is too short to be a phone number.'
1757            );
1758        }
1759        if ($lengthOfNationalNumber > static::MAX_LENGTH_FOR_NSN) {
1760            throw new NumberParseException(
1761                NumberParseException::TOO_LONG,
1762                'The string supplied is too long to be a phone number.'
1763            );
1764        }
1765        static::setItalianLeadingZerosForPhoneNumber($normalizedNationalNumber, $phoneNumber);
1766
1767        /*
1768         * We have to store the National Number as a string instead of a "long" as Google do
1769         *
1770         * Since PHP doesn't always support 64 bit INTs, this was a float, but that had issues
1771         * with long numbers.
1772         *
1773         * We have to remove the leading zeroes ourself though
1774         */
1775        if ((int)$normalizedNationalNumber == 0) {
1776            $normalizedNationalNumber = '0';
1777        } else {
1778            $normalizedNationalNumber = ltrim($normalizedNationalNumber, '0');
1779        }
1780
1781        $phoneNumber->setNationalNumber($normalizedNationalNumber);
1782    }
1783
1784    /**
1785     * Returns a new phone number containing only the fields needed to uniquely identify a phone
1786     * number, rather than any fields that capture the context in which  the phone number was created.
1787     * These fields correspond to those set in parse() rather than parseAndKeepRawInput()
1788     *
1789     * @param PhoneNumber $phoneNumberIn
1790     * @return PhoneNumber
1791     */
1792    protected static function copyCoreFieldsOnly(PhoneNumber $phoneNumberIn)
1793    {
1794        $phoneNumber = new PhoneNumber();
1795        $phoneNumber->setCountryCode($phoneNumberIn->getCountryCode());
1796        $phoneNumber->setNationalNumber($phoneNumberIn->getNationalNumber());
1797        if (mb_strlen($phoneNumberIn->getExtension()) > 0) {
1798            $phoneNumber->setExtension($phoneNumberIn->getExtension());
1799        }
1800        if ($phoneNumberIn->isItalianLeadingZero()) {
1801            $phoneNumber->setItalianLeadingZero(true);
1802            // This field is only relevant if there are leading zeros at all.
1803            $phoneNumber->setNumberOfLeadingZeros($phoneNumberIn->getNumberOfLeadingZeros());
1804        }
1805        return $phoneNumber;
1806    }
1807
1808    /**
1809     * Converts numberToParse to a form that we can parse and write it to nationalNumber if it is
1810     * written in RFC3966; otherwise extract a possible number out of it and write to nationalNumber.
1811     * @param string $numberToParse
1812     * @param string $nationalNumber
1813     */
1814    protected function buildNationalNumberForParsing($numberToParse, &$nationalNumber)
1815    {
1816        $indexOfPhoneContext = strpos($numberToParse, static::RFC3966_PHONE_CONTEXT);
1817        if ($indexOfPhoneContext !== false) {
1818            $phoneContextStart = $indexOfPhoneContext + mb_strlen(static::RFC3966_PHONE_CONTEXT);
1819            // If the phone context contains a phone number prefix, we need to capture it, whereas domains
1820            // will be ignored.
1821            if ($phoneContextStart < (strlen($numberToParse) - 1)
1822                && substr($numberToParse, $phoneContextStart, 1) == static::PLUS_SIGN) {
1823                // Additional parameters might follow the phone context. If so, we will remove them here
1824                // because the parameters after phone context are not important for parsing the
1825                // phone number.
1826                $phoneContextEnd = strpos($numberToParse, ';', $phoneContextStart);
1827                if ($phoneContextEnd > 0) {
1828                    $nationalNumber .= substr($numberToParse, $phoneContextStart, $phoneContextEnd - $phoneContextStart);
1829                } else {
1830                    $nationalNumber .= substr($numberToParse, $phoneContextStart);
1831                }
1832            }
1833
1834            // Now append everything between the "tel:" prefix and the phone-context. This should include
1835            // the national number, an optional extension or isdn-subaddress component. Note we also
1836            // handle the case when "tel:" is missing, as we have seen in some of the phone number inputs.
1837            // In that case, we append everything from the beginning.
1838
1839            $indexOfRfc3966Prefix = strpos($numberToParse, static::RFC3966_PREFIX);
1840            $indexOfNationalNumber = ($indexOfRfc3966Prefix !== false) ? $indexOfRfc3966Prefix + strlen(static::RFC3966_PREFIX) : 0;
1841            $nationalNumber .= substr(
1842                $numberToParse,
1843                $indexOfNationalNumber,
1844                $indexOfPhoneContext - $indexOfNationalNumber
1845            );
1846        } else {
1847            // Extract a possible number from the string passed in (this strips leading characters that
1848            // could not be the start of a phone number.)
1849            $nationalNumber .= static::extractPossibleNumber($numberToParse);
1850        }
1851
1852        // Delete the isdn-subaddress and everything after it if it is present. Note extension won't
1853        // appear at the same time with isdn-subaddress according to paragraph 5.3 of the RFC3966 spec,
1854        $indexOfIsdn = strpos($nationalNumber, static::RFC3966_ISDN_SUBADDRESS);
1855        if ($indexOfIsdn > 0) {
1856            $nationalNumber = substr($nationalNumber, 0, $indexOfIsdn);
1857        }
1858        // If both phone context and isdn-subaddress are absent but other parameters are present, the
1859        // parameters are left in nationalNumber. This is because we are concerned about deleting
1860        // content from a potential number string when there is no strong evidence that the number is
1861        // actually written in RFC3966.
1862    }
1863
1864    /**
1865     * Attempts to extract a possible number from the string passed in. This currently strips all
1866     * leading characters that cannot be used to start a phone number. Characters that can be used to
1867     * start a phone number are defined in the VALID_START_CHAR_PATTERN. If none of these characters
1868     * are found in the number passed in, an empty string is returned. This function also attempts to
1869     * strip off any alternative extensions or endings if two or more are present, such as in the case
1870     * of: (530) 583-6985 x302/x2303. The second extension here makes this actually two phone numbers,
1871     * (530) 583-6985 x302 and (530) 583-6985 x2303. We remove the second extension so that the first
1872     * number is parsed correctly.
1873     *
1874     * @param int $number the string that might contain a phone number
1875     * @return string the number, stripped of any non-phone-number prefix (such as "Tel:") or an empty
1876     *                string if no character used to start phone numbers (such as + or any digit) is
1877     *                found in the number
1878     */
1879    public static function extractPossibleNumber($number)
1880    {
1881        if (static::$VALID_START_CHAR_PATTERN === null) {
1882            static::initValidStartCharPattern();
1883        }
1884
1885        $matches = array();
1886        $match = preg_match('/' . static::$VALID_START_CHAR_PATTERN . '/ui', $number, $matches, PREG_OFFSET_CAPTURE);
1887        if ($match > 0) {
1888            $number = substr($number, $matches[0][1]);
1889            // Remove trailing non-alpha non-numerical characters.
1890            $trailingCharsMatcher = new Matcher(static::$UNWANTED_END_CHAR_PATTERN, $number);
1891            if ($trailingCharsMatcher->find() && $trailingCharsMatcher->start() > 0) {
1892                $number = substr($number, 0, $trailingCharsMatcher->start());
1893            }
1894
1895            // Check for extra numbers at the end.
1896            $match = preg_match('%' . static::$SECOND_NUMBER_START_PATTERN . '%', $number, $matches, PREG_OFFSET_CAPTURE);
1897            if ($match > 0) {
1898                $number = substr($number, 0, $matches[0][1]);
1899            }
1900
1901            return $number;
1902        }
1903
1904        return '';
1905    }
1906
1907    /**
1908     * Checks to see that the region code used is valid, or if it is not valid, that the number to
1909     * parse starts with a + symbol so that we can attempt to infer the region from the number.
1910     * Returns false if it cannot use the region provided and the region cannot be inferred.
1911     * @param string $numberToParse
1912     * @param string $defaultRegion
1913     * @return bool
1914     */
1915    protected function checkRegionForParsing($numberToParse, $defaultRegion)
1916    {
1917        if (!$this->isValidRegionCode($defaultRegion)) {
1918            // If the number is null or empty, we can't infer the region.
1919            $plusCharsPatternMatcher = new Matcher(static::$PLUS_CHARS_PATTERN, $numberToParse);
1920            if ($numberToParse === null || mb_strlen($numberToParse) == 0 || !$plusCharsPatternMatcher->lookingAt()) {
1921                return false;
1922            }
1923        }
1924        return true;
1925    }
1926
1927    /**
1928     * Tries to extract a country calling code from a number. This method will return zero if no
1929     * country calling code is considered to be present. Country calling codes are extracted in the
1930     * following ways:
1931     * <ul>
1932     *  <li> by stripping the international dialing prefix of the region the person is dialing from,
1933     *       if this is present in the number, and looking at the next digits
1934     *  <li> by stripping the '+' sign if present and then looking at the next digits
1935     *  <li> by comparing the start of the number and the country calling code of the default region.
1936     *       If the number is not considered possible for the numbering plan of the default region
1937     *       initially, but starts with the country calling code of this region, validation will be
1938     *       reattempted after stripping this country calling code. If this number is considered a
1939     *       possible number, then the first digits will be considered the country calling code and
1940     *       removed as such.
1941     * </ul>
1942     * It will throw a NumberParseException if the number starts with a '+' but the country calling
1943     * code supplied after this does not match that of any known region.
1944     *
1945     * @param string $number non-normalized telephone number that we wish to extract a country calling
1946     *     code from - may begin with '+'
1947     * @param PhoneMetadata $defaultRegionMetadata metadata about the region this number may be from
1948     * @param string $nationalNumber a string buffer to store the national significant number in, in the case
1949     *     that a country calling code was extracted. The number is appended to any existing contents.
1950     *     If no country calling code was extracted, this will be left unchanged.
1951     * @param bool $keepRawInput true if the country_code_source and preferred_carrier_code fields of
1952     *     phoneNumber should be populated.
1953     * @param PhoneNumber $phoneNumber the PhoneNumber object where the country_code and country_code_source need
1954     *     to be populated. Note the country_code is always populated, whereas country_code_source is
1955     *     only populated when keepCountryCodeSource is true.
1956     * @return int the country calling code extracted or 0 if none could be extracted
1957     * @throws NumberParseException
1958     */
1959    public function maybeExtractCountryCode(
1960        $number,
1961        PhoneMetadata $defaultRegionMetadata = null,
1962        &$nationalNumber,
1963        $keepRawInput,
1964        PhoneNumber $phoneNumber
1965    ) {
1966        if (mb_strlen($number) == 0) {
1967            return 0;
1968        }
1969        $fullNumber = $number;
1970        // Set the default prefix to be something that will never match.
1971        $possibleCountryIddPrefix = 'NonMatch';
1972        if ($defaultRegionMetadata !== null) {
1973            $possibleCountryIddPrefix = $defaultRegionMetadata->getInternationalPrefix();
1974        }
1975        $countryCodeSource = $this->maybeStripInternationalPrefixAndNormalize($fullNumber, $possibleCountryIddPrefix);
1976
1977        if ($keepRawInput) {
1978            $phoneNumber->setCountryCodeSource($countryCodeSource);
1979        }
1980        if ($countryCodeSource != CountryCodeSource::FROM_DEFAULT_COUNTRY) {
1981            if (mb_strlen($fullNumber) <= static::MIN_LENGTH_FOR_NSN) {
1982                throw new NumberParseException(
1983                    NumberParseException::TOO_SHORT_AFTER_IDD,
1984                    'Phone number had an IDD, but after this was not long enough to be a viable phone number.'
1985                );
1986            }
1987            $potentialCountryCode = $this->extractCountryCode($fullNumber, $nationalNumber);
1988
1989            if ($potentialCountryCode != 0) {
1990                $phoneNumber->setCountryCode($potentialCountryCode);
1991                return $potentialCountryCode;
1992            }
1993
1994            // If this fails, they must be using a strange country calling code that we don't recognize,
1995            // or that doesn't exist.
1996            throw new NumberParseException(
1997                NumberParseException::INVALID_COUNTRY_CODE,
1998                'Country calling code supplied was not recognised.'
1999            );
2000        }
2001
2002        if ($defaultRegionMetadata !== null) {
2003            // Check to see if the number starts with the country calling code for the default region. If
2004            // so, we remove the country calling code, and do some checks on the validity of the number
2005            // before and after.
2006            $defaultCountryCode = $defaultRegionMetadata->getCountryCode();
2007            $defaultCountryCodeString = (string)$defaultCountryCode;
2008            $normalizedNumber = $fullNumber;
2009            if (strpos($normalizedNumber, $defaultCountryCodeString) === 0) {
2010                $potentialNationalNumber = substr($normalizedNumber, mb_strlen($defaultCountryCodeString));
2011                $generalDesc = $defaultRegionMetadata->getGeneralDesc();
2012                // Don't need the carrier code.
2013                $carriercode = null;
2014                $this->maybeStripNationalPrefixAndCarrierCode(
2015                    $potentialNationalNumber,
2016                    $defaultRegionMetadata,
2017                    $carriercode
2018                );
2019                // If the number was not valid before but is valid now, or if it was too long before, we
2020                // consider the number with the country calling code stripped to be a better result and
2021                // keep that instead.
2022                if ((!$this->matcherAPI->matchNationalNumber($fullNumber, $generalDesc, false)
2023                        && $this->matcherAPI->matchNationalNumber($potentialNationalNumber, $generalDesc, false))
2024                    || $this->testNumberLength($fullNumber, $defaultRegionMetadata) === ValidationResult::TOO_LONG
2025                ) {
2026                    $nationalNumber .= $potentialNationalNumber;
2027                    if ($keepRawInput) {
2028                        $phoneNumber->setCountryCodeSource(CountryCodeSource::FROM_NUMBER_WITHOUT_PLUS_SIGN);
2029                    }
2030                    $phoneNumber->setCountryCode($defaultCountryCode);
2031                    return $defaultCountryCode;
2032                }
2033            }
2034        }
2035        // No country calling code present.
2036        $phoneNumber->setCountryCode(0);
2037        return 0;
2038    }
2039
2040    /**
2041     * Strips any international prefix (such as +, 00, 011) present in the number provided, normalizes
2042     * the resulting number, and indicates if an international prefix was present.
2043     *
2044     * @param string $number the non-normalized telephone number that we wish to strip any international
2045     *     dialing prefix from.
2046     * @param string $possibleIddPrefix string the international direct dialing prefix from the region we
2047     *     think this number may be dialed in
2048     * @return int the corresponding CountryCodeSource if an international dialing prefix could be
2049     *     removed from the number, otherwise CountryCodeSource.FROM_DEFAULT_COUNTRY if the number did
2050     *     not seem to be in international format.
2051     */
2052    public function maybeStripInternationalPrefixAndNormalize(&$number, $possibleIddPrefix)
2053    {
2054        if (mb_strlen($number) == 0) {
2055            return CountryCodeSource::FROM_DEFAULT_COUNTRY;
2056        }
2057        $matches = array();
2058        // Check to see if the number begins with one or more plus signs.
2059        $match = preg_match('/^' . static::$PLUS_CHARS_PATTERN . '/' . static::REGEX_FLAGS, $number, $matches, PREG_OFFSET_CAPTURE);
2060        if ($match > 0) {
2061            $number = mb_substr($number, $matches[0][1] + mb_strlen($matches[0][0]));
2062            // Can now normalize the rest of the number since we've consumed the "+" sign at the start.
2063            $number = static::normalize($number);
2064            return CountryCodeSource::FROM_NUMBER_WITH_PLUS_SIGN;
2065        }
2066        // Attempt to parse the first digits as an international prefix.
2067        $iddPattern = $possibleIddPrefix;
2068        $number = static::normalize($number);
2069        return $this->parsePrefixAsIdd($iddPattern, $number)
2070            ? CountryCodeSource::FROM_NUMBER_WITH_IDD
2071            : CountryCodeSource::FROM_DEFAULT_COUNTRY;
2072    }
2073
2074    /**
2075     * Normalizes a string of characters representing a phone number. This performs
2076     * the following conversions:
2077     *   Punctuation is stripped.
2078     *   For ALPHA/VANITY numbers:
2079     *   Letters are converted to their numeric representation on a telephone
2080     *       keypad. The keypad used here is the one defined in ITU Recommendation
2081     *       E.161. This is only done if there are 3 or more letters in the number,
2082     *       to lessen the risk that such letters are typos.
2083     *   For other numbers:
2084     *    - Wide-ascii digits are converted to normal ASCII (European) digits.
2085     *    - Arabic-Indic numerals are converted to European numerals.
2086     *    - Spurious alpha characters are stripped.
2087     *
2088     * @param string $number a string of characters representing a phone number.
2089     * @return string the normalized string version of the phone number.
2090     */
2091    public static function normalize(&$number)
2092    {
2093        if (static::$ALPHA_PHONE_MAPPINGS === null) {
2094            static::initAlphaPhoneMappings();
2095        }
2096
2097        $m = new Matcher(static::VALID_ALPHA_PHONE_PATTERN, $number);
2098        if ($m->matches()) {
2099            return static::normalizeHelper($number, static::$ALPHA_PHONE_MAPPINGS, true);
2100        }
2101
2102        return static::normalizeDigitsOnly($number);
2103    }
2104
2105    /**
2106     * Normalizes a string of characters representing a phone number. This converts wide-ascii and
2107     * arabic-indic numerals to European numerals, and strips punctuation and alpha characters.
2108     *
2109     * @param $number string  a string of characters representing a phone number
2110     * @return string the normalized string version of the phone number
2111     */
2112    public static function normalizeDigitsOnly($number)
2113    {
2114        return static::normalizeDigits($number, false /* strip non-digits */);
2115    }
2116
2117    /**
2118     * @param string $number
2119     * @param bool $keepNonDigits
2120     * @return string
2121     */
2122    public static function normalizeDigits($number, $keepNonDigits)
2123    {
2124        $normalizedDigits = '';
2125        $numberAsArray = preg_split('/(?<!^)(?!$)/u', $number);
2126        foreach ($numberAsArray as $character) {
2127            // Check if we are in the unicode number range
2128            if (array_key_exists($character, static::$numericCharacters)) {
2129                $normalizedDigits .= static::$numericCharacters[$character];
2130            } elseif (is_numeric($character)) {
2131                $normalizedDigits .= $character;
2132            } elseif ($keepNonDigits) {
2133                $normalizedDigits .= $character;
2134            }
2135        }
2136        return $normalizedDigits;
2137    }
2138
2139    /**
2140     * Strips the IDD from the start of the number if present. Helper function used by
2141     * maybeStripInternationalPrefixAndNormalize.
2142     * @param string $iddPattern
2143     * @param string $number
2144     * @return bool
2145     */
2146    protected function parsePrefixAsIdd($iddPattern, &$number)
2147    {
2148        $m = new Matcher($iddPattern, $number);
2149        if ($m->lookingAt()) {
2150            $matchEnd = $m->end();
2151            // Only strip this if the first digit after the match is not a 0, since country calling codes
2152            // cannot begin with 0.
2153            $digitMatcher = new Matcher(static::$CAPTURING_DIGIT_PATTERN, substr($number, $matchEnd));
2154            if ($digitMatcher->find()) {
2155                $normalizedGroup = static::normalizeDigitsOnly($digitMatcher->group(1));
2156                if ($normalizedGroup == '0') {
2157                    return false;
2158                }
2159            }
2160            $number = substr($number, $matchEnd);
2161            return true;
2162        }
2163        return false;
2164    }
2165
2166    /**
2167     * Extracts country calling code from fullNumber, returns it and places the remaining number in  nationalNumber.
2168     * It assumes that the leading plus sign or IDD has already been removed.
2169     * Returns 0 if fullNumber doesn't start with a valid country calling code, and leaves nationalNumber unmodified.
2170     * @param string $fullNumber
2171     * @param string $nationalNumber
2172     * @return int
2173     * @internal
2174     */
2175    public function extractCountryCode($fullNumber, &$nationalNumber)
2176    {
2177        if ((mb_strlen($fullNumber) == 0) || ($fullNumber[0] == '0')) {
2178            // Country codes do not begin with a '0'.
2179            return 0;
2180        }
2181        $numberLength = mb_strlen($fullNumber);
2182        for ($i = 1; $i <= static::MAX_LENGTH_COUNTRY_CODE && $i <= $numberLength; $i++) {
2183            $potentialCountryCode = (int)substr($fullNumber, 0, $i);
2184            if (isset($this->countryCallingCodeToRegionCodeMap[$potentialCountryCode])) {
2185                $nationalNumber .= substr($fullNumber, $i);
2186                return $potentialCountryCode;
2187            }
2188        }
2189        return 0;
2190    }
2191
2192    /**
2193     * Strips any national prefix (such as 0, 1) present in the number provided.
2194     *
2195     * @param string $number the normalized telephone number that we wish to strip any national
2196     *     dialing prefix from
2197     * @param PhoneMetadata $metadata the metadata for the region that we think this number is from
2198     * @param string $carrierCode a place to insert the carrier code if one is extracted
2199     * @return bool true if a national prefix or carrier code (or both) could be extracted.
2200     */
2201    public function maybeStripNationalPrefixAndCarrierCode(&$number, PhoneMetadata $metadata, &$carrierCode)
2202    {
2203        $numberLength = mb_strlen($number);
2204        $possibleNationalPrefix = $metadata->getNationalPrefixForParsing();
2205        if ($numberLength == 0 || $possibleNationalPrefix === null || mb_strlen($possibleNationalPrefix) == 0) {
2206            // Early return for numbers of zero length.
2207            return false;
2208        }
2209
2210        // Attempt to parse the first digits as a national prefix.
2211        $prefixMatcher = new Matcher($possibleNationalPrefix, $number);
2212        if ($prefixMatcher->lookingAt()) {
2213            $generalDesc = $metadata->getGeneralDesc();
2214            // Check if the original number is viable.
2215            $isViableOriginalNumber = $this->matcherAPI->matchNationalNumber($number, $generalDesc, false);
2216            // $prefixMatcher->group($numOfGroups) === null implies nothing was captured by the capturing
2217            // groups in $possibleNationalPrefix; therefore, no transformation is necessary, and we just
2218            // remove the national prefix
2219            $numOfGroups = $prefixMatcher->groupCount();
2220            $transformRule = $metadata->getNationalPrefixTransformRule();
2221            if ($transformRule === null
2222                || mb_strlen($transformRule) == 0
2223                || $prefixMatcher->group($numOfGroups - 1) === null
2224            ) {
2225                // If the original number was viable, and the resultant number is not, we return.
2226                if ($isViableOriginalNumber &&
2227                    !$this->matcherAPI->matchNationalNumber(
2228                        substr($number, $prefixMatcher->end()),
2229                        $generalDesc,
2230                        false
2231                    )) {
2232                    return false;
2233                }
2234                if ($carrierCode !== null && $numOfGroups > 0 && $prefixMatcher->group($numOfGroups) !== null) {
2235                    $carrierCode .= $prefixMatcher->group(1);
2236                }
2237
2238                $number = substr($number, $prefixMatcher->end());
2239                return true;
2240            }
2241
2242            // Check that the resultant number is still viable. If not, return. Check this by copying
2243            // the string and making the transformation on the copy first.
2244            $transformedNumber = $number;
2245            $transformedNumber = substr_replace(
2246                $transformedNumber,
2247                $prefixMatcher->replaceFirst($transformRule),
2248                0,
2249                $numberLength
2250            );
2251            if ($isViableOriginalNumber
2252                && !$this->matcherAPI->matchNationalNumber($transformedNumber, $generalDesc, false)) {
2253                return false;
2254            }
2255            if ($carrierCode !== null && $numOfGroups > 1) {
2256                $carrierCode .= $prefixMatcher->group(1);
2257            }
2258            $number = substr_replace($number, $transformedNumber, 0, mb_strlen($number));
2259            return true;
2260        }
2261        return false;
2262    }
2263
2264    /**
2265     * Convenience wrapper around isPossibleNumberForTypeWithReason. Instead of returning the reason
2266     * for failure, this method returns true if the number is either a possible fully-qualified
2267     * number (containing the area code and country code), or if the number could be a possible local
2268     * number (with a country code, but missing an area code). Local numbers are considered possible
2269     * if they could be possibly dialled in this format: if the area code is needed for a call to
2270     * connect, the number is not considered possible without it.
2271     *
2272     * @param PhoneNumber $number The number that needs to be checked
2273     * @param int $type PhoneNumberType The type we are interested in
2274     * @return bool true if the number is possible for this particular type
2275     */
2276    public function isPossibleNumberForType(PhoneNumber $number, $type)
2277    {
2278        $result = $this->isPossibleNumberForTypeWithReason($number, $type);
2279        return $result === ValidationResult::IS_POSSIBLE
2280            || $result === ValidationResult::IS_POSSIBLE_LOCAL_ONLY;
2281    }
2282
2283    /**
2284     * Helper method to check a number against possible lengths for this number type, and determine
2285     * whether it matches, or is too short or too long.
2286     *
2287     * @param string $number
2288     * @param PhoneMetadata $metadata
2289     * @param int $type PhoneNumberType
2290     * @return int ValidationResult
2291     */
2292    protected function testNumberLength($number, PhoneMetadata $metadata, $type = PhoneNumberType::UNKNOWN)
2293    {
2294        $descForType = $this->getNumberDescByType($metadata, $type);
2295        // There should always be "possibleLengths" set for every element. This is declared in the XML
2296        // schema which is verified by PhoneNumberMetadataSchemaTest.
2297        // For size efficiency, where a sub-description (e.g. fixed-line) has the same possibleLengths
2298        // as the parent, this is missing, so we fall back to the general desc (where no numbers of the
2299        // type exist at all, there is one possible length (-1) which is guaranteed not to match the
2300        // length of any real phone number).
2301        $possibleLengths = (count($descForType->getPossibleLength()) === 0)
2302            ? $metadata->getGeneralDesc()->getPossibleLength() : $descForType->getPossibleLength();
2303
2304        $localLengths = $descForType->getPossibleLengthLocalOnly();
2305
2306        if ($type === PhoneNumberType::FIXED_LINE_OR_MOBILE) {
2307            if (!static::descHasPossibleNumberData($this->getNumberDescByType($metadata, PhoneNumberType::FIXED_LINE))) {
2308                // The rate case has been encountered where no fixedLine data is available (true for some
2309                // non-geographical entities), so we just check mobile.
2310                return $this->testNumberLength($number, $metadata, PhoneNumberType::MOBILE);
2311            }
2312
2313            $mobileDesc = $this->getNumberDescByType($metadata, PhoneNumberType::MOBILE);
2314            if (static::descHasPossibleNumberData($mobileDesc)) {
2315                // Note that when adding the possible lengths from mobile, we have to again check they
2316                // aren't empty since if they are this indicates they are the same as the general desc and
2317                // should be obtained from there.
2318                $possibleLengths = array_merge(
2319                    $possibleLengths,
2320                    (count($mobileDesc->getPossibleLength()) === 0)
2321                        ? $metadata->getGeneralDesc()->getPossibleLength() : $mobileDesc->getPossibleLength()
2322                );
2323
2324                // The current list is sorted; we need to merge in the new list and re-sort (duplicates
2325                // are okay). Sorting isn't so expensive because the lists are very small.
2326                sort($possibleLengths);
2327
2328                if (count($localLengths) === 0) {
2329                    $localLengths = $mobileDesc->getPossibleLengthLocalOnly();
2330                } else {
2331                    $localLengths = array_merge($localLengths, $mobileDesc->getPossibleLengthLocalOnly());
2332                    sort($localLengths);
2333                }
2334            }
2335        }
2336
2337
2338        // If the type is not supported at all (indicated by the possible lengths containing -1 at this
2339        // point) we return invalid length.
2340
2341        if ($possibleLengths[0] === -1) {
2342            return ValidationResult::INVALID_LENGTH;
2343        }
2344
2345        $actualLength = mb_strlen($number);
2346
2347        // This is safe because there is never an overlap between the possible lengths and the local-only
2348        // lengths; this is checked at build time.
2349
2350        if (in_array($actualLength, $localLengths)) {
2351            return ValidationResult::IS_POSSIBLE_LOCAL_ONLY;
2352        }
2353
2354        $minimumLength = reset($possibleLengths);
2355        if ($minimumLength == $actualLength) {
2356            return ValidationResult::IS_POSSIBLE;
2357        }
2358
2359        if ($minimumLength > $actualLength) {
2360            return ValidationResult::TOO_SHORT;
2361        } elseif (isset($possibleLengths[count($possibleLengths) - 1]) && $possibleLengths[count($possibleLengths) - 1] < $actualLength) {
2362            return ValidationResult::TOO_LONG;
2363        }
2364
2365        // We skip the first element; we've already checked it.
2366        array_shift($possibleLengths);
2367        return in_array($actualLength, $possibleLengths) ? ValidationResult::IS_POSSIBLE : ValidationResult::INVALID_LENGTH;
2368    }
2369
2370    /**
2371     * Returns a list with the region codes that match the specific country calling code. For
2372     * non-geographical country calling codes, the region code 001 is returned. Also, in the case
2373     * of no region code being found, an empty list is returned.
2374     * @param int $countryCallingCode
2375     * @return array
2376     */
2377    public function getRegionCodesForCountryCode($countryCallingCode)
2378    {
2379        $regionCodes = isset($this->countryCallingCodeToRegionCodeMap[$countryCallingCode]) ? $this->countryCallingCodeToRegionCodeMap[$countryCallingCode] : null;
2380        return $regionCodes === null ? array() : $regionCodes;
2381    }
2382
2383    /**
2384     * Returns the country calling code for a specific region. For example, this would be 1 for the
2385     * United States, and 64 for New Zealand. Assumes the region is already valid.
2386     *
2387     * @param string $regionCode the region that we want to get the country calling code for
2388     * @return int the country calling code for the region denoted by regionCode
2389     */
2390    public function getCountryCodeForRegion($regionCode)
2391    {
2392        if (!$this->isValidRegionCode($regionCode)) {
2393            return 0;
2394        }
2395        return $this->getCountryCodeForValidRegion($regionCode);
2396    }
2397
2398    /**
2399     * Returns the country calling code for a specific region. For example, this would be 1 for the
2400     * United States, and 64 for New Zealand. Assumes the region is already valid.
2401     *
2402     * @param string $regionCode the region that we want to get the country calling code for
2403     * @return int the country calling code for the region denoted by regionCode
2404     * @throws \InvalidArgumentException if the region is invalid
2405     */
2406    protected function getCountryCodeForValidRegion($regionCode)
2407    {
2408        $metadata = $this->getMetadataForRegion($regionCode);
2409        if ($metadata === null) {
2410            throw new \InvalidArgumentException('Invalid region code: ' . $regionCode);
2411        }
2412        return $metadata->getCountryCode();
2413    }
2414
2415    /**
2416     * Returns a number formatted in such a way that it can be dialed from a mobile phone in a
2417     * specific region. If the number cannot be reached from the region (e.g. some countries block
2418     * toll-free numbers from being called outside of the country), the method returns an empty
2419     * string.
2420     *
2421     * @param PhoneNumber $number the phone number to be formatted
2422     * @param string $regionCallingFrom the region where the call is being placed
2423     * @param boolean $withFormatting whether the number should be returned with formatting symbols, such as
2424     *     spaces and dashes.
2425     * @return string the formatted phone number
2426     */
2427    public function formatNumberForMobileDialing(PhoneNumber $number, $regionCallingFrom, $withFormatting)
2428    {
2429        $countryCallingCode = $number->getCountryCode();
2430        if (!$this->hasValidCountryCallingCode($countryCallingCode)) {
2431            return $number->hasRawInput() ? $number->getRawInput() : '';
2432        }
2433
2434        $formattedNumber = '';
2435        // Clear the extension, as that part cannot normally be dialed together with the main number.
2436        $numberNoExt = new PhoneNumber();
2437        $numberNoExt->mergeFrom($number)->clearExtension();
2438        $regionCode = $this->getRegionCodeForCountryCode($countryCallingCode);
2439        $numberType = $this->getNumberType($numberNoExt);
2440        $isValidNumber = ($numberType !== PhoneNumberType::UNKNOWN);
2441        if ($regionCallingFrom == $regionCode) {
2442            $isFixedLineOrMobile = ($numberType == PhoneNumberType::FIXED_LINE) || ($numberType == PhoneNumberType::MOBILE) || ($numberType == PhoneNumberType::FIXED_LINE_OR_MOBILE);
2443            // Carrier codes may be needed in some countries. We handle this here.
2444            if ($regionCode == 'CO' && $numberType == PhoneNumberType::FIXED_LINE) {
2445                $formattedNumber = $this->formatNationalNumberWithCarrierCode(
2446                    $numberNoExt,
2447                    static::COLOMBIA_MOBILE_TO_FIXED_LINE_PREFIX
2448                );
2449            } elseif ($regionCode == 'BR' && $isFixedLineOrMobile) {
2450                // Historically, we set this to an empty string when parsing with raw input if none was
2451                // found in the input string. However, this doesn't result in a number we can dial. For this
2452                // reason, we treat the empty string the same as if it isn't set at all.
2453                $formattedNumber = mb_strlen($numberNoExt->getPreferredDomesticCarrierCode()) > 0
2454                    ? $this->formatNationalNumberWithPreferredCarrierCode($numberNoExt, '')
2455                    // Brazilian fixed line and mobile numbers need to be dialed with a carrier code when
2456                    // called within Brazil. Without that, most of the carriers won't connect the call.
2457                    // Because of that, we return an empty string here.
2458                    : '';
2459            } elseif ($countryCallingCode === static::NANPA_COUNTRY_CODE) {
2460                // For NANPA countries, we output international format for numbers that can be dialed
2461                // internationally, since that always works, except for numbers which might potentially be
2462                // short numbers, which are always dialled in national format.
2463                $regionMetadata = $this->getMetadataForRegion($regionCallingFrom);
2464                if ($this->canBeInternationallyDialled($numberNoExt)
2465                    && $this->testNumberLength($this->getNationalSignificantNumber($numberNoExt), $regionMetadata)
2466                    !== ValidationResult::TOO_SHORT
2467                ) {
2468                    $formattedNumber = $this->format($numberNoExt, PhoneNumberFormat::INTERNATIONAL);
2469                } else {
2470                    $formattedNumber = $this->format($numberNoExt, PhoneNumberFormat::NATIONAL);
2471                }
2472            } elseif ((
2473                $regionCode == static::REGION_CODE_FOR_NON_GEO_ENTITY ||
2474                    // MX fixed line and mobile numbers should always be formatted in international format,
2475                    // even when dialed within MX. For national format to work, a carrier code needs to be
2476                    // used, and the correct carrier code depends on if the caller and callee are from the
2477                    // same local area. It is trickier to get that to work correctly than using
2478                    // international format, which is tested to work fine on all carriers.
2479                    // CL fixed line numbers need the national prefix when dialing in the national format,
2480                    // but don't have it when used for display. The reverse is true for mobile numbers.
2481                    // As a result, we output them in the international format to make it work.
2482                    (
2483                        ($regionCode === 'MX' || $regionCode === 'CL' || $regionCode === 'UZ')
2484                        && $isFixedLineOrMobile
2485                    )
2486            ) && $this->canBeInternationallyDialled($numberNoExt)
2487            ) {
2488                $formattedNumber = $this->format($numberNoExt, PhoneNumberFormat::INTERNATIONAL);
2489            } else {
2490                $formattedNumber = $this->format($numberNoExt, PhoneNumberFormat::NATIONAL);
2491            }
2492        } elseif ($isValidNumber && $this->canBeInternationallyDialled($numberNoExt)) {
2493            // We assume that short numbers are not diallable from outside their region, so if a number
2494            // is not a valid regular length phone number, we treat it as if it cannot be internationally
2495            // dialled.
2496            return $withFormatting ?
2497                $this->format($numberNoExt, PhoneNumberFormat::INTERNATIONAL) :
2498                $this->format($numberNoExt, PhoneNumberFormat::E164);
2499        }
2500        return $withFormatting ? $formattedNumber : static::normalizeDiallableCharsOnly($formattedNumber);
2501    }
2502
2503    /**
2504     * Formats a phone number in national format for dialing using the carrier as specified in the
2505     * {@code carrierCode}. The {@code carrierCode} will always be used regardless of whether the
2506     * phone number already has a preferred domestic carrier code stored. If {@code carrierCode}
2507     * contains an empty string, returns the number in national format without any carrier code.
2508     *
2509     * @param PhoneNumber $number the phone number to be formatted
2510     * @param string $carrierCode the carrier selection code to be used
2511     * @return string the formatted phone number in national format for dialing using the carrier as
2512     * specified in the {@code carrierCode}
2513     */
2514    public function formatNationalNumberWithCarrierCode(PhoneNumber $number, $carrierCode)
2515    {
2516        $countryCallingCode = $number->getCountryCode();
2517        $nationalSignificantNumber = $this->getNationalSignificantNumber($number);
2518        if (!$this->hasValidCountryCallingCode($countryCallingCode)) {
2519            return $nationalSignificantNumber;
2520        }
2521
2522        // Note getRegionCodeForCountryCode() is used because formatting information for regions which
2523        // share a country calling code is contained by only one region for performance reasons. For
2524        // example, for NANPA regions it will be contained in the metadata for US.
2525        $regionCode = $this->getRegionCodeForCountryCode($countryCallingCode);
2526        // Metadata cannot be null because the country calling code is valid.
2527        $metadata = $this->getMetadataForRegionOrCallingCode($countryCallingCode, $regionCode);
2528
2529        $formattedNumber = $this->formatNsn(
2530            $nationalSignificantNumber,
2531            $metadata,
2532            PhoneNumberFormat::NATIONAL,
2533            $carrierCode
2534        );
2535        $this->maybeAppendFormattedExtension($number, $metadata, PhoneNumberFormat::NATIONAL, $formattedNumber);
2536        $this->prefixNumberWithCountryCallingCode(
2537            $countryCallingCode,
2538            PhoneNumberFormat::NATIONAL,
2539            $formattedNumber
2540        );
2541        return $formattedNumber;
2542    }
2543
2544    /**
2545     * Formats a phone number in national format for dialing using the carrier as specified in the
2546     * preferredDomesticCarrierCode field of the PhoneNumber object passed in. If that is missing,
2547     * use the {@code fallbackCarrierCode} passed in instead. If there is no
2548     * {@code preferredDomesticCarrierCode}, and the {@code fallbackCarrierCode} contains an empty
2549     * string, return the number in national format without any carrier code.
2550     *
2551     * <p>Use {@link #formatNationalNumberWithCarrierCode} instead if the carrier code passed in
2552     * should take precedence over the number's {@code preferredDomesticCarrierCode} when formatting.
2553     *
2554     * @param PhoneNumber $number the phone number to be formatted
2555     * @param string $fallbackCarrierCode the carrier selection code to be used, if none is found in the
2556     *     phone number itself
2557     * @return string the formatted phone number in national format for dialing using the number's
2558     *     {@code preferredDomesticCarrierCode}, or the {@code fallbackCarrierCode} passed in if
2559     *     none is found
2560     */
2561    public function formatNationalNumberWithPreferredCarrierCode(PhoneNumber $number, $fallbackCarrierCode)
2562    {
2563        return $this->formatNationalNumberWithCarrierCode(
2564            $number,
2565            // Historically, we set this to an empty string when parsing with raw input if none was
2566            // found in the input string. However, this doesn't result in a number we can dial. For this
2567            // reason, we treat the empty string the same as if it isn't set at all.
2568            mb_strlen($number->getPreferredDomesticCarrierCode()) > 0
2569                ? $number->getPreferredDomesticCarrierCode()
2570                : $fallbackCarrierCode
2571        );
2572    }
2573
2574    /**
2575     * Returns true if the number can be dialled from outside the region, or unknown. If the number
2576     * can only be dialled from within the region, returns false. Does not check the number is a valid
2577     * number. Note that, at the moment, this method does not handle short numbers (which are
2578     * currently all presumed to not be diallable from outside their country).
2579     *
2580     * @param PhoneNumber $number the phone-number for which we want to know whether it is diallable from outside the region
2581     * @return bool
2582     */
2583    public function canBeInternationallyDialled(PhoneNumber $number)
2584    {
2585        $metadata = $this->getMetadataForRegion($this->getRegionCodeForNumber($number));
2586        if ($metadata === null) {
2587            // Note numbers belonging to non-geographical entities (e.g. +800 numbers) are always
2588            // internationally diallable, and will be caught here.
2589            return true;
2590        }
2591        $nationalSignificantNumber = $this->getNationalSignificantNumber($number);
2592        return !$this->isNumberMatchingDesc($nationalSignificantNumber, $metadata->getNoInternationalDialling());
2593    }
2594
2595    /**
2596     * Normalizes a string of characters representing a phone number. This strips all characters which
2597     * are not diallable on a mobile phone keypad (including all non-ASCII digits).
2598     *
2599     * @param string $number a string of characters representing a phone number
2600     * @return string the normalized string version of the phone number
2601     */
2602    public static function normalizeDiallableCharsOnly($number)
2603    {
2604        if (count(static::$DIALLABLE_CHAR_MAPPINGS) === 0) {
2605            static::initDiallableCharMappings();
2606        }
2607
2608        return static::normalizeHelper($number, static::$DIALLABLE_CHAR_MAPPINGS, true /* remove non matches */);
2609    }
2610
2611    /**
2612     * Formats a phone number for out-of-country dialing purposes.
2613     *
2614     * Note that in this version, if the number was entered originally using alpha characters and
2615     * this version of the number is stored in raw_input, this representation of the number will be
2616     * used rather than the digit representation. Grouping information, as specified by characters
2617     * such as "-" and " ", will be retained.
2618     *
2619     * <p><b>Caveats:</b></p>
2620     * <ul>
2621     *  <li> This will not produce good results if the country calling code is both present in the raw
2622     *       input _and_ is the start of the national number. This is not a problem in the regions
2623     *       which typically use alpha numbers.
2624     *  <li> This will also not produce good results if the raw input has any grouping information
2625     *       within the first three digits of the national number, and if the function needs to strip
2626     *       preceding digits/words in the raw input before these digits. Normally people group the
2627     *       first three digits together so this is not a huge problem - and will be fixed if it
2628     *       proves to be so.
2629     * </ul>
2630     *
2631     * @param PhoneNumber $number the phone number that needs to be formatted
2632     * @param String $regionCallingFrom the region where the call is being placed
2633     * @return String the formatted phone number
2634     */
2635    public function formatOutOfCountryKeepingAlphaChars(PhoneNumber $number, $regionCallingFrom)
2636    {
2637        $rawInput = $number->getRawInput();
2638        // If there is no raw input, then we can't keep alpha characters because there aren't any.
2639        // In this case, we return formatOutOfCountryCallingNumber.
2640        if (mb_strlen($rawInput) == 0) {
2641            return $this->formatOutOfCountryCallingNumber($number, $regionCallingFrom);
2642        }
2643        $countryCode = $number->getCountryCode();
2644        if (!$this->hasValidCountryCallingCode($countryCode)) {
2645            return $rawInput;
2646        }
2647        // Strip any prefix such as country calling code, IDD, that was present. We do this by comparing
2648        // the number in raw_input with the parsed number.
2649        // To do this, first we normalize punctuation. We retain number grouping symbols such as " "
2650        // only.
2651        $rawInput = self::normalizeHelper($rawInput, static::$ALL_PLUS_NUMBER_GROUPING_SYMBOLS, true);
2652        // Now we trim everything before the first three digits in the parsed number. We choose three
2653        // because all valid alpha numbers have 3 digits at the start - if it does not, then we don't
2654        // trim anything at all. Similarly, if the national number was less than three digits, we don't
2655        // trim anything at all.
2656        $nationalNumber = $this->getNationalSignificantNumber($number);
2657        if (mb_strlen($nationalNumber) > 3) {
2658            $firstNationalNumberDigit = strpos($rawInput, substr($nationalNumber, 0, 3));
2659            if ($firstNationalNumberDigit !== false) {
2660                $rawInput = substr($rawInput, $firstNationalNumberDigit);
2661            }
2662        }
2663        $metadataForRegionCallingFrom = $this->getMetadataForRegion($regionCallingFrom);
2664        if ($countryCode == static::NANPA_COUNTRY_CODE) {
2665            if ($this->isNANPACountry($regionCallingFrom)) {
2666                return $countryCode . ' ' . $rawInput;
2667            }
2668        } elseif ($metadataForRegionCallingFrom !== null &&
2669            $countryCode == $this->getCountryCodeForValidRegion($regionCallingFrom)
2670        ) {
2671            $formattingPattern =
2672                $this->chooseFormattingPatternForNumber(
2673                    $metadataForRegionCallingFrom->numberFormats(),
2674                    $nationalNumber
2675                );
2676            if ($formattingPattern === null) {
2677                // If no pattern above is matched, we format the original input.
2678                return $rawInput;
2679            }
2680            $newFormat = new NumberFormat();
2681            $newFormat->mergeFrom($formattingPattern);
2682            // The first group is the first group of digits that the user wrote together.
2683            $newFormat->setPattern("(\\d+)(.*)");
2684            // Here we just concatenate them back together after the national prefix has been fixed.
2685            $newFormat->setFormat('$1$2');
2686            // Now we format using this pattern instead of the default pattern, but with the national
2687            // prefix prefixed if necessary.
2688            // This will not work in the cases where the pattern (and not the leading digits) decide
2689            // whether a national prefix needs to be used, since we have overridden the pattern to match
2690            // anything, but that is not the case in the metadata to date.
2691            return $this->formatNsnUsingPattern($rawInput, $newFormat, PhoneNumberFormat::NATIONAL);
2692        }
2693        $internationalPrefixForFormatting = '';
2694        // If an unsupported region-calling-from is entered, or a country with multiple international
2695        // prefixes, the international format of the number is returned, unless there is a preferred
2696        // international prefix.
2697        if ($metadataForRegionCallingFrom !== null) {
2698            $internationalPrefix = $metadataForRegionCallingFrom->getInternationalPrefix();
2699            $uniqueInternationalPrefixMatcher = new Matcher(static::SINGLE_INTERNATIONAL_PREFIX, $internationalPrefix);
2700            $internationalPrefixForFormatting =
2701                $uniqueInternationalPrefixMatcher->matches()
2702                    ? $internationalPrefix
2703                    : $metadataForRegionCallingFrom->getPreferredInternationalPrefix();
2704        }
2705        $formattedNumber = $rawInput;
2706        $regionCode = $this->getRegionCodeForCountryCode($countryCode);
2707        // Metadata cannot be null because the country calling code is valid.
2708        $metadataForRegion = $this->getMetadataForRegionOrCallingCode($countryCode, $regionCode);
2709        $this->maybeAppendFormattedExtension(
2710            $number,
2711            $metadataForRegion,
2712            PhoneNumberFormat::INTERNATIONAL,
2713            $formattedNumber
2714        );
2715        if (mb_strlen($internationalPrefixForFormatting) > 0) {
2716            $formattedNumber = $internationalPrefixForFormatting . ' ' . $countryCode . ' ' . $formattedNumber;
2717        } else {
2718            // Invalid region entered as country-calling-from (so no metadata was found for it) or the
2719            // region chosen has multiple international dialling prefixes.
2720            $this->prefixNumberWithCountryCallingCode(
2721                $countryCode,
2722                PhoneNumberFormat::INTERNATIONAL,
2723                $formattedNumber
2724            );
2725        }
2726        return $formattedNumber;
2727    }
2728
2729    /**
2730     * Formats a phone number for out-of-country dialing purposes. If no regionCallingFrom is
2731     * supplied, we format the number in its INTERNATIONAL format. If the country calling code is the
2732     * same as that of the region where the number is from, then NATIONAL formatting will be applied.
2733     *
2734     * <p>If the number itself has a country calling code of zero or an otherwise invalid country
2735     * calling code, then we return the number with no formatting applied.
2736     *
2737     * <p>Note this function takes care of the case for calling inside of NANPA and between Russia and
2738     * Kazakhstan (who share the same country calling code). In those cases, no international prefix
2739     * is used. For regions which have multiple international prefixes, the number in its
2740     * INTERNATIONAL format will be returned instead.
2741     *
2742     * @param PhoneNumber $number the phone number to be formatted
2743     * @param string $regionCallingFrom the region where the call is being placed
2744     * @return string  the formatted phone number
2745     */
2746    public function formatOutOfCountryCallingNumber(PhoneNumber $number, $regionCallingFrom)
2747    {
2748        if (!$this->isValidRegionCode($regionCallingFrom)) {
2749            return $this->format($number, PhoneNumberFormat::INTERNATIONAL);
2750        }
2751        $countryCallingCode = $number->getCountryCode();
2752        $nationalSignificantNumber = $this->getNationalSignificantNumber($number);
2753        if (!$this->hasValidCountryCallingCode($countryCallingCode)) {
2754            return $nationalSignificantNumber;
2755        }
2756        if ($countryCallingCode == static::NANPA_COUNTRY_CODE) {
2757            if ($this->isNANPACountry($regionCallingFrom)) {
2758                // For NANPA regions, return the national format for these regions but prefix it with the
2759                // country calling code.
2760                return $countryCallingCode . ' ' . $this->format($number, PhoneNumberFormat::NATIONAL);
2761            }
2762        } elseif ($countryCallingCode == $this->getCountryCodeForValidRegion($regionCallingFrom)) {
2763            // If regions share a country calling code, the country calling code need not be dialled.
2764            // This also applies when dialling within a region, so this if clause covers both these cases.
2765            // Technically this is the case for dialling from La Reunion to other overseas departments of
2766            // France (French Guiana, Martinique, Guadeloupe), but not vice versa - so we don't cover this
2767            // edge case for now and for those cases return the version including country calling code.
2768            // Details here: http://www.petitfute.com/voyage/225-info-pratiques-reunion
2769            return $this->format($number, PhoneNumberFormat::NATIONAL);
2770        }
2771        // Metadata cannot be null because we checked 'isValidRegionCode()' above.
2772        /** @var PhoneMetadata $metadataForRegionCallingFrom */
2773        $metadataForRegionCallingFrom = $this->getMetadataForRegion($regionCallingFrom);
2774
2775        $internationalPrefix = $metadataForRegionCallingFrom->getInternationalPrefix();
2776
2777        // In general, if there is a preferred international prefix, use that. Otherwise, for regions
2778        // that have multiple international prefixes, the international format of the number is
2779        // returned since we would not know which one to use.
2780        $internationalPrefixForFormatting = '';
2781        if ($metadataForRegionCallingFrom->hasPreferredInternationalPrefix()) {
2782            $internationalPrefixForFormatting = $metadataForRegionCallingFrom->getPreferredInternationalPrefix();
2783        } else {
2784            $uniqueInternationalPrefixMatcher = new Matcher(static::SINGLE_INTERNATIONAL_PREFIX, $internationalPrefix);
2785
2786            if ($uniqueInternationalPrefixMatcher->matches()) {
2787                $internationalPrefixForFormatting = $internationalPrefix;
2788            }
2789        }
2790
2791        $regionCode = $this->getRegionCodeForCountryCode($countryCallingCode);
2792        // Metadata cannot be null because the country calling code is valid.
2793        /** @var PhoneMetadata $metadataForRegion */
2794        $metadataForRegion = $this->getMetadataForRegionOrCallingCode($countryCallingCode, $regionCode);
2795        $formattedNationalNumber = $this->formatNsn(
2796            $nationalSignificantNumber,
2797            $metadataForRegion,
2798            PhoneNumberFormat::INTERNATIONAL
2799        );
2800        $formattedNumber = $formattedNationalNumber;
2801        $this->maybeAppendFormattedExtension(
2802            $number,
2803            $metadataForRegion,
2804            PhoneNumberFormat::INTERNATIONAL,
2805            $formattedNumber
2806        );
2807        if (mb_strlen($internationalPrefixForFormatting) > 0) {
2808            $formattedNumber = $internationalPrefixForFormatting . ' ' . $countryCallingCode . ' ' . $formattedNumber;
2809        } else {
2810            $this->prefixNumberWithCountryCallingCode(
2811                $countryCallingCode,
2812                PhoneNumberFormat::INTERNATIONAL,
2813                $formattedNumber
2814            );
2815        }
2816        return $formattedNumber;
2817    }
2818
2819    /**
2820     * Checks if this is a region under the North American Numbering Plan Administration (NANPA).
2821     * @param string $regionCode
2822     * @return boolean true if regionCode is one of the regions under NANPA
2823     */
2824    public function isNANPACountry($regionCode)
2825    {
2826        return in_array($regionCode, $this->nanpaRegions);
2827    }
2828
2829    /**
2830     * Formats a phone number using the original phone number format that the number is parsed from.
2831     * The original format is embedded in the country_code_source field of the PhoneNumber object
2832     * passed in. If such information is missing, the number will be formatted into the NATIONAL
2833     * format by default. When we don't have a formatting pattern for the number, the method returns
2834     * the raw input when it is available.
2835     *
2836     * Note this method guarantees no digit will be inserted, removed or modified as a result of
2837     * formatting.
2838     *
2839     * @param PhoneNumber $number the phone number that needs to be formatted in its original number format
2840     * @param string $regionCallingFrom the region whose IDD needs to be prefixed if the original number
2841     *     has one
2842     * @return string the formatted phone number in its original number format
2843     */
2844    public function formatInOriginalFormat(PhoneNumber $number, $regionCallingFrom)
2845    {
2846        if ($number->hasRawInput() && !$this->hasFormattingPatternForNumber($number)) {
2847            // We check if we have the formatting pattern because without that, we might format the number
2848            // as a group without national prefix.
2849            return $number->getRawInput();
2850        }
2851        if (!$number->hasCountryCodeSource()) {
2852            return $this->format($number, PhoneNumberFormat::NATIONAL);
2853        }
2854        switch ($number->getCountryCodeSource()) {
2855            case CountryCodeSource::FROM_NUMBER_WITH_PLUS_SIGN:
2856                $formattedNumber = $this->format($number, PhoneNumberFormat::INTERNATIONAL);
2857                break;
2858            case CountryCodeSource::FROM_NUMBER_WITH_IDD:
2859                $formattedNumber = $this->formatOutOfCountryCallingNumber($number, $regionCallingFrom);
2860                break;
2861            case CountryCodeSource::FROM_NUMBER_WITHOUT_PLUS_SIGN:
2862                $formattedNumber = substr($this->format($number, PhoneNumberFormat::INTERNATIONAL), 1);
2863                break;
2864            case CountryCodeSource::FROM_DEFAULT_COUNTRY:
2865                // Fall-through to default case.
2866            default:
2867
2868                $regionCode = $this->getRegionCodeForCountryCode($number->getCountryCode());
2869                // We strip non-digits from the NDD here, and from the raw input later, so that we can
2870                // compare them easily.
2871                $nationalPrefix = $this->getNddPrefixForRegion($regionCode, true /* strip non-digits */);
2872                $nationalFormat = $this->format($number, PhoneNumberFormat::NATIONAL);
2873                if ($nationalPrefix === null || mb_strlen($nationalPrefix) == 0) {
2874                    // If the region doesn't have a national prefix at all, we can safely return the national
2875                    // format without worrying about a national prefix being added.
2876                    $formattedNumber = $nationalFormat;
2877                    break;
2878                }
2879                // Otherwise, we check if the original number was entered with a national prefix.
2880                if ($this->rawInputContainsNationalPrefix(
2881                    $number->getRawInput(),
2882                    $nationalPrefix,
2883                    $regionCode
2884                )
2885                ) {
2886                    // If so, we can safely return the national format.
2887                    $formattedNumber = $nationalFormat;
2888                    break;
2889                }
2890                // Metadata cannot be null here because getNddPrefixForRegion() (above) returns null if
2891                // there is no metadata for the region.
2892                $metadata = $this->getMetadataForRegion($regionCode);
2893                $nationalNumber = $this->getNationalSignificantNumber($number);
2894                $formatRule = $this->chooseFormattingPatternForNumber($metadata->numberFormats(), $nationalNumber);
2895                // The format rule could still be null here if the national number was 0 and there was no
2896                // raw input (this should not be possible for numbers generated by the phonenumber library
2897                // as they would also not have a country calling code and we would have exited earlier).
2898                if ($formatRule === null) {
2899                    $formattedNumber = $nationalFormat;
2900                    break;
2901                }
2902                // When the format we apply to this number doesn't contain national prefix, we can just
2903                // return the national format.
2904                // TODO: Refactor the code below with the code in isNationalPrefixPresentIfRequired.
2905                $candidateNationalPrefixRule = $formatRule->getNationalPrefixFormattingRule();
2906                // We assume that the first-group symbol will never be _before_ the national prefix.
2907                $indexOfFirstGroup = strpos($candidateNationalPrefixRule, '$1');
2908                if ($indexOfFirstGroup <= 0) {
2909                    $formattedNumber = $nationalFormat;
2910                    break;
2911                }
2912                $candidateNationalPrefixRule = substr($candidateNationalPrefixRule, 0, $indexOfFirstGroup);
2913                $candidateNationalPrefixRule = static::normalizeDigitsOnly($candidateNationalPrefixRule);
2914                if (mb_strlen($candidateNationalPrefixRule) == 0) {
2915                    // National prefix not used when formatting this number.
2916                    $formattedNumber = $nationalFormat;
2917                    break;
2918                }
2919                // Otherwise, we need to remove the national prefix from our output.
2920                $numFormatCopy = new NumberFormat();
2921                $numFormatCopy->mergeFrom($formatRule);
2922                $numFormatCopy->clearNationalPrefixFormattingRule();
2923                $numberFormats = array();
2924                $numberFormats[] = $numFormatCopy;
2925                $formattedNumber = $this->formatByPattern($number, PhoneNumberFormat::NATIONAL, $numberFormats);
2926                break;
2927        }
2928        $rawInput = $number->getRawInput();
2929        // If no digit is inserted/removed/modified as a result of our formatting, we return the
2930        // formatted phone number; otherwise we return the raw input the user entered.
2931        if ($formattedNumber !== null && mb_strlen($rawInput) > 0) {
2932            $normalizedFormattedNumber = static::normalizeDiallableCharsOnly($formattedNumber);
2933            $normalizedRawInput = static::normalizeDiallableCharsOnly($rawInput);
2934            if ($normalizedFormattedNumber != $normalizedRawInput) {
2935                $formattedNumber = $rawInput;
2936            }
2937        }
2938        return $formattedNumber;
2939    }
2940
2941    /**
2942     * @param PhoneNumber $number
2943     * @return bool
2944     */
2945    protected function hasFormattingPatternForNumber(PhoneNumber $number)
2946    {
2947        $countryCallingCode = $number->getCountryCode();
2948        $phoneNumberRegion = $this->getRegionCodeForCountryCode($countryCallingCode);
2949        $metadata = $this->getMetadataForRegionOrCallingCode($countryCallingCode, $phoneNumberRegion);
2950        if ($metadata === null) {
2951            return false;
2952        }
2953        $nationalNumber = $this->getNationalSignificantNumber($number);
2954        $formatRule = $this->chooseFormattingPatternForNumber($metadata->numberFormats(), $nationalNumber);
2955        return $formatRule !== null;
2956    }
2957
2958    /**
2959     * Returns the national dialling prefix for a specific region. For example, this would be 1 for
2960     * the United States, and 0 for New Zealand. Set stripNonDigits to true to strip symbols like "~"
2961     * (which indicates a wait for a dialling tone) from the prefix returned. If no national prefix is
2962     * present, we return null.
2963     *
2964     * <p>Warning: Do not use this method for do-your-own formatting - for some regions, the
2965     * national dialling prefix is used only for certain types of numbers. Use the library's
2966     * formatting functions to prefix the national prefix when required.
2967     *
2968     * @param string $regionCode the region that we want to get the dialling prefix for
2969     * @param boolean $stripNonDigits true to strip non-digits from the national dialling prefix
2970     * @return string the dialling prefix for the region denoted by regionCode
2971     */
2972    public function getNddPrefixForRegion($regionCode, $stripNonDigits)
2973    {
2974        $metadata = $this->getMetadataForRegion($regionCode);
2975        if ($metadata === null) {
2976            return null;
2977        }
2978        $nationalPrefix = $metadata->getNationalPrefix();
2979        // If no national prefix was found, we return null.
2980        if (mb_strlen($nationalPrefix) == 0) {
2981            return null;
2982        }
2983        if ($stripNonDigits) {
2984            // Note: if any other non-numeric symbols are ever used in national prefixes, these would have
2985            // to be removed here as well.
2986            $nationalPrefix = str_replace('~', '', $nationalPrefix);
2987        }
2988        return $nationalPrefix;
2989    }
2990
2991    /**
2992     * Check if rawInput, which is assumed to be in the national format, has a national prefix. The
2993     * national prefix is assumed to be in digits-only form.
2994     * @param string $rawInput
2995     * @param string $nationalPrefix
2996     * @param string $regionCode
2997     * @return bool
2998     */
2999    protected function rawInputContainsNationalPrefix($rawInput, $nationalPrefix, $regionCode)
3000    {
3001        $normalizedNationalNumber = static::normalizeDigitsOnly($rawInput);
3002        if (strpos($normalizedNationalNumber, $nationalPrefix) === 0) {
3003            try {
3004                // Some Japanese numbers (e.g. 00777123) might be mistaken to contain the national prefix
3005                // when written without it (e.g. 0777123) if we just do prefix matching. To tackle that, we
3006                // check the validity of the number if the assumed national prefix is removed (777123 won't
3007                // be valid in Japan).
3008                return $this->isValidNumber(
3009                    $this->parse(substr($normalizedNationalNumber, mb_strlen($nationalPrefix)), $regionCode)
3010                );
3011            } catch (NumberParseException $e) {
3012                return false;
3013            }
3014        }
3015        return false;
3016    }
3017
3018    /**
3019     * Tests whether a phone number matches a valid pattern. Note this doesn't verify the number
3020     * is actually in use, which is impossible to tell by just looking at a number itself. It only
3021     * verifies whether the parsed, canonicalised number is valid: not whether a particular series of
3022     * digits entered by the user is diallable from the region provided when parsing. For example, the
3023     * number +41 (0) 78 927 2696 can be parsed into a number with country code "41" and national
3024     * significant number "789272696". This is valid, while the original string is not diallable.
3025     *
3026     * @param PhoneNumber $number the phone number that we want to validate
3027     * @return boolean that indicates whether the number is of a valid pattern
3028     */
3029    public function isValidNumber(PhoneNumber $number)
3030    {
3031        $regionCode = $this->getRegionCodeForNumber($number);
3032        return $this->isValidNumberForRegion($number, $regionCode);
3033    }
3034
3035    /**
3036     * Tests whether a phone number is valid for a certain region. Note this doesn't verify the number
3037     * is actually in use, which is impossible to tell by just looking at a number itself. If the
3038     * country calling code is not the same as the country calling code for the region, this
3039     * immediately exits with false. After this, the specific number pattern rules for the region are
3040     * examined. This is useful for determining for example whether a particular number is valid for
3041     * Canada, rather than just a valid NANPA number.
3042     * Warning: In most cases, you want to use {@link #isValidNumber} instead. For example, this
3043     * method will mark numbers from British Crown dependencies such as the Isle of Man as invalid for
3044     * the region "GB" (United Kingdom), since it has its own region code, "IM", which may be
3045     * undesirable.
3046     *
3047     * @param PhoneNumber $number the phone number that we want to validate
3048     * @param string $regionCode the region that we want to validate the phone number for
3049     * @return boolean that indicates whether the number is of a valid pattern
3050     */
3051    public function isValidNumberForRegion(PhoneNumber $number, $regionCode)
3052    {
3053        $countryCode = $number->getCountryCode();
3054        $metadata = $this->getMetadataForRegionOrCallingCode($countryCode, $regionCode);
3055        if (($metadata === null) ||
3056            (static::REGION_CODE_FOR_NON_GEO_ENTITY !== $regionCode &&
3057                $countryCode !== $this->getCountryCodeForValidRegion($regionCode))
3058        ) {
3059            // Either the region code was invalid, or the country calling code for this number does not
3060            // match that of the region code.
3061            return false;
3062        }
3063        $nationalSignificantNumber = $this->getNationalSignificantNumber($number);
3064
3065        return $this->getNumberTypeHelper($nationalSignificantNumber, $metadata) != PhoneNumberType::UNKNOWN;
3066    }
3067
3068    /**
3069     * Parses a string and returns it as a phone number in proto buffer format. The method is quite
3070     * lenient and looks for a number in the input text (raw input) and does not check whether the
3071     * string is definitely only a phone number. To do this, it ignores punctuation and white-space,
3072     * as well as any text before the number (e.g. a leading “Tel: ”) and trims the non-number bits.
3073     * It will accept a number in any format (E164, national, international etc), assuming it can
3074     * interpreted with the defaultRegion supplied. It also attempts to convert any alpha characters
3075     * into digits if it thinks this is a vanity number of the type "1800 MICROSOFT".
3076     *
3077     * <p> This method will throw a {@link NumberParseException} if the number is not considered to
3078     * be a possible number. Note that validation of whether the number is actually a valid number
3079     * for a particular region is not performed. This can be done separately with {@link #isValidNumber}.
3080     *
3081     * <p> Note this method canonicalizes the phone number such that different representations can be
3082     * easily compared, no matter what form it was originally entered in (e.g. national,
3083     * international). If you want to record context about the number being parsed, such as the raw
3084     * input that was entered, how the country code was derived etc. then call {@link
3085     * #parseAndKeepRawInput} instead.
3086     *
3087     * @param string $numberToParse number that we are attempting to parse. This can contain formatting
3088     *                          such as +, ( and -, as well as a phone number extension.
3089     * @param string|null $defaultRegion region that we are expecting the number to be from. This is only used
3090     *                          if the number being parsed is not written in international format.
3091     *                          The country_code for the number in this case would be stored as that
3092     *                          of the default region supplied. If the number is guaranteed to
3093     *                          start with a '+' followed by the country calling code, then
3094     *                          "ZZ" or null can be supplied.
3095     * @param PhoneNumber|null $phoneNumber
3096     * @param bool $keepRawInput
3097     * @return PhoneNumber a phone number proto buffer filled with the parsed number
3098     * @throws NumberParseException  if the string is not considered to be a viable phone number (e.g.
3099     *                               too few or too many digits) or if no default region was supplied
3100     *                               and the number is not in international format (does not start
3101     *                               with +)
3102     */
3103    public function parse($numberToParse, $defaultRegion = null, PhoneNumber $phoneNumber = null, $keepRawInput = false)
3104    {
3105        if ($phoneNumber === null) {
3106            $phoneNumber = new PhoneNumber();
3107        }
3108        $this->parseHelper($numberToParse, $defaultRegion, $keepRawInput, true, $phoneNumber);
3109        return $phoneNumber;
3110    }
3111
3112    /**
3113     * Formats a phone number in the specified format using client-defined formatting rules. Note that
3114     * if the phone number has a country calling code of zero or an otherwise invalid country calling
3115     * code, we cannot work out things like whether there should be a national prefix applied, or how
3116     * to format extensions, so we return the national significant number with no formatting applied.
3117     *
3118     * @param PhoneNumber $number the phone number to be formatted
3119     * @param int $numberFormat the format the phone number should be formatted into
3120     * @param array $userDefinedFormats formatting rules specified by clients
3121     * @return String the formatted phone number
3122     */
3123    public function formatByPattern(PhoneNumber $number, $numberFormat, array $userDefinedFormats)
3124    {
3125        $countryCallingCode = $number->getCountryCode();
3126        $nationalSignificantNumber = $this->getNationalSignificantNumber($number);
3127        if (!$this->hasValidCountryCallingCode($countryCallingCode)) {
3128            return $nationalSignificantNumber;
3129        }
3130        // Note getRegionCodeForCountryCode() is used because formatting information for regions which
3131        // share a country calling code is contained by only one region for performance reasons. For
3132        // example, for NANPA regions it will be contained in the metadata for US.
3133        $regionCode = $this->getRegionCodeForCountryCode($countryCallingCode);
3134        // Metadata cannot be null because the country calling code is valid.
3135        $metadata = $this->getMetadataForRegionOrCallingCode($countryCallingCode, $regionCode);
3136
3137        $formattedNumber = '';
3138
3139        $formattingPattern = $this->chooseFormattingPatternForNumber($userDefinedFormats, $nationalSignificantNumber);
3140        if ($formattingPattern === null) {
3141            // If no pattern above is matched, we format the number as a whole.
3142            $formattedNumber .= $nationalSignificantNumber;
3143        } else {
3144            $numFormatCopy = new NumberFormat();
3145            // Before we do a replacement of the national prefix pattern $NP with the national prefix, we
3146            // need to copy the rule so that subsequent replacements for different numbers have the
3147            // appropriate national prefix.
3148            $numFormatCopy->mergeFrom($formattingPattern);
3149            $nationalPrefixFormattingRule = $formattingPattern->getNationalPrefixFormattingRule();
3150            if (mb_strlen($nationalPrefixFormattingRule) > 0) {
3151                $nationalPrefix = $metadata->getNationalPrefix();
3152                if (mb_strlen($nationalPrefix) > 0) {
3153                    // Replace $NP with national prefix and $FG with the first group ($1).
3154                    $nationalPrefixFormattingRule = str_replace(
3155                        array(static::NP_STRING, static::FG_STRING),
3156                        array($nationalPrefix, '$1'),
3157                        $nationalPrefixFormattingRule
3158                    );
3159                    $numFormatCopy->setNationalPrefixFormattingRule($nationalPrefixFormattingRule);
3160                } else {
3161                    // We don't want to have a rule for how to format the national prefix if there isn't one.
3162                    $numFormatCopy->clearNationalPrefixFormattingRule();
3163                }
3164            }
3165            $formattedNumber .= $this->formatNsnUsingPattern($nationalSignificantNumber, $numFormatCopy, $numberFormat);
3166        }
3167        $this->maybeAppendFormattedExtension($number, $metadata, $numberFormat, $formattedNumber);
3168        $this->prefixNumberWithCountryCallingCode($countryCallingCode, $numberFormat, $formattedNumber);
3169        return $formattedNumber;
3170    }
3171
3172    /**
3173     * Gets a valid number for the specified region.
3174     *
3175     * @param string regionCode  the region for which an example number is needed
3176     * @return PhoneNumber a valid fixed-line number for the specified region. Returns null when the metadata
3177     *    does not contain such information, or the region 001 is passed in. For 001 (representing
3178     *    non-geographical numbers), call {@link #getExampleNumberForNonGeoEntity} instead.
3179     */
3180    public function getExampleNumber($regionCode)
3181    {
3182        return $this->getExampleNumberForType($regionCode, PhoneNumberType::FIXED_LINE);
3183    }
3184
3185    /**
3186     * Gets an invalid number for the specified region. This is useful for unit-testing purposes,
3187     * where you want to test what will happen with an invalid number. Note that the number that is
3188     * returned will always be able to be parsed and will have the correct country code. It may also
3189     * be a valid *short* number/code for this region. Validity checking such numbers is handled with
3190     * {@link ShortNumberInfo}.
3191     *
3192     * @param string $regionCode The region for which an example number is needed
3193     * @return PhoneNumber|null An invalid number for the specified region. Returns null when an unsupported region
3194     * or the region 001 (Earth) is passed in.
3195     */
3196    public function getInvalidExampleNumber($regionCode)
3197    {
3198        if (!$this->isValidRegionCode($regionCode)) {
3199            return null;
3200        }
3201
3202        // We start off with a valid fixed-line number since every country supports this. Alternatively
3203        // we could start with a different number type, since fixed-line numbers typically have a wide
3204        // breadth of valid number lengths and we may have to make it very short before we get an
3205        // invalid number.
3206
3207        $desc = $this->getNumberDescByType($this->getMetadataForRegion($regionCode), PhoneNumberType::FIXED_LINE);
3208
3209        if ($desc->getExampleNumber() == '') {
3210            // This shouldn't happen; we have a test for this.
3211            return null;
3212        }
3213
3214        $exampleNumber = $desc->getExampleNumber();
3215
3216        // Try and make the number invalid. We do this by changing the length. We try reducing the
3217        // length of the number, since currently no region has a number that is the same length as
3218        // MIN_LENGTH_FOR_NSN. This is probably quicker than making the number longer, which is another
3219        // alternative. We could also use the possible number pattern to extract the possible lengths of
3220        // the number to make this faster, but this method is only for unit-testing so simplicity is
3221        // preferred to performance.  We don't want to return a number that can't be parsed, so we check
3222        // the number is long enough. We try all possible lengths because phone number plans often have
3223        // overlapping prefixes so the number 123456 might be valid as a fixed-line number, and 12345 as
3224        // a mobile number. It would be faster to loop in a different order, but we prefer numbers that
3225        // look closer to real numbers (and it gives us a variety of different lengths for the resulting
3226        // phone numbers - otherwise they would all be MIN_LENGTH_FOR_NSN digits long.)
3227        for ($phoneNumberLength = mb_strlen($exampleNumber) - 1; $phoneNumberLength >= static::MIN_LENGTH_FOR_NSN; $phoneNumberLength--) {
3228            $numberToTry = mb_substr($exampleNumber, 0, $phoneNumberLength);
3229            try {
3230                $possiblyValidNumber = $this->parse($numberToTry, $regionCode);
3231                if (!$this->isValidNumber($possiblyValidNumber)) {
3232                    return $possiblyValidNumber;
3233                }
3234            } catch (NumberParseException $e) {
3235                // Shouldn't happen: we have already checked the length, we know example numbers have
3236                // only valid digits, and we know the region code is fine.
3237            }
3238        }
3239        // We have a test to check that this doesn't happen for any of our supported regions.
3240        return null;
3241    }
3242
3243    /**
3244     * Gets a valid number for the specified region and number type.
3245     *
3246     * @param string|int $regionCodeOrType the region for which an example number is needed
3247     * @param int $type the PhoneNumberType of number that is needed
3248     * @return PhoneNumber|null a valid number for the specified region and type. Returns null when the metadata
3249     *     does not contain such information or if an invalid region or region 001 was entered.
3250     *     For 001 (representing non-geographical numbers), call
3251     *     {@link #getExampleNumberForNonGeoEntity} instead.
3252     *
3253     * If $regionCodeOrType is the only parameter supplied, then a valid number for the specified number type
3254     * will be returned that may belong to any country.
3255     */
3256    public function getExampleNumberForType($regionCodeOrType, $type = null)
3257    {
3258        if ($regionCodeOrType !== null && $type === null) {
3259            /*
3260             * Gets a valid number for the specified number type (it may belong to any country).
3261             */
3262            foreach ($this->getSupportedRegions() as $regionCode) {
3263                $exampleNumber = $this->getExampleNumberForType($regionCode, $regionCodeOrType);
3264                if ($exampleNumber !== null) {
3265                    return $exampleNumber;
3266                }
3267            }
3268
3269            // If there wasn't an example number for a region, try the non-geographical entities.
3270            foreach ($this->getSupportedGlobalNetworkCallingCodes() as $countryCallingCode) {
3271                $desc = $this->getNumberDescByType($this->getMetadataForNonGeographicalRegion($countryCallingCode), $regionCodeOrType);
3272                try {
3273                    if ($desc->getExampleNumber() != '') {
3274                        return $this->parse('+' . $countryCallingCode . $desc->getExampleNumber(), static::UNKNOWN_REGION);
3275                    }
3276                } catch (NumberParseException $e) {
3277                    // noop
3278                }
3279            }
3280            // There are no example numbers of this type for any country in the library.
3281            return null;
3282        }
3283
3284        // Check the region code is valid.
3285        if (!$this->isValidRegionCode($regionCodeOrType)) {
3286            return null;
3287        }
3288        $desc = $this->getNumberDescByType($this->getMetadataForRegion($regionCodeOrType), $type);
3289        try {
3290            if ($desc->hasExampleNumber()) {
3291                return $this->parse($desc->getExampleNumber(), $regionCodeOrType);
3292            }
3293        } catch (NumberParseException $e) {
3294            // noop
3295        }
3296        return null;
3297    }
3298
3299    /**
3300     * @param PhoneMetadata $metadata
3301     * @param int $type PhoneNumberType
3302     * @return PhoneNumberDesc
3303     */
3304    protected function getNumberDescByType(PhoneMetadata $metadata, $type)
3305    {
3306        switch ($type) {
3307            case PhoneNumberType::PREMIUM_RATE:
3308                return $metadata->getPremiumRate();
3309            case PhoneNumberType::TOLL_FREE:
3310                return $metadata->getTollFree();
3311            case PhoneNumberType::MOBILE:
3312                return $metadata->getMobile();
3313            case PhoneNumberType::FIXED_LINE:
3314            case PhoneNumberType::FIXED_LINE_OR_MOBILE:
3315                return $metadata->getFixedLine();
3316            case PhoneNumberType::SHARED_COST:
3317                return $metadata->getSharedCost();
3318            case PhoneNumberType::VOIP:
3319                return $metadata->getVoip();
3320            case PhoneNumberType::PERSONAL_NUMBER:
3321                return $metadata->getPersonalNumber();
3322            case PhoneNumberType::PAGER:
3323                return $metadata->getPager();
3324            case PhoneNumberType::UAN:
3325                return $metadata->getUan();
3326            case PhoneNumberType::VOICEMAIL:
3327                return $metadata->getVoicemail();
3328            default:
3329                return $metadata->getGeneralDesc();
3330        }
3331    }
3332
3333    /**
3334     * Gets a valid number for the specified country calling code for a non-geographical entity.
3335     *
3336     * @param int $countryCallingCode the country calling code for a non-geographical entity
3337     * @return PhoneNumber a valid number for the non-geographical entity. Returns null when the metadata
3338     *    does not contain such information, or the country calling code passed in does not belong
3339     *    to a non-geographical entity.
3340     */
3341    public function getExampleNumberForNonGeoEntity($countryCallingCode)
3342    {
3343        $metadata = $this->getMetadataForNonGeographicalRegion($countryCallingCode);
3344        if ($metadata !== null) {
3345            // For geographical entities, fixed-line data is always present. However, for non-geographical
3346            // entities, this is not the case, so we have to go through different types to find the
3347            // example number. We don't check fixed-line or personal number since they aren't used by
3348            // non-geographical entities (if this changes, a unit-test will catch this.)
3349            /** @var PhoneNumberDesc[] $list */
3350            $list = array(
3351                $metadata->getMobile(),
3352                $metadata->getTollFree(),
3353                $metadata->getSharedCost(),
3354                $metadata->getVoip(),
3355                $metadata->getVoicemail(),
3356                $metadata->getUan(),
3357                $metadata->getPremiumRate(),
3358            );
3359            foreach ($list as $desc) {
3360                try {
3361                    if ($desc !== null && $desc->hasExampleNumber()) {
3362                        return $this->parse('+' . $countryCallingCode . $desc->getExampleNumber(), self::UNKNOWN_REGION);
3363                    }
3364                } catch (NumberParseException $e) {
3365                    // noop
3366                }
3367            }
3368        }
3369        return null;
3370    }
3371
3372
3373    /**
3374     * Takes two phone numbers and compares them for equality.
3375     *
3376     * <p>Returns EXACT_MATCH if the country_code, NSN, presence of a leading zero
3377     * for Italian numbers and any extension present are the same. Returns NSN_MATCH
3378     * if either or both has no region specified, and the NSNs and extensions are
3379     * the same. Returns SHORT_NSN_MATCH if either or both has no region specified,
3380     * or the region specified is the same, and one NSN could be a shorter version
3381     * of the other number. This includes the case where one has an extension
3382     * specified, and the other does not. Returns NO_MATCH otherwise. For example,
3383     * the numbers +1 345 657 1234 and 657 1234 are a SHORT_NSN_MATCH. The numbers
3384     * +1 345 657 1234 and 345 657 are a NO_MATCH.
3385     *
3386     * @param $firstNumberIn PhoneNumber|string First number to compare. If it is a
3387     * string it can contain formatting, and can have country calling code specified
3388     * with + at the start.
3389     * @param $secondNumberIn PhoneNumber|string Second number to compare. If it is a
3390     * string it can contain formatting, and can have country calling code specified
3391     * with + at the start.
3392     * @throws \InvalidArgumentException
3393     * @return int {MatchType} NOT_A_NUMBER, NO_MATCH,
3394     */
3395    public function isNumberMatch($firstNumberIn, $secondNumberIn)
3396    {
3397        if (is_string($firstNumberIn) && is_string($secondNumberIn)) {
3398            try {
3399                $firstNumberAsProto = $this->parse($firstNumberIn, static::UNKNOWN_REGION);
3400                return $this->isNumberMatch($firstNumberAsProto, $secondNumberIn);
3401            } catch (NumberParseException $e) {
3402                if ($e->getErrorType() === NumberParseException::INVALID_COUNTRY_CODE) {
3403                    try {
3404                        $secondNumberAsProto = $this->parse($secondNumberIn, static::UNKNOWN_REGION);
3405                        return $this->isNumberMatch($secondNumberAsProto, $firstNumberIn);
3406                    } catch (NumberParseException $e2) {
3407                        if ($e2->getErrorType() === NumberParseException::INVALID_COUNTRY_CODE) {
3408                            try {
3409                                $firstNumberProto = new PhoneNumber();
3410                                $secondNumberProto = new PhoneNumber();
3411                                $this->parseHelper($firstNumberIn, null, false, false, $firstNumberProto);
3412                                $this->parseHelper($secondNumberIn, null, false, false, $secondNumberProto);
3413                                return $this->isNumberMatch($firstNumberProto, $secondNumberProto);
3414                            } catch (NumberParseException $e3) {
3415                                // Fall through and return MatchType::NOT_A_NUMBER
3416                            }
3417                        }
3418                    }
3419                }
3420            }
3421            return MatchType::NOT_A_NUMBER;
3422        }
3423        if ($firstNumberIn instanceof PhoneNumber && is_string($secondNumberIn)) {
3424            // First see if the second number has an implicit country calling code, by attempting to parse
3425            // it.
3426            try {
3427                $secondNumberAsProto = $this->parse($secondNumberIn, static::UNKNOWN_REGION);
3428                return $this->isNumberMatch($firstNumberIn, $secondNumberAsProto);
3429            } catch (NumberParseException $e) {
3430                if ($e->getErrorType() === NumberParseException::INVALID_COUNTRY_CODE) {
3431                    // The second number has no country calling code. EXACT_MATCH is no longer possible.
3432                    // We parse it as if the region was the same as that for the first number, and if
3433                    // EXACT_MATCH is returned, we replace this with NSN_MATCH.
3434                    $firstNumberRegion = $this->getRegionCodeForCountryCode($firstNumberIn->getCountryCode());
3435                    try {
3436                        if ($firstNumberRegion != static::UNKNOWN_REGION) {
3437                            $secondNumberWithFirstNumberRegion = $this->parse($secondNumberIn, $firstNumberRegion);
3438                            $match = $this->isNumberMatch($firstNumberIn, $secondNumberWithFirstNumberRegion);
3439                            if ($match === MatchType::EXACT_MATCH) {
3440                                return MatchType::NSN_MATCH;
3441                            }
3442                            return $match;
3443                        }
3444
3445                        // If the first number didn't have a valid country calling code, then we parse the
3446                        // second number without one as well.
3447                        $secondNumberProto = new PhoneNumber();
3448                        $this->parseHelper($secondNumberIn, null, false, false, $secondNumberProto);
3449                        return $this->isNumberMatch($firstNumberIn, $secondNumberProto);
3450                    } catch (NumberParseException $e2) {
3451                        // Fall-through to return NOT_A_NUMBER.
3452                    }
3453                }
3454            }
3455        }
3456        if ($firstNumberIn instanceof PhoneNumber && $secondNumberIn instanceof PhoneNumber) {
3457            // We only care about the fields that uniquely define a number, so we copy these across
3458            // explicitly.
3459            $firstNumber = self::copyCoreFieldsOnly($firstNumberIn);
3460            $secondNumber = self::copyCoreFieldsOnly($secondNumberIn);
3461
3462            // Early exit if both had extensions and these are different.
3463            if ($firstNumber->hasExtension() && $secondNumber->hasExtension() &&
3464                $firstNumber->getExtension() != $secondNumber->getExtension()
3465            ) {
3466                return MatchType::NO_MATCH;
3467            }
3468
3469            $firstNumberCountryCode = $firstNumber->getCountryCode();
3470            $secondNumberCountryCode = $secondNumber->getCountryCode();
3471            // Both had country_code specified.
3472            if ($firstNumberCountryCode != 0 && $secondNumberCountryCode != 0) {
3473                if ($firstNumber->equals($secondNumber)) {
3474                    return MatchType::EXACT_MATCH;
3475                }
3476
3477                if ($firstNumberCountryCode == $secondNumberCountryCode &&
3478                    $this->isNationalNumberSuffixOfTheOther($firstNumber, $secondNumber)) {
3479                    // A SHORT_NSN_MATCH occurs if there is a difference because of the presence or absence of
3480                    // an 'Italian leading zero', the presence or absence of an extension, or one NSN being a
3481                    // shorter variant of the other.
3482                    return MatchType::SHORT_NSN_MATCH;
3483                }
3484                // This is not a match.
3485                return MatchType::NO_MATCH;
3486            }
3487            // Checks cases where one or both country_code fields were not specified. To make equality
3488            // checks easier, we first set the country_code fields to be equal.
3489            $firstNumber->setCountryCode($secondNumberCountryCode);
3490            // If all else was the same, then this is an NSN_MATCH.
3491            if ($firstNumber->equals($secondNumber)) {
3492                return MatchType::NSN_MATCH;
3493            }
3494            if ($this->isNationalNumberSuffixOfTheOther($firstNumber, $secondNumber)) {
3495                return MatchType::SHORT_NSN_MATCH;
3496            }
3497            return MatchType::NO_MATCH;
3498        }
3499        return MatchType::NOT_A_NUMBER;
3500    }
3501
3502    /**
3503     * Returns true when one national number is the suffix of the other or both are the same.
3504     * @param PhoneNumber $firstNumber
3505     * @param PhoneNumber $secondNumber
3506     * @return bool
3507     */
3508    protected function isNationalNumberSuffixOfTheOther(PhoneNumber $firstNumber, PhoneNumber $secondNumber)
3509    {
3510        $firstNumberNationalNumber = trim((string)$firstNumber->getNationalNumber());
3511        $secondNumberNationalNumber = trim((string)$secondNumber->getNationalNumber());
3512        return $this->stringEndsWithString($firstNumberNationalNumber, $secondNumberNationalNumber) ||
3513        $this->stringEndsWithString($secondNumberNationalNumber, $firstNumberNationalNumber);
3514    }
3515
3516    /**
3517     * Returns true if a string ends with a given substring, false otherwise.
3518     *
3519     * @param string $hayStack
3520     * @param string $needle
3521     * @return bool
3522     */
3523    protected function stringEndsWithString($hayStack, $needle)
3524    {
3525        $revNeedle = strrev($needle);
3526        $revHayStack = strrev($hayStack);
3527        return strpos($revHayStack, $revNeedle) === 0;
3528    }
3529
3530    /**
3531     * Returns true if the supplied region supports mobile number portability. Returns false for
3532     * invalid, unknown or regions that don't support mobile number portability.
3533     *
3534     * @param string $regionCode the region for which we want to know whether it supports mobile number
3535     *                    portability or not.
3536     * @return bool
3537     */
3538    public function isMobileNumberPortableRegion($regionCode)
3539    {
3540        $metadata = $this->getMetadataForRegion($regionCode);
3541        if ($metadata === null) {
3542            return false;
3543        }
3544
3545        return $metadata->isMobileNumberPortableRegion();
3546    }
3547
3548    /**
3549     * Check whether a phone number is a possible number given a number in the form of a string, and
3550     * the region where the number could be dialed from. It provides a more lenient check than
3551     * {@link #isValidNumber}. See {@link #isPossibleNumber(PhoneNumber)} for details.
3552     *
3553     * Convenience wrapper around {@link #isPossibleNumberWithReason}. Instead of returning the reason
3554     * for failure, this method returns a boolean value.
3555     * For failure, this method returns true if the number is either a possible fully-qualified number
3556     * (containing the area code and country code), or if the number could be a possible local number
3557     * (with a country code, but missing an area code). Local numbers are considered possible if they
3558     * could be possibly dialled in this format: if the area code is needed for a call to connect, the
3559     * number is not considered possible without it.
3560     *
3561     * Note: There are two ways to call this method.
3562     *
3563     * isPossibleNumber(PhoneNumber $numberObject)
3564     * isPossibleNumber(string '+441174960126', string 'GB')
3565     *
3566     * @param PhoneNumber|string $number the number that needs to be checked, in the form of a string
3567     * @param string|null $regionDialingFrom the region that we are expecting the number to be dialed from.
3568     *     Note this is different from the region where the number belongs.  For example, the number
3569     *     +1 650 253 0000 is a number that belongs to US. When written in this form, it can be
3570     *     dialed from any region. When it is written as 00 1 650 253 0000, it can be dialed from any
3571     *     region which uses an international dialling prefix of 00. When it is written as
3572     *     650 253 0000, it can only be dialed from within the US, and when written as 253 0000, it
3573     *     can only be dialed from within a smaller area in the US (Mountain View, CA, to be more
3574     *     specific).
3575     * @return boolean true if the number is possible
3576     */
3577    public function isPossibleNumber($number, $regionDialingFrom = null)
3578    {
3579        if (is_string($number)) {
3580            try {
3581                return $this->isPossibleNumber($this->parse($number, $regionDialingFrom));
3582            } catch (NumberParseException $e) {
3583                return false;
3584            }
3585        } else {
3586            $result = $this->isPossibleNumberWithReason($number);
3587            return $result === ValidationResult::IS_POSSIBLE
3588                || $result === ValidationResult::IS_POSSIBLE_LOCAL_ONLY;
3589        }
3590    }
3591
3592
3593    /**
3594     * Check whether a phone number is a possible number. It provides a more lenient check than
3595     * {@link #isValidNumber} in the following sense:
3596     * <ol>
3597     *   <li> It only checks the length of phone numbers. In particular, it doesn't check starting
3598     *        digits of the number.
3599     *   <li> It doesn't attempt to figure out the type of the number, but uses general rules which
3600     *        applies to all types of phone numbers in a region. Therefore, it is much faster than
3601     *        isValidNumber.
3602     *   <li> For some numbers (particularly fixed-line), many regions have the concept of area code,
3603     *        which together with subscriber number constitute the national significant number. It is
3604     *        sometimes okay to dial only the subscriber number when dialing in the same area. This
3605     *        function will return IS_POSSIBLE_LOCAL_ONLY if the subscriber-number-only version is
3606     *        passed in. On the other hand, because isValidNumber validates using information on both
3607     *        starting digits (for fixed line numbers, that would most likely be area codes) and
3608     *        length (obviously includes the length of area codes for fixed line numbers), it will
3609     *        return false for the subscriber-number-only version.
3610     * </ol>
3611     * @param PhoneNumber $number the number that needs to be checked
3612     * @return int a ValidationResult object which indicates whether the number is possible
3613     */
3614    public function isPossibleNumberWithReason(PhoneNumber $number)
3615    {
3616        return $this->isPossibleNumberForTypeWithReason($number, PhoneNumberType::UNKNOWN);
3617    }
3618
3619    /**
3620     * Check whether a phone number is a possible number of a particular type. For types that don't
3621     * exist in a particular region, this will return a result that isn't so useful; it is recommended
3622     * that you use {@link #getSupportedTypesForRegion} or {@link #getSupportedTypesForNonGeoEntity}
3623     * respectively before calling this method to determine whether you should call it for this number
3624     * at all.
3625     *
3626     * This provides a more lenient check than {@link #isValidNumber} in the following sense:
3627     *
3628     * <ol>
3629     *   <li> It only checks the length of phone numbers. In particular, it doesn't check starting
3630     *        digits of the number.
3631     *   <li> For some numbers (particularly fixed-line), many regions have the concept of area code,
3632     *        which together with subscriber number constitute the national significant number. It is
3633     *        sometimes okay to dial only the subscriber number when dialing in the same area. This
3634     *        function will return IS_POSSIBLE_LOCAL_ONLY if the subscriber-number-only version is
3635     *        passed in. On the other hand, because isValidNumber validates using information on both
3636     *        starting digits (for fixed line numbers, that would most likely be area codes) and
3637     *        length (obviously includes the length of area codes for fixed line numbers), it will
3638     *        return false for the subscriber-number-only version.
3639     * </ol>
3640     *
3641     * @param PhoneNumber $number the number that needs to be checked
3642     * @param int $type the PhoneNumberType we are interested in
3643     * @return int a ValidationResult object which indicates whether the number is possible
3644     */
3645    public function isPossibleNumberForTypeWithReason(PhoneNumber $number, $type)
3646    {
3647        $nationalNumber = $this->getNationalSignificantNumber($number);
3648        $countryCode = $number->getCountryCode();
3649
3650        // Note: For regions that share a country calling code, like NANPA numbers, we just use the
3651        // rules from the default region (US in this case) since the getRegionCodeForNumber will not
3652        // work if the number is possible but not valid. There is in fact one country calling code (290)
3653        // where the possible number pattern differs between various regions (Saint Helena and Tristan
3654        // da Cuñha), but this is handled by putting all possible lengths for any country with this
3655        // country calling code in the metadata for the default region in this case.
3656        if (!$this->hasValidCountryCallingCode($countryCode)) {
3657            return ValidationResult::INVALID_COUNTRY_CODE;
3658        }
3659
3660        $regionCode = $this->getRegionCodeForCountryCode($countryCode);
3661        // Metadata cannot be null because the country calling code is valid.
3662        $metadata = $this->getMetadataForRegionOrCallingCode($countryCode, $regionCode);
3663        return $this->testNumberLength($nationalNumber, $metadata, $type);
3664    }
3665
3666    /**
3667     * Attempts to extract a valid number from a phone number that is too long to be valid, and resets
3668     * the PhoneNumber object passed in to that valid version. If no valid number could be extracted,
3669     * the PhoneNumber object passed in will not be modified.
3670     *
3671     * @param PhoneNumber $number a PhoneNumber object which contains a number that is too long to be valid.
3672     * @return boolean true if a valid phone number can be successfully extracted.
3673     */
3674    public function truncateTooLongNumber(PhoneNumber $number)
3675    {
3676        if ($this->isValidNumber($number)) {
3677            return true;
3678        }
3679        $numberCopy = new PhoneNumber();
3680        $numberCopy->mergeFrom($number);
3681        $nationalNumber = $number->getNationalNumber();
3682        do {
3683            $nationalNumber = floor($nationalNumber / 10);
3684            $numberCopy->setNationalNumber($nationalNumber);
3685            if ($this->isPossibleNumberWithReason($numberCopy) == ValidationResult::TOO_SHORT || $nationalNumber == 0) {
3686                return false;
3687            }
3688        } while (!$this->isValidNumber($numberCopy));
3689        $number->setNationalNumber($nationalNumber);
3690        return true;
3691    }
3692}
3693