PHP Developers Network

A community of PHP developers offering assistance, advice, discussion, and friendship.
 
Loading
It is currently Fri May 29, 2020 7:51 am

All times are UTC - 5 hours




Post new topic Reply to topic  [ 3 posts ] 
Author Message
PostPosted: Wed Dec 07, 2011 10:20 am 
Offline
Forum Newbie

Joined: Wed Dec 07, 2011 10:18 am
Posts: 2
Hi;

I had an email from my hosting company which said that my account was hacked and one script in images folder is trying to send thousands of spams(file name : "/public_html/images/sm5vy7.php"). they blocked my account and asked me to check if there is any script or code that may cause this problem.
The only server side page I had was a contact.php file that has mail() function in it. the code is like this;
Syntax: [ Download ] [ Hide ]
if( isset($_POST['submit'])) {
$name=$_POST['name'];
$comment=$_POST['comment'];
$email=$_POST['email'];
$phone=$_POST['phone'];
$to = "sample@gmail.com";
$subject = "sample";
$message = "sample";
$from = "$email";
$headers = "Content-type:text;charset=utf-8" . "\r\n";
$headers .= "From: $from" . "\r\n";
mail($to,$subject,$message,$headers);
}
 


My question is "can the code I used cause any security problem that someone be able to create a php file in my images folder or someone has accessed my account?"

Thank you in advance
I'm really in a big trouble


Top
 Profile  
 
PostPosted: Wed Dec 07, 2011 3:19 pm 
Offline
Moderator
User avatar

Joined: Mon Nov 03, 2003 7:13 pm
Posts: 5978
Location: Odessa, Ukraine
This particular snippet is unlikely to have allowed php file upload. However it's prone to email header injection |(because you did not validate the data in $email variable), which alone is enough to be able to send spam from your site.

What you need to be aware though is that many of such issues result from the website's owner computers being infected with a trojan/backdoor/rootkit that steals ftp/ssh passwords. So in addition to removing malicious scripts from your site you need to check your own computer (or any other computer you might have used to access webserver's filesystem).


Top
 Profile  
 
PostPosted: Sun Dec 11, 2011 9:18 pm 
Offline
Forum Contributor

Joined: Wed Feb 03, 2010 2:22 am
Posts: 102
sanitize email address to prevent form hijacking injecton attacks:
Syntax: [ Download ] [ Hide ]
function SanitizeEmail($email)
   {
      return preg_replace( '((?:\n|\r|\t|%0A|%0D|%08|%09)+)i' , '', $email);
   }


validate the proper email address format:
Syntax: [ Download ] [ Hide ]
<?php
/**
 * http://isemail.info/about
 *
 * To validate an email address according to RFCs 5321, 5322 and others
 *
 * Copyright © 2008-2011, Dominic Sayers                                       <br>
 * Test schema documentation Copyright © 2011, Daniel Marschall                        <br>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *     - Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *     - Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 *     - Neither the name of Dominic Sayers nor the names of its contributors may be
 *       used to endorse or promote products derived from this software without
 *       specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @package     is_email
 * @author      Dominic Sayers <dominic@sayers.cc>
 * @copyright   2008-2011 Dominic Sayers
 * @license     http://www.opensource.org/licenses/bsd-license.php BSD License
 * @link        http://www.dominicsayers.com/isemail
 * @version     3.01.1 - Fixed examples and readme.txt
 */


// The quality of this code has been improved greatly by using PHPLint
// Copyright (c) 2010 Umberto Salsi
// This is free software; see the license for copying conditions.
// More info: http://www.icosaedro.it/phplint/
/*.
        require_module 'standard';
        require_module 'pcre';
.*/


if (!defined('ISEMAIL_VALID')) {
/*:diagnostic constants start:*/
// This part of the code is generated using data from test/meta.xml. Beware of making manual alterations
        // Categories
        define('ISEMAIL_VALID_CATEGORY', 1);
        define('ISEMAIL_DNSWARN', 7);
        define('ISEMAIL_RFC5321', 15);
        define('ISEMAIL_CFWS', 31);
        define('ISEMAIL_DEPREC', 63);
        define('ISEMAIL_RFC5322', 127);
        define('ISEMAIL_ERR', 255);

        // Diagnoses
        // Address is valid
        define('ISEMAIL_VALID', 0);
        // Address is valid but a DNS check was not successful
        define('ISEMAIL_DNSWARN_NO_MX_RECORD', 5);
        define('ISEMAIL_DNSWARN_NO_RECORD', 6);
        // Address is valid for SMTP but has unusual elements
        define('ISEMAIL_RFC5321_TLD', 9);
        define('ISEMAIL_RFC5321_TLDNUMERIC', 10);
        define('ISEMAIL_RFC5321_QUOTEDSTRING', 11);
        define('ISEMAIL_RFC5321_ADDRESSLITERAL', 12);
        define('ISEMAIL_RFC5321_IPV6DEPRECATED', 13);
        // Address is valid within the message but cannot be used unmodified for the envelope
        define('ISEMAIL_CFWS_COMMENT', 17);
        define('ISEMAIL_CFWS_FWS', 18);
        // Address contains deprecated elements but may still be valid in restricted contexts
        define('ISEMAIL_DEPREC_LOCALPART', 33);
        define('ISEMAIL_DEPREC_FWS', 34);
        define('ISEMAIL_DEPREC_QTEXT', 35);
        define('ISEMAIL_DEPREC_QP', 36);
        define('ISEMAIL_DEPREC_COMMENT', 37);
        define('ISEMAIL_DEPREC_CTEXT', 38);
        define('ISEMAIL_DEPREC_CFWS_NEAR_AT', 49);
        // The address is only valid according to the broad definition of RFC 5322. It is otherwise invalid.
        define('ISEMAIL_RFC5322_DOMAIN', 65);
        define('ISEMAIL_RFC5322_TOOLONG', 66);
        define('ISEMAIL_RFC5322_LOCAL_TOOLONG', 67);
        define('ISEMAIL_RFC5322_DOMAIN_TOOLONG', 68);
        define('ISEMAIL_RFC5322_LABEL_TOOLONG', 69);
        define('ISEMAIL_RFC5322_DOMAINLITERAL', 70);
        define('ISEMAIL_RFC5322_DOMLIT_OBSDTEXT', 71);
        define('ISEMAIL_RFC5322_IPV6_GRPCOUNT', 72);
        define('ISEMAIL_RFC5322_IPV6_2X2XCOLON', 73);
        define('ISEMAIL_RFC5322_IPV6_BADCHAR', 74);
        define('ISEMAIL_RFC5322_IPV6_MAXGRPS', 75);
        define('ISEMAIL_RFC5322_IPV6_COLONSTRT', 76);
        define('ISEMAIL_RFC5322_IPV6_COLONEND', 77);
        // Address is invalid for any purpose
        define('ISEMAIL_ERR_EXPECTING_DTEXT', 129);
        define('ISEMAIL_ERR_NOLOCALPART', 130);
        define('ISEMAIL_ERR_NODOMAIN', 131);
        define('ISEMAIL_ERR_CONSECUTIVEDOTS', 132);
        define('ISEMAIL_ERR_ATEXT_AFTER_CFWS', 133);
        define('ISEMAIL_ERR_ATEXT_AFTER_QS', 134);
        define('ISEMAIL_ERR_ATEXT_AFTER_DOMLIT', 135);
        define('ISEMAIL_ERR_EXPECTING_QPAIR', 136);
        define('ISEMAIL_ERR_EXPECTING_ATEXT', 137);
        define('ISEMAIL_ERR_EXPECTING_QTEXT', 138);
        define('ISEMAIL_ERR_EXPECTING_CTEXT', 139);
        define('ISEMAIL_ERR_BACKSLASHEND', 140);
        define('ISEMAIL_ERR_DOT_START', 141);
        define('ISEMAIL_ERR_DOT_END', 142);
        define('ISEMAIL_ERR_DOMAINHYPHENSTART', 143);
        define('ISEMAIL_ERR_DOMAINHYPHENEND', 144);
        define('ISEMAIL_ERR_UNCLOSEDQUOTEDSTR', 145);
        define('ISEMAIL_ERR_UNCLOSEDCOMMENT', 146);
        define('ISEMAIL_ERR_UNCLOSEDDOMLIT', 147);
        define('ISEMAIL_ERR_FWS_CRLF_X2', 148);
        define('ISEMAIL_ERR_FWS_CRLF_END', 149);
        define('ISEMAIL_ERR_CR_NO_LF', 150);
// End of generated code
/*:diagnostic constants end:*/

        // function control
        define('ISEMAIL_THRESHOLD'              , 16);

        // Email parts
        define('ISEMAIL_COMPONENT_LOCALPART'    , 0);
        define('ISEMAIL_COMPONENT_DOMAIN'       , 1);
        define('ISEMAIL_COMPONENT_LITERAL'      , 2);
        define('ISEMAIL_CONTEXT_COMMENT'        , 3);
        define('ISEMAIL_CONTEXT_FWS'            , 4);
        define('ISEMAIL_CONTEXT_QUOTEDSTRING'   , 5);
        define('ISEMAIL_CONTEXT_QUOTEDPAIR'     , 6);

        // Miscellaneous string constants
        define('ISEMAIL_STRING_AT'              , '@');
        define('ISEMAIL_STRING_BACKSLASH'       , '\\');
        define('ISEMAIL_STRING_DOT'             , '.');
        define('ISEMAIL_STRING_DQUOTE'          , '"');
        define('ISEMAIL_STRING_OPENPARENTHESIS' , '(');
        define('ISEMAIL_STRING_CLOSEPARENTHESIS', ')');
        define('ISEMAIL_STRING_OPENSQBRACKET'   , '[');
        define('ISEMAIL_STRING_CLOSESQBRACKET'  , ']');
        define('ISEMAIL_STRING_HYPHEN'          , '-');
        define('ISEMAIL_STRING_COLON'           , ':');
        define('ISEMAIL_STRING_DOUBLECOLON'     , '::');
        define('ISEMAIL_STRING_SP'              , ' ');
        define('ISEMAIL_STRING_HTAB'            , "\t");
        define('ISEMAIL_STRING_CR'              , "\r");
        define('ISEMAIL_STRING_LF'              , "\n");
        define('ISEMAIL_STRING_IPV6TAG'         , 'IPv6:');
        // US-ASCII visible characters not valid for atext (http://tools.ietf.org/html/rfc5322#section-3.2.3)
        define('ISEMAIL_STRING_SPECIALS'        , '()<>[]:;@\\,."');
}

