Version 1
[yaffs-website] / vendor / egulias / email-validator / src / Egulias / EmailValidator / EmailValidator.php
1 <?php
2
3 namespace Egulias\EmailValidator;
4
5 /**
6  * EmailValidator
7  *
8  * @author Eduardo Gulias Davis <me@egulias.com>
9  */
10 class EmailValidator implements EmailValidatorInterface
11 {
12     /**
13      * Critical validation errors used to indicate that
14      * an email address is invalid:
15      */
16     const ERR_CONSECUTIVEATS     = 128;
17     const ERR_EXPECTING_DTEXT    = 129;
18     const ERR_NOLOCALPART        = 130;
19     const ERR_NODOMAIN           = 131;
20     const ERR_CONSECUTIVEDOTS    = 132;
21     const ERR_ATEXT_AFTER_CFWS   = 133;
22     const ERR_EXPECTING_QPAIR    = 136;
23     const ERR_EXPECTING_ATEXT    = 137;
24     const ERR_EXPECTING_CTEXT    = 139;
25     const ERR_DOT_START          = 141;
26     const ERR_DOT_END            = 142;
27     const ERR_DOMAINHYPHENEND    = 144;
28     const ERR_UNCLOSEDQUOTEDSTR  = 145;
29     const ERR_UNCLOSEDCOMMENT    = 146;
30     const ERR_FWS_CRLF_X2        = 148;
31     const ERR_FWS_CRLF_END       = 149;
32     const ERR_CR_NO_LF           = 150;
33     const ERR_DEPREC_REACHED     = 151;
34     const ERR_UNOPENEDCOMMENT    = 152;
35     const ERR_ATEXT_AFTER_QS     = 134; // not in use
36     const ERR_ATEXT_AFTER_DOMLIT = 135; // not in use
37     const ERR_EXPECTING_QTEXT    = 138; // not in use
38     const ERR_BACKSLASHEND       = 140; // not in use
39     const ERR_DOMAINHYPHENSTART  = 143; // not in use
40     const ERR_UNCLOSEDDOMLIT     = 147; // not in use
41
42     /**
43      * Informational validation warnings regarding unusual or
44      * deprecated features found in an email address:
45      */
46     // Address is valid for SMTP (RFC-5321), but has unusual elements.
47     const RFC5321_TLD             = 9;
48     const RFC5321_QUOTEDSTRING    = 11;
49     const RFC5321_ADDRESSLITERAL  = 12;
50     const RFC5321_IPV6DEPRECATED  = 13;
51     const RFC5321_TLDNUMERIC      = 10; // not in use
52     // Address is only valid according to the broad
53     // definition of RFC-5322. It is otherwise invalid.
54     const RFC5322_LOCAL_TOOLONG   = 64;
55     const RFC5322_LABEL_TOOLONG   = 63;
56     const RFC5322_TOOLONG         = 66;
57     const RFC5322_DOMAIN_TOOLONG  = 255;
58     const RFC5322_DOMAINLITERAL   = 70;
59     const RFC5322_DOMLIT_OBSDTEXT = 71;
60     const RFC5322_IPV6_GRPCOUNT   = 72;
61     const RFC5322_IPV6_2X2XCOLON  = 73;
62     const RFC5322_IPV6_BADCHAR    = 74;
63     const RFC5322_IPV6_MAXGRPS    = 75;
64     const RFC5322_IPV6_COLONSTRT  = 76;
65     const RFC5322_IPV6_COLONEND   = 77;
66     const RFC5322_DOMAIN          = 65; // not in use
67     // Address contains deprecated elements, but may
68     // still be valid in restricted contexts.
69     const DEPREC_QP               = 36;
70     const DEPREC_COMMENT          = 37;
71     const DEPREC_CFWS_NEAR_AT     = 49;
72     const DEPREC_LOCALPART        = 33; // not in use
73     const DEPREC_FWS              = 34; // not in use
74     const DEPREC_QTEXT            = 35; // not in use
75     const DEPREC_CTEXT            = 38; // not in use
76     // Address is valid within the message,
77     // but cannot be used unmodified in the envelope.
78     const CFWS_COMMENT            = 17;
79     const CFWS_FWS                = 18;
80     // Hostname DNS checks were unsuccessful.
81     const DNSWARN_NO_MX_RECORD    = 5;
82     const DNSWARN_NO_RECORD       = 6;
83
84     /**
85      * @var EmailParser
86      */
87     protected $parser;
88
89     /**
90      * Contains any informational warnings regarding unusual/deprecated
91      * features that were encountered during validation.
92      *
93      * @var array
94      */
95     protected $warnings = array();
96
97     /**
98      * If a critical validation problem is encountered, this will be
99      * set to the value of one of this class's ERR_* constants.
100      *
101      * @var int
102      */
103     protected $error;
104
105     /**
106      * @var int
107      */
108     protected $threshold = 255;
109
110     public function __construct()
111     {
112         $this->parser = new EmailParser(new EmailLexer());
113     }
114
115     /**
116      * {@inheritdoc}
117      */
118     public function isValid($email, $checkDNS = false, $strict = false)
119     {
120         try {
121             $this->parser->parse((string)$email);
122             $this->warnings = $this->parser->getWarnings();
123         } catch (\Exception $e) {
124             $rClass = new \ReflectionClass($this);
125             $this->error = $rClass->getConstant($e->getMessage());
126             return false;
127         }
128
129         $dnsProblemExists = ($checkDNS ? !$this->checkDNS() : false);
130
131         if ($this->hasWarnings() && ((int) max($this->warnings) > $this->threshold)) {
132             $this->error = self::ERR_DEPREC_REACHED;
133             return false;
134         }
135
136         return ($strict ? (!$this->hasWarnings() && !$dnsProblemExists) : true);
137     }
138
139     /**
140      * {@inheritdoc}
141      */
142     public function hasWarnings()
143     {
144         return !empty($this->warnings);
145     }
146
147     /**
148      * {@inheritdoc}
149      */
150     public function getWarnings()
151     {
152         return $this->warnings;
153     }
154
155     /**
156      * {@inheritdoc}
157      */
158     public function getError()
159     {
160         return $this->error;
161     }
162
163     /**
164      * {@inheritdoc}
165      */
166     public function setThreshold($threshold)
167     {
168         $this->threshold = (int) $threshold;
169
170         return $this;
171     }
172
173     /**
174      * {@inheritdoc}
175      */
176     public function getThreshold()
177     {
178         return $this->threshold;
179     }
180
181     /**
182      * @return bool Whether or not an MX record exists for the
183      *              email address's host name.
184      */
185     protected function checkDNS()
186     {
187         $host = $this->parser->getParsedDomainPart();
188         $host = rtrim($host, '.') . '.';
189
190         $mxRecordExists = checkdnsrr($host, 'MX');
191
192         if (!$mxRecordExists) {
193             $this->warnings[] = self::DNSWARN_NO_RECORD;
194             $this->addTLDWarnings();
195         }
196
197         return $mxRecordExists;
198     }
199
200     protected function addTLDWarnings()
201     {
202         if (!in_array(self::DNSWARN_NO_RECORD, $this->warnings) &&
203             !in_array(self::DNSWARN_NO_MX_RECORD, $this->warnings) &&
204             in_array(self::RFC5322_DOMAINLITERAL, $this->warnings)
205         ) {
206             $this->warnings[] = self::RFC5321_TLD;
207         }
208     }
209 }