Project:Email Field
Version:6.x-1.x-dev
Component:Code
Category:support request
Priority:normal
Assigned:Unassigned
Status:active

Issue Summary

If I enter, say, "user@gmail" for the email address it passes through as-is when, I assume, it should be flagged as invalid.

I feel like I'm missing something because the module is so simple but I don't see any options, really. And I know the module is working because it created a new mailto link on the address.

Comments

#1

that could be valid email address... root@localhost would end up in admin's inbox on most unit machines.

#2

Ah, I see. Is there any way to force the module to not allow that? We've had a few users enter something like I mentioned above, "user@gmail" and while usually it's apparent what they mean (such as with gmail) other times it's not. I never have any use for root@localhost anyways.

#3

+1 on more validation options

the root@localhost example seems to be a rather extreme exception to me .. but it would certainly be nice to be able to configure for that if needed

it seems that in the vast majority of cases being able to validate on an email address with a valid external email address is what is desired

#4

Hey guys - sorry I don't have time to roll this in a patch - but there is an easy answer - The email case 'validate' (in the email field module) uses drupal's core email validation function (which we don't want to use in this case) - so I modified it like this:

<?php
function email_field($op, &$node, $field, &$items, $teaser, $page) {
  switch (
$op) {
    case
'validate':
      if (
is_array($items)) {
        foreach (
$items as $delta => $item) {
       
$validator = new EmailAddressValidator;
        if (
$validator->check_email_address(trim($item['email']))) {
           
$email_valid = TRUE;
        }
          if (
$item['email'] != '' && !$email_valid) {
           
form_set_error($field['field_name'],t('"%mail" is not a valid email address',array('%mail' => $item['email'])));
          }
        }
     }
     break;

    case
'sanitize':
      foreach (
$items as $delta => $item) {
       
$items[$delta]['safe'] = check_plain($item['email']);
      }
      break;
  }
}
?>

and then pasted in google-code email validation located here at the end of the email module:

http://code.google.com/p/php-email-address-validation/source/browse/trun...

code is pasted here for reference:

<?php

   
/*

        EmailAddressValidator Class
        <a href="http://code.google.com/p/php-email-address-validation/
" title="http://code.google.com/p/php-email-address-validation/
" rel="nofollow">http://code.google.com/p/php-email-address-validation/
</a>        Released under New BSD license
        <a href="http://www.opensource.org/licenses/bsd-license.php
" title="http://www.opensource.org/licenses/bsd-license.php
" rel="nofollow">http://www.opensource.org/licenses/bsd-license.php
</a>       
        Sample Code
        ----------------
        $validator = new EmailAddressValidator;
        if ($validator->check_email_address('test@example.org')) {
            // Email address is technically valid
        }

    */

   
class EmailAddressValidator {

       
/**
         * Check email address validity
         * @param   strEmailAddress     Email address to be checked
         * @return  True if email is valid, false if not
         */
       
public function check_email_address($strEmailAddress) {
           
           
// If magic quotes is "on", email addresses with quote marks will
            // fail validation because of added escape characters. Uncommenting
            // the next three lines will allow for this issue.
            //if (get_magic_quotes_gpc()) {
            //    $strEmailAddress = stripslashes($strEmailAddress);
            //}

            // Control characters are not allowed
           
if (preg_match('/[\x00-\x1F\x7F-\xFF]/', $strEmailAddress)) {
                return
false;
            }

           
// Check email length - min 3 (a@a), max 256
           
if (!$this->check_text_length($strEmailAddress, 3, 256)) {
                return
false;
            }

           
// Split it into sections using last instance of "@"
           
$intAtSymbol = strrpos($strEmailAddress, '@');
            if (
$intAtSymbol === false) {
               
// No "@" symbol in email.
               
return false;
            }
           
$arrEmailAddress[0] = substr($strEmailAddress, 0, $intAtSymbol);
           
$arrEmailAddress[1] = substr($strEmailAddress, $intAtSymbol + 1);

           
// Count the "@" symbols. Only one is allowed, except where
            // contained in quote marks in the local part. Quickest way to
            // check this is to remove anything in quotes. We also remove
            // characters escaped with backslash, and the backslash
            // character.
           
$arrTempAddress[0] = preg_replace('/\./'
                                            
,''
                                            
,$arrEmailAddress[0]);
           
$arrTempAddress[0] = preg_replace('/"[^"]+"/'
                                            
,''
                                            
,$arrTempAddress[0]);
           
$arrTempAddress[1] = $arrEmailAddress[1];
           
$strTempAddress = $arrTempAddress[0] . $arrTempAddress[1];
           
// Then check - should be no "@" symbols.
           
if (strrpos($strTempAddress, '@') !== false) {
               
// "@" symbol found
               
return false;
            }

           
// Check local portion
           
if (!$this->check_local_portion($arrEmailAddress[0])) {
                return
false;
            }

           
// Check domain portion
           
if (!$this->check_domain_portion($arrEmailAddress[1])) {
                return
false;
            }

           
// If we're still here, all checks above passed. Email is valid.
           
return true;

        }

       
/**
         * Checks email section before "@" symbol for validity
         * @param   strLocalPortion     Text to be checked
         * @return  True if local portion is valid, false if not
         */
       
protected function check_local_portion($strLocalPortion) {
           
// Local portion can only be from 1 to 64 characters, inclusive.
            // Please note that servers are encouraged to accept longer local
            // parts than 64 characters.
           
if (!$this->check_text_length($strLocalPortion, 1, 64)) {
                return
false;
            }
           
// Local portion must be:
            // 1) a dot-atom (strings separated by periods)
            // 2) a quoted string
            // 3) an obsolete format string (combination of the above)
           
$arrLocalPortion = explode('.', $strLocalPortion);
            for (
$i = 0, $max = sizeof($arrLocalPortion); $i < $max; $i++) {
                 if (!
preg_match('.^('
                               
.    '([A-Za-z0-9!#$%&\'*+/=?^_`{|}~-]'
                               
.    '[A-Za-z0-9!#$%&\'*+/=?^_`{|}~-]{0,63})'
                               
.'|'
                               
.    '("[^\\\"]{0,62}")'
                               
.')$.'
                               
,$arrLocalPortion[$i])) {
                    return
false;
                }
            }
            return
true;
        }

       
/**
         * Checks email section after "@" symbol for validity
         * @param   strDomainPortion     Text to be checked
         * @return  True if domain portion is valid, false if not
         */
       
protected function check_domain_portion($strDomainPortion) {
           
// Total domain can only be from 1 to 255 characters, inclusive
           
if (!$this->check_text_length($strDomainPortion, 1, 255)) {
                return
false;
            }
           
// Check if domain is IP, possibly enclosed in square brackets.
           
if (preg_match('/^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])'
              
.'(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}$/'
              
,$strDomainPortion) ||
               
preg_match('/^\[(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])'
              
.'(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}\]$/'
              
,$strDomainPortion)) {
                return
true;
            } else {
               
$arrDomainPortion = explode('.', $strDomainPortion);
                if (
sizeof($arrDomainPortion) < 2) {
                    return
false; // Not enough parts to domain
               
}
                for (
$i = 0, $max = sizeof($arrDomainPortion); $i < $max; $i++) {
                   
// Each portion must be between 1 and 63 characters, inclusive
                   
if (!$this->check_text_length($arrDomainPortion[$i], 1, 63)) {
                        return
false;
                    }
                    if (!
preg_match('/^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|'
                      
.'([A-Za-z0-9]+))$/', $arrDomainPortion[$i])) {
                        return
false;
                    }
                    if (
$i == $max - 1) { // TLD cannot be only numbers
                       
if (strlen(preg_replace('/[0-9]/', '', $arrDomainPortion[$i])) <= 0) {
                            return
false;
                        }
                    }
                }
            }
            return
true;
        }

       
/**
         * Check given text length is between defined bounds
         * @param   strText     Text to be checked
         * @param   intMinimum  Minimum acceptable length
         * @param   intMaximum  Maximum acceptable length
         * @return  True if string is within bounds (inclusive), false if not
         */
       
protected function check_text_length($strText, $intMinimum, $intMaximum) {
           
// Minimum and maximum are both inclusive
           
$intTextLength = strlen($strText);
            if ((
$intTextLength < $intMinimum) || ($intTextLength > $intMaximum)) {
                return
false;
            } else {
                return
true;
            }
        }

    }

?>

#5

You probably want to do something like this:

http://www.webdigi.co.uk/blog/2009/how-to-check-if-an-email-address-exis...

The fact that the address is syntactically correct does not prove that it exists.

cheers

#6

This is perfect, just what I was searching for, #4 worked.

It would great at one point to see a UI setting to allow only emails with an actual domain attached. I agree with the above, "email@localhost" is an extreme case.

#7

I agree that because email@localhost is the exception it should be dealt with like any other exception in validation (as in validate this pattern as OK).

#8

This module reportedly uses the technique from the link in #5

http://drupal.org/project/email_verify

#9

Well, there's two different validations. One is for whether the email address really exists. The other (which I what I was looking for) is just to make sure the person doesn't make a dumb mistake, like "user@gmail."

And while root@localhost may be a valid email address, how often is that address going to be put into a form? I agree that an option in the interface would be best.