How to validate phone numbers using php without regexp? - php

I want to validate users phone numbers when they register in my website. I use this code to do this :
$mobile = mysql_real_escape_string($_POST['mobile']);
//check mobile validity
$options = array('options' => array('min_range' => 0));
if(filter_var($mobile, FILTER_VALIDATE_INT, $options) == FALSE)
{
$_SESSION['warnings']['warning_mobile'] = ENTER_VALID_MOBILE;
}
else
{
$_SESSION['warnings']['warning_mobile'] = '';
$_SESSION['temp_post']['mobile'] = $mobile;
}
As you can see the code check if this number contains valid int digits and if it is everything going ok if not it give me error message .
My problem is : This code does not accept numbers which starts with zero for example (0 555 555 5555 this is invalid number).
Is there a way to allow this code to accept this numbers starting with zero??

Leaving on a side the fact that with a regular expression you could solve this problem easily, there are a couple of things to consider:
$mobile is a string: filter_var($mobile, FILTER_VALIDATE_INT)
will allways return false.
do you want to consider digits only or you need to support numbers containing characters such as spaces, hyphen and plus? e.g. "+1 23-4555-555"
If you need to support "plain numeric" only, take a look to is_numeric. It checks if a variable is a number or a string made only by digits.
About your question:
Is there a way to allow this code to accept this numbers starting with
zero??
Your code doesn't work because $mobile is not an integer, and not because your number starts with 0.
The final suggestion still is to use a regexes, which are the optimal solution for this kind of problems.

Related

adding negative statement to regex

I am trying to check if a phone number like this exists in using regex.
(001) 33992292
So, I used
if(preg_match("/[0-9\(\)]+/", $row)){
//is phone number
}
But, the problem with this is that, strings containing numbers get passed as well, like foo134#yahoo.com, so how can I evaluate a phone number and exclude # character is strings all together?
UDPATED
/^(\(\d+\))*\s?(\d+\s*)+$/
you missed start string ^ sign and end string $ sign, what else your regex is wrong
because 5545()4535 will also pass match
You need to use anchors in your regular expression, a proper syntax would be:
if(preg_match('~^\(\d{3}\) *\d{8}$~', $row)) { ... }
Telephone numbers are notorious for people to get wrong - and by people I mean programmers.
For example, these are all "common" ways of writing a phone number:
(001) 33992292
001 33992292
00133992292
001 3399 2292
(001) 3399-2292
A saner approach it to just remove everything that isn't a number and check the length:
$phonenumber = "(001) 33992292";
$phonenumber = preg_replace("/[^0-9,.]/", "", $phonenumber );
if (strlen($phonenumber) == 11) {
// do thing
}

Validating UK phone numbers in PHP

