Created
June 5, 2014 17:00
-
-
Save wpsmith/4541a05954aef58a59c5 to your computer and use it in GitHub Desktop.
PHP: Sanitize & Format US Phone Numbers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
function sanitize_phone( $phone, $international = false ) { | |
$format = "/(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:\(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*\)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)?([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})(?:\s*(?:#|x\.?|ext\.?|extension)\s*(\d+))?$/"; | |
$alt_format = '/^(\+\s*)?((0{0,2}1{1,3}[^\d]+)?\(?\s*([2-9][0-9]{2})\s*[^\d]?\s*([2-9][0-9]{2})\s*[^\d]?\s*([\d]{4})){1}(\s*([[:alpha:]#][^\d]*\d.*))?$/'; | |
// Trim & Clean extension | |
$phone = trim( $phone ); | |
$phone = preg_replace( '/\s+(#|x|ext(ension)?)\.?:?\s*(\d+)/', ' ext \3', $phone ); | |
if ( preg_match( $alt_format, $phone, $matches ) ) { | |
return '(' . $matches[4] . ') ' . $matches[5] . '-' . $matches[6] . ( !empty( $matches[8] ) ? ' ' . $matches[8] : '' ); | |
} elseif( preg_match( $format, $phone, $matches ) ) { | |
// format | |
$phone = preg_replace( $format, "($2) $3-$4", $phone ); | |
// Remove likely has a preceding dash | |
$phone = ltrim( $phone, '-' ); | |
// Remove empty area codes | |
if ( false !== strpos( trim( $phone ), '()', 0 ) ) { | |
$phone = ltrim( trim( $phone ), '()' ); | |
} | |
// Trim and remove double spaces created | |
return preg_replace('/\\s+/', ' ', trim( $phone ); | |
} | |
return false; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$array = array( | |
'-234-567-8901', | |
'1-234-567-8901', | |
'1-234-567-8901 x1234', | |
'1-234-567-8901 ext1234', | |
'1 (234) 567-8901', | |
'1.234.567.8901', | |
'1/234/567/8901', | |
'12345678901', | |
'(+351) 282 43 50 50', | |
'90191919908', | |
'555-8909', | |
'001 6867684', | |
'001 6867684x1', | |
'1 (234) 567-8901', | |
'1-234-567-8901 x1234', | |
'1-234-567-8901 ext1234', | |
'1-234 567.89/01 ext.1234', | |
'1(234)5678901x1234', | |
'(123)8575973', | |
'(0055)(123)8575973', | |
'(123)456-7890', | |
'(123)-456-7890', | |
'(123) 456-7890', | |
'(123) 456-7890 x123', | |
'12 1234 123 1 x1111', | |
'12 12 12 12 12', | |
'12 1 1234 123456 x12345', | |
'+12 1234 1234', | |
'+12 12 12 1234', | |
'+12 1234 5678', | |
'+12 12345678', | |
'(123)456789', | |
'(123456789', | |
'(123 456 789', | |
'(123.456.789', | |
'(123-456-789', | |
'123)456789', | |
'123) 456 789', | |
'123).456.789', | |
'123)-456-789', | |
); | |
foreach( $array as $phone ) { | |
echo $phone . ': '; | |
echo "\t\t" . sanitize_phone( $phone ) . "\n"; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
function validate_telephone_number($number, $formats) { | |
$format = trim(ereg_replace("[0-9]", "#", $number)); | |
return (in_array($format, $formats)) ? true : false; | |
} | |
/* Usage Examples */ | |
// List of possible formats: You can add new formats or modify the existing ones | |
$formats = array( | |
'###-###-####', | |
'####-###-###', | |
'(###) ###-###', | |
'####-####-####', | |
'##-###-####-####', | |
'####-####', | |
'###-###-###', | |
'#####-###-###', | |
'##########', | |
); | |
$numbers = array( | |
'08008-555-555', | |
'123-555-555', | |
'1800-1234-5678', | |
'(800) 555-123', | |
'1234567890', | |
); | |
foreach ( $numbers as $number ) { | |
if ( validate_telephone_number( $number, $formats ) ) { | |
echo $number.' is a valid phone number.'; | |
echo "<br />"; | |
} | |
} | |
function sanitize_phone( $phone, $international = false ) { | |
$phone = trim( $phone ); | |
$phone = preg_replace( '/\s+(#|x|ext(ension)?)\.?:?\s*(\d+)/', ' ext \3', $phone ); | |
$us_number = preg_match( '/^(\+\s*)?((0{0,2}1{1,3}[^\d]+)?\(?\s*([2-9][0-9]{2})\s*[^\d]?\s*([2-9][0-9]{2})\s*[^\d]?\s*([\d]{4})){1}(\s*([[:alpha:]#][^\d]*\d.*))?$/', $phone, $matches ); | |
if ( $us_number ) { | |
return 'US: ' . $matches[4] . '-' . $matches[5] . '-' . $matches[6] . ( !empty( $matches[8] ) ? ' ' . $matches[8] : '' ); | |
} | |
if ( ! $international ) { | |
/* SET ERROR: The field must be a valid U.S. phone number (e.g. 888-888-8888) */ | |
return false; | |
} | |
$valid_number = preg_match( '/^(\+\s*)?(?=([.,\s()-]*\d){8})([\d(][\d.,\s()-]*)([[:alpha:]#][^\d]*\d.*)?$/', $phone, $matches ) && preg_match( '/\d{2}/', $phone ); | |
if ( $valid_number ) { | |
return trim( $matches[1] ) . trim( $matches[3] ) . ( !empty( $matches[4] ) ? ' ' . $matches[4] : '' ); | |
} | |
/* SET ERROR: The field must be a valid phone number (e.g. 888-888-8888) */ | |
return false; | |
} | |
function formatPhoneNumber( $s ) { | |
$rx = "/ | |
(1)?\D* # optional country code | |
(\d{3})?\D* # optional area code | |
(\d{3})\D* # first three | |
(\d{4}) # last four | |
(?:\D+|$) # extension delimiter or EOL | |
(\d*) # optional extension | |
/x"; | |
preg_match($rx, $s, $matches); | |
if(!isset($matches[0])) return false; | |
$country = $matches[1]; | |
$area = $matches[2]; | |
$three = $matches[3]; | |
$four = $matches[4]; | |
$ext = $matches[5]; | |
$out = "$three-$four"; | |
if(!empty($area)) $out = "$area-$out"; | |
if(!empty($country)) $out = "+$country-$out"; | |
if(!empty($ext)) $out .= "x$ext"; | |
// check that no digits were truncated | |
// if (preg_replace('/\D/', '', $s) != preg_replace('/\D/', '', $out)) return false; | |
return $out; | |
} | |
function format_phone_number ( $mynum, $mask ) { | |
/*********************************************************************/ | |
/* Purpose: Return either masked phone number or false */ | |
/* Masks: Val=1 or xxx xxx xxxx */ | |
/* Val=2 or xxx xxx.xxxx */ | |
/* Val=3 or xxx.xxx.xxxx */ | |
/* Val=4 or (xxx) xxx xxxx */ | |
/* Val=5 or (xxx) xxx.xxxx */ | |
/* Val=6 or (xxx).xxx.xxxx */ | |
/* Val=7 or (xxx) xxx-xxxx */ | |
/* Val=8 or (xxx)-xxx-xxxx */ | |
/*********************************************************************/ | |
$val_num = validate_phone_number ( $mynum ); | |
if ( !$val_num && !is_string ( $mynum ) ) { | |
echo "Number $mynum is not a valid phone number! \n"; | |
return false; | |
} // end if !$val_num | |
if ( ( $mask == 1 ) || ( $mask == 'xxx xxx xxxx' ) ) { | |
$phone = preg_replace('~.*(\d{3})[^\d]*(\d{3})[^\d]*(\d{4}).*~', | |
'$1 $2 $3'." \n", $mynum); | |
return $phone; | |
} // end if $mask == 1 | |
if ( ( $mask == 2 ) || ( $mask == 'xxx xxx.xxxx' ) ) { | |
$phone = preg_replace('~.*(\d{3})[^\d]*(\d{3})[^\d]*(\d{4}).*~', | |
'$1 $2.$3'." \n", $mynum); | |
return $phone; | |
} // end if $mask == 2 | |
if ( ( $mask == 3 ) || ( $mask == 'xxx.xxx.xxxx' ) ) { | |
$phone = preg_replace('~.*(\d{3})[^\d]*(\d{3})[^\d]*(\d{4}).*~', | |
'$1.$2.$3'." \n", $mynum); | |
return $phone; | |
} // end if $mask == 3 | |
if ( ( $mask == 4 ) || ( $mask == '(xxx) xxx xxxx' ) ) { | |
$phone = preg_replace('~.*(\d{3})[^\d]*(\d{3})[^\d]*(\d{4}).*~', | |
'($1) $2 $3'." \n", $mynum); | |
return $phone; | |
} // end if $mask == 4 | |
if ( ( $mask == 5 ) || ( $mask == '(xxx) xxx.xxxx' ) ) { | |
$phone = preg_replace('~.*(\d{3})[^\d]*(\d{3})[^\d]*(\d{4}).*~', | |
'($1) $2.$3'." \n", $mynum); | |
return $phone; | |
} // end if $mask == 5 | |
if ( ( $mask == 6 ) || ( $mask == '(xxx).xxx.xxxx' ) ) { | |
$phone = preg_replace('~.*(\d{3})[^\d]*(\d{3})[^\d]*(\d{4}).*~', | |
'($1).$2.$3'." \n", $mynum); | |
return $phone; | |
} // end if $mask == 6 | |
if ( ( $mask == 7 ) || ( $mask == '(xxx) xxx-xxxx' ) ) { | |
$phone = preg_replace('~.*(\d{3})[^\d]*(\d{3})[^\d]*(\d{4}).*~', | |
'($1) $2-$3'." \n", $mynum); | |
return $phone; | |
} // end if $mask == 7 | |
if ( ( $mask == 8 ) || ( $mask == '(xxx)-xxx-xxxx' ) ) { | |
$phone = preg_replace('~.*(\d{3})[^\d]*(\d{3})[^\d]*(\d{4}).*~', | |
'($1)-$2-$3'." \n", $mynum); | |
return $phone; | |
} // end if $mask == 8 | |
return false; // Returns false if no conditions meet or input | |
} // end function format_phone_number | |
function validate_phone_number ( $phone ) { | |
/*********************************************************************/ | |
/* Purpose: To determine if the passed string is a valid phone */ | |
/* number following one of the establish formatting */ | |
/* styles for phone numbers. This function also breaks */ | |
/* a valid number into it's respective components of: */ | |
/* 3-digit area code, */ | |
/* 3-digit exchange code, */ | |
/* 4-digit subscriber number */ | |
/* and validates the number against 10 digit US NANPA */ | |
/* guidelines. */ | |
/*********************************************************************/ | |
$format_pattern = '/^(?:(?:\((?=\d{3}\)))?(\d{3})(?:(?<=\(\d{3})\))'. | |
'?[\s.\/-]?)?(\d{3})[\s\.\/-]?(\d{4})\s?(?:(?:(?:'. | |
'(?:e|x|ex|ext)\.?\:?|extension\:?)\s?)(?=\d+)'. | |
'(\d+))?$/'; | |
$nanpa_pattern = '/^(?:1)?(?(?!(37|96))[2-9][0-8][0-9](?<!(11)))?'. | |
'[2-9][0-9]{2}(?<!(11))[0-9]{4}(?<!(555(01([0-9]'. | |
'[0-9])|1212)))$/'; | |
// Init array of variables to false | |
$valid = array('format' => false, | |
'nanpa' => false, | |
'ext' => false, | |
'all' => false); | |
//Check data against the format analyzer | |
if ( preg_match ( $format_pattern, $phone, $matchset ) ) { | |
$valid['format'] = true; | |
} | |
//If formatted properly, continue | |
//if($valid['format']) { | |
if ( !$valid['format'] ) { | |
return false; | |
} else { | |
//Set array of new components | |
$components = array ( 'ac' => $matchset[1], //area code | |
'xc' => $matchset[2], //exchange code | |
'sn' => $matchset[3] //subscriber number | |
); | |
// $components = array ( 'ac' => $matchset[1], //area code | |
// 'xc' => $matchset[2], //exchange code | |
// 'sn' => $matchset[3], //subscriber number | |
// 'xn' => $matchset[4] //extension number | |
// ); | |
//Set array of number variants | |
$numbers = array ( 'original' => $matchset[0], | |
'stripped' => substr(preg_replace('[\D]', '', $matchset[0]), 0, 10) | |
); | |
//Now let's check the first ten digits against NANPA standards | |
if(preg_match($nanpa_pattern, $numbers['stripped'])) { | |
$valid['nanpa'] = true; | |
} | |
//If the NANPA guidelines have been met, continue | |
if ( $valid['nanpa'] ) { | |
if ( !empty ( $components['xn'] ) ) { | |
if ( preg_match ( '/^[\d]{1,6}$/', $components['xn'] ) ) { | |
$valid['ext'] = true; | |
} // end if if preg_match | |
} else { | |
$valid['ext'] = true; | |
} // end if if !empty | |
} // end if $valid nanpa | |
//If the extension number is valid or non-existent, continue | |
if ( $valid['ext'] ) { | |
$valid['all'] = true; | |
} // end if $valid ext | |
} // end if $valid | |
return $valid['all']; | |
} // end functon validate_phone_number | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#0 | |
^(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:\(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*\)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)?([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})(?:\s*(?:#|x\.?|ext\.?|extension)\s*(\d+))?$ | |
#1 | |
1?\W*([2-9][0-8][0-9])\W*([2-9][0-9]{2})\W*([0-9]{4})(\se?x?t?(\d*))? | |
'1?\s*\W?\s*([2-9][0-8][0-9])\s*\W?\s*([2-9][0-9]{2})\s*\W?\s*([0-9]{4})(\se?x?t?(\d*))?'; | |
print "match [$1-$2-$3]\n" if not defined $4; | |
print "match [$1-$2-$3 $5]\n" if defined $4; | |
#2 | |
/^(?:(?:\(?(?:00|\+)([1-4]\d\d|[1-9]\d?)\)?)?[\-\.\ \\\/]?)?((?:\(?\d{1,}\)?[\-\.\ \\\/]?){0,})(?:[\-\.\ \\\/]?(?:#|ext\.?|extension|x)[\-\.\ \\\/]?(\d+))?$/i | |
#3 | |
^((((\(\d{3}\))|(\d{3}-))\d{3}-\d{4})|(\+?\d{2}((-| )\d{1,8}){1,5}))(( x| ext)\d{1,5}){0,1}$ | |
#4 | |
^\d?(?:(?:[\+]?(?:[\d]{1,3}(?:[ ]+|[\-.])))?[(]?(?:[\d]{3})[\-/)]?(?:[ ]+)?)?(?:[a-zA-Z2-9][a-zA-Z0-9 \-.]{6,})(?:(?:[ ]+|[xX]|(i:ext[\.]?)){1,2}(?:[\d]{1,5}))?$ | |
#5 | |
$replace = array( ' ', '-', '/', '(', ')', ',', '.' ); //etc; as needed | |
preg_match( '/1?[0-9]{10}((ext|x)[0-9]{1,4})?/i', str_replace( $replace, '', $phone_num ); | |
#6 | |
^(\\(?\\d\\d\\d\\)?)( |-|\\.)?\\d\\d\\d( |-|\\.)?\\d{4,4}(( |-|\\.)?[ext\\.]+ ?\\d+)?$ | |
#7 | |
/\(?([0-9]{3})\)?([ .-]?)([0-9]{3})\2([0-9]{4})/ | |
#8 | |
^(\(?\d{3}\)?)([ .-])(\d{3})([ .-])(\d{4})$ | |
#9 | |
/\(?([0-9]{3})\)?([ .-]?)([0-9]{3})\2([0-9]{4})/ | |
#10 | |
/\(([0-9]{3})\)([ .-]?)([0-9]{3})\2([0-9]{4})|([0-9]{3})([ .-]?)([0-9]{3})\5([0-9]{4})/ | |
#11 | |
^(?:\([2-9]\d{2}\)\ ?|[2-9]\d{2}(?:\-?|\ ?))[2-9]\d{2}[- ]?\d{4}$ |
+7 (777) 777-7777 ext 777
Fails to validate using sanitize_phone()
within the sanitize_phone.php
file.
It returns:
+7 (777) 777-7777 ext 777 :: +7 () 777-7777
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you, great work. For the sanitize_phone.php you have a missing ')' closing parenthesis at line 30.