/**
 * Check that an email address conforms to RFCs 5321, 5322 and others
 *
 * As of Version 3.0, we are now distinguishing clearly between a Mailbox
 * as defined by RFC 5321 and an addr-spec as defined by RFC 5322. Depending
 * on the context, either can be regarded as a valid email address. The
 * RFC 5321 Mailbox specification is more restrictive (comments, white space
 * and obsolete forms are not allowed)
 *
 * @param string        $email          The email address to check
 * @param boolean       $checkDNS       If true then a DNS check for MX records will be made
 * @param mixed         $errorlevel     Determines the boundary between valid and invalid addresses.
 *                                      Status codes above this number will be returned as-is,
 *                                      status codes below will be returned as ISEMAIL_VALID. Thus the
 *                                      calling program can simply look for ISEMAIL_VALID if it is
 *                                      only interested in whether an address is valid or not. The
 *                                      errorlevel will determine how "picky" is_email() is about
 *                                      the address.
 *
 *                                      If omitted or passed as false then is_email() will return
 *                                      true or false rather than an integer error or warning.
 *
 *                                      NB Note the difference between $errorlevel = false and
 *                                      $errorlevel = 0
 * @param array         $parsedata      If passed, returns the parsed address components
 */

/*.mixed.*/ function is_email($email, $checkDNS = false, $errorlevel = false, &$parsedata = array()) {
        // Check that $email is a valid address. Read the following RFCs to understand the constraints:
        //      (http://tools.ietf.org/html/rfc5321)
        //      (http://tools.ietf.org/html/rfc5322)
        //      (http://tools.ietf.org/html/rfc4291#section-2.2)
        //      (http://tools.ietf.org/html/rfc1123#section-2.1)
        //      (http://tools.ietf.org/html/rfc3696) (guidance only)
// version 2.0: Enhance $diagnose parameter to $errorlevel
// version 3.0: Introduced status categories
// revision 3.1: BUG: $parsedata was passed by value instead of by reference

        if (is_bool($errorlevel)) {
                $threshold      = ISEMAIL_VALID;
                $diagnose       = (bool) $errorlevel;
        } else {
                $diagnose       = true;

                switch ((int) $errorlevel) {
                case E_WARNING: $threshold      = ISEMAIL_THRESHOLD;    break;  // For backward compatibility
                case E_ERROR:   $threshold      = ISEMAIL_VALID;        break;  // For backward compatibility
                default:        $threshold      = (int) $errorlevel;
                }
        }

        $return_status = array(ISEMAIL_VALID);

        // Parse the address into components, character by character
        $raw_length     = strlen($email);
        $context        = ISEMAIL_COMPONENT_LOCALPART;  // Where we are
        $context_stack  = array($context);              // Where we have been
        $context_prior  = ISEMAIL_COMPONENT_LOCALPART;  // Where we just came from
        $token          = '';                           // The current character
        $token_prior    = '';                           // The previous character
        $parsedata      = array(
                                ISEMAIL_COMPONENT_LOCALPART     => '',
                                ISEMAIL_COMPONENT_DOMAIN        => ''
                               );                       // For the components of the address

        $atomlist       = array(
                                ISEMAIL_COMPONENT_LOCALPART     => array(''),
                                ISEMAIL_COMPONENT_DOMAIN        => array('')
                               );                       // For the dot-atom elements of the address
        $element_count  = 0;
        $element_len    = 0;
        $hyphen_flag    = false;                        // Hyphen cannot occur at the end of a subdomain
        $end_or_die     = false;                        // CFWS can only appear at the end of the element

//-echo "<table style=\"clear:left;\">"; // debug
        for ($i = 0; $i < $raw_length; $i++) {
                $token = $email[$i];
//-echo "<tr><td><strong>$context|",(($end_or_die) ? 'true' : 'false'),"|$token|" . max($return_status) . "</strong></td>"; // debug

                switch ($context) {
                //-------------------------------------------------------------
                // local-part
                //-------------------------------------------------------------
                case ISEMAIL_COMPONENT_LOCALPART:
                        // http://tools.ietf.org/html/rfc5322#section-3.4.1
                        //   local-part      =   dot-atom / quoted-string / obs-local-part
                        //
                        //   dot-atom        =   [CFWS] dot-atom-text [CFWS]
                        //
                        //   dot-atom-text   =   1*atext *("." 1*atext)
                        //
                        //   quoted-string   =   [CFWS]
                        //                       DQUOTE *([FWS] qcontent) [FWS] DQUOTE
                        //                       [CFWS]
                        //
                        //   obs-local-part  =   word *("." word)
                        //
                        //   word            =   atom / quoted-string
                        //
                        //   atom            =   [CFWS] 1*atext [CFWS]
                        switch ($token) {
                        // Comment
                        case ISEMAIL_STRING_OPENPARENTHESIS:
                                if ($element_len === 0)
                                        // Comments are OK at the beginning of an element
                                        $return_status[]        = ($element_count === 0) ? ISEMAIL_CFWS_COMMENT : ISEMAIL_DEPREC_COMMENT;
                                else {
                                        $return_status[]        = ISEMAIL_CFWS_COMMENT;
                                        $end_or_die             = true; // We can't start a comment in the middle of an element, so this better be the end
                                }

                                $context_stack[]        = $context;
                                $context                = ISEMAIL_CONTEXT_COMMENT;
                                break;
                        // Next dot-atom element
                        case ISEMAIL_STRING_DOT:
                                if ($element_len === 0)
                                        // Another dot, already?
                                        $return_status[] = ($element_count === 0) ? ISEMAIL_ERR_DOT_START : ISEMAIL_ERR_CONSECUTIVEDOTS;        // Fatal error
                                else
                                        // The entire local-part can be a quoted string for RFC 5321
                                        // If it's just one atom that is quoted then it's an RFC 5322 obsolete form
                                        if ($end_or_die) $return_status[] = ISEMAIL_DEPREC_LOCALPART;

                                        $end_or_die     = false;        // CFWS & quoted strings are OK again now we're at the beginning of an element (although they are obsolete forms)
                                        $element_len    = 0;
                                        $element_count++;
                                        $parsedata[ISEMAIL_COMPONENT_LOCALPART]                 .= $token;
                                        $atomlist[ISEMAIL_COMPONENT_LOCALPART][$element_count]  = '';

                                break;
                        // Quoted string
                        case ISEMAIL_STRING_DQUOTE:
                                if ($element_len === 0) {
                                        // The entire local-part can be a quoted string for RFC 5321
                                        // If it's just one atom that is quoted then it's an RFC 5322 obsolete form
                                        $return_status[]        = ($element_count === 0) ? ISEMAIL_RFC5321_QUOTEDSTRING : ISEMAIL_DEPREC_LOCALPART;

                                        $parsedata[ISEMAIL_COMPONENT_LOCALPART]                 .= $token;
                                        $atomlist[ISEMAIL_COMPONENT_LOCALPART][$element_count]  .= $token;
                                        $element_len++;
                                        $end_or_die             = true; // Quoted string must be the entire element
                                        $context_stack[]        = $context;
                                        $context                = ISEMAIL_CONTEXT_QUOTEDSTRING;
                                } else {
                                        $return_status[]        = ISEMAIL_ERR_EXPECTING_ATEXT;  // Fatal error
                                }

                                break;
                        // Folding White Space
                        case ISEMAIL_STRING_CR:
                        case ISEMAIL_STRING_SP:
                        case ISEMAIL_STRING_HTAB:
                                if (($token === ISEMAIL_STRING_CR) && ((++$i === $raw_length) || ($email[$i] !== ISEMAIL_STRING_LF))) {$return_status[] = ISEMAIL_ERR_CR_NO_LF; break;} // Fatal error

                                if ($element_len === 0)
                                        $return_status[] = ($element_count === 0) ? ISEMAIL_CFWS_FWS : ISEMAIL_DEPREC_FWS;
                                else
                                        $end_or_die = true;     // We can't start FWS in the middle of an element, so this better be the end

                                $context_stack[]        = $context;
                                $context                = ISEMAIL_CONTEXT_FWS;
                                $token_prior            = $token;

                                break;
                        // @
                        case ISEMAIL_STRING_AT:
                                // At this point we should have a valid local-part
                                if (count($context_stack) !== 1) die('Unexpected item on context stack');

                                if      ($parsedata[ISEMAIL_COMPONENT_LOCALPART] === '')
                                                                $return_status[]        = ISEMAIL_ERR_NOLOCALPART;      // Fatal error
                                elseif  ($element_len === 0)    $return_status[]        = ISEMAIL_ERR_DOT_END;  // Fatal error
                                // http://tools.ietf.org/html/rfc5321#section-4.5.3.1.1
                                //   The maximum total length of a user name or other local-part is 64
                                //   octets.
                                elseif  (strlen($parsedata[ISEMAIL_COMPONENT_LOCALPART]) > 64)
                                                                $return_status[]        = ISEMAIL_RFC5322_LOCAL_TOOLONG;
                                // http://tools.ietf.org/html/rfc5322#section-3.4.1
                                //   Comments and folding white space
                                //   SHOULD NOT be used around the "@" in the addr-spec.
                                //
                                // http://tools.ietf.org/html/rfc2119
                                // 4. SHOULD NOT   This phrase, or the phrase "NOT RECOMMENDED" mean that
                                //    there may exist valid reasons in particular circumstances when the
                                //    particular behavior is acceptable or even useful, but the full
                                //    implications should be understood and the case carefully weighed
                                //    before implementing any behavior described with this label.
                                elseif  (($context_prior === ISEMAIL_CONTEXT_COMMENT) || ($context_prior === ISEMAIL_CONTEXT_FWS))
                                                                $return_status[]        = ISEMAIL_DEPREC_CFWS_NEAR_AT;

                                // Clear everything down for the domain parsing
                                $context        = ISEMAIL_COMPONENT_DOMAIN;     // Where we are
                                $context_stack  = array($context);              // Where we have been
                                $element_count  = 0;
                                $element_len    = 0;
                                $end_or_die     = false;                        // CFWS can only appear at the end of the element

                                break;
                        // atext
                        default:
                                // http://tools.ietf.org/html/rfc5322#section-3.2.3
                                //    atext           =   ALPHA / DIGIT /    ; Printable US-ASCII
                                //                        "!" / "#" /        ;  characters not including
                                //                        "$" / "%" /        ;  specials.  Used for atoms.
                                //                        "&" / "'" /
                                //                        "*" / "+" /
                                //                        "-" / "/" /
                                //                        "=" / "?" /
                                //                        "^" / "_" /
                                //                        "`" / "{" /
                                //                        "|" / "}" /
                                //                        "~"
                                if ($end_or_die) {
                                        // We have encountered atext where it is no longer valid
                                        switch ($context_prior) {
                                        case ISEMAIL_CONTEXT_COMMENT:
                                        case ISEMAIL_CONTEXT_FWS:
                                                $return_status[]        = ISEMAIL_ERR_ATEXT_AFTER_CFWS;
                                                break;
                                        case ISEMAIL_CONTEXT_QUOTEDSTRING:
                                                $return_status[]        = ISEMAIL_ERR_ATEXT_AFTER_QS;
                                                break;
                                        default:
                                                die ("More atext found where none is allowed, but unrecognised prior context: $context_prior");
                                        }
                                } else {
                                        $context_prior  = $context;
                                        $ord            = ord($token);

                                        if (($ord < 33) || ($ord > 126) || ($ord === 10) || (!is_bool(strpos(ISEMAIL_STRING_SPECIALS, $token))))
                                                $return_status[]        = ISEMAIL_ERR_EXPECTING_ATEXT;  // Fatal error

                                        $parsedata[ISEMAIL_COMPONENT_LOCALPART]                 .= $token;
                                        $atomlist[ISEMAIL_COMPONENT_LOCALPART][$element_count]  .= $token;
                                        $element_len++;
                                }
                        }

                        break;
                //-------------------------------------------------------------
                // Domain
                //-------------------------------------------------------------
                case ISEMAIL_COMPONENT_DOMAIN:
                        // http://tools.ietf.org/html/rfc5322#section-3.4.1
                        //   domain          =   dot-atom / domain-literal / obs-domain
                        //
                        //   dot-atom        =   [CFWS] dot-atom-text [CFWS]
                        //
                        //   dot-atom-text   =   1*atext *("." 1*atext)
                        //
                        //   domain-literal  =   [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS]
                        //
                        //   dtext           =   %d33-90 /          ; Printable US-ASCII
                        //                       %d94-126 /         ;  characters not including
                        //                       obs-dtext          ;  "[", "]", or "\"
                        //
                        //   obs-domain      =   atom *("." atom)
                        //
                        //   atom            =   [CFWS] 1*atext [CFWS]


                        // http://tools.ietf.org/html/rfc5321#section-4.1.2
                        //   Mailbox        = Local-part "@" ( Domain / address-literal )
                        //
                        //   Domain         = sub-domain *("." sub-domain)
                        //
                        //   address-literal  = "[" ( IPv4-address-literal /
                        //                    IPv6-address-literal /
                        //                    General-address-literal ) "]"
                        //                    ; See Section 4.1.3

                        // http://tools.ietf.org/html/rfc5322#section-3.4.1
                        //      Note: A liberal syntax for the domain portion of addr-spec is
                        //      given here.  However, the domain portion contains addressing
                        //      information specified by and used in other protocols (e.g.,
                        //      [RFC1034], [RFC1035], [RFC1123], [RFC5321]).  It is therefore
                        //      incumbent upon implementations to conform to the syntax of
                        //      addresses for the context in which they are used.
                        // is_email() author's note: it's not clear how to interpret this in
                        // the context of a general email address validator. The conclusion I
                        // have reached is this: "addressing information" must comply with
                        // RFC 5321 (and in turn RFC 1035), anything that is "semantically
                        // invisible" must comply only with RFC 5322.
                        switch ($token) {
                        // Comment
                        case ISEMAIL_STRING_OPENPARENTHESIS:
                                if ($element_len === 0)
                                        // Comments at the start of the domain are deprecated in the text
                                        // Comments at the start of a subdomain are obs-domain
                                        // (http://tools.ietf.org/html/rfc5322#section-3.4.1)
                                        $return_status[]        = ($element_count === 0) ? ISEMAIL_DEPREC_CFWS_NEAR_AT : ISEMAIL_DEPREC_COMMENT;
                                else {
                                        $return_status[]        = ISEMAIL_CFWS_COMMENT;
                                        $end_or_die             = true; // We can't start a comment in the middle of an element, so this better be the end
                                }

                                $context_stack[]        = $context;
                                $context                = ISEMAIL_CONTEXT_COMMENT;
                                break;
                        // Next dot-atom element
                        case ISEMAIL_STRING_DOT:
                                if ($element_len === 0)
                                        // Another dot, already?
                                        $return_status[]        = ($element_count === 0) ? ISEMAIL_ERR_DOT_START : ISEMAIL_ERR_CONSECUTIVEDOTS; // Fatal error
                                elseif ($hyphen_flag)
                                        // Previous subdomain ended in a hyphen
                                        $return_status[]        = ISEMAIL_ERR_DOMAINHYPHENEND;  // Fatal error
                                else
                                        // Nowhere in RFC 5321 does it say explicitly that the
                                        // domain part of a Mailbox must be a valid domain according
                                        // to the DNS standards set out in RFC 1035, but this *is*
                                        // implied in several places. For instance, wherever the idea
                                        // of host routing is discussed the RFC says that the domain
                                        // must be looked up in the DNS. This would be nonsense unless
                                        // the domain was designed to be a valid DNS domain. Hence we
                                        // must conclude that the RFC 1035 restriction on label length
                                        // also applies to RFC 5321 domains.
                                        //
                                        // http://tools.ietf.org/html/rfc1035#section-2.3.4
                                        // labels          63 octets or less
                                        if ($element_len > 63) $return_status[] = ISEMAIL_RFC5322_LABEL_TOOLONG;

                                        $end_or_die             = false;        // CFWS is OK again now we're at the beginning of an element (although it may be obsolete CFWS)
                                        $element_len            = 0;
                                        $element_count++;
                                        $atomlist[ISEMAIL_COMPONENT_DOMAIN][$element_count]     = '';
                                        $parsedata[ISEMAIL_COMPONENT_DOMAIN]                    .= $token;

                                break;
                        // Domain literal
                        case ISEMAIL_STRING_OPENSQBRACKET:
                                if ($parsedata[ISEMAIL_COMPONENT_DOMAIN] === '') {
                                        $end_or_die             = true; // Domain literal must be the only component
                                        $element_len++;
                                        $context_stack[]        = $context;
                                        $context                = ISEMAIL_COMPONENT_LITERAL;
                                        $parsedata[ISEMAIL_COMPONENT_DOMAIN]                    .= $token;
                                        $atomlist[ISEMAIL_COMPONENT_DOMAIN][$element_count]     .= $token;
                                        $parsedata[ISEMAIL_COMPONENT_LITERAL]                   = '';
                                } else {
                                        $return_status[]        = ISEMAIL_ERR_EXPECTING_ATEXT;  // Fatal error
                                }

                                break;
                        // Folding White Space
                        case ISEMAIL_STRING_CR:
                        case ISEMAIL_STRING_SP:
                        case ISEMAIL_STRING_HTAB:
                                if (($token === ISEMAIL_STRING_CR) && ((++$i === $raw_length) || ($email[$i] !== ISEMAIL_STRING_LF))) {$return_status[] = ISEMAIL_ERR_CR_NO_LF; break;} // Fatal error

                                if ($element_len === 0)
                                        $return_status[]        = ($element_count === 0) ? ISEMAIL_DEPREC_CFWS_NEAR_AT : ISEMAIL_DEPREC_FWS;
                                else {
                                        $return_status[]        = ISEMAIL_CFWS_FWS;
                                        $end_or_die     = true; // We can't start FWS in the middle of an element, so this better be the end
                                }

                                $context_stack[]        = $context;
                                $context                = ISEMAIL_CONTEXT_FWS;
                                $token_prior            = $token;
                                break;
                        // atext
                        default:
                                // RFC 5322 allows any atext...
                                // http://tools.ietf.org/html/rfc5322#section-3.2.3
                                //    atext           =   ALPHA / DIGIT /    ; Printable US-ASCII
                                //                        "!" / "#" /        ;  characters not including
                                //                        "$" / "%" /        ;  specials.  Used for atoms.
                                //                        "&" / "'" /
                                //                        "*" / "+" /
                                //                        "-" / "/" /
                                //                        "=" / "?" /
                                //                        "^" / "_" /
                                //                        "`" / "{" /
                                //                        "|" / "}" /
                                //                        "~"

                                // But RFC 5321 only allows letter-digit-hyphen to comply with DNS rules (RFCs 1034 & 1123)
                                // http://tools.ietf.org/html/rfc5321#section-4.1.2
                                //   sub-domain     = Let-dig [Ldh-str]
                                //
                                //   Let-dig        = ALPHA / DIGIT
                                //
                                //   Ldh-str        = *( ALPHA / DIGIT / "-" ) Let-dig
                                //
                                if ($end_or_die) {
                                        // We have encountered atext where it is no longer valid
                                        switch ($context_prior) {
                                        case ISEMAIL_CONTEXT_COMMENT:
                                        case ISEMAIL_CONTEXT_FWS:
                                                $return_status[]        = ISEMAIL_ERR_ATEXT_AFTER_CFWS;
                                                break;
                                        case ISEMAIL_COMPONENT_LITERAL:
                                                $return_status[]        = ISEMAIL_ERR_ATEXT_AFTER_DOMLIT;
                                                break;
                                        default:
                                                die ("More atext found where none is allowed, but unrecognised prior context: $context_prior");
                                        }
                                }

                                $ord            = ord($token);
                                $hyphen_flag    = false;        // Assume this token isn't a hyphen unless we discover it is

                                if (($ord < 33) || ($ord > 126) || (!is_bool(strpos(ISEMAIL_STRING_SPECIALS, $token)))) {
                                        $return_status[]        = ISEMAIL_ERR_EXPECTING_ATEXT;  // Fatal error
                                } elseif ($token === ISEMAIL_STRING_HYPHEN) {
                                        if ($element_len === 0) {
                                                // Hyphens can't be at the beginning of a subdomain
                                                $return_status[]        = ISEMAIL_ERR_DOMAINHYPHENSTART;        // Fatal error
                                        }

                                        $hyphen_flag = true;
                                } elseif (!(($ord > 47 && $ord < 58) || ($ord > 64 && $ord < 91) || ($ord > 96 && $ord < 123))) {
                                        // Not an RFC 5321 subdomain, but still OK by RFC 5322
                                        $return_status[]        = ISEMAIL_RFC5322_DOMAIN;
                                }

                                $parsedata[ISEMAIL_COMPONENT_DOMAIN]                    .= $token;
                                $atomlist[ISEMAIL_COMPONENT_DOMAIN][$element_count]     .= $token;
                                $element_len++;
                        }

                        break;
                //-------------------------------------------------------------
                // Domain literal
                //-------------------------------------------------------------
                case ISEMAIL_COMPONENT_LITERAL:
                        // http://tools.ietf.org/html/rfc5322#section-3.4.1
                        //   domain-literal  =   [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS]
                        //
                        //   dtext           =   %d33-90 /          ; Printable US-ASCII
                        //                       %d94-126 /         ;  characters not including
                        //                       obs-dtext          ;  "[", "]", or "\"
                        //
                        //   obs-dtext       =   obs-NO-WS-CTL / quoted-pair
                        switch ($token) {
                        // End of domain literal
                        case ISEMAIL_STRING_CLOSESQBRACKET:
                                if ((int) max($return_status) < ISEMAIL_DEPREC) {
                                        // Could be a valid RFC 5321 address literal, so let's check

                                        // http://tools.ietf.org/html/rfc5321#section-4.1.2
                                        //   address-literal  = "[" ( IPv4-address-literal /
                                        //                    IPv6-address-literal /
                                        //                    General-address-literal ) "]"
                                        //                    ; See Section 4.1.3
                                        //
                                        // http://tools.ietf.org/html/rfc5321#section-4.1.3
                                        //   IPv4-address-literal  = Snum 3("."  Snum)
                                        //
                                        //   IPv6-address-literal  = "IPv6:" IPv6-addr
                                        //
                                        //   General-address-literal  = Standardized-tag ":" 1*dcontent
                                        //
                                        //   Standardized-tag  = Ldh-str
                                        //                     ; Standardized-tag MUST be specified in a
                                        //                     ; Standards-Track RFC and registered with IANA
                                        //
                                        //   dcontent       = %d33-90 / ; Printable US-ASCII
                                        //                  %d94-126 ; excl. "[", "\", "]"
                                        //
                                        //   Snum           = 1*3DIGIT
                                        //                  ; representing a decimal integer
                                        //                  ; value in the range 0 through 255
                                        //
                                        //   IPv6-addr      = IPv6-full / IPv6-comp / IPv6v4-full / IPv6v4-comp
                                        //
                                        //   IPv6-hex       = 1*4HEXDIG
                                        //
                                        //   IPv6-full      = IPv6-hex 7(":" IPv6-hex)
                                        //
                                        //   IPv6-comp      = [IPv6-hex *5(":" IPv6-hex)] "::"
                                        //                  [IPv6-hex *5(":" IPv6-hex)]
                                        //                  ; The "::" represents at least 2 16-bit groups of
                                        //                  ; zeros.  No more than 6 groups in addition to the
                                        //                  ; "::" may be present.
                                        //
                                        //   IPv6v4-full    = IPv6-hex 5(":" IPv6-hex) ":" IPv4-address-literal
                                        //
                                        //   IPv6v4-comp    = [IPv6-hex *3(":" IPv6-hex)] "::"
                                        //                  [IPv6-hex *3(":" IPv6-hex) ":"]
                                        //                  IPv4-address-literal
                                        //                  ; The "::" represents at least 2 16-bit groups of
                                        //                  ; zeros.  No more than 4 groups in addition to the
                                        //                  ; "::" and IPv4-address-literal may be present.
                                        //
                                        // is_email() author's note: We can't use ip2long() to validate
                                        // IPv4 addresses because it accepts abbreviated addresses
                                        // (xxx.xxx.xxx), expanding the last group to complete the address.
                                        // filter_var() validates IPv6 address inconsistently (up to PHP 5.3.3
                                        // at least) -- see http://bugs.php.net/bug.php?id=53236 for example
                                        $max_groups     = 8;
                                        $matchesIP      = array();
                        /*.mixed.*/     $index          = false;
                                        $addressliteral = $parsedata[ISEMAIL_COMPONENT_LITERAL];

                                        // Extract IPv4 part from the end of the address-literal (if there is one)
                                        if (preg_match('/\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/', $addressliteral, $matchesIP) > 0) {
                                                $index = strrpos($addressliteral, $matchesIP[0]);
                                                if ($index !== 0) $addressliteral = substr($addressliteral, 0, $index) . '0:0'; // Convert IPv4 part to IPv6 format for further testing
                                        }

                                        if ($index === 0) {
                                                // Nothing there except a valid IPv4 address, so...
                                                $return_status[]        = ISEMAIL_RFC5321_ADDRESSLITERAL;
                                        } elseif (strncasecmp($addressliteral, ISEMAIL_STRING_IPV6TAG, 5) !== 0) {
                                                $return_status[]        = ISEMAIL_RFC5322_DOMAINLITERAL;
                                        } else {
                                                $IPv6           = substr($addressliteral, 5);
                                                $matchesIP      = explode(ISEMAIL_STRING_COLON, $IPv6); // Revision 2.7: Daniel Marschall's new IPv6 testing strategy
                                                $groupCount     = count($matchesIP);
                                                $index          = strpos($IPv6,ISEMAIL_STRING_DOUBLECOLON);

                                                if ($index === false) {
                                                        // We need exactly the right number of groups
                                                        if ($groupCount !== $max_groups)
                                                                $return_status[]        = ISEMAIL_RFC5322_IPV6_GRPCOUNT;
                                                } else {
                                                        if ($index !== strrpos($IPv6,ISEMAIL_STRING_DOUBLECOLON))
                                                                $return_status[]        = ISEMAIL_RFC5322_IPV6_2X2XCOLON;
                                                        else {
                                                                if ($index === 0 || $index === (strlen($IPv6) - 2)) $max_groups++;      // RFC 4291 allows :: at the start or end of an address with 7 other groups in addition

                                                                if ($groupCount > $max_groups)
                                                                        $return_status[]        = ISEMAIL_RFC5322_IPV6_MAXGRPS;
                                                                elseif ($groupCount === $max_groups)
                                                                        $return_status[]        = ISEMAIL_RFC5321_IPV6DEPRECATED;       // Eliding a single "::"
                                                        }
                                                }

                                                // Revision 2.7: Daniel Marschall's new IPv6 testing strategy
                                                if ((substr($IPv6, 0,  1) === ISEMAIL_STRING_COLON) && (substr($IPv6, 1,  1) !== ISEMAIL_STRING_COLON))
                                                        $return_status[]        = ISEMAIL_RFC5322_IPV6_COLONSTRT;       // Address starts with a single colon
                                                elseif ((substr($IPv6, -1) === ISEMAIL_STRING_COLON) && (substr($IPv6, -2, 1) !== ISEMAIL_STRING_COLON))
                                                        $return_status[]        = ISEMAIL_RFC5322_IPV6_COLONEND;        // Address ends with a single colon
                                                elseif (count(preg_grep('/^[0-9A-Fa-f]{0,4}$/', $matchesIP, PREG_GREP_INVERT)) !== 0)
                                                        $return_status[]        = ISEMAIL_RFC5322_IPV6_BADCHAR; // Check for unmatched characters
                                                else
                                                        $return_status[]        = ISEMAIL_RFC5321_ADDRESSLITERAL;
                                        }
                                } else
                                        $return_status[]        = ISEMAIL_RFC5322_DOMAINLITERAL;


                                $parsedata[ISEMAIL_COMPONENT_DOMAIN]                    .= $token;
                                $atomlist[ISEMAIL_COMPONENT_DOMAIN][$element_count]     .= $token;
                                $element_len++;
                                $context_prior          = $context;
                                $context                = (int) array_pop($context_stack);
                                break;
                        case ISEMAIL_STRING_BACKSLASH:
                                $return_status[]        = ISEMAIL_RFC5322_DOMLIT_OBSDTEXT;
                                $context_stack[]        = $context;
                                $context                = ISEMAIL_CONTEXT_QUOTEDPAIR;
                                break;
                        // Folding White Space
                        case ISEMAIL_STRING_CR:
                        case ISEMAIL_STRING_SP:
                        case ISEMAIL_STRING_HTAB:
                                if (($token === ISEMAIL_STRING_CR) && ((++$i === $raw_length) || ($email[$i] !== ISEMAIL_STRING_LF))) {$return_status[] = ISEMAIL_ERR_CR_NO_LF; break;} // Fatal error

                                $return_status[]        = ISEMAIL_CFWS_FWS;

                                $context_stack[]        = $context;
                                $context                = ISEMAIL_CONTEXT_FWS;
                                $token_prior            = $token;
                                break;
                        // dtext
                        default:
                                // http://tools.ietf.org/html/rfc5322#section-3.4.1
                                //   dtext           =   %d33-90 /          ; Printable US-ASCII
                                //                       %d94-126 /         ;  characters not including
                                //                       obs-dtext          ;  "[", "]", or "\"
                                //
                                //   obs-dtext       =   obs-NO-WS-CTL / quoted-pair
                                //
                                //   obs-NO-WS-CTL   =   %d1-8 /            ; US-ASCII control
                                //                       %d11 /             ;  characters that do not
                                //                       %d12 /             ;  include the carriage
                                //                       %d14-31 /          ;  return, line feed, and
                                //                       %d127              ;  white space characters
                                $ord = ord($token);

                                // CR, LF, SP & HTAB have already been parsed above
                                if (($ord > 127) || ($ord === 0) || ($token === ISEMAIL_STRING_OPENSQBRACKET)) {
                                        $return_status[]        = ISEMAIL_ERR_EXPECTING_DTEXT;  // Fatal error
                                        break;
                                } elseif (($ord < 33) || ($ord === 127)) {
                                        $return_status[]        = ISEMAIL_RFC5322_DOMLIT_OBSDTEXT;
                                }

                                $parsedata[ISEMAIL_COMPONENT_LITERAL]                   .= $token;
                                $parsedata[ISEMAIL_COMPONENT_DOMAIN]                    .= $token;
                                $atomlist[ISEMAIL_COMPONENT_DOMAIN][$element_count]     .= $token;
                                $element_len++;
                        }

                        break;
                //-------------------------------------------------------------
                // Quoted string
                //-------------------------------------------------------------
                case ISEMAIL_CONTEXT_QUOTEDSTRING:
                        // http://tools.ietf.org/html/rfc5322#section-3.2.4
                        //   quoted-string   =   [CFWS]
                        //                       DQUOTE *([FWS] qcontent) [FWS] DQUOTE
                        //                       [CFWS]
                        //
                        //   qcontent        =   qtext / quoted-pair
                        switch ($token) {
                        // Quoted pair
                        case ISEMAIL_STRING_BACKSLASH:
                                $context_stack[]        = $context;
                                $context                = ISEMAIL_CONTEXT_QUOTEDPAIR;
                                break;
                        // Folding White Space
                        // Inside a quoted string, spaces are allowed as regular characters.
                        // It's only FWS if we include HTAB or CRLF
                        case ISEMAIL_STRING_CR:
                        case ISEMAIL_STRING_HTAB:
                                if (($token === ISEMAIL_STRING_CR) && ((++$i === $raw_length) || ($email[$i] !== ISEMAIL_STRING_LF))) {$return_status[] = ISEMAIL_ERR_CR_NO_LF; break;} // Fatal error

                                // http://tools.ietf.org/html/rfc5322#section-3.2.2
                                //   Runs of FWS, comment, or CFWS that occur between lexical tokens in a
                                //   structured header field are semantically interpreted as a single
                                //   space character.

                                // http://tools.ietf.org/html/rfc5322#section-3.2.4
                                //   the CRLF in any FWS/CFWS that appears within the quoted-string [is]
                                //   semantically "invisible" and therefore not part of the quoted-string
                                $parsedata[ISEMAIL_COMPONENT_LOCALPART]                 .= ISEMAIL_STRING_SP;
                                $atomlist[ISEMAIL_COMPONENT_LOCALPART][$element_count]  .= ISEMAIL_STRING_SP;
                                $element_len++;

                                $return_status[]                = ISEMAIL_CFWS_FWS;
                                $context_stack[]                = $context;
                                $context                        = ISEMAIL_CONTEXT_FWS;
                                $token_prior                    = $token;
                                break;
                        // End of quoted string
                        case ISEMAIL_STRING_DQUOTE:
                                $parsedata[ISEMAIL_COMPONENT_LOCALPART]                 .= $token;
                                $atomlist[ISEMAIL_COMPONENT_LOCALPART][$element_count]  .= $token;
                                $element_len++;
                                $context_prior                  = $context;
                                $context                        = (int) array_pop($context_stack);
                                break;
                        // qtext
                        default:
                                // http://tools.ietf.org/html/rfc5322#section-3.2.4
                                //   qtext           =   %d33 /             ; Printable US-ASCII
                                //                       %d35-91 /          ;  characters not including
                                //                       %d93-126 /         ;  "\" or the quote character
                                //                       obs-qtext
                                //
                                //   obs-qtext       =   obs-NO-WS-CTL
                                //
                                //   obs-NO-WS-CTL   =   %d1-8 /            ; US-ASCII control
                                //                       %d11 /             ;  characters that do not
                                //                       %d12 /             ;  include the carriage
                                //                       %d14-31 /          ;  return, line feed, and
                                //                       %d127              ;  white space characters
                                $ord = ord($token);

                                if (($ord > 127) || ($ord === 0) || ($ord === 10)) {
                                        $return_status[]        = ISEMAIL_ERR_EXPECTING_QTEXT;  // Fatal error
                                } elseif (($ord < 32) || ($ord === 127))
                                        $return_status[]        = ISEMAIL_DEPREC_QTEXT;

                                $parsedata[ISEMAIL_COMPONENT_LOCALPART]                 .= $token;
                                $atomlist[ISEMAIL_COMPONENT_LOCALPART][$element_count]  .= $token;
                                $element_len++;
                        }

                        // http://tools.ietf.org/html/rfc5322#section-3.4.1
                        //   If the
                        //   string can be represented as a dot-atom (that is, it contains no
                        //   characters other than atext characters or "." surrounded by atext
                        //   characters), then the dot-atom form SHOULD be used and the quoted-
                        //   string form SHOULD NOT be used.
// To do
                        break;
                //-------------------------------------------------------------
                // Quoted pair
                //-------------------------------------------------------------
                case ISEMAIL_CONTEXT_QUOTEDPAIR:
                        // http://tools.ietf.org/html/rfc5322#section-3.2.1
                        //   quoted-pair     =   ("\" (VCHAR / WSP)) / obs-qp
                        //
                        //   VCHAR           =  %d33-126            ; visible (printing) characters
                        //   WSP             =  SP / HTAB           ; white space
                        //
                        //   obs-qp          =   "\" (%d0 / obs-NO-WS-CTL / LF / CR)
                        //
                        //   obs-NO-WS-CTL   =   %d1-8 /            ; US-ASCII control
                        //                       %d11 /             ;  characters that do not
                        //                       %d12 /             ;  include the carriage
                        //                       %d14-31 /          ;  return, line feed, and
                        //                       %d127              ;  white space characters
                        //
                        // i.e. obs-qp       =  "\" (%d0-8, %d10-31 / %d127)
                        $ord = ord($token);

                        if      ($ord > 127)
                                        $return_status[]        = ISEMAIL_ERR_EXPECTING_QPAIR;  // Fatal error
                        elseif  ((($ord < 31) && ($ord !== 9)) || ($ord === 127))       // SP & HTAB are allowed
                                        $return_status[]        = ISEMAIL_DEPREC_QP;

                        // At this point we know where this qpair occurred so
                        // we could check to see if the character actually
                        // needed to be quoted at all.
                        // http://tools.ietf.org/html/rfc5321#section-4.1.2
                        //   the sending system SHOULD transmit the
                        //   form that uses the minimum quoting possible.
// To do: check whether the character needs to be quoted (escaped) in this context
                        $context_prior  = $context;
                        $context        = (int) array_pop($context_stack);      // End of qpair
                        $token          = ISEMAIL_STRING_BACKSLASH . $token;

                        switch ($context) {
                        case ISEMAIL_CONTEXT_COMMENT:
                                break;
                        case ISEMAIL_CONTEXT_QUOTEDSTRING:
                                $parsedata[ISEMAIL_COMPONENT_LOCALPART]                 .= $token;
                                $atomlist[ISEMAIL_COMPONENT_LOCALPART][$element_count]  .= $token;
                                $element_len    += 2;   // The maximum sizes specified by RFC 5321 are octet counts, so we must include the backslash
                                break;
                        case ISEMAIL_COMPONENT_LITERAL:
                                $parsedata[ISEMAIL_COMPONENT_DOMAIN]                    .= $token;
                                $atomlist[ISEMAIL_COMPONENT_DOMAIN][$element_count]     .= $token;
                                $element_len    += 2;   // The maximum sizes specified by RFC 5321 are octet counts, so we must include the backslash
                                break;
                        default:
                                die("Quoted pair logic invoked in an invalid context: $context");
                        }

                        break;
                //-------------------------------------------------------------
                // Comment
                //-------------------------------------------------------------
                case ISEMAIL_CONTEXT_COMMENT:
                        // http://tools.ietf.org/html/rfc5322#section-3.2.2
                        //   comment         =   "(" *([FWS] ccontent) [FWS] ")"
                        //
                        //   ccontent        =   ctext / quoted-pair / comment
                        switch ($token) {
                        // Nested comment
                        case ISEMAIL_STRING_OPENPARENTHESIS:
                                // Nested comments are OK
                                $context_stack[]        = $context;
                                $context                = ISEMAIL_CONTEXT_COMMENT;
                                break;
                        // End of comment
                        case ISEMAIL_STRING_CLOSEPARENTHESIS:
                                $context_prior          = $context;
                                $context                = (int) array_pop($context_stack);

                                // http://tools.ietf.org/html/rfc5322#section-3.2.2
                                //   Runs of FWS, comment, or CFWS that occur between lexical tokens in a
                                //   structured header field are semantically interpreted as a single
                                //   space character.
                                //
                                // is_email() author's note: This *cannot* mean that we must add a
                                // space to the address wherever CFWS appears. This would result in
                                // any addr-spec that had CFWS outside a quoted string being invalid
                                // for RFC 5321.
//                              if (($context === ISEMAIL_COMPONENT_LOCALPART) || ($context === ISEMAIL_COMPONENT_DOMAIN)) {
//                                      $parsedata[$context]                    .= ISEMAIL_STRING_SP;
//                                      $atomlist[$context][$element_count]     .= ISEMAIL_STRING_SP;
//                                      $element_len++;
//                              }

                                break;
                        // Quoted pair
                        case ISEMAIL_STRING_BACKSLASH:
                                $context_stack[]        = $context;
                                $context                = ISEMAIL_CONTEXT_QUOTEDPAIR;
                                break;
                        // Folding White Space
                        case ISEMAIL_STRING_CR:
                        case ISEMAIL_STRING_SP:
                        case ISEMAIL_STRING_HTAB:
                                if (($token === ISEMAIL_STRING_CR) && ((++$i === $raw_length) || ($email[$i] !== ISEMAIL_STRING_LF))) {$return_status[] = ISEMAIL_ERR_CR_NO_LF; break;} // Fatal error

                                $return_status[]        = ISEMAIL_CFWS_FWS;

                                $context_stack[]        = $context;
                                $context                = ISEMAIL_CONTEXT_FWS;
                                $token_prior            = $token;
                                break;
                        // ctext
                        default:
                                // http://tools.ietf.org/html/rfc5322#section-3.2.3
                                //   ctext           =   %d33-39 /          ; Printable US-ASCII
                                //                       %d42-91 /          ;  characters not including
                                //                       %d93-126 /         ;  "(", ")", or "\"
                                //                       obs-ctext
                                //
                                //   obs-ctext       =   obs-NO-WS-CTL
                                //
                                //   obs-NO-WS-CTL   =   %d1-8 /            ; US-ASCII control
                                //                       %d11 /             ;  characters that do not
                                //                       %d12 /             ;  include the carriage
                                //                       %d14-31 /          ;  return, line feed, and
                                //                       %d127              ;  white space characters
                                $ord = ord($token);

                                if (($ord > 127) || ($ord === 0) || ($ord === 10)) {
                                        $return_status[]        = ISEMAIL_ERR_EXPECTING_CTEXT;  // Fatal error
                                        break;
                                } elseif (($ord < 32) || ($ord === 127)) {
                                        $return_status[]        = ISEMAIL_DEPREC_CTEXT;
                                }
                        }

                        break;
                //-------------------------------------------------------------
                // Folding White Space
                //-------------------------------------------------------------
                case ISEMAIL_CONTEXT_FWS:
                        // http://tools.ietf.org/html/rfc5322#section-3.2.2
                        //   FWS             =   ([*WSP CRLF] 1*WSP) /  obs-FWS
                        //                                          ; Folding white space

                        // But note the erratum:
                        // http://www.rfc-editor.org/errata_search ... 2&eid=1908:
                        //   In the obsolete syntax, any amount of folding white space MAY be
                        //   inserted where the obs-FWS rule is allowed.  This creates the
                        //   possibility of having two consecutive "folds" in a line, and
                        //   therefore the possibility that a line which makes up a folded header
                        //   field could be composed entirely of white space.
                        //
                        //   obs-FWS         =   1*([CRLF] WSP)
                        if ($token_prior === ISEMAIL_STRING_CR) {
                                if ($token === ISEMAIL_STRING_CR) {
                                        $return_status[]        = ISEMAIL_ERR_FWS_CRLF_X2;      // Fatal error
                                        break;
                                }

                                if (isset($crlf_count)) {
                                        if (++$crlf_count > 1)
                                                $return_status[]        = ISEMAIL_DEPREC_FWS;   // Multiple folds = obsolete FWS
                                } else $crlf_count = 1;
                        }

                        switch ($token) {
                        case ISEMAIL_STRING_CR:
                                if ((++$i === $raw_length) || ($email[$i] !== ISEMAIL_STRING_LF))
                                        $return_status[]        = ISEMAIL_ERR_CR_NO_LF; // Fatal error

                                break;
                        case ISEMAIL_STRING_SP:
                        case ISEMAIL_STRING_HTAB:
                                break;
                        default:
                                if ($token_prior === ISEMAIL_STRING_CR) {
                                        $return_status[]        = ISEMAIL_ERR_FWS_CRLF_END;     // Fatal error
                                        break;
                                }

                                if (isset($crlf_count)) unset($crlf_count);

                                $context_prior                                  = $context;
                                $context                                        = (int) array_pop($context_stack);      // End of FWS

                                // http://tools.ietf.org/html/rfc5322#section-3.2.2
                                //   Runs of FWS, comment, or CFWS that occur between lexical tokens in a
                                //   structured header field are semantically interpreted as a single
                                //   space character.
                                //
                                // is_email() author's note: This *cannot* mean that we must add a
                                // space to the address wherever CFWS appears. This would result in
                                // any addr-spec that had CFWS outside a quoted string being invalid
                                // for RFC 5321.
//                              if (($context === ISEMAIL_COMPONENT_LOCALPART) || ($context === ISEMAIL_COMPONENT_DOMAIN)) {
//                                      $parsedata[$context]                    .= ISEMAIL_STRING_SP;
//                                      $atomlist[$context][$element_count]     .= ISEMAIL_STRING_SP;
//                                      $element_len++;
//                              }

                                $i--;   // Look at this token again in the parent context
                        }

                        $token_prior = $token;
                        break;
                //-------------------------------------------------------------
                // A context we aren't expecting
                //-------------------------------------------------------------
                default:
                        die("Unknown context: $context");
                }

//-echo "<td>$context|",(($end_or_die) ? 'true' : 'false'),"|$token|" . max($return_status) . "</td></tr>"; // debug
                if ((int) max($return_status) > ISEMAIL_RFC5322) break; // No point going on if we've got a fatal error
        }

        // Some simple final tests
        if ((int) max($return_status) < ISEMAIL_RFC5322) {
                if      ($context       === ISEMAIL_CONTEXT_QUOTEDSTRING)       $return_status[]        = ISEMAIL_ERR_UNCLOSEDQUOTEDSTR;        // Fatal error
                elseif  ($context       === ISEMAIL_CONTEXT_QUOTEDPAIR)         $return_status[]        = ISEMAIL_ERR_BACKSLASHEND;             // Fatal error
                elseif  ($context       === ISEMAIL_CONTEXT_COMMENT)            $return_status[]        = ISEMAIL_ERR_UNCLOSEDCOMMENT;          // Fatal error
                elseif  ($context       === ISEMAIL_COMPONENT_LITERAL)          $return_status[]        = ISEMAIL_ERR_UNCLOSEDDOMLIT;           // Fatal error
                elseif  ($token         === ISEMAIL_STRING_CR)                  $return_status[]        = ISEMAIL_ERR_FWS_CRLF_END;             // Fatal error
                elseif  ($parsedata[ISEMAIL_COMPONENT_DOMAIN]   === '')         $return_status[]        = ISEMAIL_ERR_NODOMAIN;                 // Fatal error
                elseif  ($element_len   === 0)                                  $return_status[]        = ISEMAIL_ERR_DOT_END;                  // Fatal error
                elseif  ($hyphen_flag)                                          $return_status[]        = ISEMAIL_ERR_DOMAINHYPHENEND;          // Fatal error
                // http://tools.ietf.org/html/rfc5321#section-4.5.3.1.2
                //   The maximum total length of a domain name or number is 255 octets.
                elseif  (strlen($parsedata[ISEMAIL_COMPONENT_DOMAIN]) > 255)
                                                                                $return_status[]        = ISEMAIL_RFC5322_DOMAIN_TOOLONG;
                // http://tools.ietf.org/html/rfc5321#section-4.1.2
                //   Forward-path   = Path
                //
                //   Path           = "<" [ A-d-l ":" ] Mailbox ">"
                //
                // http://tools.ietf.org/html/rfc5321#section-4.5.3.1.3
                //   The maximum total length of a reverse-path or forward-path is 256
                //   octets (including the punctuation and element separators).
                //
                // Thus, even without (obsolete) routing information, the Mailbox can
                // only be 254 characters long. This is confirmed by this verified
                // erratum to RFC 3696:
                //
                // http://www.rfc-editor.org/errata_search ... 6&eid=1690
                //   However, there is a restriction in RFC 2821 on the length of an
                //   address in MAIL and RCPT commands of 254 characters.  Since addresses
                //   that do not fit in those fields are not normally useful, the upper
                //   limit on address lengths should normally be considered to be 254.
                elseif  (strlen($parsedata[ISEMAIL_COMPONENT_LOCALPART] . ISEMAIL_STRING_AT . $parsedata[ISEMAIL_COMPONENT_DOMAIN]) > 254)
                                                                                $return_status[]        = ISEMAIL_RFC5322_TOOLONG;
                // http://tools.ietf.org/html/rfc1035#section-2.3.4
                // labels          63 octets or less
                elseif ($element_len > 63)                                      $return_status[]        = ISEMAIL_RFC5322_LABEL_TOOLONG;
        }

        // Check DNS?
        $dns_checked = false;

        if ($checkDNS && ((int) max($return_status) < ISEMAIL_DNSWARN) && function_exists('dns_get_record')) {
                // http://tools.ietf.org/html/rfc5321#section-2.3.5
                //   Names that can
                //   be resolved to MX RRs or address (i.e., A or AAAA) RRs (as discussed
                //   in Section 5) are permitted, as are CNAME RRs whose targets can be
                //   resolved, in turn, to MX or address RRs.
                //
                // http://tools.ietf.org/html/rfc5321#section-5.1
                //   The lookup first attempts to locate an MX record associated with the
                //   name.  If a CNAME record is found, the resulting name is processed as
                //   if it were the initial name. ... If an empty list of MXs is returned,
                //   the address is treated as if it was associated with an implicit MX
                //   RR, with a preference of 0, pointing to that host.
                //
                // is_email() author's note: We will regard the existence of a CNAME to be
                // sufficient evidence of the domain's existence. For performance reasons
                // we will not repeat the DNS lookup for the CNAME's target, but we will
                // raise a warning because we didn't immediately find an MX record.
                if ($element_count === 0) $parsedata[ISEMAIL_COMPONENT_DOMAIN] .= '.';          // Checking TLD DNS seems to work only if you explicitly check from the root

                $result = @dns_get_record($parsedata[ISEMAIL_COMPONENT_DOMAIN], DNS_MX);        // Not using checkdnsrr because of a suspected bug in PHP 5.3 (http://bugs.php.net/bug.php?id=51844)

                if ((is_bool($result) && !(bool) $result))
                        $return_status[] = ISEMAIL_DNSWARN_NO_RECORD;                   // Domain can't be found in DNS
                else {
                        if (count($result) === 0) {
                                $return_status[]        = ISEMAIL_DNSWARN_NO_MX_RECORD;         // MX-record for domain can't be found
                                $result                 = @dns_get_record($parsedata[ISEMAIL_COMPONENT_DOMAIN], DNS_A + DNS_CNAME);

                                if (count($result) === 0)
                                        $return_status[] = ISEMAIL_DNSWARN_NO_RECORD;           // No usable records for the domain can be found
                        } else $dns_checked = true;
                }
        }

        // Check for TLD addresses
        // -----------------------
        // TLD addresses are specifically allowed in RFC 5321 but they are
        // unusual to say the least. We will allocate a separate
        // status to these addresses on the basis that they are more likely
        // to be typos than genuine addresses (unless we've already
        // established that the domain does have an MX record)
        //
        // http://tools.ietf.org/html/rfc5321#section-2.3.5
        //   In the case
        //   of a top-level domain used by itself in an email address, a single
        //   string is used without any dots.  This makes the requirement,
        //   described in more detail below, that only fully-qualified domain
        //   names appear in SMTP transactions on the public Internet,
        //   particularly important where top-level domains are involved.
        //
        // TLD format
        // ----------
        // The format of TLDs has changed a number of times. The standards
        // used by IANA have been largely ignored by ICANN, leading to
        // confusion over the standards being followed. These are not defined
        // anywhere, except as a general component of a DNS host name (a label).
        // However, this could potentially lead to 123.123.123.123 being a
        // valid DNS name (rather than an IP address) and thereby creating
        // an ambiguity. The most authoritative statement on TLD formats that
        // the author can find is in a (rejected!) erratum to RFC 1123
        // submitted by John Klensin, the author of RFC 5321:
        //
        // http://www.rfc-editor.org/errata_search ... 3&eid=1353
        //   However, a valid host name can never have the dotted-decimal
        //   form #.#.#.#, since this change does not permit the highest-level
        //   component label to start with a digit even if it is not all-numeric.
        if (!$dns_checked && ((int) max($return_status) < ISEMAIL_DNSWARN)) {
                if      ($element_count === 0)  $return_status[]        = ISEMAIL_RFC5321_TLD;

                if      (is_numeric($atomlist[ISEMAIL_COMPONENT_DOMAIN][$element_count][0]))
                                                $return_status[]        = ISEMAIL_RFC5321_TLDNUMERIC;
        }

        $return_status          = array_unique($return_status);
        $final_status           = (int) max($return_status);

        if (count($return_status) !== 1) array_shift($return_status); // remove redundant ISEMAIL_VALID

        $parsedata['status']    = $return_status;

        if ($final_status < $threshold) $final_status = ISEMAIL_VALID;

        return ($diagnose) ? $final_status : ($final_status < ISEMAIL_THRESHOLD);
}
?>


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 3 posts ] 

All times are UTC - 5 hours


Who is online

Users browsing this forum: No registered users and 3 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group