I want to validate some email addresses.
The input is given by users in a textarea and the addresses are seperated by comma, like this:
email1#domain1.com, email2#domain2.com, etc. etc.
This is the script i use to check the addresses:
$emailadressen = explode(',', $_POST['uitnodigen']);
$aantal = count($emailadressen);
$i = 1;
foreach($emailadressen as $emails)
{
if(check_email_address($emails) == false) {
$Melding['omschrijving'] = '<div class="error">Error in address number '.$i.'</div>';
$i++;
}
}
And this is the function i use:
function check_email_address($email) {
// First, we check that there's one # symbol, and that the lengths are right
if (!preg_match("/^[^#]{1,64}#[^#]{1,255}$/", $email)) {
// Email invalid because wrong number of characters in one section, or wrong number of # symbols.
return false;
}
// Split it into sections to make life easier
$email_array = explode("#", $email);
$local_array = explode(".", $email_array[0]);
for ($i = 0; $i < sizeof($local_array); $i++) {
if (!preg_match("/^(([A-Za-z0-9!#$%&'*+\/=?^_`{|}~-][A-Za-z0-9!#$%&'*+\/=?^_`{|}~\.-]{0,63})|(\"[^(\\|\")]{0,62}\"))$/", $local_array[$i])) {
return false;
}
}
if (!preg_match("/^\[?[0-9\.]+\]?$/", $email_array[1])) { // Check if domain is IP. If not, it should be valid domain name
$domain_array = explode(".", $email_array[1]);
if (sizeof($domain_array) < 2) {
return false; // Not enough parts to domain
}
for ($i = 0; $i < sizeof($domain_array); $i++) {
if (!preg_match("/^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]+))$/", $domain_array[$i])) {
return false;
}
}
}
return true;
}
When the array only contains one emailaddress there is no problem and everything is working fine.
But when I have 2 emailaddresses at least, I get the FALSE error everytime. (Even when the emailaddresses are valid)
What do i do wrong?
I would have used
filter_var($email, FILTER_VALIDATE_EMAIL)
And:
filter_var($email, FILTER_SANITIZE_EMAIL)
Just like
foreach($emailadressen as $email)
{
if(filter_var($email, FILTER_SANITIZE_EMAIL === FALSE) ||
filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE)
{
$Melding['omschrijving'] =
'<div class="error">Error in address number '.$i.'</div>';
$i++;
}
}
I think space is getting added in your email address try by using trim
foreach($emailadressen as $emails) {
if(check_email_address(trim($emails)) == false) {
echo '<div class="error">Error in address number '.$i.' ' . $emails. '</div>';
}
else {
echo '<div class="noerror">No Error in address number '.$i. ' ' . $emails. '</div>';
}
$i++;
}
Using a filter, you should be able to simply use:
foreach($emailadressen as $emails)
{
if(!filter_var($emails, FILTER_VALIDATE_EMAIL))
{
$Melding['omschrijving'] = '<div class="error">Error in address number '.$i.'</div>';
$i++;
}
}
Without the need for any of that huge function.
This is assuming that by the time you run this foreach, the array from the post is containing the email only.
Related
So, I want to check the users-input, if it contains some of these characters:
" ' < >
I hope someone can show me a better way with less code
Thanks!
I used preg_match, but i just managed it with 4 nested if's.
/*Checks if the given value is valid*/
private function checkValidInput($input)
{
/*If there is no " */
if(preg_match('/"/', $input) == false)
{
/*If there is no ' */
if(preg_match("/'/", $input) == false)
{
/*If there is no <*/
if(preg_match("/</", $input) == false)
{
/*If there is no >*/
if(preg_match("/>/", $input) == false)
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
else
{
return false;
}
}
else
{
return false;
}
}
You could create a regex class
preg_match('#["\'<>]#', $input);
Edit:
If you need to check for all characters then use strpos() with for loop
function checkInput($val) {
$contains = true;
$required = "<>a";
for($i = 0, $count = strlen($required); $i < $count ; ++$i) {
$contains = $contains && false !== strpos($val, $required[$i]);
}
return $contains;
}
var_dump(checkInput('abcd<>a')); // true
var_dump(checkInput('abcd>a')); // false, doesn't contain <
I'm using an IPv6 class found on GitHub to do some IP manipulation but I noticed that there is an issue with shortening certain address, typically ending in 0.
When I enter the address 2001::6dcd:8c74:0:0:0:0, it results in 2001::6dcd:8c74::::.
$address = '2001::6dcd:8c74:0:0:0:0';
// Check to see if address is already compacted
if (strpos($address, '::') === FALSE) {
$parts = explode(':', $address);
$new_parts = array();
$ignore = FALSE;
$done = FALSE;
for ($i = 0; $i < count($parts); $i++) {
if (intval(hexdec($parts[$i])) === 0 && $ignore == FALSE && $done == FALSE) {
$ignore = TRUE;
$new_parts[] = '';
if ($i == 0) {
$new_parts = '';
}
} else if (intval(hexdec($parts[$i])) === 0 && $ignore == TRUE && $done == FALSE) {
continue;
} else if (intval(hexdec($parts[$i])) !== 0 && $ignore == TRUE) {
$done = TRUE;
$ignore = FALSE;
$new_parts[] = $parts[$i];
} else {
$new_parts[] = $parts[$i];
}
}
// Glue everything back together
$address = implode(':', $new_parts);
}
// Remove the leading 0's
$new_address = preg_replace("/:0{1,3}/", ":", $address);
// $this->compact = $new_address;
// return $this->compact;
echo $new_address; // Outputs: 2001::6dcd:8c74::::
To compress ipv6 addresses, use php functions inet_ntop and inet_pton to do the formatting, by converting the ipv6 to binary and back.
Sample ipv6 - 2001::6dcd:8c74:0:0:0:0
Test usage:
echo inet_ntop(inet_pton('2001::6dcd:8c74:0:0:0:0'));
Output : 2001:0:6dcd:8c74::
Without that problem line at the bottom you get 2001::6dcd:8c74:0:0:0:0.
Now, before the leading 0's are all replaced, the function checks to see if the address ends in :0 before removing all leading 0's.
if (substr($address, -2) != ':0') {
$new_address = preg_replace("/:0{1,3}/", ":", $address);
} else {
$new_address = $address;
}
Another check is added to catch other possible valid IPv6 addresses from being malformed.
if (isset($new_parts)) {
if (count($new_parts) < 8 && array_pop($new_parts) == '') {
$new_address .= ':0';
}
}
The new full function looks like this:
// Check to see if address is already compacted
if (strpos($address, '::') === FALSE) {
$parts = explode(':', $address);
$new_parts = array();
$ignore = FALSE;
$done = FALSE;
for ($i = 0; $i < count($parts); $i++) {
if (intval(hexdec($parts[$i])) === 0 && $ignore == FALSE && $done == FALSE) {
$ignore = TRUE;
$new_parts[] = '';
if ($i == 0) {
$new_parts = '';
}
} else if (intval(hexdec($parts[$i])) === 0 && $ignore == TRUE && $done == FALSE) {
continue;
} else if (intval(hexdec($parts[$i])) !== 0 && $ignore == TRUE) {
$done = TRUE;
$ignore = FALSE;
$new_parts[] = $parts[$i];
} else {
$new_parts[] = $parts[$i];
}
}
// Glue everything back together
$address = implode(':', $new_parts);
}
// Check to see if this ends in a shortened :0 before replacing all
// leading 0's
if (substr($address, -2) != ':0') {
// Remove the leading 0's
$new_address = preg_replace("/:0{1,3}/", ":", $address);
} else {
$new_address = $address;
}
// Since new_parts isn't always set, check to see if it's set before
// trying to fix possibly broken shortened addresses ending in 0.
// (Ex: Trying to shorten 2001:19f0::0 will result in unset array)
if (isset($new_parts)) {
// Some addresses (Ex: starting addresses for a range) can end in
// all 0's resulting in the last value in the new parts array to be
// an empty string. Catch that case here and add the remaining :0
// for a complete shortened address.
if (count($new_parts) < 8 && array_pop($new_parts) == '') {
$new_address .= ':0';
}
}
// $this->compact = $new_address;
// return $this->compact;
echo $new_address; // Outputs: 2001::6dcd:8c74:0:0:0:0
It's not the cleanest solution and could possibly have holes in its logic depending on what the address is. If I find any other issues with it I will update this question/answer.
Assume that I am creating a registration form. I have code like the below and it is hard to manage because of all the nested if statements.
I want to know the cleanest and easiest to follow way to write code that functions similarly to what I have below.
EDIT: People have told me that I can move the empty($_POST['email']) to the validation functions. I can't do that because I need to know 1) whether user has posted data or not, and 2) whether the data user posted is valid.
For example, when the user first goes to the registration page, they have not posted any data so $_POST['email'] will generate PHP warnings because they don't exist. That's why I check whether data has been posted before I validate.
Does this make sense?
function validate_email($str) {
$str = trim(strtolower($str));
if(!filter_var($str, FILTER_VALIDATE_EMAIL)) {
return false;
} else {
return $str;
}
}
function validate_password($str) {
$str = trim($str);
if(strlen($str) < 5 || strlen($str) > 70) {
return false;
} else {
return $str;
}
}
$email = false;
$password = false;
$errorMessage = false;
if(!empty($_POST['email'])) {
$email = validate_email($_POST['email']);
if($email) {
if(!empty($_POST['password'])) {
$password = validate_password($_POST['password']);
if($password) {
createNewUser($email,$password);
} else {
$errorMessage = "The password is not valid";
}
} else {
$errorMessage = "The password is not valid";
}
} else {
$errorMessage = "Email address is invalid";
}
} else {
$errorMessage = "Email address is invalid";
}
if($errorMessage) echo $errorMessage;
Whenever you have nested if()s you can flip the logic "inside out":
if (A)
if (B)
if (C)
final()
change to:
if (!A) return
if (!B) return
if (!C) return
final()
In your case instead of returning you could throw an exception.
try {
validateAndCreateNewUser();
}
catch(ValidationError $e) {
display($e->getMessage());
}
You don't need the empty checks at that point, move them to the validation functions.
For example:
function validate_email($str) {
if(empty($str)) {
return false;
}
$str = trim(strtolower($str));
if(!filter_var($str, FILTER_VALIDATE_EMAIL)) {
return false;
} else {
return $str;
}
}
$email = validate_email($_POST['email']);
if($email) {
// your code
}
This is a bit cleaner:
function validate_email($str) {
if (empty($str)) return false;
$str = trim(strtolower($str));
if(!filter_var($str, FILTER_VALIDATE_EMAIL)) {
return false;
} else {
return $str;
}
}
function validate_password($str) {
if (empty($str)) return false;
$str = trim($str);
if(strlen($str) < 5 || strlen($str) > 70) {
return false;
} else {
return $str;
}
}
$email = false;
$password = false;
$errorMessage = false;
$email = validate_email($_POST['email']);
if($email) {
$password = validate_password($_POST['password']);
if($password) {
createNewUser($email,$password);
} else {
$errorMessage = "The password is not valid";
}
} else {
$errorMessage = "Email address is invalid";
}
if($errorMessage) echo $errorMessage;
I have this If statement to check user submitted data. The data is first turned into an array which is then passed to a function where this if statement is located.
$errCount = 0;
$errMSG ='';
// Check Name
if ($submitData['FullName'] != '') {
if (strlen ($submitData['FullName']) < 4) {
$errCount + 1;
$errMSG .='The Full Name was too short!';
}
} else {
$errCount + 1;
$errMSG .='The Full Name Field was left blank!';
}
When this is run, even with an empty string, none of the errors are being triggered.
Am I missing something?
Thanks!
You are not assigning values to $errCount varaible when incrementing it;
$errCount = 0;
$errMSG ='';
$submitData['FullName']='';
// Check Name
if ($submitData['FullName'] != '') {
if (strlen ($submitData['FullName']) < 4) {
$errCount=$errCount + 1; // or u can write $errCount++;
$errMSG .='The Full Name was too short!';
}
} else {
$errCount=$errCount + 1; // or u can write $errCount++;
$errMSG .='The Full Name Field was left blank!';
}
echo $errMSG;
echo $errCount;
This will work.....
$errCount = 0;
$errMSG ='';
// Check Name
if(isset($submitData['FullName']) && strlen ($submitData['FullName'])>0 && strlen ($submitData['FullName'])<4)
{
$errCount++;
$errMSG .='The Full Name was too short!';
}
else if($submitData['FullName'] == '')
{
$errCount++;
$errMSG .='The Full Name Field was left blank!';
}
else
{
//success
}
I thought to do a preg_count for each "/<[a-z0-9]+>/i" and then count if exists the same number with the closed tags ie: "/</[a-z0-9]+>/i"
But I am not too sure. How would you count all opened tags and check if exists all closed tags?
Ps. i don't need to check for attribute and for xml /> single close tag. I just need a count on plain simple html tag
Thanks
I wrote this handy functions. I think it could be faster if I search both opened/closed tags within one preg_match_all but as this it's more readable:
<?php
//> Will count number of <[a-z]> tag and </[a-z]> tag (will also validate the order)
//> Note br should be in the form of <br /> for not causing problems
function validHTML($html,$checkOrder=true) {
preg_match_all( '#<([a-z]+)>#i' , $html, $start, PREG_OFFSET_CAPTURE );
preg_match_all( '#<\/([a-z]+)>#i' , $html, $end, PREG_OFFSET_CAPTURE );
$start = $start[1];
$end = $end[1];
if (count($start) != count($end) )
throw new Exception('Check numbers of tags');
if ($checkOrder) {
$is = 0;
foreach($end as $v){
if ($v[0] != $start[$is][0] || $v[1] < $start[$is][1] )
throw new Exception('End tag ['.$v[0].'] not opened');
$is++;
}
}
return true;
}
//> Usage::
try {
validHTML('<p>hello</p><li></li></p><p>');
} catch (Exception $e) {
echo $e->getMessage();
}
Note if you need to catch even h1 or any other tag with numbers you need to add 0-9 within pattern of preg
The proper way to validate HTML is using a HTML parser. Using Regexes to deal with HTML is very wrong - see RegEx match open tags except XHTML self-contained tags
My case
function checkHtml($html) {
$level = 0;
$map = [];
$length = strlen($html);
$open = false;
$tag = '';
for($i = 0; $i < $length; $i ++) {
$c = substr($html, $i, 1);
if($c == '<') {
$open = true;
$tag = '';
} else if($open && ($c == '>' || ord($c) == 32)) {
$open = false;
if(in_array($tag, ['br', 'br/', 'hr/', 'img/', 'hr', 'img'])) {
continue;
}
if(strpos($tag, '/') === 0) {
if(!isset($map[$tag.($level-1)])) {
return false;
}
$level --;
unset($map[$tag.$level]);
} else {
$map['/'.$tag.$level] = true;
$level ++;
}
} else if($open) {
$tag .= $c;
}
}
return $level == 0;
}
ok, one solution would be:
function open_tags($page)
{
$arr=array();
$page // your html/xml/somthing content
$i=0;
while ($i<strlen($page))
{
$i=strpos($page,'<',$i); //position of starting the tag
$end=strpos($page,'>',$i); //position of ending the tag
if(strpos($page,'/')<$end) //if it's an end tag
{
if (array_pop($arr)!=substr($page,$i,$end-$i)); // pop the last value inserted into the stack, and check if it's the same as this one
return FALSE;
}
else
{
array_push($arr,substr($page,$i,$end-$i)); // push the new tag value into the stack
}
}
return $arr;
}
this will return opened tags by order, or false if error.
edit:
function open_tags($page)
{
$arr=array();
$page // your html/xml/somthing content
$i=0;
while ($i<strlen($page))
{
$i=strpos($page,'<',$i); //position of starting the tag
$end=strpos($page,'>',$i); //position of ending the tag
if($end>strpos($page,'<',$i))
return false;
if(strpos($page,'/')<$end) //if it's an end tag
{
if (array_pop($arr)!=substr($page,$i,$end-$i)); // pop the last value inserted into the stack, and check if it's the same as this one
return FALSE;
}
else
{
array_push($arr,substr($page,$i,$end-$i)); // push the new tag value into the stack
}
}
return $arr;
}