1547 | | // Test for the minimum length the email can be |
1548 | | if ( strlen( $email ) < 3 ) { |
1549 | | return apply_filters( 'is_email', false, $email, 'email_too_short' ); |
1550 | | } |
| 1548 | /*** Refer to RFC 2822 for ABNF grammar ***/ |
| 1549 | |
| 1550 | //All basic building blocks |
| 1551 | $rfc2822['NO-WS-CTL'] = '[\x01-\x08\x0B\x0C\x0E-\x19\x7F]'; |
| 1552 | $rfc2822['WSP'] = '[ \t]'; |
| 1553 | $rfc2822['CRLF'] = '(?:\r\n)'; |
| 1554 | $rfc2822['FWS'] = '(?:(?:' . $rfc2822['WSP'] . '*' . $rfc2822['CRLF'] . ')?' . $rfc2822['WSP'] . ')'; |
| 1555 | $rfc2822['text'] = '[\x00-\x08\x0B\x0C\x0E-\x7F]'; |
| 1556 | $rfc2822['quoted-pair'] = '(?:\\\\' . $rfc2822['text'] . ')'; |
| 1557 | $rfc2822['ctext'] = '(?:' . $rfc2822['NO-WS-CTL'] . '|[\x21-\x27\x2A-\x5B\x5D-\x7E])'; |
| 1558 | //Uses recursive PCRE (?1) -- could be a weak point?? |
| 1559 | $rfc2822['ccontent'] = '(?:' . $rfc2822['ctext'] . '|' . $rfc2822['quoted-pair'] . '|(?1))'; |
| 1560 | $rfc2822['comment'] = '(\((?:' . $rfc2822['FWS'] . '|' . $rfc2822['ccontent']. ')*' . $rfc2822['FWS'] . '?\))'; |
| 1561 | $rfc2822['CFWS'] = '(?:(?:' . $rfc2822['FWS'] . '?' . $rfc2822['comment'] . ')*(?:(?:' . $rfc2822['FWS'] . '?' . $rfc2822['comment'] . ')|' . $rfc2822['FWS'] . '))'; |
| 1562 | $rfc2822['qtext'] = '(?:' . $rfc2822['NO-WS-CTL'] . '|[\x21\x23-\x5B\x5D-\x7E])'; |
| 1563 | $rfc2822['qcontent'] = '(?:' . $rfc2822['qtext'] . '|' . $rfc2822['quoted-pair'] . ')'; |
| 1564 | $rfc2822['quoted-string'] = '(?:' . $rfc2822['CFWS'] . '?"' . '(' . $rfc2822['FWS'] . '?' . $rfc2822['qcontent'] . ')*' . $rfc2822['FWS'] . '?"' . $rfc2822['CFWS'] . '?)'; |
| 1565 | $rfc2822['atext'] = '[a-zA-Z0-9!#\$%&\'\*\+\-\/=\?\^_`\{\}\|~]'; |
| 1566 | $rfc2822['atom'] = '(?:' . $rfc2822['CFWS'] . '?' . $rfc2822['atext'] . '+' . $rfc2822['CFWS'] . '?)'; |
| 1567 | $rfc2822['dot-atom-text'] = '(?:' . $rfc2822['atext'] . '+' . '(\.' . $rfc2822['atext'] . '+)*)'; |
| 1568 | $rfc2822['dot-atom'] = '(?:' . $rfc2822['CFWS'] . '?' . $rfc2822['dot-atom-text'] . '+' . $rfc2822['CFWS'] . '?)'; |
| 1569 | $rfc2822['word'] = '(?:' . $rfc2822['atom'] . '|' . $rfc2822['quoted-string'] . ')'; |
| 1570 | $rfc2822['phrase'] = '(?:' . $rfc2822['word'] . '+?)'; |
| 1571 | $rfc2822['no-fold-quote'] = '(?:"(?:' . $rfc2822['qtext'] . '|' . $rfc2822['quoted-pair'] . ')*")'; |
| 1572 | $rfc2822['dtext'] = '(?:' . $rfc2822['NO-WS-CTL'] . '|[\x21-\x5A\x5E-\x7E])'; |
| 1573 | $rfc2822['no-fold-literal'] = '(?:\[(?:' . $rfc2822['dtext'] . '|' . $rfc2822['quoted-pair'] . ')*\])'; |
| 1574 | //Message IDs |
| 1575 | $rfc2822['id-left'] = '(?:' . $rfc2822['dot-atom-text'] . '|' . $rfc2822['no-fold-quote'] . ')'; |
| 1576 | $rfc2822['id-right'] = '(?:' . $rfc2822['dot-atom-text'] . '|' . $rfc2822['no-fold-literal'] . ')'; |
| 1577 | //Addresses, mailboxes and paths |
| 1578 | $rfc2822['local-part'] = '(?:' . $rfc2822['dot-atom'] . '|' . $rfc2822['quoted-string'] . ')'; |
| 1579 | $rfc2822['dcontent'] = '(?:' . $rfc2822['dtext'] . '|' . $rfc2822['quoted-pair'] . ')'; |
| 1580 | $rfc2822['domain-literal'] = '(?:' . $rfc2822['CFWS'] . '?\[(' . $rfc2822['FWS'] . '?' . $rfc2822['dcontent'] . ')*?' . $rfc2822['FWS'] . '?\]' . $rfc2822['CFWS'] . '?)'; |
| 1581 | $rfc2822['domain'] = '(?:' . $rfc2822['dot-atom'] . '|' . $rfc2822['domain-literal'] . ')'; |
| 1582 | $rfc2822['addr-spec'] = '(?:' . $rfc2822['local-part'] . '@' . $rfc2822['domain'] . ')'; |
1557 | | // Split out the local and domain parts |
1558 | | list( $local, $domain ) = explode( '@', $email, 2 ); |
1559 | | |
1560 | | // LOCAL PART |
1561 | | // Test for invalid characters |
1562 | | if ( !preg_match( '/^[a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.-]+$/', $local ) ) { |
1563 | | return apply_filters( 'is_email', false, $email, 'local_invalid_chars' ); |
1564 | | } |
1565 | | |
1566 | | // DOMAIN PART |
1567 | | // Test for sequences of periods |
1568 | | if ( preg_match( '/\.{2,}/', $domain ) ) { |
1569 | | return apply_filters( 'is_email', false, $email, 'domain_period_sequence' ); |
1570 | | } |
1571 | | |
1572 | | // Test for leading and trailing periods and whitespace |
1573 | | if ( trim( $domain, " \t\n\r\0\x0B." ) !== $domain ) { |
1574 | | return apply_filters( 'is_email', false, $email, 'domain_period_limits' ); |
1575 | | } |
1576 | | |
1577 | | // Split the domain into subs |
1578 | | $subs = explode( '.', $domain ); |
1579 | | |
1580 | | // Assume the domain will have at least two subs |
1581 | | if ( 2 > count( $subs ) ) { |
1582 | | return apply_filters( 'is_email', false, $email, 'domain_no_periods' ); |
1583 | | } |
1584 | | |
1585 | | // Loop through each sub |
1586 | | foreach ( $subs as $sub ) { |
1587 | | // Test for leading and trailing hyphens and whitespace |
1588 | | if ( trim( $sub, " \t\n\r\0\x0B-" ) !== $sub ) { |
1589 | | return apply_filters( 'is_email', false, $email, 'sub_hyphen_limits' ); |
1590 | | } |
1591 | | |
1592 | | // Test for invalid characters |
1593 | | if ( !preg_match('/^[a-z0-9-]+$/i', $sub ) ) { |
1594 | | return apply_filters( 'is_email', false, $email, 'sub_invalid_chars' ); |
1595 | | } |
1596 | | } |
1597 | | |
1598 | | // Congratulations your email made it! |
1599 | | return apply_filters( 'is_email', $email, $email, null ); |
| 1586 | return apply_filters( 'is_email', false, $email, 'not_RFC_2822_compliant' ); |