I purchased a contact form. Great little thing but I need to convert the validation for the phone number to allow for UK number formats - in other words, to allow for spaces.
Right now it validates without spaces and has a minimum length of 8 characters:
if(is_numeric($phone))
{
if(!$phone || strlen($phone) < 8)
{
$error .= "Please enter your phone number without spaces.<br />";
}
}
else
{
$error .= "Please enter numeric characters in the phone number field.<br />";
}
Phone numbers are typically horrible for regex patterns, which is what you will need.
This pattern for example:
$pattern = "/^(\+44\s?7\d{3}|\(?07\d{3}\)?)\s?\d{3}\s?\d{3}$/";
$match = preg_match($pattern,$input);
if ($match != false) {
// We have a valid phone number
} else {
// We have an invalid phone number
}
That pattern will match with +44 included or not e.g.
all these will match:
07222 555555
(07222) 555555
+44 7222 555 555
These won't
7222 555555
+44 07222 555555
(+447222) 555555
There are a load of sites that offer tutorials / cheat sheets etc. for regular expressions try some of these:
http://regexlib.com/Default.aspx
as well as a very good stack overflow post:
A comprehensive regex for phone number validation
So you just want to allow spaces?
Then you could use str_replace() to ignore spaces, right at the beginning:
$phone = str_replace(' ', '', $phone);
The is_numeric function that you're using isn't really even a suitable choice for American phone numbers. For example it accepts hexadecimal numbers like 0xABCDEF, which it should reject.
For simple text matching like this, regular expressions are often the easiest solution. A regular expression specifies a pattern of text. PHP has functions to let you search for or replace regular expression matches in text.
If you define a phone number as a string of at least 7 characters containing only digits and spaces, the corresponding regular expression would be /^[0-9 ]{7,}$/. The text inside the brackets represents a set of characters, the {7,} indicates that we're looking for at least 7 of these characters in a row, and the ^ and $ indicate that our match should start at the beginning of the string and end at the end of the string. The PHP documentation has a section explaining regular expressions in greater detail.
You would use the preg_match function to
ensure the phone number matched:
if (preg_match('/^[0-9 ]{7,}$/', $phone)) {
This matches all UK formats with a wide variety of punctuation:
^\(?(?:(?:0(?:0|11)\)?[\s-]?\(?|\+)44\)?[\s-]?\(?(?:0\)?[\s-]?\(?)?|0)(?:\d{5}\)?[\s-]?\d{4,5}|\d{4}\)?[\s-]?(?:\d{5}|\d{3}[\s-]?\d{3})|\d{3}\)?[\s-]?\d{3}[\s-]?\d{3,4}|\d{2}\)?[\s-]?\d{4}[\s-]?\d{4}|8(?:00[\s-]?11[\s-]?11|45[\s-]?46[\s-]?4\d))(?:(?:[\s-]?(?:x|ext\.?\s?|\#)\d+)?)$
Extract the various parts using this pattern
^\(?(?:(?:0(?:0|11)\)?[\s-]?\(?|\+)(44)\)?[\s-]?\(?(?:0\)?[\s-]?\(?)?|0)([1-9]\d{1,4}\)?[\s\d-]+)(?:((?:x|ext\.?\s?|\#)\d+)?)$
The country code is in $1 (and is null for national format). The NSN is in $2. The optional extension is in $3.
Remove all non-digits from $2 for further processing. The next step is to make sure the NSN is in a valid range and is a valid length (either 9 or 10 digits, depending on the range).
The list of patterns is too long to reproduce here but is available at:
http://aa-asterisk.org.uk/index.php/Regular_Expressions_for_Validating_and_Formatting_GB_Telephone_Numbers
You could parse the input to an integer, then validate for the correct number of digits;
$mobileNumber = intval($mobileNumber);
if (preg_match('/(^\d{12}$)|(^\d{10}$)/',$mobileNumber)==TRUE) {
//number has the right number of digits for a UK mobile number
} else {
//number does not have the right number of digits
}
Explained;
$mobileNumber = intval($mobileNumber);
This removes all non numerical characters from the string, and leading zero (eg spaces, brackets, plus signs, decimals etc);
*if (preg_match('/(^\d{12}$)|(^\d{10}$)/',$mobileNumber)==TRUE) {*
This regular expression then checks that the string contains either 12 or 10 digits which would cover 447712345678 (12 digits) or 7791234567 (10 digits). It is matched in two sub clauses (^\d{12}$) or (^\d{10}$) the carat (^) and dollar ($) represent to match everything from the very beginning (^) and to the very end ($) of the string. the \d represents any digit, and the following {12} means match the previous statement that number of times.
This does not mean that the number is valid, you could use an API like twillio to do additional validation of the numebr https://www.twilio.com/help/faq/sms/does-twilio-check-to-see-if-phone-numbers-can-receive-sms
For example;
$mobileNumber = '+447791234567';
$mobileNumber = intval($mobileNumber); //$mobileNumber is now 447791234567
if (preg_match('/(^\d{12}$)|(^\d{10}$)/',$mobileNumber)==TRUE) {
//$mobileNumber matches (^\d{12}$) and is valid
}
You could also add a check to ensure that number starts with either '07' or '447', required for UK mobiles, like this;
function isValidMobile($aNumber){
$aNumber = intval($aNumber);
return preg_match('/(^\d{12}$)|(^\d{10}$)/', $aNumber) && preg_match('/(^7)|(^447)/', $aNumber);
}
the intval removes leading zero,so the regular expression checks for a leadin 7 or 447.
I have found a solution with javascript according to the standards mentioned [here][1].**its not regex.**if you are using this solution there are three things to take care
validation can be used inside the UK
space cant be added. you need to type in your number without spaces
number has to begin with zero
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script >
var name=window.prompt("Enter cell number");
var sixformat=["013397","013398","013873","015242","015394","015395","015396","016973","016974","017683","017684","017687","019467","019755","019756"];
var twoformat=["01","02","03","05","07","08","09"];
sixdi=name.substring(0,6);
twodi=name.substring(0,2);
document.write("phone number:",name,"<br>");
document.write("phone-number length:",name.length);
if(sixformat.includes(sixdi)&&name.length==11)
{
document.write("<br><h1>valid</h1>");
}
else if(sixdi=="016977"&&name.length==10)
{
document.write("<br><h1>valid<h1>");
}
else if(twoformat.includes(twodi)&&(name.length==11))//011########
{
document.write("<br><h1>valid</h1>");
}
else if(twodi=="01"&&(name.length==10))
{
document.write("<br><h1>valid</h1>");
}
else if(name.substring(0,4)=="0800"&&(name.length==10))
{
document.write("<br><h1>Valid</h1></br>");
}
else
{
document.write("<h1>invalid</h1>");
}
</script>
</body>
</html>

Validating special form of IP address

I have encountered a strange IP which has redundant zero values among the octets. Is there anyway to properly validate this as an IP or use regular expression to remove those redundant zeroes?
example is of follows:
218.064.215.239 (take note of the extra zero at the second octet "064").
I do have one working IP validation function but it will not validiate this Ip properly due to the nature of the regular expression unable to accept that extra zero. Following is the code in PHP:
function valid_ip($ip) {
return preg_match("/^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])" .
"(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$/", $ip);
}
thanks for any help in advance peeps! :D
This will correct them:
$ip = "123.456.007.89";
$octets = explode(".", $ip);
$corrected = array();
foreach ($octets as $octet) {
array_push($corrected, (int)$octet);
}
echo implode(".", $corrected);
You have to accept the zero like this:
^(0?[1-9]|0?[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.(0?[0-9]|0?[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$
Play with this regular expression on rubular.com.
The 0? I added matches zero or one occurence of 0. So 0?[1-9][0-9] for example matches both 010 and 10 for example.
Change the bare |1 occurrences to |[01]. Are you sure this is not supposed to be interpreted as an octal number, though? Some resolvers do that.
Use ip2long().
You should figure out where those extra zeroes are coming from. Those leading zeroes can't be just dropped. On most platforms they mean that the octet is in octal form instead of decimal. That is: 064 octal equals 52 decimal.
Did you have a go yourself? It's really quite simple.
|1[0-9][0-9]| matches 100-199, as you are now wanting to match 000-199 (as above that it is 200-155) you just need to make a set for the 1 to be 1 or 0.
function valid_ip($ip) {
return preg_match("/^([1-9]|[1-9][0-9]|[01][0-9][0-9]|2[0-4][0-9]|25[0-5])".
"(\.([0-9]|[1-9][0-9]|[01][0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$/", $ip);
}
And that can be refactored down (allowing leading zeroes) to:
function valid_ip($ip) {
return preg_match("/^([01]?[0-9]{1,2}|2[0-4][0-9]|25[0-5])".
"(\.([01]?[0-9]{1,2}|2[0-4][0-9]|25[0-5])){3}$/", $ip);
}
Or to strip these unneeded zeros:
function strip_ip($ip) {
return preg_replace( '/0+([^0])(\.|$)/' , '$1$2' , $ip );
}

Using regex to fix phone numbers in a CSV with PHP

My new phone does not recognize a phone number unless its area code matches the incoming call. Since I live in Idaho where an area code is not needed for in-state calls, many of my contacts were saved without an area code. Since I have thousands of contacts stored in my phone, it would not be practical to manually update them. I decided to write the following PHP script to handle the problem. It seems to work well, except that I'm finding duplicate area codes at the beginning of random contacts.
<?php
//the script can take a while to complete
set_time_limit(200);
function validate_area_code($number) {
//digits are taken one by one out of $number, and insert in to $numString
$numString = "";
for ($i = 0; $i < strlen($number); $i++) {
$curr = substr($number,$i,1);
//only copy from $number to $numString when the character is numeric
if (is_numeric($curr)) {
$numString = $numString . $curr;
}
}
//add area code "208" to the beginning of any phone number of length 7
if (strlen($numString) == 7) {
return "208" . $numString;
//remove country code (none of the contacts are outside the U.S.)
} else if (strlen($numString) == 11) {
return preg_replace("/^1/","",$numString);
} else {
return $numString;
}
}
//matches any phone number in the csv
$pattern = "/((1? ?\(?[2-9]\d\d\)? *)? ?\d\d\d-?\d\d\d\d)/";
$csv = file_get_contents("contacts2.CSV");
preg_match_all($pattern,$csv,$matches);
foreach ($matches[0] as $key1 => $value) {
/*create a pattern that matches the specific phone number by adding slashes before possible special characters*/
$pattern = preg_replace("/\(|\)|\-/","\\\\$0",$value);
//create the replacement phone number
$replacement = validate_area_code($value);
//add delimeters
$pattern = "/" . $pattern . "/";
$csv = preg_replace($pattern,$replacement,$csv);
}
echo $csv;
?>
Is there a better approach to modifying the CSV? Also, is there a way to minimize the number of passes over the CSV? In the script above, preg_replace is called thousands of times on a very large String.
If I understand you correctly, you just need to prepend the area code to any 7-digit phone number anywhere in this file, right? I have no idea what kind of system you're on, but if you have some decent tools, here are a couple options. And of course, the approaches they take can presumably be implemented in PHP; that's just not one of my languages.
So, how about a sed one-liner? Just look for 7-digit phone numbers, bounded by either beginning of line or comma on the left, and comma or end of line on the right.
sed -r 's/(^|,)([0-9]{3}-[0-9]{4})(,|$)/\1208-\2\3/g' contacts.csv
Or if you want to only apply it to certain fields, perl (or awk) would be easier. Suppose it's the second field:
perl -F, -ane '$"=","; $F[1]=~s/^[0-9]{3}-[0-9]{4}$/208-$&/; print "#F";' contacts.csv
The -F, indicates the field separator, the $" is the output field separator (yes, it gets assigned once per loop, oh well), the arrays are zero-indexed so second field is $F[1], there's a run-of-the-mill substitution, and you print the results.
Ah programs... sometimes a 10-min hack is better.
If it were me... I'd import the CSV into Excel, sort it by something - maybe the length of the phone number or something. Make a new col for the fixed phone number. When you have a group of similarly-fouled numbers, make a formula to fix. Same for the next group. Should be pretty quick, no? Then export to .csv again, omitting the bad col.
A little more digging on my own revealed the issues with the regex in my question. The problem is with duplicate contacts in the csv.
Example:
(208) 555-5555, 555-5555
After the first pass becomes:
2085555555, 208555555
and After the second pass becomes
2082085555555, 2082085555555
I worked around this by changing the replacement regex to:
//add escapes for special characters
$pattern = preg_replace("/\(|\)|\-|\./","\\\\$0",$value);
//add delimiters, and optional area code
$pattern = "/(\(?[0-9]{3}\)?)? ?" . $pattern . "/";

How to add currency strings (non-standardized input) together in PHP?

I have a form in which people will be entering dollar values.
Possible inputs:
$999,999,999.99
999,999,999.99
999999999
99,999
$99,999
The user can enter a dollar value however they wish. I want to read the inputs as doubles so I can total them.
I tried just typecasting the strings to doubles but that didn't work. Total just equals 50 when it is output:
$string1 = "$50,000";
$string2 = "$50000";
$string3 = "50,000";
$total = (double)$string1 + (double)$string2 + (double)$string3;
echo $total;
A regex won't convert your string into a number. I would suggest that you use a regex to validate the field (confirm that it fits one of your allowed formats), and then just loop over the string, discarding all non-digit and non-period characters. If you don't care about validation, you could skip the first step. The second step will still strip it down to digits and periods only.
By the way, you cannot safely use floats when calculating currency values. You will lose precision, and very possibly end up with totals that do not exactly match the inputs.
Update: Here are two functions you could use to verify your input and to convert it into a decimal-point representation.
function validateCurrency($string)
{
return preg_match('/^\$?(\d{1,3})(,\d{3})*(.\d{2})?$/', $string) ||
preg_match('/^\$?\d+(.\d{2})?$/', $string);
}
function makeCurrency($string)
{
$newstring = "";
$array = str_split($string);
foreach($array as $char)
{
if (($char >= '0' && $char <= '9') || $char == '.')
{
$newstring .= $char;
}
}
return $newstring;
}
The first function will match the bulk of currency formats you can expect "$99", "99,999.00", etc. It will not match ".00" or "99.", nor will it match most European-style numbers (99.999,00). Use this on your original string to verify that it is a valid currency string.
The second function will just strip out everything except digits and decimal points. Note that by itself it may still return invalid strings (e.g. "", "....", and "abc" come out as "", "....", and ""). Use this to eliminate extraneous commas once the string is validated, or possibly use this by itself if you want to skip validation.
You don't ever want to represent monetary values as floats!
For example, take the following (seemingly straight forward) code:
$x = 1.0;
for ($ii=0; $ii < 10; $ii++) {
$x = $x - .1;
}
var_dump($x);
You might assume that it would produce the value zero, but that is not the case. Since $x is a floating point, it actually ends up being a tiny bit more than zero (1.38777878078E-16), which isn't a big deal in itself, but it means that comparing the value with another value isn't guaranteed to be correct. For example $x == 0 would produce false.
http://p2p.wrox.com/topic.asp?TOPIC_ID=3099
goes through it step by step
[edit] typical...the site seems to be down now... :(
not a one liner, but if you strip out the ','s you can do: (this is pseudocode)
m/^\$?(\d+)(?:\.(\d\d))?$/
$value = $1 + $2/100;
That allows $9.99 but not $9. or $9.9 and fails to complain about missplaced thousands separators (bug or feature?)
There is a potential 'locality' issue here because you are assuming that thousands are done with ',' and cents as '.' but in europe it is opposite (e.g. 1.000,99)
I recommend not to use a float for storing currency values. You can get rounding errors if the sum gets large. (Ok, if it gets very large.)
Better use an integer variable with a large enough range, and store the input in cents, not dollars.
I belive that you can accomplish this with printf, which is similar to the c function of the same name. its parameters can be somewhat esoteric though. you can also use php's number_format function
Assuming that you are getting real money values, you could simply strip characters that are not digits or the decimal point:
(pseudocode)
newnumber = replace(oldnumber, /[^0-9.]/, //)
Now you can convert using something like
double(newnumber)
However, this will not take care of strings such as "5.6.3" and other such non-money strings. Which raises the question, "Do you need to handle badly formatted strings?"

Categories