2010-06-24 09:40:05 +01:00
< ? php
2010-10-02 11:42:31 +01:00
/*
2011-01-15 13:29:43 +00:00
* This file is part of the Symfony package .
2010-10-02 11:42:31 +01:00
*
2011-03-06 11:40:06 +00:00
* ( c ) Fabien Potencier < fabien @ symfony . com >
2010-10-02 11:42:31 +01:00
*
2011-01-15 13:29:43 +00:00
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
2010-10-02 11:42:31 +01:00
*/
2011-01-15 13:29:43 +00:00
namespace Symfony\Component\Validator\Constraints ;
2016-06-23 07:36:47 +01:00
use Egulias\EmailValidator\Validation\EmailValidation ;
2016-11-23 17:18:18 +00:00
use Egulias\EmailValidator\Validation\NoRFCWarningsValidation ;
2010-08-20 22:09:55 +01:00
use Symfony\Component\Validator\Constraint ;
use Symfony\Component\Validator\ConstraintValidator ;
2014-09-24 10:48:52 +01:00
use Symfony\Component\Validator\Exception\RuntimeException ;
2010-08-20 22:09:55 +01:00
use Symfony\Component\Validator\Exception\UnexpectedTypeException ;
2010-06-24 09:40:05 +01:00
2011-07-20 09:37:57 +01:00
/**
2012-02-09 16:54:30 +00:00
* @ author Bernhard Schussek < bschussek @ gmail . com >
2011-07-20 09:37:57 +01:00
*/
2010-06-24 09:40:05 +01:00
class EmailValidator extends ConstraintValidator
{
2017-10-05 16:50:07 +01:00
/**
* @ internal
*/
const PATTERN_HTML5 = '/^[a-zA-Z0-9.!#$%&\'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/' ;
2017-12-11 20:07:32 +00:00
2017-10-05 16:50:07 +01:00
/**
* @ internal
*/
const PATTERN_LOOSE = '/^.+\@\S+\.\S+$/' ;
private static $emailPatterns = array (
Email :: VALIDATION_MODE_LOOSE => self :: PATTERN_LOOSE ,
Email :: VALIDATION_MODE_HTML5 => self :: PATTERN_HTML5 ,
);
2013-09-19 17:03:48 +01:00
2017-10-05 16:50:07 +01:00
/**
* @ var string
*/
private $defaultMode ;
/**
* @ param string $defaultMode
*/
public function __construct ( $defaultMode = Email :: VALIDATION_MODE_LOOSE )
2013-09-19 17:03:48 +01:00
{
2017-10-05 16:50:07 +01:00
if ( is_bool ( $defaultMode )) {
2018-01-02 16:34:13 +00:00
@ trigger_error ( sprintf ( 'Calling `new %s(%s)` is deprecated since Symfony 4.1 and will be removed in 5.0, use `new %s("%s")` instead.' , self :: class , $defaultMode ? 'true' : 'false' , self :: class , $defaultMode ? Email :: VALIDATION_MODE_STRICT : Email :: VALIDATION_MODE_LOOSE ), E_USER_DEPRECATED );
2017-10-05 16:50:07 +01:00
$defaultMode = $defaultMode ? Email :: VALIDATION_MODE_STRICT : Email :: VALIDATION_MODE_LOOSE ;
}
if ( ! in_array ( $defaultMode , Email :: $validationModes , true )) {
throw new \InvalidArgumentException ( 'The "defaultMode" parameter value is not valid.' );
}
$this -> defaultMode = $defaultMode ;
2013-09-19 17:03:48 +01:00
}
2011-07-20 09:37:57 +01:00
/**
2014-04-15 06:57:34 +01:00
* { @ inheritdoc }
2011-07-20 09:37:57 +01:00
*/
2012-02-09 17:02:12 +00:00
public function validate ( $value , Constraint $constraint )
2010-06-24 09:40:05 +01:00
{
2014-03-10 12:51:04 +00:00
if ( ! $constraint instanceof Email ) {
throw new UnexpectedTypeException ( $constraint , __NAMESPACE__ . '\Email' );
}
2010-12-21 02:59:17 +00:00
if ( null === $value || '' === $value ) {
2012-02-09 16:54:30 +00:00
return ;
2010-06-24 10:24:08 +01:00
}
2010-06-24 09:40:05 +01:00
2011-05-07 20:01:44 +01:00
if ( ! is_scalar ( $value ) && ! ( is_object ( $value ) && method_exists ( $value , '__toString' ))) {
2010-06-24 10:24:08 +01:00
throw new UnexpectedTypeException ( $value , 'string' );
}
2010-06-24 09:40:05 +01:00
2011-03-31 13:02:00 +01:00
$value = ( string ) $value ;
2014-09-24 10:48:52 +01:00
2017-10-05 16:50:07 +01:00
if ( null !== $constraint -> strict ) {
2018-01-02 16:34:13 +00:00
@ trigger_error ( sprintf ( 'The %s::$strict property is deprecated since Symfony 4.1 and will be removed in 5.0. Use %s::mode="%s" instead.' , Email :: class , Email :: class , Email :: VALIDATION_MODE_STRICT ), E_USER_DEPRECATED );
2017-10-05 16:50:07 +01:00
if ( $constraint -> strict ) {
$constraint -> mode = Email :: VALIDATION_MODE_STRICT ;
} else {
$constraint -> mode = Email :: VALIDATION_MODE_LOOSE ;
}
}
if ( null === $constraint -> mode ) {
$constraint -> mode = $this -> defaultMode ;
}
if ( ! in_array ( $constraint -> mode , Email :: $validationModes , true )) {
throw new \InvalidArgumentException ( sprintf ( 'The %s::$mode parameter value is not valid.' , get_class ( $constraint )));
2013-09-19 17:03:48 +01:00
}
2017-10-05 16:50:07 +01:00
if ( Email :: VALIDATION_MODE_STRICT === $constraint -> mode ) {
2016-06-29 16:37:25 +01:00
if ( ! class_exists ( '\Egulias\EmailValidator\EmailValidator' )) {
throw new RuntimeException ( 'Strict email validation requires egulias/email-validator ~1.2|~2.0' );
2014-09-24 10:48:52 +01:00
}
$strictValidator = new \Egulias\EmailValidator\EmailValidator ();
2016-11-23 17:18:18 +00:00
if ( interface_exists ( EmailValidation :: class ) && ! $strictValidator -> isValid ( $value , new NoRFCWarningsValidation ())) {
2016-06-23 07:36:47 +01:00
$this -> context -> buildViolation ( $constraint -> message )
-> setParameter ( '{{ value }}' , $this -> formatValue ( $value ))
-> setCode ( Email :: INVALID_FORMAT_ERROR )
-> addViolation ();
return ;
} elseif ( ! interface_exists ( EmailValidation :: class ) && ! $strictValidator -> isValid ( $value , false , true )) {
2015-01-09 08:12:06 +00:00
$this -> context -> buildViolation ( $constraint -> message )
-> setParameter ( '{{ value }}' , $this -> formatValue ( $value ))
-> setCode ( Email :: INVALID_FORMAT_ERROR )
-> addViolation ();
2016-01-14 00:18:51 +00:00
return ;
2014-09-24 10:48:52 +01:00
}
2017-10-05 16:50:07 +01:00
} elseif ( ! preg_match ( self :: $emailPatterns [ $constraint -> mode ], $value )) {
2016-01-14 00:18:51 +00:00
$this -> context -> buildViolation ( $constraint -> message )
-> setParameter ( '{{ value }}' , $this -> formatValue ( $value ))
-> setCode ( Email :: INVALID_FORMAT_ERROR )
-> addViolation ();
2014-09-24 10:48:52 +01:00
return ;
2013-09-19 17:03:48 +01:00
}
2010-06-24 09:40:05 +01:00
2017-03-24 22:09:52 +00:00
$host = ( string ) substr ( $value , strrpos ( $value , '@' ) + 1 );
2013-09-19 17:03:48 +01:00
2014-09-24 10:48:52 +01:00
// Check for host DNS resource records
if ( $constraint -> checkMX ) {
if ( ! $this -> checkMX ( $host )) {
2016-01-14 00:18:51 +00:00
$this -> context -> buildViolation ( $constraint -> message )
-> setParameter ( '{{ value }}' , $this -> formatValue ( $value ))
-> setCode ( Email :: MX_CHECK_FAILED_ERROR )
-> addViolation ();
2011-05-15 10:15:13 +01:00
}
2014-09-24 10:48:52 +01:00
return ;
2010-06-24 10:24:08 +01:00
}
2014-09-24 10:48:52 +01:00
if ( $constraint -> checkHost && ! $this -> checkHost ( $host )) {
2016-01-14 00:18:51 +00:00
$this -> context -> buildViolation ( $constraint -> message )
-> setParameter ( '{{ value }}' , $this -> formatValue ( $value ))
-> setCode ( Email :: HOST_CHECK_FAILED_ERROR )
-> addViolation ();
2011-05-14 11:43:46 +01:00
}
2010-06-24 09:40:05 +01:00
}
2010-06-24 10:24:08 +01:00
/**
2010-12-10 14:42:29 +00:00
* Check DNS Records for MX type .
2010-06-24 10:24:08 +01:00
*/
2017-10-28 19:15:32 +01:00
private function checkMX ( string $host ) : bool
2010-06-24 09:40:05 +01:00
{
2017-03-24 22:09:52 +00:00
return '' !== $host && checkdnsrr ( $host , 'MX' );
2010-06-24 09:40:05 +01:00
}
2012-05-01 13:46:26 +01:00
2012-04-06 01:33:41 +01:00
/**
* Check if one of MX , A or AAAA DNS RR exists .
*/
2017-10-28 19:15:32 +01:00
private function checkHost ( string $host ) : bool
2012-04-06 01:33:41 +01:00
{
2017-03-24 22:09:52 +00:00
return '' !== $host && ( $this -> checkMX ( $host ) || ( checkdnsrr ( $host , 'A' ) || checkdnsrr ( $host , 'AAAA' )));
2012-04-06 01:33:41 +01:00
}
2011-06-08 11:16:48 +01:00
}