PHP Phone Validation / Look Up

Ghost

Active Coder
Moderator
Apr 19, 2019
317
142
43
I created a small class/script that handles validating phone numbers through an API.
It's quite simple to use & it just outputs some data. It is not 100% accurate because sometimes it will get the carrier or location wrong, but it can definitely figure out if a phone number is in the correct format, change the format if needed (ex: adding +1 to the start of a number) and provide some useful information. I use the free version of an API (250 requests per month) to do this.

I called my class WuburPV, for Wubur Phone Validation
  1. the verify() function accepts an array that can include the following keys: number, api_key, format (0 for regular, 1 for "pretty json"), and the country_code.
  2. You only need to pass in the phone number with array("number"=>1234567899) for example. You can skip the other values format/country code/etc because our settings file actually has default values for this to avoid inputting all the settings on each page that uses WuburPV.
  3. the fetchURL($url) function is used by verify() func to actually fetch the content from the API we are using. It expects JSON specifically, so I use a try/exception to make sure it's in JSON format. If it errors and the exception is thrown, we know there's an issue with the data return.
  4. The __construct() function fires when the WuburPV class is initiated, which fetches the "public_html/core/settings.php" file and sets the contents to the $this->settings variable, which you can see in use.
"public_html/core/WuburPV.php"
PHP:
<?php
if(!class_exists("WuburPV")){
    class WuburPV{
       
        public function verify($data){
            if(!isset($data['number'])){
                $this->error("You must supply a phone number to verify.");
                return false;
            }
            foreach($this->settings['DEFAULT'] as $opt=>$val){ // get default settings for missing keys
                if(!in_array($data, $opt)){
                   $data[$opt] = $val;
                }
            }
            $url = $this->settings['API_URL'];
            foreach($data as $option=>$value){
                $url = str_replace("{%".strtoupper($option)."%}", $value, $url);
            }
            return $this->fetchURL($url);
        }
       
        public function fetchURL($url){
            if(strpos($url, "http://") !== 0 && strpos($url, "https://") !== 0){
                $url = "https://$url";
            }
            if(FILTER_VAR($url, FILTER_VALIDATE_URL)){
                $contents = @file_get_contents($url);
                try{
                    $contents = json_decode($contents, true);
                    return $contents;
                } catch (Exception $e){
                    $this->error("The results are not in JSON format.");
                    return false;
                }
            } else {
                $this->error("You did not supply a valid URL.");
                return false;
            }
        }
       
        private function error($err){
            $this->error_msg = $err;
        }
       
        public function __construct(){
            $this->settings = include_once __DIR__ . "/settings.php";
            if(!is_array($this->settings)){
                $this->error("The settings file did not return a valid data array.");
            }
        }
    }
}
?>
This next file is the settings file, which is a simple return of an array. I wrote the file this way because its only purpose is to be set to $this->settings in the WuburPV class. Is it ideal or normal? No, but it does the job. You can see that I set an API_URL with some basic "template variables". These variables match the array keys in the "DEFAULT" part of the array, as well as the 'NUMBER' variable supplied when WuburPV is initiated. Any of these variables can be altered when you call WuburPV. The only reason for this settings file to exist is to 1) declare the URL for our API, and 2) provide default values for each piece of data. This allows WuburPV to alter the country code or even the API key, but still fall back to the default if no new value is supplied at run time.

"public_html/core/settings.php"
PHP:
<?php
return array(
    "API_URL"=>"http://apilayer.net/api/validate?access_key={%API_KEY%}&number={%NUMBER%}&country_code={%COUNTRY_CODE%}&format={%FORMAT%}",
    "DEFAULT"=>array(
        "COUNTRY_CODE"=>"US",
        "FORMAT"=>1,
        "API_KEY"=>"HIDDEN-GO-GET-YOUR-OWN"
        )
    );
