Compare commits

...

57 Commits

Author SHA1 Message Date
Eduardo Gulias Davis 5631c3fe2e Merge pull request #59 from egulias/next-min-ver
Improve UTF8 detection, domain part validation, others
2015-04-26 17:49:00 +02:00
Eduardo Gulias Davis c383717824 Improve UTF8 detection within the regexp, update tests for non-ascii char, fix #55 2015-04-26 17:38:14 +02:00
Eduardo Gulias Davis aabed98198 Improve domain part controls for non allowed chars. Fix #57 for DQUOTE 2015-04-26 17:38:14 +02:00
Eduardo Gulias Davis 3b0fd01aa3 Merge pull request #58 from xabbuh/travis-config
update Travis configuration
2015-04-23 11:44:43 +02:00
Christian Flothmann 4efe697504 update Travis configuration
* run builds on the container-based infrastructure
* add a build for PHP 7
* report the build status as soon as possible (either when a mandatory
  job fails or when only jobs allowed to fail are left)
2015-04-23 10:08:34 +02:00
Eduardo Gulias Davis 7a4c5714f5 Merge pull request #50 from xabbuh/test-deps
test low and high dependency versions
2015-04-23 00:10:58 +02:00
Eduardo Gulias Davis 0a26375a7a Merge pull request #54 from xabbuh/update-readme-markdown
fix readme markup
2015-03-08 01:24:16 +01:00
Christian Flothmann 773fe5f4a3 fix readme markup
Before, the character would have been rendered as is instead of being
treated as the final character of the headline.
2015-03-05 20:05:56 +01:00
Eduardo Gulias Davis 4a209951ee Merge pull request #49 from DavidPrevot/lexer
The latest php-doctrine-lexer is needed
2015-02-08 22:30:23 +01:00
Christian Flothmann a8b0bab5aa test low and high dependency versions 2015-02-06 10:43:29 +01:00
David Prévot cc0b91f311 The latest php-doctrine-lexer is needed
The tests actually fail with version 1.0.
2015-02-03 14:23:48 -04:00
Eduardo Gulias Davis 8092ecaeff Merge pull request #48 from 0x46616c6b/tests-doubledot-german-umlauts
Tests: Double dots in domain part, German Umlauts as valid e-mail
2015-01-27 01:03:43 +01:00
Eduardo Gulias Davis f19defb373 Merge pull request #47 from 0x46616c6b/vendors-phpunit
add phpunit to require-dev
2015-01-27 01:02:44 +01:00
louis 9a518fb1bd extends tests with invalid domain part with two dots and valid email with german umlauts 2015-01-26 14:13:13 +01:00
louis 9b184605e8 add phpunit to require-dev 2015-01-26 14:05:53 +01:00
Eduardo Gulias Davis 7a4842c60f Merge pull request #45 from kbond/semicolon-name
added test for email with semi-colon in name
2015-01-05 23:23:13 +01:00
Kevin Bond 687ab6a66e added test for email with semi-colon in name 2015-01-05 11:39:38 -05:00
Eduardo Gulias Davis 116d4054fa #21 - Test for words after domain part 2015-01-04 23:54:28 +01:00
Eduardo Gulias Davis af9417f765 #40 - require latest lexer 2015-01-04 23:42:32 +01:00
Eduardo Gulias Davis ab0bcfb424 Merge pull request #44 from egulias/kbond-semicolon-fail
From #43 - Kbond semicolon fail
2015-01-04 17:36:06 +01:00
Eduardo Gulias Davis 833b3e7924 #41 - Semicolon in domain 2015-01-04 17:28:58 +01:00
Eduardo Gulias Davis fec1609458 Update tests for DNSCheck 2015-01-04 17:24:36 +01:00
Eduardo Gulias Davis add559b99c Add PhpStorm logo
Thanks for supporting!
2015-01-04 17:03:09 +01:00
Kevin Bond 19e390d863 added failing test for email with semi-colon in domain 2014-12-18 11:00:21 -05:00
Eduardo Gulias Davis 5320c26b38 Merge pull request #39 from shakaran/patch-1
Rename Ohter.md to Other.md
2014-11-30 19:03:44 +01:00
Ángel Guzmán Maeso 3b6ab3bcd5 Rename Ohter.md to Other.md
Fix small filename typo.
2014-11-30 02:17:28 +01:00
Eduardo Gulias Davis 7a64ea18af Merge pull request #38 from egulias/improved-utf8
#30 - Improved utf8
2014-11-29 10:09:14 +01:00
Eduardo Gulias Davis 9103f4f99b #30 - Improved control for UTF8 chars 2014-11-29 10:05:19 +01:00
Eduardo Gulias Davis 3f623e9006 Merge pull request #37 from egulias/multiple_spaces
#36 - Multiple spaces in local part
2014-11-17 01:23:05 +01:00
Eduardo Gulias Davis 833eb65135 #30 - [WIP] - improve utf-8 control 2014-11-17 01:18:11 +01:00
Eduardo Gulias Davis e61481fefb #36 - Multiple spaces in local part 2014-11-16 19:15:26 +01:00
Eduardo Gulias Davis 518f80a0ff Merge pull request #35 from craue/fix-strict-check
make strict check work again
2014-11-06 09:59:44 +01:00
Christian Raue 2ec7babda6 fixed strict check 2014-11-05 01:09:55 +01:00
Christian Raue 05367768d6 improved tests for strict checking 2014-11-04 14:01:13 +01:00
Eduardo Gulias Davis 5c3a79217c Merge pull request #33 from egulias/32_strict_and_dns_bug
#32 - Fixed usage of DNS check and strict parameter
2014-11-03 00:13:57 +01:00
Eduardo Gulias Davis 749b423775 #32 - Fixed usage of DNS check and strict parameter 2014-11-03 00:05:58 +01:00
Eduardo Gulias Davis 49494c3189 Merge pull request #31 from egulias/18-discrep-isemail
#18 Differences with isemail
2014-10-26 23:13:52 +01:00
Eduardo Gulias Davis 8b62522238 Scrutinizer patch 2014-10-26 23:02:09 +01:00
Eduardo Gulias Davis 82fb2d6ce1 Remove under development tests emails 2014-10-26 22:55:42 +01:00
Eduardo Gulias Davis 2933b7bbd1 Reset state 2014-10-26 22:54:30 +01:00
Eduardo Gulias Davis f5c48f62d3 Remove commens 2014-10-26 22:54:21 +01:00
Eduardo Gulias Davis 43650e8566 Merge pull request #29 from rdohms/patch-1
Update README.md
2014-10-22 14:39:14 +02:00
Rafael Dohms 3d94cc6487 Update README.md
Updated composer installation instructions.
It now follows the recommendation of using the "require" command and letting Composer auto-define the latest version.
2014-10-22 14:29:38 +02:00
Eduardo Gulias Davis 65c8c3d7bb Merge pull request #28 from DotZecker/patch-1
Fix namespace
2014-10-21 23:52:23 +02:00
Rafael Antonio 57f8ae443b Fix namespace 2014-10-21 09:28:45 +02:00
Eduardo Gulias Davis 18df863858 #18 - [WIP] - Almost done with erros, dobule backslask left and utf8 chars 2014-10-14 00:48:32 +02:00
Eduardo Gulias Davis 953cbdbbcf Merge pull request #26 from stof/patch-1
Fixed the SensioLabsInsight project id
2014-09-17 14:47:23 +02:00
Christophe Coevoet 41cb75ec00 Fixed the SensioLabsInsight project id
Closes #23
2014-09-17 14:12:41 +02:00
Eduardo Gulias Davis 8927160d8d Merge pull request #25 from thewilkybarkid/constraint
Improve suggested constraint
2014-09-17 11:02:18 +02:00
thewilkybarkid 887605ad1b Fix typo 2014-09-17 09:06:33 +01:00
thewilkybarkid 43e1825cd8 Improve suggested constraint 2014-09-17 09:06:22 +01:00
Eduardo Gulias Davis 2f44d7b1e1 #23 - SensioLabsInsight errors 2014-09-16 23:20:11 +02:00
Eduardo Gulias Davis 355cb7e604 Merge pull request #22 from stof/patch-1
Fixed the branch alias for master
2014-09-16 23:00:05 +02:00
Eduardo Gulias Davis d6fcd2d7ca Merge pull request #24 from mhor/patch-1
Typo
2014-09-16 22:58:54 +02:00
Maxime Horcholle 9be8eb420a typo 2014-09-16 19:07:39 +02:00
Christophe Coevoet 20066b1c1e Fixed the branch alias for master 2014-09-16 17:45:41 +02:00
Eduardo Gulias Davis 39b451bb2b #19 and #10 - Improvement of QuotedPart parsing 2014-09-02 00:35:48 +02:00
13 changed files with 1349 additions and 165 deletions
+19 -3
View File
@@ -1,3 +1,5 @@
sudo: false
language: php
php:
@@ -5,11 +7,25 @@ php:
- 5.4
- 5.5
- 5.6
- 7.0
- hhvm
before_script:
- wget http://getcomposer.org/composer.phar
- php composer.phar install --dev --no-interaction
env:
global:
- deps=no
matrix:
fast_finish: true
include:
- php: 5.3
env: deps=low
- php: 5.6
env: deps=high
install:
- if [ "$deps" = "no" ]; then composer install; fi
- if [ "$deps" = "low" ]; then composer update --prefer-lowest; fi
- if [ "$deps" = "high" ]; then composer update; fi
script:
- mkdir -p build/logs
+13 -5
View File
@@ -1,8 +1,16 @@
EmailValidator [![Build Status](https://travis-ci.org/egulias/EmailValidator.png?branch=master)](https://travis-ci.org/egulias/EmailValidator) [![Coverage Status](https://coveralls.io/repos/egulias/EmailValidator/badge.png?branch=master)](https://coveralls.io/r/egulias/EmailValidator?branch=master) [![SensioLabsInsight](https://insight.sensiolabs.com/projects/b18d473e-bd5a-4d88-a7b2-7aeaee0ebd7b/small.png)](https://insight.sensiolabs.com/projects/b18d473e-bd5a-4d88-a7b2-7aeaee0ebd7b)[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/egulias/EmailValidator/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/egulias/EmailValidator/?branch=master)
#EmailValidator
[![Build Status](https://travis-ci.org/egulias/EmailValidator.png?branch=master)](https://travis-ci.org/egulias/EmailValidator) [![Coverage Status](https://coveralls.io/repos/egulias/EmailValidator/badge.png?branch=master)](https://coveralls.io/r/egulias/EmailValidator?branch=master) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/egulias/EmailValidator/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/egulias/EmailValidator/?branch=master) [![SensioLabsInsight](https://insight.sensiolabs.com/projects/22ba6692-9c02-42e5-a65d-1c5696bfffc6/small.png)](https://insight.sensiolabs.com/projects/22ba6692-9c02-42e5-a65d-1c5696bfffc6)
=============================
With the help of
![Powered by PhpStorm](https://www.jetbrains.com/phpstorm/documentation/docs/logo_phpstorm.png)
##Installation##
Install via composer. Add to your current compooser.json ```require``` key: ```"egulias/email-validator":"1.0.x-dev" ```
Run the command below to install via Composer
```shell
composer require egulias/email-validator
```
##Usage##
@@ -24,7 +32,7 @@ More advanced example (returns detailed diagnostic error codes):
```php
<?php
use egulias\EmailValidator\EmailValidator;
use Egulias\EmailValidator\EmailValidator;
$validator = new EmailValidator;
$email = 'dominic@sayers.cc';
@@ -46,6 +54,6 @@ As this is a port from another library and work, here are other people related t
* Josepf Bielawski [@stloyd](http://github.com/stloyd): For its first re-work of Dominic's lib
* Dominic Sayers [@dominicsayers](http://github.com/dominicsayers): The original isemail function
##Licence##
Released under the MIT Licence attached with this code.
##License##
Released under the MIT License attached with this code.
+4 -3
View File
@@ -10,15 +10,16 @@
],
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
"dev-master": "1.3.x-dev"
}
},
"require": {
"php": ">= 5.3.3",
"doctrine/lexer": "~1.0"
"doctrine/lexer": "~1.0,>=1.0.1"
},
"require-dev" : {
"satooshi/php-coveralls": "dev-master"
"satooshi/php-coveralls": "dev-master",
"phpunit/phpunit": "~4.4"
},
"autoload": {
"psr-0": {
Generated
+902 -110
View File
File diff suppressed because it is too large Load Diff
+75 -10
View File
@@ -31,10 +31,13 @@ class EmailLexer extends AbstractLexer
const S_SEMICOLON = 275;
const S_OPENQBRACKET = 276;
const S_CLOSEQBRACKET = 277;
const S_SLASH = 278;
const S_EMPTY = null;
const GENERIC = 300;
const CRLF = 301;
const INVALID = 302;
const ASCII_INVALID_FROM = 127;
const ASCII_INVALID_TO = 199;
/**
* US-ASCII visible characters not valid for atext (@link http://tools.ietf.org/html/rfc5322#section-3.2.3)
@@ -52,6 +55,7 @@ class EmailLexer extends AbstractLexer
';' => self::S_SEMICOLON,
'@' => self::S_AT,
'\\' => self::S_BACKSLASH,
'/' => self::S_SLASH,
',' => self::S_COMMA,
'.' => self::S_DOT,
'"' => self::S_DQUOTE,
@@ -67,14 +71,29 @@ class EmailLexer extends AbstractLexer
'>' => self::S_GREATERTHAN,
'{' => self::S_OPENQBRACKET,
'}' => self::S_CLOSEQBRACKET,
'' => self::S_EMPTY
'' => self::S_EMPTY,
'\0' => self::C_NUL,
);
protected $hasInvalidTokens = false;
protected $previous;
public function reset()
{
$this->hasInvalidTokens = false;
parent::reset();
}
public function hasInvalidTokens()
{
return $this->hasInvalidTokens;
}
/**
* @param $type
* @throws \UnexpectedValueException
* @return boolean
*/
public function find($type)
{
@@ -84,6 +103,7 @@ class EmailLexer extends AbstractLexer
if (!$search->lookahead) {
throw new \UnexpectedValueException($type . ' not found');
}
return true;
}
/**
@@ -99,7 +119,7 @@ class EmailLexer extends AbstractLexer
/**
* moveNext
*
* @return mixed
* @return boolean
*/
public function moveNext()
{
@@ -111,17 +131,17 @@ class EmailLexer extends AbstractLexer
/**
* Lexical catchable patterns.
*
* @return array
* @return string[]
*/
protected function getCatchablePatterns()
{
return array(
'[a-zA-Z_]+[46]?',
'[a-zA-Z_]+[46]?', //ASCII and domain literal
'[^\x00-\x7F]', //UTF-8
'[0-9]+',
'\r\n',
'::',
'\s+',
'[\x10-\x1F]+',
'\s+?',
'.',
);
}
@@ -129,11 +149,11 @@ class EmailLexer extends AbstractLexer
/**
* Lexical non-catchable patterns.
*
* @return array
* @return string[]
*/
protected function getNonCatchablePatterns()
{
return array('[\x7f-\xff]+');
return array('[\xA0-\xff]+');
}
/**
@@ -145,14 +165,59 @@ class EmailLexer extends AbstractLexer
*/
protected function getType(&$value)
{
if (isset($this->charValue[$value])) {
if ($this->isNullType($value)) {
return self::C_NUL;
}
if ($this->isValid($value)) {
return $this->charValue[$value];
}
if (preg_match('/[\x10-\x1F]+/', $value)) {
if ($this->isUTF8Invalid($value)) {
$this->hasInvalidTokens = true;
return self::INVALID;
}
return self::GENERIC;
}
protected function isValid($value)
{
if (isset($this->charValue[$value])) {
return true;
}
return false;
}
/**
* @param $value
* @return bool
*/
protected function isNullType($value)
{
if ($value === "\0") {
return true;
}
return false;
}
/**
* @param $value
* @return bool
*/
protected function isUTF8Invalid($value)
{
if (preg_match('/\p{Cc}+/u', $value)) {
return true;
}
return false;
}
protected function getModifiers()
{
return 'iu';
}
}
@@ -28,6 +28,10 @@ class EmailParser
$this->domainPartParser = new DomainPart($this->lexer);
}
/**
* @param $str
* @return array
*/
public function parse($str)
{
$this->lexer->setInput($str);
@@ -36,11 +40,16 @@ class EmailParser
throw new \InvalidArgumentException('ERR_NOLOCALPART');
}
$this->localPartParser->parse($str);
$this->domainPartParser->parse($str);
$this->setParts($str);
if ($this->lexer->hasInvalidTokens()) {
throw new \InvalidArgumentException('ERR_INVALID_ATEXT');
}
return array('local' => $this->localPart, 'domain' => $this->domainPart);
}
@@ -78,6 +87,10 @@ class EmailParser
return true;
}
/**
* @param string $localPart
* @param string $parsedDomainPart
*/
protected function addLongEmailWarning($localPart, $parsedDomainPart)
{
if (strlen($localPart . '@' . $parsedDomainPart) > self::EMAIL_MAX_LENGTH) {
+2 -11
View File
@@ -2,8 +2,6 @@
namespace Egulias\EmailValidator;
use Egulias\EmailValidator\Parser\LocalPart;
/**
* EmailValidator
*
@@ -97,7 +95,7 @@ class EmailValidator
return false;
}
return ($strict) ? (!$this->hasWarnings() && $dns) : true;
return !$strict || (!$this->hasWarnings() && $dns);
}
/**
@@ -146,16 +144,9 @@ class EmailValidator
protected function checkDNS()
{
$checked = false;
if (!function_exists('dns_get_record') && (
in_array(self::DNSWARN_NO_RECORD, $this->warnings) &&
in_array(self::DNSWARN_NO_MX_RECORD, $this->warnings)
)) {
return $checked;
}
$checked = true;
$result = checkdnsrr(trim($this->parser->getParsedDomainPart()), 'MX');
$checked = true;
if (!$result) {
$this->warnings[] = self::DNSWARN_NO_RECORD;
@@ -23,6 +23,9 @@ class DomainPart extends Parser
if ($this->lexer->token['type'] === EmailLexer::S_EMPTY) {
throw new \InvalidArgumentException('ERR_NODOMAIN');
}
if ($this->lexer->token['type'] === EmailLexer::S_HYPHEN) {
throw new \InvalidArgumentException('ERR_DOMAINHYPHENEND');
}
if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) {
$this->warnings[] = EmailValidator::DEPREC_COMMENT;
@@ -101,8 +104,13 @@ class DomainPart extends Parser
{
$domain = '';
do {
$prev = $this->lexer->getPrevious();
if ($this->lexer->token['type'] === EmailLexer::S_SLASH) {
throw new \InvalidArgumentException('ERR_DOMAIN_CHAR_NOT_ALLOWED');
}
if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) {
$this->parseComments();
$this->lexer->moveNext();
@@ -235,6 +243,17 @@ class DomainPart extends Parser
protected function checkDomainPartExceptions($prev)
{
$invalidDomainTokens = array(
EmailLexer::S_DQUOTE => true,
EmailLexer::S_SEMICOLON => true,
EmailLexer::S_GREATERTHAN => true,
EmailLexer::S_LOWERTHAN => true,
);
if (isset($invalidDomainTokens[$this->lexer->token['type']])) {
throw new \InvalidArgumentException('ERR_EXPECTING_ATEXT');
}
if ($this->lexer->token['type'] === EmailLexer::S_COMMA) {
throw new \InvalidArgumentException('ERR_COMMA_IN_DOMAIN');
}
@@ -295,5 +314,4 @@ class DomainPart extends Parser
throw new \InvalidArgumentException('ERR_EXPECTING_ATEXT');
}
}
}
}
+77 -12
View File
@@ -3,15 +3,16 @@
namespace Egulias\EmailValidator\Parser;
use Egulias\EmailValidator\EmailLexer;
use Egulias\EmailValidator\Parser\Parser;
use Egulias\EmailValidator\EmailValidator;
use \InvalidArgumentException;
class LocalPart extends Parser
{
public function parse($localPart)
{
$parseDQuote = true;
$closingQuote = false;
while ($this->lexer->token['type'] !== EmailLexer::S_AT && $this->lexer->token) {
if ($this->lexer->token['type'] === EmailLexer::S_DOT && !$this->lexer->getPrevious()) {
@@ -19,6 +20,9 @@ class LocalPart extends Parser
}
$closingQuote = $this->checkDQUOTE($closingQuote);
if ($closingQuote && $parseDQuote) {
$parseDQuote = $this->parseDoubleQuote();
}
if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) {
$this->parseComments();
@@ -26,20 +30,15 @@ class LocalPart extends Parser
$this->checkConsecutiveDots();
if ($this->lexer->token['type'] === EmailLexer::S_DOT && $this->lexer->isNextToken(EmailLexer::S_AT)) {
if (
$this->lexer->token['type'] === EmailLexer::S_DOT &&
$this->lexer->isNextToken(EmailLexer::S_AT)
) {
throw new \InvalidArgumentException('ERR_DOT_END');
}
$this->warnEscaping();
if ($this->lexer->isNextTokenAny(
array(
EmailLexer::INVALID, EmailLexer::S_LOWERTHAN, EmailLexer::S_GREATERTHAN
)
)
) {
throw new \InvalidArgumentException('ERR_EXPECTING_ATEXT');
}
$this->isInvalidToken($this->lexer->token, $closingQuote);
if ($this->isFWS()) {
$this->parseFWS();
@@ -53,4 +52,70 @@ class LocalPart extends Parser
$this->warnings[] = EmailValidator::RFC5322_LOCAL_TOOLONG;
}
}
protected function parseDoubleQuote()
{
$parseAgain = true;
$special = array(
EmailLexer::S_CR => true,
EmailLexer::S_HTAB => true,
EmailLexer::S_LF => true
);
$invalid = array(
EmailLexer::C_NUL => true,
EmailLexer::S_HTAB => true,
EmailLexer::S_CR => true,
EmailLexer::S_LF => true
);
$setSpecialsWarning = true;
$this->lexer->moveNext();
while ($this->lexer->token['type'] !== EmailLexer::S_DQUOTE && $this->lexer->token) {
$parseAgain = false;
if (isset($special[$this->lexer->token['type']]) && $setSpecialsWarning) {
$this->warnings[] = EmailValidator::CFWS_FWS;
$setSpecialsWarning = false;
}
$this->lexer->moveNext();
if (!$this->escaped() && isset($invalid[$this->lexer->token['type']])) {
throw new InvalidArgumentException("ERR_EXPECTED_ATEXT");
}
}
$prev = $this->lexer->getPrevious();
if ($prev['type'] === EmailLexer::S_BACKSLASH) {
if (!$this->checkDQUOTE(false)) {
throw new \InvalidArgumentException("ERR_UNCLOSED_DQUOTE");
}
}
if (!$this->lexer->isNextToken(EmailLexer::S_AT) && $prev['type'] !== EmailLexer::S_BACKSLASH) {
throw new \InvalidArgumentException("ERR_EXPECED_AT");
}
return $parseAgain;
}
protected function isInvalidToken($token, $closingQuote)
{
$forbidden = array(
EmailLexer::S_COMMA,
EmailLexer::S_CLOSEBRACKET,
EmailLexer::S_OPENBRACKET,
EmailLexer::S_GREATERTHAN,
EmailLexer::S_LOWERTHAN,
EmailLexer::S_COLON,
EmailLexer::S_SEMICOLON,
EmailLexer::INVALID
);
if (in_array($token['type'], $forbidden) && !$closingQuote) {
throw new \InvalidArgumentException('ERR_EXPECTING_ATEXT');
}
}
}
+20 -1
View File
@@ -102,6 +102,10 @@ abstract class Parser
protected function isFWS()
{
if ($this->escaped()) {
return false;
}
if ($this->lexer->token['type'] === EmailLexer::S_SP ||
$this->lexer->token['type'] === EmailLexer::S_HTAB ||
$this->lexer->token['type'] === EmailLexer::S_CR ||
@@ -114,6 +118,20 @@ abstract class Parser
return false;
}
protected function escaped()
{
$previous = $this->lexer->getPrevious();
if ($previous['type'] === EmailLexer::S_BACKSLASH
&&
$this->lexer->token['type'] !== EmailLexer::GENERIC
) {
return true;
}
return false;
}
protected function warnEscaping()
{
if ($this->lexer->token['type'] !== EmailLexer::S_BACKSLASH) {
@@ -145,6 +163,7 @@ abstract class Parser
if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous['type'] === EmailLexer::GENERIC) {
throw new \InvalidArgumentException('ERR_EXPECTING_ATEXT');
}
$this->warnings[] = EmailValidator::RFC5321_QUOTEDSTRING;
try {
$this->lexer->find(EmailLexer::S_DQUOTE);
@@ -168,4 +187,4 @@ abstract class Parser
throw new \InvalidArgumentException("ERR_FWS_CRLF_END");
}
}
}
}
@@ -26,6 +26,73 @@ class EmailLexerTests extends \PHPUnit_Framework_TestCase
$this->assertEquals($token, $lexer->token['type']);
}
public function testLexerParsesMultipleSpaces()
{
$lexer = new EmailLexer();
$lexer->setInput(' ');
$lexer->moveNext();
$lexer->moveNext();
$this->assertEquals(EmailLexer::S_SP, $lexer->token['type']);
$lexer->moveNext();
$this->assertEquals(EmailLexer::S_SP, $lexer->token['type']);
}
/**
* @dataProvider invalidUTF8CharsProvider
*/
public function testLexerParsesInvalidUTF8($char)
{
$lexer = new EmailLexer();
$lexer->setInput($char);
$lexer->moveNext();
$lexer->moveNext();
$this->assertEquals(EmailLexer::INVALID, $lexer->token['type']);
}
public function invalidUTF8CharsProvider()
{
$chars = array();
for ($i = 0; $i < 0x100; ++$i) {
$c = $this->utf8Chr($i);
if (preg_match('/(?=\p{Cc})(?=[^\t\n\n\r])/u', $c) && !preg_match('/\x{0000}/u', $c)) {
$chars[] = array($c);
}
}
return $chars;
}
protected function utf8Chr($code_point)
{
if ($code_point < 0 || 0x10FFFF < $code_point || (0xD800 <= $code_point && $code_point <= 0xDFFF)) {
return '';
}
if ($code_point < 0x80) {
$hex[0] = $code_point;
$ret = chr($hex[0]);
} elseif ($code_point < 0x800) {
$hex[0] = 0x1C0 | $code_point >> 6;
$hex[1] = 0x80 | $code_point & 0x3F;
$ret = chr($hex[0]).chr($hex[1]);
} elseif ($code_point < 0x10000) {
$hex[0] = 0xE0 | $code_point >> 12;
$hex[1] = 0x80 | $code_point >> 6 & 0x3F;
$hex[2] = 0x80 | $code_point & 0x3F;
$ret = chr($hex[0]).chr($hex[1]).chr($hex[2]);
} else {
$hex[0] = 0xF0 | $code_point >> 18;
$hex[1] = 0x80 | $code_point >> 12 & 0x3F;
$hex[2] = 0x80 | $code_point >> 6 & 0x3F;
$hex[3] = 0x80 | $code_point & 0x3F;
$ret = chr($hex[0]).chr($hex[1]).chr($hex[2]).chr($hex[3]);
}
return $ret;
}
public function testLexerForTab()
{
$lexer = new EmailLexer();
@@ -36,6 +103,25 @@ class EmailLexerTests extends \PHPUnit_Framework_TestCase
$this->assertEquals(EmailLexer::S_HTAB, $lexer->token['type']);
}
public function testLexerForUTF8()
{
$lexer = new EmailLexer();
$lexer->setInput("áÇ@bar.com");
$lexer->moveNext();
$lexer->moveNext();
$this->assertEquals(EmailLexer::GENERIC, $lexer->token['type']);
$lexer->moveNext();
$this->assertEquals(EmailLexer::GENERIC, $lexer->token['type']);
}
public function testLexerSearchToken()
{
$lexer = new EmailLexer();
$lexer->setInput("foo\tbar");
$lexer->moveNext();
$this->assertTrue($lexer->find(EmailLexer::S_HTAB));
}
public function getTokens()
{
return array(
@@ -53,6 +139,7 @@ class EmailLexerTests extends \PHPUnit_Framework_TestCase
array("\"", EmailLexer::S_DQUOTE),
array("-", EmailLexer::S_HYPHEN),
array("\\", EmailLexer::S_BACKSLASH),
array("/", EmailLexer::S_SLASH),
array("(", EmailLexer::S_OPENPARENTHESIS),
array(")", EmailLexer::S_CLOSEPARENTHESIS),
array('<', EmailLexer::S_LOWERTHAN),
@@ -66,7 +153,9 @@ class EmailLexerTests extends \PHPUnit_Framework_TestCase
array('{', EmailLexer::S_OPENQBRACKET),
array('}', EmailLexer::S_CLOSEQBRACKET),
array('', EmailLexer::S_EMPTY),
array(chr(31), EmailLexer::INVALID)
array(chr(31), EmailLexer::INVALID),
array(chr(226), EmailLexer::GENERIC),
array(chr(0), EmailLexer::C_NUL)
);
}
}
@@ -26,19 +26,43 @@ class EmailValidatorTest extends \PHPUnit_Framework_TestCase
$this->assertTrue($this->validator->isValid($email));
}
public function testInvalidUTF8Email()
{
$validator = new EmailValidator;
$email = "\x80\x81\x82@\x83\x84\x85.\x86\x87\x88";
$this->assertFalse($validator->isValid($email));
}
public function getValidEmails()
{
return array(
array('â@iana.org'),
array('fabien@symfony.com'),
array('example@example.co.uk'),
array('fabien_potencier@example.fr'),
array('example@localhost'),
array('fab\'ien@symfony.com'),
array('fab\ ien@symfony.com'),
array('example((example))@fakedfake.co.uk'),
array('example@faked(fake).co.uk'),
array('fabien+@symfony.com'),
array('инфо@письмо.рф'),
array('"username"@example.com'),
array('"user,name"@example.com'),
array('"user name"@example.com'),
array('"user@name"@example.com'),
array('"\a"@iana.org'),
array('"test\ test"@iana.org'),
array('""@iana.org'),
array('"\""@iana.org'),
array('müller@möller.de'),
array('test@email*'),
array('test@email!'),
array('test@email&'),
array('test@email^'),
array('test@email%'),
array('test@email$'),
);
}
@@ -53,9 +77,12 @@ class EmailValidatorTest extends \PHPUnit_Framework_TestCase
public function getInvalidEmails()
{
return array(
array('test@example.com test'),
array('user name@example.com'),
array('user name@example.com'),
array('example.@example.co.uk'),
array('example@example@example.co.uk'),
array('(fabien_potencier@example.fr)'),
array('(test_exampel@example.fr)'),
array('example(example)example@example.co.uk'),
array('.example@localhost'),
array('ex\ample@localhost'),
@@ -66,6 +93,36 @@ class EmailValidatorTest extends \PHPUnit_Framework_TestCase
array('example@(fake).com'),
array('example@(fake.com'),
array('username@example,com'),
array('usern,ame@example.com'),
array('user[na]me@example.com'),
array('"""@iana.org'),
array('"\"@iana.org'),
array('"test"test@iana.org'),
array('"test""test"@iana.org'),
array('"test"."test"@iana.org'),
array('"test".test@iana.org'),
array('"test"' . chr(0) . '@iana.org'),
array('"test\"@iana.org'),
array(chr(226) . '@iana.org'),
array('test@' . chr(226) . '.org'),
array('\r\ntest@iana.org'),
array('\r\n test@iana.org'),
array('\r\n \r\ntest@iana.org'),
array('\r\n \r\ntest@iana.org'),
array('\r\n \r\n test@iana.org'),
array('test@iana.org \r\n'),
array('test@iana.org \r\n '),
array('test@iana.org \r\n \r\n'),
array('test@iana.org \r\n\r\n'),
array('test@iana.org \r\n\r\n '),
array('test@iana/icann.org'),
array('test@foo;bar.com'),
array('test;123@foobar.com'),
array('test@example..com'),
array('email.email@email."'),
array('test@email>'),
array('test@email<'),
array('test@email{'),
);
}
@@ -105,30 +162,58 @@ class EmailValidatorTest extends \PHPUnit_Framework_TestCase
array(EmailValidator::ERR_CR_NO_LF, "example@exa\rmple.co.uk"),
array(EmailValidator::ERR_CR_NO_LF, "example@[\r]"),
array(EmailValidator::ERR_CR_NO_LF, "exam\rple@example.co.uk"),
array(EmailValidator::ERR_CR_NO_LF, "\"\r\"@localhost"),
);
}
/**
* @dataProvider getInvalidEmailsWithWarnings
*/
public function testInvalidEmailsWithWarningsCheck($warnings, $email)
public function testValidEmailsWithWarningsCheck($warnings, $email)
{
$this->assertTrue($this->validator->isValid($email, true));
$this->assertEquals($warnings, $this->validator->getWarnings());
}
/**
* @dataProvider getInvalidEmailsWithWarnings
*/
public function testInvalidEmailsWithDnsCheckAndStrictMode($warnings, $email)
{
$this->assertFalse($this->validator->isValid($email, true, true));
$this->assertEquals($warnings, $this->validator->getWarnings());
}
public function getInvalidEmailsWithWarnings()
{
return array(
array(array( EmailValidator::DEPREC_CFWS_NEAR_AT,), 'example @example.co.uk'),
array(array( EmailValidator::DEPREC_CFWS_NEAR_AT,), 'example@ example.co.uk'),
array(array( EmailValidator::CFWS_COMMENT,), 'example@example(examplecomment).co.uk'),
array(
array(
EmailValidator::DEPREC_CFWS_NEAR_AT,
EmailValidator::DNSWARN_NO_RECORD
),
'example @example.co.uk'
),
array(
array(
EmailValidator::DEPREC_CFWS_NEAR_AT,
EmailValidator::DNSWARN_NO_RECORD
),
'example@ example.co.uk'
),
array(
array(
EmailValidator::CFWS_COMMENT,
EmailValidator::DNSWARN_NO_RECORD
),
'example@example(examplecomment).co.uk'
),
array(
array(
EmailValidator::CFWS_COMMENT,
EmailValidator::DEPREC_CFWS_NEAR_AT,
EmailValidator::DNSWARN_NO_RECORD,
),
'example(examplecomment)@example.co.uk'
),
@@ -136,9 +221,18 @@ class EmailValidatorTest extends \PHPUnit_Framework_TestCase
array(
EmailValidator::RFC5321_QUOTEDSTRING,
EmailValidator::CFWS_FWS,
EmailValidator::DNSWARN_NO_RECORD,
),
"\"\t\"@example.co.uk"
),
array(
array(
EmailValidator::RFC5321_QUOTEDSTRING,
EmailValidator::CFWS_FWS,
EmailValidator::DNSWARN_NO_RECORD
),
"\"\r\"@example.co.uk"
),
array(
array(
EmailValidator::RFC5321_ADDRESSLITERAL,
@@ -227,12 +321,14 @@ class EmailValidatorTest extends \PHPUnit_Framework_TestCase
array(
array(
EmailValidator::RFC5321_QUOTEDSTRING,
EmailValidator::DNSWARN_NO_RECORD
),
'"example"@example.co.uk'
),
array(
array(
EmailValidator::RFC5322_LOCAL_TOOLONG,
EmailValidator::DNSWARN_NO_RECORD
),
'too_long_localpart_too_long_localpart_too_long_localpart_too_long_localpart@example.co.uk'
),
@@ -263,6 +359,17 @@ class EmailValidatorTest extends \PHPUnit_Framework_TestCase
'parttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalparttoolonglocalpart'.
'toolonglocalparttoolonglocalparttoolonglocalparttoolonglocalpar'
),
array(
array(
EmailValidator::DNSWARN_NO_RECORD,
),
'test@test'
),
);
}
public function testInvalidEmailsWithStrict()
{
$this->assertFalse($this->validator->isValid('"test"@test', false, true));
}
}