mirror of
https://github.com/egulias/EmailValidator.git
synced 2026-09-10 01:56:30 +00:00
Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1ac0be80b3 | |||
| c38e9600fb | |||
| 777864f79e | |||
| ecbcdcef05 | |||
| b28de87213 | |||
| 6d6a87e5d9 | |||
| 0170967656 | |||
| 4c72190f32 | |||
| 413b263617 | |||
| 18b9e5b572 | |||
| 1ca313dfcd | |||
| cf5908bb1a | |||
| b241b54919 | |||
| 74d2f16d9d | |||
| f88dcf4b14 | |||
| a5ed8d58ed | |||
| e3c1f426e5 | |||
| 312b65911f | |||
| d51b279b5f | |||
| 9aab2ceed6 | |||
| 007bfd424e | |||
| 5cc04719d0 | |||
| c70449e7b1 | |||
| 36425ab1f9 | |||
| 4c7033b422 | |||
| 037594add3 | |||
| 4cccb8186b |
+3
-2
@@ -3,11 +3,12 @@ imports:
|
|||||||
|
|
||||||
build:
|
build:
|
||||||
environment:
|
environment:
|
||||||
php: '7.2.13'
|
php: '7.3'
|
||||||
tests:
|
tests:
|
||||||
override:
|
override:
|
||||||
-
|
-
|
||||||
command: 'vendor/bin/phpunit --coverage-clover=clover.xml --exclude-group slow'
|
command: 'vendor/bin/phpunit --coverage-clover=clover.xml --exclude-group flaky'
|
||||||
coverage:
|
coverage:
|
||||||
file: 'clover.xml'
|
file: 'clover.xml'
|
||||||
format: 'clover'
|
format: 'clover'
|
||||||
|
- php-scrutinizer-run
|
||||||
|
|||||||
+4
-8
@@ -2,24 +2,20 @@ language: php
|
|||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- php: 7.2
|
|
||||||
env:
|
|
||||||
- psalm=yes
|
|
||||||
dist: bionic
|
|
||||||
- php: 7.3
|
- php: 7.3
|
||||||
dist: bionic
|
|
||||||
env:
|
env:
|
||||||
- psalm=yes
|
- psalm=yes
|
||||||
|
dist: bionic
|
||||||
- php: 7.4
|
- php: 7.4
|
||||||
|
dist: bionic
|
||||||
env:
|
env:
|
||||||
- psalm=yes
|
- psalm=yes
|
||||||
dist: bionic
|
|
||||||
- php: 8.0
|
- php: 8.0
|
||||||
env:
|
env:
|
||||||
- psalm=yes
|
- psalm=yes
|
||||||
dist: bionic
|
dist: bionic
|
||||||
#ppc64le support code
|
#ppc64le support code
|
||||||
- php: 7.2
|
- php: 7.3
|
||||||
arch: ppc64le
|
arch: ppc64le
|
||||||
env:
|
env:
|
||||||
- psalm=yes
|
- psalm=yes
|
||||||
@@ -38,7 +34,7 @@ before_script:
|
|||||||
- mkdir -p build/logs
|
- mkdir -p build/logs
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- vendor/bin/phpunit --coverage-clover build/logs/clover.xml --exclude-group slow
|
- vendor/bin/phpunit --coverage-clover build/logs/clover.xml --exclude-group flaky
|
||||||
- if [ "$psalm" = "yes" ]; then vendor/bin/psalm; fi
|
- if [ "$psalm" = "yes" ]; then vendor/bin/psalm; fi
|
||||||
|
|
||||||
after_script:
|
after_script:
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ When doing a PR to v2 remember that you also have to do the PR port to v3, or te
|
|||||||
3. Describe the changes you are proposing
|
3. Describe the changes you are proposing
|
||||||
1. If adding an extra validation state the benefits of adding it and the problem is solving
|
1. If adding an extra validation state the benefits of adding it and the problem is solving
|
||||||
2. Document in the readme, by adding it to the list
|
2. Document in the readme, by adding it to the list
|
||||||
4. Provide appropiate tests for the code you are submitting: aim to keep the existing coverage percentage.
|
4. Provide appropriate tests for the code you are submitting: aim to keep the existing coverage percentage.
|
||||||
5. Add your Twitter handle (if you have) so we can thank you there.
|
5. Add your Twitter handle (if you have) so we can thank you there.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
# EmailValidator
|
# EmailValidator
|
||||||
|
|
||||||
[](https://travis-ci.org/egulias/EmailValidator)
|
[](https://app.travis-ci.com/github/egulias/EmailValidator)
|
||||||
[](https://scrutinizer-ci.com/g/egulias/EmailValidator/?branch=3.x)
|
[](https://scrutinizer-ci.com/g/egulias/EmailValidator/?branch=3.x)
|
||||||
[](https://scrutinizer-ci.com/g/egulias/EmailValidator/?branch=3.x)
|
[](https://scrutinizer-ci.com/g/egulias/EmailValidator/?branch=3.x)
|
||||||
[](https://insight.symfony.com/projects/22ba6692-9c02-42e5-a65d-1c5696bfffc6)
|
|
||||||
|
|
||||||
A library for validating emails against several RFC.
|
A library for validating emails against several RFC.
|
||||||
|
|
||||||
@@ -20,7 +19,7 @@ This library aims to support RFCs:
|
|||||||
|
|
||||||
## Supported versions
|
## Supported versions
|
||||||
|
|
||||||
**Curent major version with full support is v3**
|
**Current major version with full support is v3**
|
||||||
|
|
||||||
| Version | Released | EOL | Only critical bug fixes | Full |
|
| Version | Released | EOL | Only critical bug fixes | Full |
|
||||||
| ---- | :----: | :----: | :----: | :----: |
|
| ---- | :----: | :----: | :----: | :----: |
|
||||||
@@ -33,7 +32,7 @@ This library aims to support RFCs:
|
|||||||
|
|
||||||
* PHP 7.2
|
* PHP 7.2
|
||||||
* [Composer](https://getcomposer.org) is required for installation
|
* [Composer](https://getcomposer.org) is required for installation
|
||||||
* [Spoofchecking](/src/Validation/SpoofCheckValidation.php) and [DNSCheckValidation](/src/Validation/DNSCheckValidation.php) validation requires that your PHP system has the [PHP Internationalization Libraries](https://php.net/manual/en/book.intl.php) (also known as PHP Intl)
|
* [Spoofchecking](/src/Validation/Extra/SpoofCheckValidation.php) and [DNSCheckValidation](/src/Validation/DNSCheckValidation.php) validation requires that your PHP system has the [PHP Internationalization Libraries](https://php.net/manual/en/book.intl.php) (also known as PHP Intl)
|
||||||
|
|
||||||
**Note**: `PHP version upgrades will happen to accomodate to the pace of major frameworks. Minor versions bumps will go via minor versions of this library (i.e: PHP7.3 -> v3.x+1). Major versions will go with major versions of the library`
|
**Note**: `PHP version upgrades will happen to accomodate to the pace of major frameworks. Minor versions bumps will go via minor versions of this library (i.e: PHP7.3 -> v3.x+1). Major versions will go with major versions of the library`
|
||||||
|
|
||||||
@@ -47,7 +46,7 @@ composer require egulias/email-validator
|
|||||||
|
|
||||||
## Getting Started ##
|
## Getting Started ##
|
||||||
|
|
||||||
`EmailValidator`requires you to decide which (or combination of them) validation/s strategy/ies you'd like to follow for each [validation](#available-validations).
|
`EmailValidator` requires you to decide which (or combination of them) validation/s strategy/ies you'd like to follow for each [validation](#available-validations).
|
||||||
|
|
||||||
A basic example with the RFC validation
|
A basic example with the RFC validation
|
||||||
```php
|
```php
|
||||||
@@ -65,12 +64,12 @@ $validator->isValid("example@example.com", new RFCValidation()); //true
|
|||||||
|
|
||||||
1. [RFCValidation](/src/Validation/RFCValidation.php): Standard RFC-like email validation.
|
1. [RFCValidation](/src/Validation/RFCValidation.php): Standard RFC-like email validation.
|
||||||
2. [NoRFCWarningsValidation](/src/Validation/NoRFCWarningsValidation.php): RFC-like validation that will fail when warnings* are found.
|
2. [NoRFCWarningsValidation](/src/Validation/NoRFCWarningsValidation.php): RFC-like validation that will fail when warnings* are found.
|
||||||
3. [DNSCheckValidation](/src/Validation/DNSCheckValidation.php): Will check if there are DNS records that signal that the server accepts emails. This does not entails that the email exists.
|
3. [DNSCheckValidation](/src/Validation/DNSCheckValidation.php): Will check if there are DNS records that signal that the server accepts emails. This does not entail that the email exists.
|
||||||
5. [MultipleValidationWithAnd](/src/Validation/MultipleValidationWithAnd.php): It is a validation that operates over other validations performing a logical and (&&) over the result of each validation.
|
5. [MultipleValidationWithAnd](/src/Validation/MultipleValidationWithAnd.php): It is a validation that operates over other validations performing a logical and (&&) over the result of each validation.
|
||||||
6. [MessageIDValidation](/src/Validation/MessageIDValidation.php): Follows [RFC2822 for message-id](https://tools.ietf.org/html/rfc2822#section-3.6.4) to validate that field, that has some differences in the domain part.
|
6. [MessageIDValidation](/src/Validation/MessageIDValidation.php): Follows [RFC2822 for message-id](https://tools.ietf.org/html/rfc2822#section-3.6.4) to validate that field, that has some differences in the domain part.
|
||||||
7. [Your own validation](#how-to-extend): You can extend the library behaviour by implementing your own validations.
|
7. [Your own validation](#how-to-extend): You can extend the library behaviour by implementing your own validations.
|
||||||
|
|
||||||
*warnings: Warnings are deviations from the RFC that in a broader interpretation are acceptded.
|
*warnings: Warnings are deviations from the RFC that in a broader interpretation are accepted.
|
||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
<?php
|
||||||
@@ -85,7 +84,7 @@ $multipleValidations = new MultipleValidationWithAnd([
|
|||||||
new RFCValidation(),
|
new RFCValidation(),
|
||||||
new DNSCheckValidation()
|
new DNSCheckValidation()
|
||||||
]);
|
]);
|
||||||
//ietf.org has MX records signaling a server with email capabilites
|
//ietf.org has MX records signaling a server with email capabilities
|
||||||
$validator->isValid("example@ietf.org", $multipleValidations); //true
|
$validator->isValid("example@ietf.org", $multipleValidations); //true
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
Generated
+1286
-752
File diff suppressed because it is too large
Load Diff
+15
-29
@@ -1,31 +1,17 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd" backupGlobals="false" backupStaticAttributes="false" bootstrap="vendor/autoload.php" colors="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" executionOrder="defects" processIsolation="false" stopOnFailure="false">
|
||||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<coverage>
|
||||||
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
|
<include>
|
||||||
backupGlobals="false"
|
<directory>./src/</directory>
|
||||||
backupStaticAttributes="false"
|
</include>
|
||||||
bootstrap="vendor/autoload.php"
|
<exclude>
|
||||||
colors="true"
|
<directory suffix=".php">./src/Result/Reason</directory>
|
||||||
convertErrorsToExceptions="true"
|
</exclude>
|
||||||
convertNoticesToExceptions="true"
|
</coverage>
|
||||||
convertWarningsToExceptions="true"
|
<testsuites>
|
||||||
executionOrder="defects"
|
<testsuite name="EmailValidator Test Suite">
|
||||||
processIsolation="false"
|
<directory>./tests/EmailValidator</directory>
|
||||||
stopOnFailure="false"
|
<exclude>./vendor/</exclude>
|
||||||
>
|
</testsuite>
|
||||||
<testsuites>
|
</testsuites>
|
||||||
<testsuite name="EmailValidator Test Suite">
|
|
||||||
<directory>./tests/EmailValidator</directory>
|
|
||||||
<exclude>./vendor/</exclude>
|
|
||||||
</testsuite>
|
|
||||||
</testsuites>
|
|
||||||
|
|
||||||
<filter>
|
|
||||||
<whitelist>
|
|
||||||
<directory>./src/</directory>
|
|
||||||
<exclude>
|
|
||||||
<directory suffix=".php">./src/Result/Reason</directory>
|
|
||||||
</exclude>
|
|
||||||
</whitelist>
|
|
||||||
</filter>
|
|
||||||
</phpunit>
|
</phpunit>
|
||||||
+76
-98
@@ -61,7 +61,7 @@ class EmailLexer extends AbstractLexer
|
|||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $charValue = array(
|
protected $charValue = [
|
||||||
'{' => self::S_OPENCURLYBRACES,
|
'{' => self::S_OPENCURLYBRACES,
|
||||||
'}' => self::S_CLOSECURLYBRACES,
|
'}' => self::S_CLOSECURLYBRACES,
|
||||||
'(' => self::S_OPENPARENTHESIS,
|
'(' => self::S_OPENPARENTHESIS,
|
||||||
@@ -105,11 +105,29 @@ class EmailLexer extends AbstractLexer
|
|||||||
'?' => self::QUESTIONMARK,
|
'?' => self::QUESTIONMARK,
|
||||||
'#' => self::NUMBER_SIGN,
|
'#' => self::NUMBER_SIGN,
|
||||||
'¡' => self::INVERT_EXCLAMATION,
|
'¡' => self::INVERT_EXCLAMATION,
|
||||||
);
|
];
|
||||||
|
|
||||||
/**
|
const INVALID_CHARS_REGEX = "/[^\p{S}\p{C}\p{Cc}]+/iu";
|
||||||
* @var bool
|
|
||||||
*/
|
const VALID_UTF8_REGEX = '/\p{Cc}+/u';
|
||||||
|
|
||||||
|
const CATCHABLE_PATTERNS = [
|
||||||
|
'[a-zA-Z]+[46]?', //ASCII and domain literal
|
||||||
|
'[^\x00-\x7F]', //UTF-8
|
||||||
|
'[0-9]+',
|
||||||
|
'\r\n',
|
||||||
|
'::',
|
||||||
|
'\s+?',
|
||||||
|
'.',
|
||||||
|
];
|
||||||
|
|
||||||
|
const NON_CATCHABLE_PATTERNS = [
|
||||||
|
'[\xA0-\xff]+',
|
||||||
|
];
|
||||||
|
|
||||||
|
const MODIFIERS = 'iu';
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
protected $hasInvalidTokens = false;
|
protected $hasInvalidTokens = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -137,23 +155,17 @@ class EmailLexer extends AbstractLexer
|
|||||||
*/
|
*/
|
||||||
public $lookahead;
|
public $lookahead;
|
||||||
|
|
||||||
/**
|
/** @psalm-var array{value:'', type:null, position:0} */
|
||||||
* @psalm-var array{value:'', type:null, position:0}
|
|
||||||
*/
|
|
||||||
private static $nullToken = [
|
private static $nullToken = [
|
||||||
'value' => '',
|
'value' => '',
|
||||||
'type' => null,
|
'type' => null,
|
||||||
'position' => 0,
|
'position' => 0,
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/** @var string */
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $accumulator = '';
|
private $accumulator = '';
|
||||||
|
|
||||||
/**
|
/** @var bool */
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
private $hasToRecord = false;
|
private $hasToRecord = false;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
@@ -162,24 +174,13 @@ class EmailLexer extends AbstractLexer
|
|||||||
$this->lookahead = null;
|
$this->lookahead = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function reset() : void
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function reset()
|
|
||||||
{
|
{
|
||||||
$this->hasInvalidTokens = false;
|
$this->hasInvalidTokens = false;
|
||||||
parent::reset();
|
parent::reset();
|
||||||
$this->previous = $this->token = self::$nullToken;
|
$this->previous = $this->token = self::$nullToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function hasInvalidTokens()
|
|
||||||
{
|
|
||||||
return $this->hasInvalidTokens;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $type
|
* @param int $type
|
||||||
* @throws \UnexpectedValueException
|
* @throws \UnexpectedValueException
|
||||||
@@ -187,7 +188,7 @@ class EmailLexer extends AbstractLexer
|
|||||||
*
|
*
|
||||||
* @psalm-suppress InvalidScalarArgument
|
* @psalm-suppress InvalidScalarArgument
|
||||||
*/
|
*/
|
||||||
public function find($type)
|
public function find($type) : bool
|
||||||
{
|
{
|
||||||
$search = clone $this;
|
$search = clone $this;
|
||||||
$search->skipUntil($type);
|
$search->skipUntil($type);
|
||||||
@@ -198,30 +199,24 @@ class EmailLexer extends AbstractLexer
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* getPrevious
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getPrevious()
|
|
||||||
{
|
|
||||||
return $this->previous;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* moveNext
|
* moveNext
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function moveNext()
|
public function moveNext() : bool
|
||||||
{
|
{
|
||||||
if ($this->hasToRecord && $this->previous === self::$nullToken) {
|
if ($this->hasToRecord && $this->previous === self::$nullToken) {
|
||||||
$this->accumulator .= $this->token['value'];
|
$this->accumulator .= $this->token['value'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->previous = $this->token;
|
$this->previous = $this->token;
|
||||||
|
|
||||||
|
if($this->lookahead === null) {
|
||||||
|
$this->lookahead = self::$nullToken;
|
||||||
|
}
|
||||||
|
|
||||||
$hasNext = parent::moveNext();
|
$hasNext = parent::moveNext();
|
||||||
$this->token = $this->token ?: self::$nullToken;
|
|
||||||
|
|
||||||
if ($this->hasToRecord) {
|
if ($this->hasToRecord) {
|
||||||
$this->accumulator .= $this->token['value'];
|
$this->accumulator .= $this->token['value'];
|
||||||
@@ -230,36 +225,6 @@ class EmailLexer extends AbstractLexer
|
|||||||
return $hasNext;
|
return $hasNext;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Lexical catchable patterns.
|
|
||||||
*
|
|
||||||
* @return string[]
|
|
||||||
*/
|
|
||||||
protected function getCatchablePatterns()
|
|
||||||
{
|
|
||||||
return array(
|
|
||||||
'[a-zA-Z]+[46]?', //ASCII and domain literal
|
|
||||||
'[^\x00-\x7F]', //UTF-8
|
|
||||||
'[0-9]+',
|
|
||||||
'\r\n',
|
|
||||||
'::',
|
|
||||||
'\s+?',
|
|
||||||
'.',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lexical non-catchable patterns.
|
|
||||||
*
|
|
||||||
* @return string[]
|
|
||||||
*/
|
|
||||||
protected function getNonCatchablePatterns()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'[\xA0-\xff]+',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve token type. Also processes the token value if necessary.
|
* Retrieve token type. Also processes the token value if necessary.
|
||||||
*
|
*
|
||||||
@@ -292,51 +257,64 @@ class EmailLexer extends AbstractLexer
|
|||||||
return self::GENERIC;
|
return self::GENERIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function isInvalidChar(string $value) : bool
|
|
||||||
{
|
|
||||||
if(preg_match("/[^\p{S}\p{C}\p{Cc}]+/iu", $value) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function isValid(string $value) : bool
|
protected function isValid(string $value) : bool
|
||||||
{
|
{
|
||||||
if (isset($this->charValue[$value])) {
|
return isset($this->charValue[$value]);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function isNullType(string $value) : bool
|
||||||
* @param string $value
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
protected function isNullType($value)
|
|
||||||
{
|
{
|
||||||
if ($value === "\0") {
|
return $value === "\0";
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
protected function isInvalidChar(string $value) : bool
|
||||||
|
{
|
||||||
|
return !preg_match(self::INVALID_CHARS_REGEX, $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function isUTF8Invalid(string $value) : bool
|
protected function isUTF8Invalid(string $value) : bool
|
||||||
{
|
{
|
||||||
if (preg_match('/\p{Cc}+/u', $value)) {
|
return preg_match(self::VALID_UTF8_REGEX, $value) !== false;
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
public function hasInvalidTokens() : bool
|
||||||
|
{
|
||||||
|
return $this->hasInvalidTokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* getPrevious
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
*/
|
*/
|
||||||
protected function getModifiers()
|
public function getPrevious() : array
|
||||||
{
|
{
|
||||||
return 'iu';
|
return $this->previous;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lexical catchable patterns.
|
||||||
|
*
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
protected function getCatchablePatterns() : array
|
||||||
|
{
|
||||||
|
return self::CATCHABLE_PATTERNS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lexical non-catchable patterns.
|
||||||
|
*
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
protected function getNonCatchablePatterns() : array
|
||||||
|
{
|
||||||
|
return self::NON_CATCHABLE_PATTERNS;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getModifiers() : string
|
||||||
|
{
|
||||||
|
return self::MODIFIERS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAccumulatedValues() : string
|
public function getAccumulatedValues() : string
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
namespace Egulias\EmailValidator;
|
namespace Egulias\EmailValidator;
|
||||||
|
|
||||||
use Egulias\EmailValidator\Parser;
|
use Egulias\EmailValidator\Parser;
|
||||||
use Egulias\EmailValidator\EmailLexer;
|
|
||||||
use Egulias\EmailValidator\Result\Result;
|
use Egulias\EmailValidator\Result\Result;
|
||||||
use Egulias\EmailValidator\Parser\IDLeftPart;
|
use Egulias\EmailValidator\Parser\IDLeftPart;
|
||||||
use Egulias\EmailValidator\Parser\IDRightPart;
|
use Egulias\EmailValidator\Parser\IDRightPart;
|
||||||
|
|||||||
@@ -22,6 +22,15 @@ use Egulias\EmailValidator\Warning\DomainLiteral as WarningDomainLiteral;
|
|||||||
|
|
||||||
class DomainLiteral extends PartParser
|
class DomainLiteral extends PartParser
|
||||||
{
|
{
|
||||||
|
const IPV4_REGEX = '/\\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]?)$/';
|
||||||
|
|
||||||
|
const OBSOLETE_WARNINGS = [
|
||||||
|
EmailLexer::INVALID,
|
||||||
|
EmailLexer::C_DEL,
|
||||||
|
EmailLexer::S_LF,
|
||||||
|
EmailLexer::S_BACKSLASH
|
||||||
|
];
|
||||||
|
|
||||||
public function parse() : Result
|
public function parse() : Result
|
||||||
{
|
{
|
||||||
$this->addTagWarnings();
|
$this->addTagWarnings();
|
||||||
@@ -138,11 +147,8 @@ class DomainLiteral extends PartParser
|
|||||||
|
|
||||||
public function convertIPv4ToIPv6(string $addressLiteralIPv4) : string
|
public function convertIPv4ToIPv6(string $addressLiteralIPv4) : string
|
||||||
{
|
{
|
||||||
$matchesIP = array();
|
$matchesIP = [];
|
||||||
$IPv4Match = preg_match(
|
$IPv4Match = preg_match(self::IPV4_REGEX, $addressLiteralIPv4, $matchesIP);
|
||||||
'/\\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]?)$/',
|
|
||||||
$addressLiteralIPv4,
|
|
||||||
$matchesIP);
|
|
||||||
|
|
||||||
// Extract IPv4 part from the end of the address-literal (if there is one)
|
// Extract IPv4 part from the end of the address-literal (if there is one)
|
||||||
if ($IPv4Match > 0) {
|
if ($IPv4Match > 0) {
|
||||||
@@ -164,11 +170,8 @@ class DomainLiteral extends PartParser
|
|||||||
*/
|
*/
|
||||||
protected function checkIPV4Tag($addressLiteral) : bool
|
protected function checkIPV4Tag($addressLiteral) : bool
|
||||||
{
|
{
|
||||||
$matchesIP = array();
|
$matchesIP = [];
|
||||||
$IPv4Match = preg_match(
|
$IPv4Match = preg_match(self::IPV4_REGEX, $addressLiteral, $matchesIP);
|
||||||
'/\\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);
|
|
||||||
|
|
||||||
// Extract IPv4 part from the end of the address-literal (if there is one)
|
// Extract IPv4 part from the end of the address-literal (if there is one)
|
||||||
|
|
||||||
@@ -186,11 +189,7 @@ class DomainLiteral extends PartParser
|
|||||||
|
|
||||||
private function addObsoleteWarnings() : void
|
private function addObsoleteWarnings() : void
|
||||||
{
|
{
|
||||||
if ($this->lexer->token['type'] === EmailLexer::INVALID ||
|
if(in_array($this->lexer->token['type'], self::OBSOLETE_WARNINGS)) {
|
||||||
$this->lexer->token['type'] === EmailLexer::C_DEL ||
|
|
||||||
$this->lexer->token['type'] === EmailLexer::S_LF ||
|
|
||||||
$this->lexer->token['type'] === EmailLexer::S_BACKSLASH
|
|
||||||
) {
|
|
||||||
$this->warnings[ObsoleteDTEXT::CODE] = new ObsoleteDTEXT();
|
$this->warnings[ObsoleteDTEXT::CODE] = new ObsoleteDTEXT();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,18 +19,19 @@ class DoubleQuote extends PartParser
|
|||||||
$validQuotedString = $this->checkDQUOTE();
|
$validQuotedString = $this->checkDQUOTE();
|
||||||
if($validQuotedString->isInvalid()) return $validQuotedString;
|
if($validQuotedString->isInvalid()) return $validQuotedString;
|
||||||
|
|
||||||
$special = array(
|
$special = [
|
||||||
EmailLexer::S_CR => true,
|
EmailLexer::S_CR => true,
|
||||||
EmailLexer::S_HTAB => true,
|
EmailLexer::S_HTAB => true,
|
||||||
EmailLexer::S_LF => true
|
EmailLexer::S_LF => true
|
||||||
);
|
];
|
||||||
|
|
||||||
$invalid = array(
|
$invalid = [
|
||||||
EmailLexer::C_NUL => true,
|
EmailLexer::C_NUL => true,
|
||||||
EmailLexer::S_HTAB => true,
|
EmailLexer::S_HTAB => true,
|
||||||
EmailLexer::S_CR => true,
|
EmailLexer::S_CR => true,
|
||||||
EmailLexer::S_LF => true
|
EmailLexer::S_LF => true
|
||||||
);
|
];
|
||||||
|
|
||||||
$setSpecialsWarning = true;
|
$setSpecialsWarning = true;
|
||||||
|
|
||||||
$this->lexer->moveNext();
|
$this->lexer->moveNext();
|
||||||
|
|||||||
@@ -15,6 +15,14 @@ use Egulias\EmailValidator\Result\ValidEmail;
|
|||||||
|
|
||||||
class FoldingWhiteSpace extends PartParser
|
class FoldingWhiteSpace extends PartParser
|
||||||
{
|
{
|
||||||
|
const FWS_TYPES = [
|
||||||
|
EmailLexer::S_SP,
|
||||||
|
EmailLexer::S_HTAB,
|
||||||
|
EmailLexer::S_CR,
|
||||||
|
EmailLexer::S_LF,
|
||||||
|
EmailLexer::CRLF
|
||||||
|
];
|
||||||
|
|
||||||
public function parse() : Result
|
public function parse() : Result
|
||||||
{
|
{
|
||||||
if (!$this->isFWS()) {
|
if (!$this->isFWS()) {
|
||||||
@@ -73,10 +81,6 @@ class FoldingWhiteSpace extends PartParser
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->lexer->token['type'] === EmailLexer::S_SP ||
|
return in_array($this->lexer->token['type'], self::FWS_TYPES);
|
||||||
$this->lexer->token['type'] === EmailLexer::S_HTAB ||
|
|
||||||
$this->lexer->token['type'] === EmailLexer::S_CR ||
|
|
||||||
$this->lexer->token['type'] === EmailLexer::S_LF ||
|
|
||||||
$this->lexer->token['type'] === EmailLexer::CRLF;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12,14 +12,14 @@ class IDRightPart extends DomainPart
|
|||||||
{
|
{
|
||||||
protected function validateTokens(bool $hasComments) : Result
|
protected function validateTokens(bool $hasComments) : Result
|
||||||
{
|
{
|
||||||
$invalidDomainTokens = array(
|
$invalidDomainTokens = [
|
||||||
EmailLexer::S_DQUOTE => true,
|
EmailLexer::S_DQUOTE => true,
|
||||||
EmailLexer::S_SQUOTE => true,
|
EmailLexer::S_SQUOTE => true,
|
||||||
EmailLexer::S_BACKTICK => true,
|
EmailLexer::S_BACKTICK => true,
|
||||||
EmailLexer::S_SEMICOLON => true,
|
EmailLexer::S_SEMICOLON => true,
|
||||||
EmailLexer::S_GREATERTHAN => true,
|
EmailLexer::S_GREATERTHAN => true,
|
||||||
EmailLexer::S_LOWERTHAN => true,
|
EmailLexer::S_LOWERTHAN => true,
|
||||||
);
|
];
|
||||||
|
|
||||||
if (isset($invalidDomainTokens[$this->lexer->token['type']])) {
|
if (isset($invalidDomainTokens[$this->lexer->token['type']])) {
|
||||||
return new InvalidEmail(new ExpectingATEXT('Invalid token in domain: ' . $this->lexer->token['value']), $this->lexer->token['value']);
|
return new InvalidEmail(new ExpectingATEXT('Invalid token in domain: ' . $this->lexer->token['value']), $this->lexer->token['value']);
|
||||||
|
|||||||
+12
-11
@@ -15,6 +15,17 @@ use Egulias\EmailValidator\Parser\CommentStrategy\LocalComment;
|
|||||||
|
|
||||||
class LocalPart extends PartParser
|
class LocalPart extends PartParser
|
||||||
{
|
{
|
||||||
|
const INVALID_TOKENS = [
|
||||||
|
EmailLexer::S_COMMA => EmailLexer::S_COMMA,
|
||||||
|
EmailLexer::S_CLOSEBRACKET => EmailLexer::S_CLOSEBRACKET,
|
||||||
|
EmailLexer::S_OPENBRACKET => EmailLexer::S_OPENBRACKET,
|
||||||
|
EmailLexer::S_GREATERTHAN => EmailLexer::S_GREATERTHAN,
|
||||||
|
EmailLexer::S_LOWERTHAN => EmailLexer::S_LOWERTHAN,
|
||||||
|
EmailLexer::S_COLON => EmailLexer::S_COLON,
|
||||||
|
EmailLexer::S_SEMICOLON => EmailLexer::S_SEMICOLON,
|
||||||
|
EmailLexer::INVALID => EmailLexer::INVALID
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
@@ -88,17 +99,7 @@ class LocalPart extends PartParser
|
|||||||
|
|
||||||
protected function validateTokens(bool $hasComments) : Result
|
protected function validateTokens(bool $hasComments) : Result
|
||||||
{
|
{
|
||||||
$invalidTokens = array(
|
if (isset(self::INVALID_TOKENS[$this->lexer->token['type']])) {
|
||||||
EmailLexer::S_COMMA => EmailLexer::S_COMMA,
|
|
||||||
EmailLexer::S_CLOSEBRACKET => EmailLexer::S_CLOSEBRACKET,
|
|
||||||
EmailLexer::S_OPENBRACKET => EmailLexer::S_OPENBRACKET,
|
|
||||||
EmailLexer::S_GREATERTHAN => EmailLexer::S_GREATERTHAN,
|
|
||||||
EmailLexer::S_LOWERTHAN => EmailLexer::S_LOWERTHAN,
|
|
||||||
EmailLexer::S_COLON => EmailLexer::S_COLON,
|
|
||||||
EmailLexer::S_SEMICOLON => EmailLexer::S_SEMICOLON,
|
|
||||||
EmailLexer::INVALID => EmailLexer::INVALID
|
|
||||||
);
|
|
||||||
if (isset($invalidTokens[$this->lexer->token['type']])) {
|
|
||||||
return new InvalidEmail(new ExpectingATEXT('Invalid token found'), $this->lexer->token['value']);
|
return new InvalidEmail(new ExpectingATEXT('Invalid token found'), $this->lexer->token['value']);
|
||||||
}
|
}
|
||||||
return new ValidEmail();
|
return new ValidEmail();
|
||||||
|
|||||||
@@ -11,6 +11,6 @@ class UnOpenedComment implements Reason
|
|||||||
|
|
||||||
public function description(): string
|
public function description(): string
|
||||||
{
|
{
|
||||||
return 'Missing openning comment parentheses - https://tools.ietf.org/html/rfc5322#section-3.2.2';
|
return 'Missing opening comment parentheses - https://tools.ietf.org/html/rfc5322#section-3.2.2';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -17,6 +17,29 @@ class DNSCheckValidation implements EmailValidation
|
|||||||
*/
|
*/
|
||||||
protected const DNS_RECORD_TYPES_TO_CHECK = DNS_MX + DNS_A + DNS_AAAA;
|
protected const DNS_RECORD_TYPES_TO_CHECK = DNS_MX + DNS_A + DNS_AAAA;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reserved Top Level DNS Names (https://tools.ietf.org/html/rfc2606#section-2),
|
||||||
|
* mDNS and private DNS Namespaces (https://tools.ietf.org/html/rfc6762#appendix-G)
|
||||||
|
*/
|
||||||
|
const RESERVED_DNS_TOP_LEVEL_NAMES = [
|
||||||
|
// Reserved Top Level DNS Names
|
||||||
|
'test',
|
||||||
|
'example',
|
||||||
|
'invalid',
|
||||||
|
'localhost',
|
||||||
|
|
||||||
|
// mDNS
|
||||||
|
'local',
|
||||||
|
|
||||||
|
// Private DNS Namespaces
|
||||||
|
'intranet',
|
||||||
|
'internal',
|
||||||
|
'private',
|
||||||
|
'corp',
|
||||||
|
'home',
|
||||||
|
'lan',
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
@@ -32,7 +55,6 @@ class DNSCheckValidation implements EmailValidation
|
|||||||
*/
|
*/
|
||||||
private $mxRecords = [];
|
private $mxRecords = [];
|
||||||
|
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
if (!function_exists('idn_to_ascii')) {
|
if (!function_exists('idn_to_ascii')) {
|
||||||
@@ -53,29 +75,8 @@ class DNSCheckValidation implements EmailValidation
|
|||||||
// Get the domain parts
|
// Get the domain parts
|
||||||
$hostParts = explode('.', $host);
|
$hostParts = explode('.', $host);
|
||||||
|
|
||||||
// Reserved Top Level DNS Names (https://tools.ietf.org/html/rfc2606#section-2),
|
|
||||||
// mDNS and private DNS Namespaces (https://tools.ietf.org/html/rfc6762#appendix-G)
|
|
||||||
$reservedTopLevelDnsNames = [
|
|
||||||
// Reserved Top Level DNS Names
|
|
||||||
'test',
|
|
||||||
'example',
|
|
||||||
'invalid',
|
|
||||||
'localhost',
|
|
||||||
|
|
||||||
// mDNS
|
|
||||||
'local',
|
|
||||||
|
|
||||||
// Private DNS Namespaces
|
|
||||||
'intranet',
|
|
||||||
'internal',
|
|
||||||
'private',
|
|
||||||
'corp',
|
|
||||||
'home',
|
|
||||||
'lan',
|
|
||||||
];
|
|
||||||
|
|
||||||
$isLocalDomain = count($hostParts) <= 1;
|
$isLocalDomain = count($hostParts) <= 1;
|
||||||
$isReservedTopLevel = in_array($hostParts[(count($hostParts) - 1)], $reservedTopLevelDnsNames, true);
|
$isReservedTopLevel = in_array($hostParts[(count($hostParts) - 1)], self::RESERVED_DNS_TOP_LEVEL_NAMES, true);
|
||||||
|
|
||||||
// Exclude reserved top level DNS names
|
// Exclude reserved top level DNS names
|
||||||
if ($isLocalDomain || $isReservedTopLevel) {
|
if ($isLocalDomain || $isReservedTopLevel) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use Egulias\EmailValidator\Result\MultipleErrors;
|
|||||||
class MultipleValidationWithAnd implements EmailValidation
|
class MultipleValidationWithAnd implements EmailValidation
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* If one of validations fails, the remaining validations will be skept.
|
* If one of validations fails, the remaining validations will be skipped.
|
||||||
* This means MultipleErrors will only contain a single error, the first found.
|
* This means MultipleErrors will only contain a single error, the first found.
|
||||||
*/
|
*/
|
||||||
const STOP_ON_ERROR = 0;
|
const STOP_ON_ERROR = 0;
|
||||||
|
|||||||
@@ -42,6 +42,6 @@ abstract class Warning
|
|||||||
|
|
||||||
public function __toString()
|
public function __toString()
|
||||||
{
|
{
|
||||||
return $this->message() . " rfc: " . $this->rfcNumber . "interal code: " . static::CODE;
|
return $this->message() . " rfc: " . $this->rfcNumber . "internal code: " . static::CODE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ class DNSCheckValidationTest extends TestCase
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @group slow
|
* @group flaky
|
||||||
*/
|
*/
|
||||||
public function testUnableToGetDNSRecord()
|
public function testUnableToGetDNSRecord()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user