?>
Lastly, we have the request file. This file is responsible for taking a phone number from a user, initiating WuburPV, passing the data to our class, and then outputting the response.
We start by seeing if the URL (ex: codeforum.org/request.php?number=2032032033) includes a phone number. If it does, we know that we can fire up WuburPV and look for phone info. We do this by passing the $_GET variables into the verify function...

$wuPV = new WuburPV(); initiates our class.
The $_GET array would look like this:
"number"=>2032032033, "country_code"=>"US", etc etc.
It's okay if some random $_GET variables are passed because our function only cares about a few array keys and so if you passed in $_GET['fake-data-key'], it wouldn't affect the result.

We then check to see if our verify() function returns "true" content. If it fails, we can echo out our $wuPV->error_msg!
Assuming we fetched the data, we can check $results['valid'] to see if the phone number is considered valid. If it's not valid, it's not a correct number for the country code. If it is valid, we know to display some information. Because I wanted to make this dynamic & it's just an example of this API (aka NOT USED IN A LIVE SITE CURRENTLY), I just use a loop to echo out each key & value on the page (see screenshots below).

"public_html/request.php"
PHP:
<?php
if(isset($_GET['number'])){
    require_once __DIR__ . "/core/WuburPV.php";
    $wuPV = new WuburPV();
    $results = $wuPV->verify($_GET);
    if($results){
        echo "<h1>Phone Information</h1>";
        if($results['valid']){
            $results['valid'] = "Yes";
            foreach($results as $info=>$val){
                if(strpos($info,"_") !== false){
                   $parts = explode("_",$info);
                   foreach($parts as $part){
                       $newinfo .= ucfirst($part) . " ";
                   }
                } else {
                    $newinfo = ucfirst($info);
                }
                echo "<strong>$newinfo</strong>: $val<br>";
                $newinfo = "";
            }
            echo "<br><a href='./request.php' style='font-size:1.2em;font-weight:800;'>Try again!</a>";
        } else {
            echo "The supplied phone number is not valid for the specified country code. Try again below!";
            $tryagain = true;
        }
    } else {
        echo $wuPV->error_msg;
        $tryagain = true;
    }
}

