Compare commits

..

28 Commits

Author SHA1 Message Date
Eduardo Gulias Davis 1ac0be80b3 bump dependencies and lock 2022-12-29 22:07:24 +01:00
Eduardo Gulias Davis c38e9600fb Merge branch 'derrabus-bump/vendors' into 3.x 2022-12-29 22:01:54 +01:00
Eduardo Gulias Davis 777864f79e Merge branch 'bump/vendors' of https://github.com/derrabus/EmailValidator into derrabus-bump/vendors 2022-12-29 22:01:11 +01:00
Eduardo Gulias Davis ecbcdcef05 Merge branch '3.x' of github.com:egulias/EmailValidator into 3.x 2022-12-29 21:59:01 +01:00
Alexander M. Turek b28de87213 Allow doctrine/lexer 2 (#340) 2022-12-29 21:52:48 +01:00
Alexander M. Turek 6d6a87e5d9 Bump all locked dependencies
- Removing openlss/lib-array2xml (1.0.0)
  - Removing phpspec/prophecy (v1.15.0)
  - Removing webmozart/path-util (2.3.0)
  - Upgrading composer/pcre (3.0.0 => 3.1.0)
  - Locking fidry/cpu-core-counter (0.4.1)
  - Upgrading guzzlehttp/guzzle (7.4.5 => 7.5.0)
  - Upgrading guzzlehttp/promises (1.5.1 => 1.5.2)
  - Upgrading guzzlehttp/psr7 (2.4.0 => 2.4.3)
  - Upgrading netresearch/jsonmapper (v4.0.0 => v4.1.0)
  - Upgrading nikic/php-parser (v4.13.2 => v4.15.2)
  - Upgrading php-coveralls/php-coveralls (v2.5.2 => v2.5.3)
  - Upgrading phpdocumentor/type-resolver (1.6.1 => 1.6.2)
  - Upgrading phpunit/php-code-coverage (9.2.15 => 9.2.23)
  - Upgrading phpunit/phpunit (9.5.20 => 9.5.27)
  - Upgrading sebastian/comparator (4.0.6 => 4.0.8)
  - Upgrading sebastian/exporter (4.0.4 => 4.0.5)
  - Upgrading sebastian/type (3.0.0 => 3.2.0)
  - Locking spatie/array-to-xml (2.17.1)
  - Upgrading symfony/config (v5.4.9 => v5.4.11)
  - Upgrading symfony/console (v5.4.9 => v5.4.16)
  - Upgrading symfony/deprecation-contracts (v2.5.1 => v2.5.2)
  - Upgrading symfony/filesystem (v5.4.9 => v5.4.13)
  - Upgrading symfony/polyfill-ctype (v1.25.0 => v1.27.0)
  - Upgrading symfony/polyfill-intl-grapheme (v1.25.0 => v1.27.0)
  - Upgrading symfony/polyfill-intl-idn (v1.26.0 => v1.27.0)
  - Upgrading symfony/polyfill-intl-normalizer (v1.26.0 => v1.27.0)
  - Upgrading symfony/polyfill-mbstring (v1.26.0 => v1.27.0)
  - Upgrading symfony/polyfill-php72 (v1.26.0 => v1.27.0)
  - Upgrading symfony/polyfill-php73 (v1.25.0 => v1.27.0)
  - Upgrading symfony/polyfill-php80 (v1.25.0 => v1.27.0)
  - Upgrading symfony/polyfill-php81 (v1.25.0 => v1.27.0)
  - Upgrading symfony/service-contracts (v2.5.1 => v2.5.2)
  - Upgrading symfony/stopwatch (v5.4.5 => v5.4.13)
  - Upgrading symfony/string (v5.4.9 => v5.4.15)
  - Upgrading symfony/yaml (v5.4.3 => v5.4.16)
  - Upgrading vimeo/psalm (4.23.0 => 5.4.0)
  - Upgrading webmozart/assert (1.10.0 => 1.11.0)
2022-12-28 13:45:16 +01:00
Alexis Lefebvre 0170967656 CHANGELOG: Fix typo “Breacking” (#333) 2022-09-03 11:54:08 +02:00
Eduardo Gulias Davis 4c72190f32 Update LICENSE 2022-08-14 20:36:33 +02:00
Mathias Reker ⚡️ 413b263617 Nullable type declaration for default null value (#328)
Adds ? before type declarations for parameters with a default null value
2022-07-13 16:53:11 +02:00
Mathias Reker ⚡️ 18b9e5b572 Visibility required (#329)
Visibility MUST be declared on all properties and methods; abstract and final MUST be declared before the visibility; static MUST be declared after the visibility.
2022-07-13 16:52:42 +02:00
Mathias Reker ⚡️ 1ca313dfcd Single blank line at eof (#330)
A PHP file without end tag must always end with a single empty line feed.
2022-07-13 16:51:51 +02:00
Mathias Reker ⚡️ cf5908bb1a No superfluous elseif (#331)
Replaces superfluous elseif with if.
2022-07-13 16:51:22 +02:00
Mathias Reker ⚡️ b241b54919 No unused imports (#332)
Unused use statements must be removed.
2022-07-13 16:50:27 +02:00
dependabot[bot] 74d2f16d9d Bump guzzlehttp/guzzle from 7.4.3 to 7.4.5 (#326)
Bumps [guzzlehttp/guzzle](https://github.com/guzzle/guzzle) from 7.4.3 to 7.4.5.
- [Release notes](https://github.com/guzzle/guzzle/releases)
- [Changelog](https://github.com/guzzle/guzzle/blob/master/CHANGELOG.md)
- [Commits](https://github.com/guzzle/guzzle/compare/7.4.3...7.4.5)

---
updated-dependencies:
- dependency-name: guzzlehttp/guzzle
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-24 20:51:04 +02:00
Nicolas Grekas f88dcf4b14 Don't use utf8_en/decode() functions, they're deprecated on PHP 8.2 (#325) 2022-06-18 22:57:19 +02:00
Eduardo Gulias Davis a5ed8d58ed Bug #321 (#323)
* Update dependencies

* dns_get_record wrapper for testing of the function's behaviour

* remove unused classes

* Fix Psalm errors

* Increase PHP Version
2022-05-29 00:19:18 +02:00
Eduardo Gulias Davis e3c1f426e5 Update dependencies 2022-05-28 17:34:06 +02:00
Daniel Winzen 312b65911f Fixed Spoofchecking link (#314) 2022-02-18 16:25:29 +01:00
Denis Gurov d51b279b5f Typos (#313)
A few typos in README
2022-02-11 18:09:16 +01:00
Robert Fridzema 9aab2ceed6 Typos (#311) 2022-02-04 21:30:40 +01:00
Julien Gidel 007bfd424e Small contribution - code readability improvements (#306)
* Some code improvements - tests same as beginning

* isUTF8Invalid returns a boolean

* Changes for tests passed

* Revert change + scrutinizer to flaky

* Null coalescing on token to return a null token

* Psalm pass and PHPunit too (php 7.4)

* Minor change to set lookahead to nullToken
2021-11-20 22:34:12 +01:00
Eduardo Gulias Davis 5cc04719d0 CI update to min supported version 2021-10-11 18:18:50 +02:00
Eduardo Gulias Davis c70449e7b1 CI update to supported versions in matrix 2021-10-11 18:15:58 +02:00
Eduardo Gulias Davis 36425ab1f9 Merge branch '3.x' of github.com:egulias/EmailValidator into 3.x 2021-10-11 18:11:58 +02:00
Eduardo Gulias Davis 4c7033b422 CI and dependencies update 2021-10-11 18:11:44 +02:00
Eduardo Gulias Davis 037594add3 Code quality 2021-10-11 17:54:24 +02:00
Eduardo Gulias Davis 4cccb8186b Update badges 2021-10-11 17:52:58 +02:00
Samuel Vicent ee0db30118 MultipleErrors->reason always returns [0] and should return first item from associative array (#305)
* Patch MultipleErrors->reason method by getting always the first item - Added Tests and a custom Exception

* Return EmptyReason instead of throwing exception when MultipleErrors has no reasons (validations accomplished)

Co-authored-by: Samuel Vicent <samuel.vicent@takeachef.com>
2021-10-11 11:18:27 +02:00
21 changed files with 1515 additions and 970 deletions
+3 -2
View File
@@ -3,11 +3,12 @@ imports:
build:
environment:
php: '7.2.13'
php: '7.3'
tests:
override:
-
command: 'vendor/bin/phpunit --coverage-clover=clover.xml --exclude-group slow'
command: 'vendor/bin/phpunit --coverage-clover=clover.xml --exclude-group flaky'
coverage:
file: 'clover.xml'
format: 'clover'
- php-scrutinizer-run
+4 -8
View File
@@ -2,24 +2,20 @@ language: php
matrix:
include:
- php: 7.2
env:
- psalm=yes
dist: bionic
- php: 7.3
dist: bionic
env:
- psalm=yes
dist: bionic
- php: 7.4
dist: bionic
env:
- psalm=yes
dist: bionic
- php: 8.0
env:
- psalm=yes
dist: bionic
#ppc64le support code
- php: 7.2
- php: 7.3
arch: ppc64le
env:
- psalm=yes
@@ -38,7 +34,7 @@ before_script:
- mkdir -p build/logs
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
after_script:
+4 -4
View File
@@ -1,6 +1,6 @@
# Contributing
When contributing to this repository make sure to follow the Pull request process below.
When contributing to this repository make sure to follow the Pull request process below.
Reduce to the minimum 3rd party dependencies.
Please note we have a [code of conduct](#Code of Conduct), please follow it in all your interactions with the project.
@@ -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
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
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.
## License
@@ -139,11 +139,11 @@ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0].
Community Impact Guidelines were inspired by
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available
at [https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
+7 -8
View File
@@ -1,9 +1,8 @@
# EmailValidator
[![Build Status](https://travis-ci.org/egulias/EmailValidator.svg?branch=3.x)](https://travis-ci.org/egulias/EmailValidator)
[![Build Status](https://app.travis-ci.com/egulias/EmailValidator.svg?branch=3.x)](https://app.travis-ci.com/github/egulias/EmailValidator)
[![Code Quality](https://scrutinizer-ci.com/g/egulias/EmailValidator/badges/quality-score.png?b=3.x)](https://scrutinizer-ci.com/g/egulias/EmailValidator/?branch=3.x)
[![Test Coverage](https://scrutinizer-ci.com/g/egulias/EmailValidator/badges/coverage.png?b=3.x)](https://scrutinizer-ci.com/g/egulias/EmailValidator/?branch=3.x)
[![SymfonyInsight](https://insight.symfony.com/projects/22ba6692-9c02-42e5-a65d-1c5696bfffc6/mini.svg)](https://insight.symfony.com/projects/22ba6692-9c02-42e5-a65d-1c5696bfffc6)
A library for validating emails against several RFC.
@@ -20,7 +19,7 @@ This library aims to support RFCs:
## 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 |
| ---- | :----: | :----: | :----: | :----: |
@@ -33,7 +32,7 @@ This library aims to support RFCs:
* PHP 7.2
* [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`
@@ -47,7 +46,7 @@ composer require egulias/email-validator
## 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
```php
@@ -65,12 +64,12 @@ $validator->isValid("example@example.com", new RFCValidation()); //true
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.
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.
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.
*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
@@ -85,7 +84,7 @@ $multipleValidations = new MultipleValidationWithAnd([
new RFCValidation(),
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
```
Generated
+1286 -752
View File
File diff suppressed because it is too large Load Diff
+16 -30
View File
@@ -1,31 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
backupGlobals="false"
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
executionOrder="defects"
processIsolation="false"
stopOnFailure="false"
>
<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 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">
<coverage>
<include>
<directory>./src/</directory>
</include>
<exclude>
<directory suffix=".php">./src/Result/Reason</directory>
</exclude>
</coverage>
<testsuites>
<testsuite name="EmailValidator Test Suite">
<directory>./tests/EmailValidator</directory>
<exclude>./vendor/</exclude>
</testsuite>
</testsuites>
</phpunit>
+76 -98
View File
@@ -61,7 +61,7 @@ class EmailLexer extends AbstractLexer
*
* @var array
*/
protected $charValue = array(
protected $charValue = [
'{' => self::S_OPENCURLYBRACES,
'}' => self::S_CLOSECURLYBRACES,
'(' => self::S_OPENPARENTHESIS,
@@ -105,11 +105,29 @@ class EmailLexer extends AbstractLexer
'?' => self::QUESTIONMARK,
'#' => self::NUMBER_SIGN,
'¡' => self::INVERT_EXCLAMATION,
);
];
/**
* @var bool
*/
const INVALID_CHARS_REGEX = "/[^\p{S}\p{C}\p{Cc}]+/iu";
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;
/**
@@ -137,23 +155,17 @@ class EmailLexer extends AbstractLexer
*/
public $lookahead;
/**
* @psalm-var array{value:'', type:null, position:0}
*/
/** @psalm-var array{value:'', type:null, position:0} */
private static $nullToken = [
'value' => '',
'type' => null,
'position' => 0,
];
/**
* @var string
*/
/** @var string */
private $accumulator = '';
/**
* @var bool
*/
/** @var bool */
private $hasToRecord = false;
public function __construct()
@@ -162,24 +174,13 @@ class EmailLexer extends AbstractLexer
$this->lookahead = null;
}
/**
* @return void
*/
public function reset()
public function reset() : void
{
$this->hasInvalidTokens = false;
parent::reset();
$this->previous = $this->token = self::$nullToken;
}
/**
* @return bool
*/
public function hasInvalidTokens()
{
return $this->hasInvalidTokens;
}
/**
* @param int $type
* @throws \UnexpectedValueException
@@ -187,7 +188,7 @@ class EmailLexer extends AbstractLexer
*
* @psalm-suppress InvalidScalarArgument
*/
public function find($type)
public function find($type) : bool
{
$search = clone $this;
$search->skipUntil($type);
@@ -198,30 +199,24 @@ class EmailLexer extends AbstractLexer
return true;
}
/**
* getPrevious
*
* @return array
*/
public function getPrevious()
{
return $this->previous;
}
/**
* moveNext
*
* @return boolean
*/
public function moveNext()
public function moveNext() : bool
{
if ($this->hasToRecord && $this->previous === self::$nullToken) {
$this->accumulator .= $this->token['value'];
}
$this->previous = $this->token;
if($this->lookahead === null) {
$this->lookahead = self::$nullToken;
}
$hasNext = parent::moveNext();
$this->token = $this->token ?: self::$nullToken;
if ($this->hasToRecord) {
$this->accumulator .= $this->token['value'];
@@ -230,36 +225,6 @@ class EmailLexer extends AbstractLexer
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.
*
@@ -292,51 +257,64 @@ class EmailLexer extends AbstractLexer
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
{
if (isset($this->charValue[$value])) {
return true;
}
return false;
return isset($this->charValue[$value]);
}
/**
* @param string $value
* @return bool
*/
protected function isNullType($value)
protected function isNullType(string $value) : bool
{
if ($value === "\0") {
return true;
}
return $value === "\0";
}
return false;
protected function isInvalidChar(string $value) : bool
{
return !preg_match(self::INVALID_CHARS_REGEX, $value);
}
protected function isUTF8Invalid(string $value) : bool
{
if (preg_match('/\p{Cc}+/u', $value)) {
return true;
}
return preg_match(self::VALID_UTF8_REGEX, $value) !== false;
}
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
-1
View File
@@ -3,7 +3,6 @@
namespace Egulias\EmailValidator;
use Egulias\EmailValidator\Parser;
use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\Result\Result;
use Egulias\EmailValidator\Parser\IDLeftPart;
use Egulias\EmailValidator\Parser\IDRightPart;
+14 -15
View File
@@ -22,6 +22,15 @@ use Egulias\EmailValidator\Warning\DomainLiteral as WarningDomainLiteral;
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
{
$this->addTagWarnings();
@@ -138,11 +147,8 @@ class DomainLiteral extends PartParser
public function convertIPv4ToIPv6(string $addressLiteralIPv4) : string
{
$matchesIP = array();
$IPv4Match = 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]?)$/',
$addressLiteralIPv4,
$matchesIP);
$matchesIP = [];
$IPv4Match = preg_match(self::IPV4_REGEX, $addressLiteralIPv4, $matchesIP);
// Extract IPv4 part from the end of the address-literal (if there is one)
if ($IPv4Match > 0) {
@@ -164,11 +170,8 @@ class DomainLiteral extends PartParser
*/
protected function checkIPV4Tag($addressLiteral) : bool
{
$matchesIP = array();
$IPv4Match = 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);
$matchesIP = [];
$IPv4Match = preg_match(self::IPV4_REGEX, $addressLiteral, $matchesIP);
// 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
{
if ($this->lexer->token['type'] === EmailLexer::INVALID ||
$this->lexer->token['type'] === EmailLexer::C_DEL ||
$this->lexer->token['type'] === EmailLexer::S_LF ||
$this->lexer->token['type'] === EmailLexer::S_BACKSLASH
) {
if(in_array($this->lexer->token['type'], self::OBSOLETE_WARNINGS)) {
$this->warnings[ObsoleteDTEXT::CODE] = new ObsoleteDTEXT();
}
}
+5 -4
View File
@@ -19,18 +19,19 @@ class DoubleQuote extends PartParser
$validQuotedString = $this->checkDQUOTE();
if($validQuotedString->isInvalid()) return $validQuotedString;
$special = array(
$special = [
EmailLexer::S_CR => true,
EmailLexer::S_HTAB => true,
EmailLexer::S_LF => true
);
];
$invalid = array(
$invalid = [
EmailLexer::C_NUL => true,
EmailLexer::S_HTAB => true,
EmailLexer::S_CR => true,
EmailLexer::S_LF => true
);
];
$setSpecialsWarning = true;
$this->lexer->moveNext();
+9 -5
View File
@@ -15,6 +15,14 @@ use Egulias\EmailValidator\Result\ValidEmail;
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
{
if (!$this->isFWS()) {
@@ -73,10 +81,6 @@ class FoldingWhiteSpace extends PartParser
return false;
}
return $this->lexer->token['type'] === EmailLexer::S_SP ||
$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;
return in_array($this->lexer->token['type'], self::FWS_TYPES);
}
}
+2 -2
View File
@@ -12,14 +12,14 @@ class IDRightPart extends DomainPart
{
protected function validateTokens(bool $hasComments) : Result
{
$invalidDomainTokens = array(
$invalidDomainTokens = [
EmailLexer::S_DQUOTE => true,
EmailLexer::S_SQUOTE => true,
EmailLexer::S_BACKTICK => true,
EmailLexer::S_SEMICOLON => true,
EmailLexer::S_GREATERTHAN => true,
EmailLexer::S_LOWERTHAN => true,
);
];
if (isset($invalidDomainTokens[$this->lexer->token['type']])) {
return new InvalidEmail(new ExpectingATEXT('Invalid token in domain: ' . $this->lexer->token['value']), $this->lexer->token['value']);
+12 -11
View File
@@ -15,6 +15,17 @@ use Egulias\EmailValidator\Parser\CommentStrategy\LocalComment;
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
*/
@@ -88,17 +99,7 @@ class LocalPart extends PartParser
protected function validateTokens(bool $hasComments) : Result
{
$invalidTokens = array(
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']])) {
if (isset(self::INVALID_TOKENS[$this->lexer->token['type']])) {
return new InvalidEmail(new ExpectingATEXT('Invalid token found'), $this->lexer->token['value']);
}
return new ValidEmail();
+4 -2
View File
@@ -2,7 +2,7 @@
namespace Egulias\EmailValidator\Result;
use Egulias\EmailValidator\Result\InvalidEmail;
use Egulias\EmailValidator\Result\Reason\EmptyReason;
use Egulias\EmailValidator\Result\Reason\Reason;
/**
@@ -34,7 +34,9 @@ class MultipleErrors extends InvalidEmail
public function reason() : Reason
{
return $this->reasons[0];
return 0 !== count($this->reasons)
? current($this->reasons)
: new EmptyReason();
}
public function description() : string
+16
View File
@@ -0,0 +1,16 @@
<?php
namespace Egulias\EmailValidator\Result\Reason;
class EmptyReason implements Reason
{
public function code() : int
{
return 0;
}
public function description() : string
{
return 'Empty reason';
}
}
+1 -1
View File
@@ -11,6 +11,6 @@ class UnOpenedComment implements Reason
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';
}
}
+24 -23
View File
@@ -17,6 +17,29 @@ class DNSCheckValidation implements EmailValidation
*/
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
*/
@@ -32,7 +55,6 @@ class DNSCheckValidation implements EmailValidation
*/
private $mxRecords = [];
public function __construct()
{
if (!function_exists('idn_to_ascii')) {
@@ -53,29 +75,8 @@ class DNSCheckValidation implements EmailValidation
// Get the domain parts
$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;
$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
if ($isLocalDomain || $isReservedTopLevel) {
+1 -1
View File
@@ -10,7 +10,7 @@ use Egulias\EmailValidator\Result\MultipleErrors;
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.
*/
const STOP_ON_ERROR = 0;
+1 -1
View File
@@ -42,6 +42,6 @@ abstract class Warning
public function __toString()
{
return $this->message() . " rfc: " . $this->rfcNumber . "interal code: " . static::CODE;
return $this->message() . " rfc: " . $this->rfcNumber . "internal code: " . static::CODE;
}
}
@@ -2,10 +2,11 @@
namespace Egulias\EmailValidator\Tests\EmailValidator\Reason;
use PHPUnit\Framework\TestCase;
use Egulias\EmailValidator\Result\MultipleErrors;
use Egulias\EmailValidator\Result\Reason\EmptyReason;
use Egulias\EmailValidator\Tests\EmailValidator\Dummy\AnotherDummyReason;
use Egulias\EmailValidator\Tests\EmailValidator\Dummy\DummyReason;
use PHPUnit\Framework\TestCase;
class MultipleErrorsTest extends TestCase
{
@@ -35,4 +36,31 @@ class MultipleErrorsTest extends TestCase
$this->assertEquals($expectedReason, $multiError->description());
$this->assertEquals($error1, $multiError->reason());
}
public function testRetrieveFirstReasonWithReasonCodeEqualsZero(): void
{
$error1 = new DummyReason();
$multiError = new MultipleErrors();
$multiError->addReason($error1);
$this->assertEquals($error1, $multiError->reason());
}
public function testRetrieveFirstReasonWithReasonCodeDistinctToZero(): void
{
$error1 = new AnotherDummyReason();
$multiError = new MultipleErrors();
$multiError->addReason($error1);
$this->assertEquals($error1, $multiError->reason());
}
public function testRetrieveFirstReasonWithNoReasonAdded()
{
$emptyReason = new EmptyReason();
$multiError = new MultipleErrors();
$this->assertEquals($emptyReason, $multiError->reason());
}
}
@@ -109,7 +109,7 @@ class DNSCheckValidationTest extends TestCase
}
/**
* @group slow
* @group flaky
*/
public function testUnableToGetDNSRecord()
{