Ok, so I've already got the bulk of this worked out... I've got a function right now that will run a pattern check on the phone number it's given and then determine whether it's a "valid" phone number based on the NANPA guidelines.
However, the problem I'm running into is that it allows people to enter "extension" numbers, but I can't figure out how to allow them in multiple formats.
For example:
It would take the following phone number: (123) 456-7890 x345 and mark it as valid... However, if I were to try using: (123) 456-7890 ext345 then it marks it as invalid.
The regex pattern I'm using for the initial check is one I found on the web, and I've done barely any modifications to it thusfar... I've made it so that it allows "." as a separator between numbers, but that's it.
Here's the function: (long winded, I know)
/*
* Function to validate a US phone number and split it into it's 3 components
* 3-digit area code, 3-digit exchange code, 4-digit subscriber number
*/
function validPhone($phone) {
//Set the regex pattern
$pattern = '/^[\(]?(\d{0,3})[\)]?[\.]?[\/]?[\s]?[\-]?(\d{3})[\s]?[\.]?[\/]?[\-]?(\d{4})[\s]?[x]?(\d*)$/';
//Set variable to false
$valid = array(
'ac'=>false,
'ec'=>false,
'sn'=>false,
'en'=>false,
'all'=>false,
);
//Look for match, then dump patterns to $matches
if (preg_match($pattern, $phone, $matches)) {
// Original number
$phone_number = $matches[0];
// 3-digit area code
$area_code = $matches[1];
// Validate area code based on NANPA standards
if(ereg('^[2-9]{1}[0-8]{1}[0-9]{1}$', $area_code)) {
if($area_code != '555') {
$valid['ac'] = true;
}
}
// 3-digit exchange code
$exchange_code = $matches[2];
// Validate exchange code based on NANPA standards
if(ereg('^[2-9]{1}[0-9]{2}$', $exchange_code)) {
$valid['ec'] = true;
}
// 4-digit subscriber number
$sub_number = $matches[3];
// Double check that subscriber number is 0-9 only
if(ereg('^[0-9]{4}$', $sub_number)) {
$valid['sn'] = true;
}
// Extension number (if entered)
$ext_number = $matches[4];
// Double check that extension is 0-9 only
if(!empty($ext_number)) {
if(ereg('^[0-9]*$', $ext_number)) {
$valid['en'] = true;
}
}
echo '<h1>Parsing phone number: '.$phone_number.'</h1>';
echo '<h4>Area Code: '.$area_code.'</h4>';
echo '<h4>Exchange Code: '.$exchange_code.'</h4>';
echo '<h4>Subscriber Number: '.$sub_number.'</h4>';
if(!empty($ext_number)) {
echo '<h4>Extension: '.$ext_number.'</h4>';
}
else {
echo '<h4>No Extension Found</h4>';
}
echo '<hr />';
// Check that all are valid
// before setting final variable
if($valid['ac']) {
echo '<h5>Step 1: Area code is valid</h5>';
if($valid['ec']) {
echo '<h5>Step 2: Extension code is valid</h5>';
if($valid['sn']) {
echo '<h5>Step 3: Subscriber number is valid</h5>';
if(!empty($ext_number) && $valid['en']) {
echo '<h5>Step 4: Extension number is valid</h5>';
$valid['all'] = true;
}
elseif(empty($ext_number)) {
echo '<h5>Step 4: Extension number not set, continuing</h5>';
$valid['all'] = true;
}
}
}
}
}
return $valid['all'];
}
I know it's not setup for efficiency right now, I have echoes everywhere for debugging...
Here's a few examples of formats it will and won't validate:
123-456-7890x123 = validates
123.456.7890x123 = validates
123 456 7890 x123 = validates
(123) 456-7890 x123 = validates
123-456-7890ex123 = doesn't validate
123.456.7890 ex123 = doesn't validate
123 456 7890 ext123 = doesn't validate
Basically, the only way it validates when extensions are entered is if the extension is in the format: x123 (with or without a leading space)
Any other format such as ex, ext, ext:, ex: etc... None of them work.
I know it has to be the original regex pattern, but I can't figure out how to solve it.
Any ideas?
EDIT: I've mixed and modified two of the answers given below to form the full function which now does what I had wanted and then some... So I figured I'd post it here in case anyone else comes looking for this same thing.
/*
* Function to analyze string against many popular formatting styles of phone numbers
* Also breaks phone number into it's respective components
* 3-digit area code, 3-digit exchange code, 4-digit subscriber number
* After which it validates the 10 digit US number against NANPA guidelines
*/
function validPhone($phone) {
$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)))$/';
//Set array of variables to false initially
$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']) {
//Set array of new components
$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;
}
}
else {
$valid['ext'] = true;
}
}
//If the extension number is valid or non-existent, continue
if($valid['ext']) {
$valid['all'] = true;
}
}
return $valid['all'];
}