if(!isset($_GET['number']) || $tryagain){
    ?>
    <h1>Verify Phone #</h1>
    <form method="get" action="">
        <input type="text" name="number" />
        <select name="country_code" id="country_code">
           <option value="" selected="">Empty (Default)</option>
           <option value="AF">Afghanistan (AF)</option>
           <option value="AL">Albania (AL)</option>
           <option value="DZ">Algeria (DZ)</option>
           <option value="AS">American Samoa (AS)</option>
           <option value="AD">Andorra (AD)</option>
           <option value="AO">Angola (AO)</option>
           <option value="AI">Anguilla (AI)</option>
           <option value="AG">Antigua (AG)</option>
           <option value="AR">Argentina (AR)</option>
           <option value="AM">Armenia (AM)</option>
           <option value="AW">Aruba (AW)</option>
           <option value="AU">Australia (AU)</option>
           <option value="AT">Austria (AT)</option>
           <option value="AZ">Azerbaijan (AZ)</option>
           <option value="BS">The Bahamas (BS)</option>
           <option value="BH">Bahrain (BH)</option>
           <option value="BD">Bangladesh (BD)</option>
           <option value="BB">Barbados (BB)</option>
           <option value="BY">Belarus (BY)</option>
           <option value="BE">Belgium (BE)</option>
           <option value="BZ">Belize (BZ)</option>
           <option value="BJ">Benin (BJ)</option>
           <option value="BM">Bermuda (BM)</option>
           <option value="BT">Bhutan (BT)</option>
           <option value="BO">Bolivia (BO)</option>
           <option value="BA">Bosnia and Herzegovina (BA)</option>
           <option value="BW">Botswana (BW)</option>
           <option value="BR">Brazil (BR)</option>
           <option value="IO">British Indian Ocean Territory (IO)</option>
           <option value="BN">Brunei (BN)</option>
           <option value="BG">Bulgaria (BG)</option>
           <option value="BF">Burkina Faso (BF)</option>
           <option value="BI">Burundi (BI)</option>
           <option value="KH">Cambodia (KH)</option>
           <option value="CM">Cameroon (CM)</option>
           <option value="CA">Canada (CA)</option>
           <option value="CV">Cape Verde (CV)</option>
           <option value="KY">Cayman Islands (KY)</option>
           <option value="CF">Central African Republic (CF)</option>
           <option value="TD">Chad (TD)</option>
           <option value="CL">Chile (CL)</option>
           <option value="CN">China (CN)</option>
           <option value="CO">Colombia (CO)</option>
           <option value="KM">Comoros (KM)</option>
           <option value="CG">Republic of the Congo (CG)</option>
           <option value="CD">Democratic Republic of Congo (CD)</option>
           <option value="CK">Cook Islands (CK)</option>
           <option value="CR">Costa Rica (CR)</option>
           <option value="CI">Côte d'Ivoire (CI)</option>
           <option value="HR">Croatia (HR)</option>
           <option value="CU">Cuba (CU)</option>
           <option value="CY">Cyprus (CY)</option>
           <option value="CZ">Czech Republic (CZ)</option>
           <option value="DK">Denmark (DK)</option>
           <option value="DJ">Djibouti (DJ)</option>
           <option value="DM">Dominica (DM)</option>
           <option value="DO">Dominican Republic (DO)</option>
           <option value="EC">Ecuador (EC)</option>
           <option value="EG">Egypt (EG)</option>
           <option value="SV">El Salvador (SV)</option>
           <option value="GQ">Equatorial Guinea (GQ)</option>
           <option value="ER">Eritrea (ER)</option>
           <option value="EE">Estonia (EE)</option>
           <option value="ET">Ethiopia (ET)</option>
           <option value="FK">Falkland Islands (FK)</option>
           <option value="FO">Faroe Islands (FO)</option>
           <option value="FJ">Fiji (FJ)</option>
           <option value="FI">Finland (FI)</option>
           <option value="FR">France (FR)</option>
           <option value="GF">French Guiana (GF)</option>
           <option value="PF">French Polynesia (PF)</option>
           <option value="GA">Gabon (GA)</option>
           <option value="GM">The Gambia (GM)</option>
           <option value="GE">Georgia (GE)</option>
           <option value="DE">Germany (DE)</option>
           <option value="GH">Ghana (GH)</option>
           <option value="GI">Gibraltar (GI)</option>
           <option value="GR">Greece (GR)</option>
           <option value="GL">Greenland (GL)</option>
           <option value="GD">Grenada (GD)</option>
           <option value="GP">Guadeloupe (GP)</option>
           <option value="GU">Guam (GU)</option>
           <option value="GT">Guatemala (GT)</option>
           <option value="GN">Guinea (GN)</option>
           <option value="GW">Guinea-Bissau (GW)</option>
           <option value="GY">Guyana (GY)</option>
           <option value="HT">Haiti (HT)</option>
           <option value="VA">Vatican City (VA)</option>
           <option value="HN">Honduras (HN)</option>
           <option value="HK">Hong Kong (HK)</option>
           <option value="HU">Hungary (HU)</option>
           <option value="IS">Iceland (IS)</option>
           <option value="IN">India (IN)</option>
           <option value="ID">Indonesia (ID)</option>
           <option value="IR">Iran (IR)</option>
           <option value="IQ">Iraq (IQ)</option>
           <option value="IE">Ireland (IE)</option>
           <option value="IL">Israel (IL)</option>
           <option value="IT">Italy (IT)</option>
           <option value="JM">Jamaica (JM)</option>
           <option value="JP">Japan (JP)</option>
           <option value="JO">Jordan (JO)</option>
           <option value="KZ">Kazakhstan (KZ)</option>
           <option value="KE">Kenya (KE)</option>
           <option value="KI">Kiribati (KI)</option>
           <option value="KR">South Korea (KR)</option>
           <option value="KW">Kuwait (KW)</option>
           <option value="KG">Kyrgyzstan (KG)</option>
           <option value="LA">Laos (LA)</option>
           <option value="LV">Latvia (LV)</option>
           <option value="LB">Lebanon (LB)</option>
           <option value="LS">Lesotho (LS)</option>
           <option value="LR">Liberia (LR)</option>
           <option value="LY">Libya (LY)</option>
           <option value="LI">Liechtenstein (LI)</option>
           <option value="LT">Lithuania (LT)</option>
           <option value="LU">Luxembourg (LU)</option>
           <option value="MO">Macau (MO)</option>
           <option value="MK">Macedonia (MK)</option>
           <option value="MG">Madagascar (MG)</option>
           <option value="MW">Malawi (MW)</option>
           <option value="MY">Malaysia (MY)</option>
           <option value="MV">Maldives (MV)</option>
           <option value="ML">Mali (ML)</option>
           <option value="MT">Malta (MT)</option>
           <option value="MH">Marshall Islands (MH)</option>
           <option value="MQ">Martinique (MQ)</option>
           <option value="MR">Mauritania (MR)</option>
           <option value="MU">Mauritius (MU)</option>
           <option value="YT">Mayotte (YT)</option>
           <option value="MX">Mexico (MX)</option>
           <option value="FM">Federated States of Micronesia (FM)</option>
           <option value="MD">Moldova (MD)</option>
           <option value="MC">Monaco (MC)</option>
           <option value="MN">Mongolia (MN)</option>
           <option value="ME">Montenegro (ME)</option>
           <option value="MS">Montserrat (MS)</option>
           <option value="MA">Morocco (MA)</option>
           <option value="MZ">Mozambique (MZ)</option>
           <option value="MM">Burma Myanmar (MM)</option>
           <option value="NA">Namibia (NA)</option>
           <option value="NR">Nauru (NR)</option>
           <option value="NP">Nepal (NP)</option>
           <option value="NL">Netherlands (NL)</option>
           <option value="AN">Netherlands Antilles (AN)</option>
           <option value="NC">New Caledonia (NC)</option>
           <option value="NZ">New Zealand (NZ)</option>
           <option value="NI">Nicaragua (NI)</option>
           <option value="NE">Niger (NE)</option>
           <option value="NG">Nigeria (NG)</option>
           <option value="NU">Niue (NU)</option>
           <option value="NF">Norfolk Island (NF)</option>
           <option value="MP">Northern Mariana Islands (MP)</option>
           <option value="NO">Norway (NO)</option>
           <option value="OM">Oman (OM)</option>
           <option value="PK">Pakistan (PK)</option>
           <option value="PW">Palau (PW)</option>
           <option value="PS">Palestine (PS)</option>
           <option value="PA">Panama (PA)</option>
           <option value="PG">Papua New Guinea (PG)</option>
           <option value="PY">Paraguay (PY)</option>
           <option value="PE">Peru (PE)</option>
           <option value="PH">Philippines (PH)</option>
           <option value="PL">Poland (PL)</option>
           <option value="PT">Portugal (PT)</option>
           <option value="PR">Puerto Rico (PR)</option>
           <option value="QA">Qatar (QA)</option>
           <option value="RE">Réunion (RE)</option>
           <option value="RO">Romania (RO)</option>
           <option value="RU">Russia (RU)</option>
           <option value="RW">Rwanda (RW)</option>
           <option value="BL">Saint Barthélemy (BL)</option>
           <option value="SH">Saint Helena (SH)</option>
           <option value="KN">Saint Kitts and Nevis (KN)</option>
           <option value="LC">St. Lucia (LC)</option>
           <option value="MF">Saint Martin (MF)</option>
           <option value="PM">Saint Pierre and Miquelon (PM)</option>
           <option value="VC">Saint Vincent and the Grenadines (VC)</option>
           <option value="WS">Samoa (WS)</option>
           <option value="SM">San Marino (SM)</option>
           <option value="ST">São Tomé and PrÃncipe (ST)</option>
           <option value="SA">Saudi Arabia (SA)</option>
           <option value="SN">Senegal (SN)</option>
           <option value="RS">Serbia (RS)</option>
           <option value="SC">Seychelles (SC)</option>
           <option value="SL">Sierra Leone (SL)</option>
           <option value="SG">Singapore (SG)</option>
           <option value="SK">Slovakia (SK)</option>
           <option value="SI">Slovenia (SI)</option>
           <option value="SB">Solomon Islands (SB)</option>
           <option value="SO">Somalia (SO)</option>
           <option value="ZA">South Africa (ZA)</option>
           <option value="ES">Spain (ES)</option>
           <option value="LK">Sri Lanka (LK)</option>
           <option value="SD">Sudan (SD)</option>
           <option value="SR">Suriname (SR)</option>
           <option value="SZ">Swaziland (SZ)</option>
           <option value="SE">Sweden (SE)</option>
           <option value="CH">Switzerland (CH)</option>
           <option value="SY">Syria (SY)</option>
           <option value="TW">Taiwan (TW)</option>
           <option value="TJ">Tajikistan (TJ)</option>
           <option value="TZ">Tanzania (TZ)</option>
           <option value="TH">Thailand (TH)</option>
           <option value="TL">Timor-Leste (TL)</option>
           <option value="TG">Togo (TG)</option>
           <option value="TK">Tokelau (TK)</option>
           <option value="TO">Tonga (TO)</option>
           <option value="TT">Trinidad and Tobago (TT)</option>
           <option value="TN">Tunisia (TN)</option>
           <option value="TR">Turkey (TR)</option>
           <option value="TM">Turkmenistan (TM)</option>
           <option value="TC">Turks and Caicos Islands (TC)</option>
           <option value="TV">Tuvalu (TV)</option>
           <option value="UG">Uganda (UG)</option>
           <option value="UA">Ukraine (UA)</option>
           <option value="AE">United Arab Emirates (AE)</option>
           <option value="GB">United Kingdom (GB)</option>
           <option value="US" selected="selected">United States (US)</option>
           <option value="UY">Uruguay (UY)</option>
           <option value="VI">US Virgin Islands (VI)</option>
           <option value="UZ">Uzbekistan (UZ)</option>
           <option value="VU">Vanuatu (VU)</option>
           <option value="VE">Venezuela (VE)</option>
           <option value="VN">Vietnam (VN)</option>
           <option value="WF">Wallis and Futuna (WF)</option>
           <option value="YE">Yemen (YE)</option>
           <option value="ZM">Zambia (ZM)</option>
           <option value="ZW">Zimbabwe (ZW)</option>
        </select>
        <button type="submit">Submit</button>
    </form>
<?php
}
?>
As you can see, if the $_GET['number'] is NOT supplied in the URL, then we know to display the basic form that accepts a phone number & a country code. We display a text field and country picker dropdown to accomplish this, with a basic submit button to push this form data to the same page (request.php).

Here are some screen shots showing it in action...

The default view for before you choose a phone number / country code:



Here is what it looks like for a valid phone number. In this case, I chose a Walmart store's phone number:


And here is what it looks like with an invalid phone number:




In conclusion, I hope that this tutorial helps you learn how to validate phone numbers with PHP, or (if you are good w/ thinking in the abstract) use a JSON API for any other information. The concept is the same for fetching data from anywhere online, even if it has nothing to do with phones! This only took me about 10-15 minutes of coding to create, so it really is a nice simple project. I used the Numverify API, which gives you 250 requests per month on the free version: https://numverify.com

You can pay a small amount for more requests per month, or explore other JSON APIs for phone validation elsewhere!
 
Last edited:
  • Like
Reactions: eeflores