Chapter 3
IN THIS CHAPTER
Validating data in the browser and on the server
Making a field mandatory
Setting restrictions on form fields
Practicing good data hygiene
Garbage in, garbage out. Or rather more felicitously: The tree of nonsense is watered with error, and from its branches swing the pumpkins of disaster.
— NICK HARKAWAY
In the old computing axiom of garbage in, garbage out (GIGO), or if in your genes or heart you’re British, rubbish in, rubbish out (yes, RIRO), lies a cautionary tale. If the data that goes into a system is inaccurate, incomplete, incompatible, or in some other way invalid, the information that comes out of that system will be outdated, outlandish, outrageous, or just outright wrong. What does this have to do with you as a web developer? Plenty, because it’s your job to make sure that the data the user enters into a form is accurate, complete, and compatible with your system. In a word, you have to make sure the data is valid. If that sounds like a lot of work, then I’ve got some happy news for you: HTML5 has data validation baked in, so you can just piggyback on the hard work of some real nerds. In this chapter, you explore these HTML5 validation techniques. Ah, but your work isn’t over yet, friend. You also have to validate the same data once again on the server. Crazy? Like a fox. But there’s more good news on the server side of things, because PHP has a few ready-to-run tools that take most of the pain out of validation. In this chapter, you also dive deep into those tools. Sleeves rolled up? Then let’s begin.
Before JavaScript came along, web servers would spend inordinate amounts of processing time checking the data submitted from a form and, all too often, returning the data back to the user to fill in an empty field or fix some invalid entry. Someone eventually realized that machines costing tens of thousands of dollars (which was the cost of the average server machine when the web was in swaddling clothes) ought to have better things to do with their time than chastising users for not entering their email address correctly (or whatever). Wouldn’t it make infinitely more sense for the validation of a form’s data to first occur within the browser before the form was even submitted?
The answer to that is an unqualified “Duh!” And once JavaScript took hold with its browser-based scripting, using it to do form validation on the browser became the new language’s most important and useful feature. Alas, data validation is a complex business, so it didn’t take long for everyone’s JavaScript validation code to run to hundreds or even thousands of lines. Plus there was no standardization, meaning that every web project had to create its own validation code from scratch, pretty much guaranteeing it wouldn’t work like any other web project’s validation code. Isn’t there a better way?
Give me another “Duh!” Perhaps that’s why the big brains who were in charge of making HTML5 a reality decided to do something about the situation. Several types of form validation are part of HTML5, which means now you can get the web browser to handle your validation chores.
It’s common for a form to contain at least one field that the user must fill in. For example, if your form is for a login, then you certainly need both the username and password fields to be mandatory, meaning you want to set up the form so that the submission won’t go through unless both fields are filled in.
Here are a few things you can do to encourage users to fill in mandatory fields:
Fields marked with * are required
at the top of the form.<input>
tags includes the checked
attribute. This ensures that one option will always be selected.<option>
tags includes the selected
attribute.Outside of these techniques, you can make any field mandatory by adding the required
attribute to the form field tag. Here's an example:
<form>
<div>
<label for="fave-beatle">Favorite Beatle:</label>
<input id="fave-beatle" type="text" required>
<button type="submit">Submit</button>
</div>
</form>
The <input>
tag has the required
attribute. If you leave this field blank and try to submit the form, the browser prevents the submission and displays a message telling you to fill in the field. This message is slightly different, depending on the web browser. Figure 3-1 shows the message that Chrome displays.
Another useful built-in HTML5 validation technique is setting restrictions on the length of the value entered into a text field. For example, you might want a password value to have a minimum length, and you might want a username to have a maximum length. Easier done than said:
minlength
attribute to the least number of characters the user must enter.maxlength
attribute to the most number of characters the user can enter.Take a look at an example:
<form>
<div>
<label for="acct-handle">Account handle (6-12 chars):</label>
<input id="acct-handle"
type="text"
placeholder="Enter 6-12 characters"
minlength="6"
maxlength="12">
<button type="submit">Submit</button>
</div>
</form>
The <input>
tag asks for a value no less than 6
and no more than 12
characters long. If the user enters a value shorter or longer and tries to submit the form, the browser prevents the submission and displays a message asking for more or fewer characters. Figure 3-2 shows the version of the message that Firefox displays.
HTML5 can also validate a numeric field based on a specified minimum or maximum value for the field. Here are the attributes to use:
min
: To add a minimum value restriction, set the min
attribute to the smallest allowable value the user can enter.max
: To add a maximum value restriction, set the max
attribute to the largest allowable value the user can enter.Here's an example:
<form>
<div>
<label for="loan-term">Loan term (years):</label>
<input id="loan-term"
type="number"
placeholder="3-25"
min="3"
max="25">
<button type="submit">Submit</button>
</div>
</form>
The number
<input>
tag asks for a value between 3
and 25
. If the user enters a value outside of this range and tries to submit the form, the browser prevents the submission and displays a message to reenter a value that's either less than or equal to the maximum (as shown in Figure 3-3) or greater than or equal to the minimum.
Generic field validation attributes such as required
, minlength
, and max
are very useful, but some form fields need a more targeted validation technique. In a field that accepts an email address, for example, any entered value should look something like username@domain
. If that sounds like a daunting challenge, you're right, it is. Fortunately, that challenge has already been taken up by some of the best coders on the planet. The result? Built-in HTML5 validation for email addresses. And when I say “built-in,” I mean built-in, because once you specify type="email"
in the <input>
tag, modern web browsers will automatically validate the field input to make sure it looks like an email address when the form is submitted, as shown in Figure 3-4.
One of the most powerful and flexible HTML5 validation techniques is pattern matching, where you specify a pattern of letters, numbers, and other symbols that the field input must match. You add pattern matching validation to a text
, email
, url
, tel
, search
, or password
field by adding the pattern
attribute:
pattern="regular_expression"
regular_expression
: A type of expression called a regular expression that uses special symbols to define the pattern you want to apply to the fieldFor example, suppose you want to set up a pattern for a ten-digit North American telephone number that includes dashes, such as 555-123-4567 or 888-987-6543. In a regular expression, the symbol d
represents any digit from 0 to 9, so your regular expression would look like this:
ddd-ddd-dddd
Here's the regular expression added to a telephone number field:
<input id="user-phone"
type="tel"
pattern="ddd-ddd-dddd"
placeholder="e.g., 123-456-7890"
title="Enter a 10-digit number in the format 123-456-7890">
Table 3-1 summarizes the most useful regular expression symbols to use with the pattern
attribute. See “Regular Expressions Reference,” later in this chapter, for a more detailed look at this powerful tool.
TABLE 3-1 The Most Useful Regular Expression Symbols
Symbol |
Matches |
|
Any digit from 0 through 9 |
|
Any character that is not a digit from 0 through 9 |
|
Any character |
|
Any whitespace character, such as the space, tab ( |
|
Any non-whitespace character |
|
Whatever characters are listed between the square brackets |
|
Anything in the range of letters or digits from |
|
Everything except whatever characters are listed between the square brackets |
|
Everything except the characters in the range of letters or digits from |
|
If the character preceding it appears just once or not at all |
|
If the character preceding it is missing or if it appears one or more times |
|
If the character preceding it appears one or more times |
|
If the character preceding it appears exactly |
|
If the character preceding it appears at least |
|
If the character preceding it appears at least |
|
Pattern |
From this table, you can see that an alternative way to write the 10-digit telephone regular expression would be the following:
[0-9]{3}-[0-9]{3}-[0-9]{4}
One useful thing you can do as a web developer is make it obvious for the user when a form field contains invalid data. Sure, the browser will display its little tooltip to alert the user when she submits the form, but that tooltip only stays onscreen for a few seconds. It would be better to style the invalid field in some way so the user always knows it needs fixing.
One straightforward way to do that is to take advantage of the CSS :invalid
pseudo-selector, which enables you to apply a CSS rule to any invalid field. For example, here's a rule that adds a red highlight around any <input>
tag that is invalid:
input:invalid {
border-color: rgba(255, 0, 0, .5);
box-shadow: 0 0 10px 2px rgba(255, 0, 0, .8);
}
The problem, however, is that the web browser checks for invalid fields as soon as it loads the page. So, for example, if you have fields with the required
attribute that are initially empty when the page loads, the browser will flag those as invalid and apply the invalid
styling. Your users will be saying, “Gimme a break, I just got here!”
One way to work around this problem is to display an initial message (such as required
) beside each required field, then replace that message with something positive (such as a check mark) when the field is filled in.
Here's some code that does that:
CSS:
input:invalid+span::after {
content:'(required)';
color: red;
}
input:valid+span::after {
content:'2713';
color: green;
}
HTML:
<form>
<div>
<label for="user-name">Name:</label>
<input id="user-name"
type="text"
placeholder="Optional"
required>
<span></span>
</div>
<div>
<label for="user-email">Email:</label>
<input id="user-email"
type="email"
placeholder="e.g., [email protected]"
required>
<span></span>
</div>
<button type="submit">Submit</button>
</form>
Notice in the HTML that both fields have the required
attribute and both fields also have an empty span
element right after them. Those span
elements are where you'll put your messages, and that’s what the CSS code is doing:
input
field, then uses the adjacent sibling select (+
) to select the span
that comes immediately after the field. The ::after
pseudo-element adds the content (required)
to the span
and colors it red
.input
field, then adds a green check mark (given by Unicode character 2713
) to the span
.Figure 3-5 shows these rules in action, where the Name
field is valid and the Email
field is invalid.
Another approach is to use jQuery to listen for the invalid
event firing on any input
element. The invalid
event fires when the user tries to submit the form and one or more fields contain invalid data. In your event handler, you could then apply a predefined class to the invalid field. Here's some code that does just that:
CSS:
.error {
border-color: rgba(255, 0, 0, .5);
box-shadow: 0 0 10px 2px rgba(255, 0, 0, .8);
}
input:valid {
border-color: lightgray;
box-shadow: none;
}
HTML:
<form>
<div>
<label for="user-name">Name:</label>
<input id="user-name"
type="text"
placeholder="Your name"
required>
</div>
<div>
<label for="user-email">Email:</label>
<input id="user-email"
type="email"
placeholder="e.g., [email protected]"
required>
</div>
<button type="submit">Submit</button>
</form>
jQuery:
$("input").on("invalid", function() {
$(this).addClass('error');
});
The HTML is the same as in the previous example, minus the extra <span>
tags. The CSS code defines a rule for the error
class that uses border-color
and box-shadow
to add a red-tinged highlight to an element. The input:valid
selector removes the border and box shadow when the field becomes valid. The jQuery code listens for the invalid
event on any input
element. When it fires, the event handler adds the error
class to the element.
You might have looked at the title of this section and cried, “The server! But we just went through validating form data in the browser! Surely we don't have to validate on the server, as well!?” First of all, calm down. Second, yep, it would be nice if we lived in a world where validating form data in the web browser was good enough. Alas, that Shangri-La doesn’t exist. The problem, you see, is that there are still a few folks surfing with very old web browsers that wouldn’t know HTML5 from Maroon 5, and so don’t support either <input>
tag types such as number
, email
, and date
, or browser-based validation. It's also possible that someone might, innocently or maliciously, bypass your form and send data directly to the server (say, by using a URL query string).
Either way, you can’t be certain that the data that shows up on the server’s doorstep has been validated, so it’s up to your server script to ensure the data is legit before processing it. Happily, as you see in the next few sections, PHP is loaded with features that make validating data straightforward and painless.
If one or more fields in your form are mandatory, you can check those fields on the server by using PHP’s empty()
function:
empty(expression)
expression
: The literal, variable, expression, or function result that you want to testThe empty()
function returns FALSE
if the expression exists and has a non-empty, non-zero value; it returns TRUE
, otherwise.
I'll go through a complete example that shows one way to handle validation errors on the server. First, here’s some HTML:
<form>
<div>
<label for="user-name">Name</label>
<input id="user-name"
type="text"
name="user-name">
</div>
<div>
<label for="user-email">Email</label>
<input id="user-email"
type="email"
name="user-email">
</div>
<button type="submit">Submit</button>
</form>
<article class="output"></article>
The form has two text fields, and there’s also an <article>
tag that you’ll use a bit later to output the server results.
On the server, I created a PHP file named validate-required-fields.php
:
<?php
// Store the default status
$server_results['status'] = 'success';
// Check the user-name field
if(isset($_GET['user-name'])) {
$user_name = $_GET['user-name'];
// Is it empty?
if(empty($user_name)) {
// If so, update the status and add an error message for the field
$server_results['status'] = 'error';
$server_results['user-name'] = 'Missing user name';
}
}
// Check the user-email field
if(isset($_GET['user-email'])) {
$user_email = $_GET['user-email'];
// Is it empty?
if(empty($user_email)) {
// If so, update the status and add an error message for the field
$server_results['status'] = 'error';
$server_results['user-email'] = 'Missing email address';
}
}
// If status is still "success", add the success message
if($server_results['status'] === 'success') {
$output = "Success! Thanks for submitting the form, $user_name.";
$server_results['output'] = $output;
}
// Create and then output the JSON data
$JSON_data = json_encode($server_results, JSON_HEX_APOS | JSON_HEX_QUOT);
echo $JSON_data;
?>
This script uses the $server_results
associative array to store the data that gets sent back to the browser. At first the array's status
key is set to success
. Then the script checks the user-name
field from the $_GET
array: If the field is empty, the array's status
key is set to error
and an array item is added that sets an error message for the field. The same process is then used for the user-email
field. If after those checks the array's status
key is still set to success
(meaning there were no validation errors), then the array is updated with a success message. Finally, the array is converted to JSON and outputted.
Back on the client, the form
element's submit
event handler converts and submits the form data, and then processes the result:
$('form').submit(function(e) {
// Prevent the default form submission
e.preventDefault();
// Convert the data to a query string
var formData = $(this).serialize();
// Send the data to the server
$.getJSON('php/validate-required-fields.php', formData, function(data) {
// Display the output element
$('.output').css('display', 'block');
// Check the validation status
if(data.status === 'success') {
// Output the success result
$('.output').html(data.output);
} else {
// Output the validation error(s)
$('.output').html('<section>Whoops! There were errors:</section>');
$.each(data, function(key, error) {
if(key !== 'status') {
// Get the label text
var label = $('label[for=' + key + ']').text();
$('.output').append('<section>Error in ' + label + ' field: ' + error + '</section>');
}
});
}
});
});
Note, in particular, the .getJSON()
callback function checks the value of data.status
: If it equals success
, the script's success message is displayed. Otherwise, the .each()
loop adds each error message to the output element. Figure 3-6 shows an example.
Besides validating that a text field exists, you might also want to perform two other validation checks on a text field:
ctype_alpha()
function:
ctype_alpha(text)
text
: Your form field's text dataThe ctype_alpha()
function returns TRUE
if the field contains only letters, FALSE
otherwise.
strlen()
function:
strlen(text)
text
: Your form field's text dataThe strlen()
function returns the number of characters in the field.
Here’s some PHP code that performs these checks on a form field called user-name
:
<?php
// Store the default status
$server_results['status'] = 'success';
// Check the user-name field
if(isset($_GET['user-name'])) {
$user_name = $_GET['user-name'];
// Is it empty?
if(empty($user_name)) {
// If so, update the status and add an error message for the field
$server_results['status'] = 'error';
$server_results['user-name'] = 'Missing user name';
} else {
// Does it contain non-alphabetic characters?
if(!ctype_alpha($user_name)){
// If so, update the status and add an error message for the field
$server_results['status'] = 'error';
$server_results['user-name'] = 'User name must be text';
} else {
// Does the user name contains less than 3 or more than 12 characters?
if(strlen($user_name) < 3 || strlen($user_name) > 12) {
// If so, update the status and add an error message for the field
$server_results['status'] = 'error';
$server_results['user-name'] = 'User name must be 3 to 12 characters long';
}
}
}
}
// If status is still "success", add the success message
if($server_results['status'] === 'success') {
$output = "Success! Thanks for submitting the form, $user_name.";
$server_results['output'] = $output;
}
// Create and then output the JSON data
$JSON_data = json_encode($server_results, JSON_HEX_APOS | JSON_HEX_QUOT);
echo $JSON_data;
?>
If you want to ensure the value of a field is a particular data type, PHP offers a powerful function called filter_var()
that can help:
filter_var(var, filter, options)
var
: The variable, expression, or function result you want to check.filter
: An optional constant value that determines the data type you want to check. Here are some useful filters: FILTER_VALIDATE_BOOLEAN
: Checks for a Boolean value.FILTER_VALIDATE_EMAIL
: Checks for a valid email address.FILTER_VALIDATE_FLOAT
: Checks for a floating point value.FILTER_VALIDATE_INT
: Checks for an integer value.FILTER_VALIDATE_URL
: Checks for a valid URL.options
: An optional array that sets one or more options for the filter
. For example, FILTER_VALIDATE_INT
accepts the options min_range
and max_range
, which set the minimum and maximum allowable integers. Here's the setup for a minimum of 0 and a maximum of 100:
array('options' => array('min_range' => 0, 'max_range' => 100))
The filter_var()
function returns the data if it’s valid according to the specified filter; if the data isn’t valid, the function returns FALSE
(or NULL
, if you're using FILTER_VALIDATE_BOOLEAN
).
Here’s an example script that checks for integer values within an allowable range:
<?php
// Store the default status
$server_results['status'] = 'success';
// Check the user-age field
if(isset($_GET['user-age'])) {
$user_age = $_GET['user-age'];
// Is it empty?
if(empty($user_age)) {
// Add an error message for the field
$server_results['status'] = 'error';
$server_results['user-age'] = 'Missing age value';
} else {
// Is the field not an integer?
if(!filter_var($user_age, FILTER_VALIDATE_INT)){
// Add an error message for the field
$server_results['status'] = 'error';
$server_results['user-age'] = 'Age must be an integer';
} else {
// Is the age not between 14 and 114?
$options = array('options' => array('min_range' => 14, 'max_range' => 114));
if(!filter_var($user_age, FILTER_VALIDATE_INT, $options)) {
// Add an error message for the field
$server_results['status'] = 'error';
$server_results['user-age'] = 'Age must be between 14 and 114';
}
}
}
}
// If status is "success", add the success message
if($server_results['status'] === 'success') {
$output = "Success! You don't look a day over " . intval($user_age - 1) . ".";
$server_results['output'] = $output;
}
// Create and then output the JSON data
$JSON_data = json_encode($server_results, JSON_HEX_APOS | JSON_HEX_QUOT);
echo $JSON_data;
?>
The script uses filter_var($user_age, FILTER_VALIDATE_INT)
twice: first without and then with the options
parameter. The first instance just checks for an integer value, whereas the second checks for an integer between 14 and 114. The integer check is redundant here, but I added both so you could get a feel for how filter_var()
works.
If you want to use a regular expression to validate a field value, PHP says “No problem!” by offering you the preg_match()
function. Here's the simplified syntax:
preg_match(pattern, string)
pattern
: The regular expression, which you enter as a string. Note, too, that the regular expression must be surrounded by slashes (/
).string
: The string (such as a form field value) that you want to match against the regular expression.The preg_match()
function returns TRUE
if string
matches pattern
, and FALSE
, otherwise.
For example, suppose you want to check an account number to ensure that it uses the pattern AA-12345 — that is, two uppercase letters, a hyphen, then five numbers. Assuming the value is stored in a variable named $account_number
, here's a preg_match()
function that will validate the variable:
preg_match(‘/[A-Z]{2}-[0-9]{5}/’, $account_number)
Here are the symbols you can use in your regular expressions:
d
: Matches any digit from 0 through 9:
Regular Expression |
String |
Match? |
|
|
Yes |
|
|
No |
|
|
No |
|
|
Yes |
D
: Matches any character that's not a digit from 0 through 9:
Regular Expression |
String |
Match? |
|
|
Yes |
|
|
No |
|
|
Yes |
w
: Matches any character that's a letter, a digit, or an underscore (_):
Regular Expression |
String |
Match? |
|
|
Yes |
|
|
No |
|
|
Yes |
|
|
No |
W
: Matches any character that's not a letter, a digit, or an underscore (_):
Regular Expression |
String |
Match? |
|
|
Yes |
|
|
No |
|
|
No |
|
|
Yes |
.
(dot): Matches any character that's not a newline:
Regular Expression |
String |
Match? |
|
|
Yes |
|
|
No |
|
|
Yes |
s
: Matches any whitespace character, such as the space, tab (
), newline (
), and carriage return (
):
Regular Expression |
String |
Match? |
|
|
Yes |
|
|
No |
|
|
No |
S
: Matches any non-whitespace character:
Regular Expression |
String |
Match? |
|
|
No |
|
|
Yes |
|
|
Yes |
[]
: Matches whatever characters are listed between the square brackets. The []
symbol also accepts a range of letters and/or digits:
Regular Expression |
String |
Match? |
|
"+123" |
Yes |
|
"$123" |
No |
|
"2-A" |
Yes |
|
"1-A" |
No |
[(]ddd[)]ddd-dddd |
"(123)555-6789" |
Yes |
|
"A123" |
Yes |
|
"a123" |
No |
|
"a123" |
Yes |
|
"3A" |
Yes |
|
"6A" |
No |
|
"9A" |
Yes |
[^]
: Matches everything but whatever characters are listed between the square brackets. As with the []
symbol, you can use letter or digit ranges.
Regular Expression |
String |
Match? |
|
"+123" |
No |
|
"123" |
Yes |
|
"2-A" |
No |
|
"1-A" |
Yes |
|
"A123" |
No |
|
"a123" |
Yes |
|
"#123" |
Yes |
|
"3A" |
No |
|
"6A" |
Yes |
|
"9A" |
No |
: Matches one or more characters if they appear on a word boundary (that is, at the beginning or the end of a word). If you place
before the characters, it matches if they appear at the beginning of a word; if you place
after the characters, it matches if they appear at the end of a word.
Regular Expression |
String |
Match? |
|
|
Yes |
|
|
No |
|
|
Yes |
|
|
No |
|
|
Yes |
B
: Matches one or more characters if they don't appear on a word boundary (the beginning or the end of a word). If you place B
before the characters, it matches if they don’t appear at the beginning of a word; if you place B
after the characters, it matches if they don't appear at the end of a word.
Regular Expression |
String |
Match? |
/Bode/ |
"odeon" |
No |
/Bode/ |
"code" |
Yes |
/odeB/ |
"code" |
No |
/odeB/ |
"odeon" |
Yes |
/BodeB/ |
"code" |
No |
/BodeB/ |
"coder" |
Yes |
?
: Matches if the character preceding it appears just once or not at all:
Regular Expression |
String |
Match? |
|
"email" |
Yes |
|
"e-mail" |
Yes |
|
"e--mail" |
No |
|
"e:mail" |
No |
*
: Matches if the character preceding it is missing or if it appears one or more times:
Regular Expression |
String |
Match? |
|
"email" |
Yes |
|
"e-mail" |
Yes |
|
"e--mail" |
Yes |
|
"e:mail" |
No |
+
: Matches if the character preceding it appears one or more times:
Regular Expression |
String |
Match? |
|
"email" |
No |
|
"e-mail" |
Yes |
|
"e--mail" |
Yes |
|
"e:mail" |
No |
{
n
}
: Matches if the character preceding it appears exactly n
times:
Regular Expression |
String |
Match? |
|
"loop" |
Yes |
|
"lop" |
No |
|
"12345" |
Yes |
|
"12345-6789" |
Yes |
{
n
,}
: Matches if the character preceding it appears at least n
times:
Regular Expression |
String |
Match? |
|
"loop" |
Yes |
|
"lop" |
No |
|
"looop" |
Yes |
|
"12345" |
Yes |
|
"123456" |
Yes |
|
"1234" |
No |
{
n
,
m
}
: Matches if the character preceding it appears at least n
times and no more than m
times:
Regular Expression |
String |
Match? |
|
"loop" |
Yes |
|
"lop" |
Yes |
|
"looop" |
No |
|
"12345" |
Yes |
|
"123456" |
No |
|
"1234" |
Yes |
^
: Matches if the characters that come after it appear at the beginning of the string:
Regular Expression |
String |
Match? |
^Java |
"JavaScript" |
Yes |
^Java |
"HotJava" |
No |
^[^+-]?ddd |
"123" |
Yes |
^[^+-]?ddd |
"+123" |
No |
$
: Matches if the characters that come after it appear at the end of the string:
Regular Expression |
String |
Match? |
Java$ |
"JavaScript" |
No |
Java$ |
"HotJava" |
Yes |
dd.d%$ |
"12.3%" |
Yes |
dd.d%$ |
"12.30%" |
No |
.com$
That’s because the dot (.
) symbol represents any character except a newline. To force the regular expression to match only a literal dot, escape the dot, like this:
.com$
|
: Place this symbol between two patterns, and the regular expression matches if the string matches one pattern or the other. (Don't confuse this symbol with JavaScript’s OR operator: ||
.)
Regular Expression |
String |
Match? |
|
"12345" |
Yes |
|
"12345-6789" |
Yes |
|
"123456789" |
No |
18.117.153.38