mirror of
https://github.com/egulias/EmailValidator.git
synced 2026-09-01 13:08:58 +00:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a6255605af | |||
| 950d0663dc | |||
| 92dd169c32 | |||
| a6c8d7101b | |||
| 128cc721d7 | |||
| c26463ff92 | |||
| a09af2de87 | |||
| c802f106b3 | |||
| 709f21f927 | |||
| e68c26e065 | |||
| 8036f2bd05 | |||
| 0043eab0c5 | |||
| 0578b32b30 |
+7
-4
@@ -1,5 +1,7 @@
|
||||
sudo: false
|
||||
|
||||
dist: trusty
|
||||
|
||||
language: php
|
||||
|
||||
php:
|
||||
@@ -8,7 +10,8 @@ php:
|
||||
- 7.0
|
||||
- 7.1
|
||||
- 7.2
|
||||
- hhvm
|
||||
- 7.3
|
||||
- 7.4snapshot
|
||||
|
||||
env:
|
||||
global:
|
||||
@@ -28,8 +31,8 @@ install:
|
||||
- if [ "$deps" = "high" ]; then composer update; fi
|
||||
|
||||
script:
|
||||
- mkdir -p build/logs
|
||||
- vendor/bin/phpunit --coverage-clover build/logs/clover.xml
|
||||
- mkdir -p build/logs
|
||||
- vendor/bin/phpunit --coverage-clover build/logs/clover.xml
|
||||
|
||||
after_script:
|
||||
- php vendor/bin/coveralls
|
||||
- php vendor/bin/coveralls
|
||||
|
||||
@@ -77,10 +77,25 @@ class EmailLexer extends AbstractLexer
|
||||
|
||||
protected $previous;
|
||||
|
||||
private static $nullToken = [
|
||||
'value' => '',
|
||||
'type' => null,
|
||||
'position' => 0,
|
||||
];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->previous = $this->token = self::$nullToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
$this->hasInvalidTokens = false;
|
||||
parent::reset();
|
||||
$this->previous = $this->token = self::$nullToken;
|
||||
}
|
||||
|
||||
public function hasInvalidTokens()
|
||||
@@ -89,7 +104,7 @@ class EmailLexer extends AbstractLexer
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $type
|
||||
* @param string $type
|
||||
* @throws \UnexpectedValueException
|
||||
* @return boolean
|
||||
*/
|
||||
@@ -122,8 +137,10 @@ class EmailLexer extends AbstractLexer
|
||||
public function moveNext()
|
||||
{
|
||||
$this->previous = $this->token;
|
||||
$hasNext = parent::moveNext();
|
||||
$this->token = $this->token ?: self::$nullToken;
|
||||
|
||||
return parent::moveNext();
|
||||
return $hasNext;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -189,7 +206,7 @@ class EmailLexer extends AbstractLexer
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @param string $value
|
||||
* @return bool
|
||||
*/
|
||||
protected function isNullType($value)
|
||||
@@ -202,7 +219,7 @@ class EmailLexer extends AbstractLexer
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $value
|
||||
* @param string $value
|
||||
* @return bool
|
||||
*/
|
||||
protected function isUTF8Invalid($value)
|
||||
@@ -214,6 +231,9 @@ class EmailLexer extends AbstractLexer
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getModifiers()
|
||||
{
|
||||
return 'iu';
|
||||
|
||||
@@ -33,7 +33,7 @@ class EmailParser
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $str
|
||||
* @param string $str
|
||||
* @return array
|
||||
*/
|
||||
public function parse($str)
|
||||
|
||||
@@ -28,7 +28,7 @@ class EmailValidator
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $email
|
||||
* @param string $email
|
||||
* @param EmailValidation $emailValidation
|
||||
* @return bool
|
||||
*/
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Egulias\EmailValidator\Exception;
|
||||
|
||||
class ExpectedQPair extends InvalidEmail
|
||||
class ExpectingQPair extends InvalidEmail
|
||||
{
|
||||
const CODE = 136;
|
||||
const REASON = "Expecting QPAIR";
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
namespace Egulias\EmailValidator\Exception;
|
||||
|
||||
use Egulias\EmailValidator\Exception\InvalidEmail;
|
||||
|
||||
class NoDNSRecord extends InvalidEmail
|
||||
{
|
||||
const CODE = 5;
|
||||
|
||||
@@ -41,21 +41,7 @@ class DomainPart extends Parser
|
||||
{
|
||||
$this->lexer->moveNext();
|
||||
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_DOT) {
|
||||
throw new DotAtStart();
|
||||
}
|
||||
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_EMPTY) {
|
||||
throw new NoDomainPart();
|
||||
}
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_HYPHEN) {
|
||||
throw new DomainHyphened();
|
||||
}
|
||||
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) {
|
||||
$this->warnings[DeprecatedComment::CODE] = new DeprecatedComment();
|
||||
$this->parseDomainComments();
|
||||
}
|
||||
$this->performDomainStartChecks();
|
||||
|
||||
$domain = $this->doParseDomainPart();
|
||||
|
||||
@@ -77,6 +63,38 @@ class DomainPart extends Parser
|
||||
$this->domainPart = $domain;
|
||||
}
|
||||
|
||||
private function performDomainStartChecks()
|
||||
{
|
||||
$this->checkInvalidTokensAfterAT();
|
||||
$this->checkEmptyDomain();
|
||||
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) {
|
||||
$this->warnings[DeprecatedComment::CODE] = new DeprecatedComment();
|
||||
$this->parseDomainComments();
|
||||
}
|
||||
}
|
||||
|
||||
private function checkEmptyDomain()
|
||||
{
|
||||
$thereIsNoDomain = $this->lexer->token['type'] === EmailLexer::S_EMPTY ||
|
||||
($this->lexer->token['type'] === EmailLexer::S_SP &&
|
||||
!$this->lexer->isNextToken(EmailLexer::GENERIC));
|
||||
|
||||
if ($thereIsNoDomain) {
|
||||
throw new NoDomainPart();
|
||||
}
|
||||
}
|
||||
|
||||
private function checkInvalidTokensAfterAT()
|
||||
{
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_DOT) {
|
||||
throw new DotAtStart();
|
||||
}
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_HYPHEN) {
|
||||
throw new DomainHyphened();
|
||||
}
|
||||
}
|
||||
|
||||
public function getDomainPart()
|
||||
{
|
||||
return $this->domainPart;
|
||||
@@ -166,7 +184,7 @@ class DomainPart extends Parser
|
||||
|
||||
$domain .= $this->lexer->token['value'];
|
||||
$this->lexer->moveNext();
|
||||
} while ($this->lexer->token);
|
||||
} while (null !== $this->lexer->token['type']);
|
||||
|
||||
return $domain;
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ class LocalPart extends Parser
|
||||
$closingQuote = false;
|
||||
$openedParenthesis = 0;
|
||||
|
||||
while ($this->lexer->token['type'] !== EmailLexer::S_AT && $this->lexer->token) {
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_DOT && !$this->lexer->getPrevious()) {
|
||||
while ($this->lexer->token['type'] !== EmailLexer::S_AT && null !== $this->lexer->token['type']) {
|
||||
if ($this->lexer->token['type'] === EmailLexer::S_DOT && null === $this->lexer->getPrevious()['type']) {
|
||||
throw new DotAtStart();
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ class LocalPart extends Parser
|
||||
|
||||
$this->lexer->moveNext();
|
||||
|
||||
while ($this->lexer->token['type'] !== EmailLexer::S_DQUOTE && $this->lexer->token) {
|
||||
while ($this->lexer->token['type'] !== EmailLexer::S_DQUOTE && null !== $this->lexer->token['type']) {
|
||||
$parseAgain = false;
|
||||
if (isset($special[$this->lexer->token['type']]) && $setSpecialsWarning) {
|
||||
$this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS();
|
||||
|
||||
@@ -8,7 +8,7 @@ use Egulias\EmailValidator\Exception\ConsecutiveDot;
|
||||
use Egulias\EmailValidator\Exception\CRLFAtTheEnd;
|
||||
use Egulias\EmailValidator\Exception\CRLFX2;
|
||||
use Egulias\EmailValidator\Exception\CRNoLF;
|
||||
use Egulias\EmailValidator\Exception\ExpectedQPair;
|
||||
use Egulias\EmailValidator\Exception\ExpectingQPair;
|
||||
use Egulias\EmailValidator\Exception\ExpectingATEXT;
|
||||
use Egulias\EmailValidator\Exception\ExpectingCTEXT;
|
||||
use Egulias\EmailValidator\Exception\UnclosedComment;
|
||||
@@ -50,7 +50,7 @@ abstract class Parser
|
||||
{
|
||||
if (!($this->lexer->token['type'] === EmailLexer::INVALID
|
||||
|| $this->lexer->token['type'] === EmailLexer::C_DEL)) {
|
||||
throw new ExpectedQPair();
|
||||
throw new ExpectingQPair();
|
||||
}
|
||||
|
||||
$this->warnings[QuotedPart::CODE] =
|
||||
|
||||
@@ -62,7 +62,8 @@ class MultipleValidationWithAnd implements EmailValidation
|
||||
$errors = [];
|
||||
foreach ($this->validations as $validation) {
|
||||
$emailLexer->reset();
|
||||
$result = $result && $validation->isValid($email, $emailLexer);
|
||||
$validationResult = $validation->isValid($email, $emailLexer);
|
||||
$result = $result && $validationResult;
|
||||
$this->warnings = array_merge($this->warnings, $validation->getWarnings());
|
||||
$errors = $this->addNewError($validation->getError(), $errors);
|
||||
|
||||
@@ -93,7 +94,9 @@ class MultipleValidationWithAnd implements EmailValidation
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* Returns the validation errors.
|
||||
*
|
||||
* @return MultipleErrors|null
|
||||
*/
|
||||
public function getError()
|
||||
{
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
# EmailValidator
|
||||
[](https://travis-ci.org/egulias/EmailValidator) [](https://coveralls.io/r/egulias/EmailValidator?branch=master) [](https://scrutinizer-ci.com/g/egulias/EmailValidator/?branch=master) [](https://insight.sensiolabs.com/projects/22ba6692-9c02-42e5-a65d-1c5696bfffc6)
|
||||
[](https://travis-ci.org/egulias/EmailValidator) [](https://coveralls.io/r/egulias/EmailValidator?branch=master) [](https://scrutinizer-ci.com/g/egulias/EmailValidator/?branch=master) [](https://insight.sensiolabs.com/projects/22ba6692-9c02-42e5-a65d-1c5696bfffc6)
|
||||
=============================
|
||||
With the help of [PHPStorm](https://www.jetbrains.com/phpstorm/)
|
||||
## Suported RFCs ##
|
||||
This library aims to support:
|
||||
|
||||
RFC 5321, 5322, 6530, 6531, 6532.
|
||||
|
||||
## Requirements ##
|
||||
|
||||
* [Composer](https://getcomposer.org) is required for installation
|
||||
* [Spoofchecking](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/SpoofCheckValidation.php) and [DNSCheckValidation](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/DNSCheckValidation.php) validation requires that your PHP system have the [PHP Internationalization Libraries](https://php.net/manual/en/book.intl.php) (also known as PHP Intl)
|
||||
* [Spoofchecking](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/SpoofCheckValidation.php) and [DNSCheckValidation](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/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)
|
||||
|
||||
## Installation ##
|
||||
|
||||
Run the command below to install via Composer
|
||||
|
||||
```shell
|
||||
composer require egulias/email-validator "~2.1"
|
||||
composer require egulias/email-validator
|
||||
```
|
||||
|
||||
## Getting Started ##
|
||||
|
||||
+50
-10
@@ -2,19 +2,23 @@
|
||||
|
||||
namespace Egulias\Tests\EmailValidator\Validation;
|
||||
|
||||
use Egulias\EmailValidator\EmailLexer;
|
||||
use Egulias\EmailValidator\EmailValidator;
|
||||
use Egulias\EmailValidator\Exception\CommaInDomain;
|
||||
use Egulias\EmailValidator\Exception\NoDomainPart;
|
||||
use Egulias\EmailValidator\Validation\MultipleErrors;
|
||||
use Egulias\EmailValidator\Validation\MultipleValidationWithAnd;
|
||||
use Egulias\EmailValidator\Validation\NoRFCWarningsValidation;
|
||||
use Egulias\EmailValidator\Validation\RFCValidation;
|
||||
use Egulias\EmailValidator\Warning\AddressLiteral;
|
||||
use Egulias\EmailValidator\Warning\DomainLiteral;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class MultipleValidationWitAndTest extends TestCase
|
||||
class MultipleValidationWithAndTest extends TestCase
|
||||
{
|
||||
public function testUsesAndLogicalOperation()
|
||||
{
|
||||
$lexer = $this->getMockBuilder("Egulias\\EmailValidator\\EmailLexer")->getMock();
|
||||
$lexer = new EmailLexer();
|
||||
$validationTrue = $this->getMockBuilder("Egulias\\EmailValidator\\Validation\\EmailValidation")->getMock();
|
||||
$validationTrue->expects($this->any())->method("isValid")->willReturn(true);
|
||||
$validationTrue->expects($this->any())->method("getWarnings")->willReturn([]);
|
||||
@@ -35,7 +39,7 @@ class MultipleValidationWitAndTest extends TestCase
|
||||
|
||||
public function testValidationIsValid()
|
||||
{
|
||||
$lexer = $this->getMockBuilder("Egulias\\EmailValidator\\EmailLexer")->getMock();
|
||||
$lexer = new EmailLexer();
|
||||
|
||||
$validation = $this->getMockBuilder("Egulias\\EmailValidator\\Validation\\EmailValidation")->getMock();
|
||||
$validation->expects($this->any())->method("isValid")->willReturn(true);
|
||||
@@ -56,7 +60,7 @@ class MultipleValidationWitAndTest extends TestCase
|
||||
];
|
||||
$expectedResult = array_merge($warnings1, $warnings2);
|
||||
|
||||
$lexer = $this->getMockBuilder("Egulias\\EmailValidator\\EmailLexer")->getMock();
|
||||
$lexer = new EmailLexer();
|
||||
$validation1 = $this->getMockBuilder("Egulias\\EmailValidator\\Validation\\EmailValidation")->getMock();
|
||||
$validation1->expects($this->any())->method("isValid")->willReturn(true);
|
||||
$validation1->expects($this->once())->method("getWarnings")->willReturn($warnings1);
|
||||
@@ -78,19 +82,43 @@ class MultipleValidationWitAndTest extends TestCase
|
||||
|
||||
$expectedResult = new MultipleErrors([$error1, $error2]);
|
||||
|
||||
$lexer = $this->getMockBuilder("Egulias\\EmailValidator\\EmailLexer")->getMock();
|
||||
$lexer = new EmailLexer();
|
||||
|
||||
$validation1 = $this->getMockBuilder("Egulias\\EmailValidator\\Validation\\EmailValidation")->getMock();
|
||||
$validation1->expects($this->any())->method("isValid")->willReturn(true);
|
||||
$validation1->expects($this->once())->method("isValid")->willReturn(false);
|
||||
$validation1->expects($this->once())->method("getWarnings")->willReturn([]);
|
||||
$validation1->expects($this->once())->method("getError")->willReturn($error1);
|
||||
|
||||
$validation2 = $this->getMockBuilder("Egulias\\EmailValidator\\Validation\\EmailValidation")->getMock();
|
||||
$validation2->expects($this->once())->method("isValid")->willReturn(false);
|
||||
$validation2->expects($this->once())->method("getWarnings")->willReturn([]);
|
||||
$validation2->expects($this->once())->method("getError")->willReturn($error2);
|
||||
|
||||
$multipleValidation = new MultipleValidationWithAnd([$validation1, $validation2]);
|
||||
$multipleValidation->isValid("example@example.com", $lexer);
|
||||
$this->assertEquals($expectedResult, $multipleValidation->getError());
|
||||
}
|
||||
|
||||
public function testStopsAfterFirstError()
|
||||
{
|
||||
$error1 = new CommaInDomain();
|
||||
$error2 = new NoDomainPart();
|
||||
|
||||
$expectedResult = new MultipleErrors([$error1]);
|
||||
|
||||
$lexer = new EmailLexer();
|
||||
|
||||
$validation1 = $this->getMockBuilder("Egulias\\EmailValidator\\Validation\\EmailValidation")->getMock();
|
||||
$validation1->expects($this->any())->method("isValid")->willReturn(false);
|
||||
$validation1->expects($this->once())->method("getWarnings")->willReturn([]);
|
||||
$validation1->expects($this->once())->method("getError")->willReturn($error1);
|
||||
|
||||
$validation2 = $this->getMockBuilder("Egulias\\EmailValidator\\Validation\\EmailValidation")->getMock();
|
||||
$validation2->expects($this->any())->method("isValid")->willReturn(false);
|
||||
$validation2->expects($this->once())->method("getWarnings")->willReturn([]);
|
||||
$validation2->expects($this->once())->method("getError")->willReturn($error2);
|
||||
$validation2->expects($this->never())->method("getWarnings")->willReturn([]);
|
||||
$validation2->expects($this->never())->method("getError")->willReturn($error2);
|
||||
|
||||
$multipleValidation = new MultipleValidationWithAnd([$validation1, $validation2]);
|
||||
$multipleValidation = new MultipleValidationWithAnd([$validation1, $validation2], MultipleValidationWithAnd::STOP_ON_ERROR);
|
||||
$multipleValidation->isValid("example@example.com", $lexer);
|
||||
$this->assertEquals($expectedResult, $multipleValidation->getError());
|
||||
}
|
||||
@@ -101,7 +129,7 @@ class MultipleValidationWitAndTest extends TestCase
|
||||
|
||||
$expectedResult = new MultipleErrors([$error]);
|
||||
|
||||
$lexer = $this->getMockBuilder("Egulias\\EmailValidator\\EmailLexer")->getMock();
|
||||
$lexer = new EmailLexer();
|
||||
|
||||
$validation1 = $this->getMockBuilder("Egulias\\EmailValidator\\Validation\\EmailValidation")->getMock();
|
||||
$validation1->expects($this->any())->method("isValid")->willReturn(false);
|
||||
@@ -117,4 +145,16 @@ class MultipleValidationWitAndTest extends TestCase
|
||||
$multipleValidation->isValid("example@example.com", $lexer);
|
||||
$this->assertEquals($expectedResult, $multipleValidation->getError());
|
||||
}
|
||||
|
||||
public function testBreakoutOnInvalidEmail()
|
||||
{
|
||||
$lexer = new EmailLexer();
|
||||
|
||||
$validationNotCalled = $this->getMockBuilder("Egulias\\EmailValidator\\Validation\\EmailValidation")->getMock();
|
||||
$validationNotCalled->expects($this->never())->method("isValid");
|
||||
$validationNotCalled->expects($this->never())->method("getWarnings");
|
||||
$validationNotCalled->expects($this->never())->method("getError");
|
||||
$multipleValidation = new MultipleValidationWithAnd([new RFCValidation(), $validationNotCalled], MultipleValidationWithAnd::STOP_ON_ERROR);
|
||||
$this->assertFalse($multipleValidation->isValid("invalid-email", $lexer));
|
||||
}
|
||||
}
|
||||
@@ -166,6 +166,7 @@ class RFCValidationTest extends TestCase
|
||||
['test@email>'],
|
||||
['test@email<'],
|
||||
['test@email{'],
|
||||
['test@ '],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
+7
-2
@@ -2,7 +2,6 @@
|
||||
"name": "egulias/email-validator",
|
||||
"description": "A library for validating emails against several RFCs",
|
||||
"homepage": "https://github.com/egulias/EmailValidator",
|
||||
"type": "Library",
|
||||
"keywords": ["email", "validation", "validator", "emailvalidation", "emailvalidator"],
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
@@ -10,7 +9,7 @@
|
||||
],
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0.x-dev"
|
||||
"dev-master": "2.1.x-dev"
|
||||
}
|
||||
},
|
||||
"repositories": [
|
||||
@@ -26,6 +25,7 @@
|
||||
"require-dev" : {
|
||||
"satooshi/php-coveralls": "^1.0.1",
|
||||
"phpunit/phpunit": "^4.8.35||^5.7||^6.0",
|
||||
"symfony/phpunit-bridge": "^4.4@dev",
|
||||
"dominicsayers/isemail": "dev-master"
|
||||
},
|
||||
"suggest": {
|
||||
@@ -35,5 +35,10 @@
|
||||
"psr-4": {
|
||||
"Egulias\\EmailValidator\\": "EmailValidator"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Egulias\\Tests\\": "test"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-4
@@ -8,7 +8,6 @@
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
syntaxCheck="false"
|
||||
bootstrap="vendor/autoload.php"
|
||||
>
|
||||
<testsuites>
|
||||
@@ -19,8 +18,12 @@
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<blacklist>
|
||||
<directory>./vendor</directory>
|
||||
</blacklist>
|
||||
<whitelist>
|
||||
<directory>./EmailValidator/</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
|
||||
<listeners>
|
||||
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener" />
|
||||
</listeners>
|
||||
</phpunit>
|
||||
|
||||
Reference in New Issue
Block a user