From dfc70d31daf5bab924a78a9aa1a008cc50c56b84 Mon Sep 17 00:00:00 2001 From: "Endurance, the Martian" Date: Wed, 2 Aug 2023 16:00:13 +0100 Subject: [PATCH 01/12] added/ local driver setup --- .DS_Store | Bin 6148 -> 0 bytes composer.json | 12 +- composer.lock | 1462 ++++++++++------- config/laravel-spammail-checker.php | 125 ++ src/Abstracts/Driver.php | 40 + src/Builders/ConfigBuilder.php | 348 ++++ src/Contracts/DriverInterface.php | 13 + src/Drivers/LocalDriver.php | 28 + .../SpamMailCheckerApiKeyNotSetException.php | 8 + ...mMailCheckerCredentialsNotSetException.php | 8 + src/Exceptions/SpamMailCheckerException.php | 8 + .../SpamMailCheckerNotFoundException.php | 8 + src/Facades/SpamMailCheckerFacade.php | 18 + .../SpamMailCheckerServiceProvider.php | 0 src/SpamMailChecker.php | 0 15 files changed, 1505 insertions(+), 573 deletions(-) delete mode 100644 .DS_Store create mode 100644 config/laravel-spammail-checker.php create mode 100644 src/Abstracts/Driver.php create mode 100644 src/Builders/ConfigBuilder.php create mode 100644 src/Contracts/DriverInterface.php create mode 100644 src/Drivers/LocalDriver.php create mode 100644 src/Exceptions/SpamMailCheckerApiKeyNotSetException.php create mode 100644 src/Exceptions/SpamMailCheckerCredentialsNotSetException.php create mode 100644 src/Exceptions/SpamMailCheckerException.php create mode 100644 src/Exceptions/SpamMailCheckerNotFoundException.php create mode 100644 src/Facades/SpamMailCheckerFacade.php rename src/{ => Providers}/SpamMailCheckerServiceProvider.php (100%) create mode 100644 src/SpamMailChecker.php diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 780af1b718d19a4cec040005fadf48597fef188d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeI0PfpuF6vn>^5u|~tR6?Q)kbHtjNUXXtsiR_v7KsoMu|oON&?>{1M%1iOH@_!q?vC#^WOaV*`A35K-JHB8^AJv3X^EL%4~{B zyQG4ZY|T5Wl0Jrmjb=9)jSHT>!V~ZW{zU@v?v_!*0AKOLeSd#$X4^(d6m^D4hjo?q z+ne^`uiGuRz4vVU_&BpSlzuZ53yFSR*an5_YbDfWi9@!b+ z^)K%a%#3rRj*`i|XL~ub*SjT_@B!P{!e@L$13TEI)-XaZw+^9H%dF!yx=83ZX8s+0 zoHFVgO9@VLkwPFFIj?ejY;j9m=UuZQoYQmxP z$n3|Ctn3$xvU{frv^!L2)aRanC*Ts8GndP9{x@cS|GPo{$`kMe{wo5i95tglmt@b@ y!s6tt4VaFY#KbQ(szaFB<5(BuD3<>fw6QIa0yVUn8f6X5{}9j^eC7$fD1pD*U+Aj< diff --git a/composer.json b/composer.json index 0fa97a1..a621c7d 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,10 @@ } ], "require": { - "php": "^7.4|^8.0", + "php": "^7.2|^7.4|^8.0", + "laravel/framework": "^5.0|^6.0|^7.0|^8.0|^9.0|^10.0", + "guzzlehttp/guzzle": "^6.0|^7.0", + "quickemailverification/quickemailverification": "*", "illuminate/support": "^8.0|^9.0|^10.0" }, "require-dev": { @@ -55,8 +58,11 @@ "extra": { "laravel": { "providers": [ - "Martian\\SpamMailChecker\\SpamMailCheckerServiceProvider" - ] + "Martian\\SpamMailChecker\\providers\\SpamMailCheckerServiceProvider" + ], + "aliases": { + "SpamMailChecker": "Martian\\SpamMailChecker\\Facades\\SpamMailCheckerFacade" + } } } } diff --git a/composer.lock b/composer.lock index 00ed522..cfd3e03 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f10ec160fb663de760612262dda27df1", + "content-hash": "371d850807dbf67e8877900f850744b7", "packages": [ { "name": "brick/math", @@ -138,28 +138,28 @@ }, { "name": "doctrine/inflector", - "version": "2.0.6", + "version": "2.0.8", "source": { "type": "git", "url": "https://github.com/doctrine/inflector.git", - "reference": "d9d313a36c872fd6ee06d9a6cbcf713eaa40f024" + "reference": "f9301a5b2fb1216b2b08f02ba04dc45423db6bff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/d9d313a36c872fd6ee06d9a6cbcf713eaa40f024", - "reference": "d9d313a36c872fd6ee06d9a6cbcf713eaa40f024", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/f9301a5b2fb1216b2b08f02ba04dc45423db6bff", + "reference": "f9301a5b2fb1216b2b08f02ba04dc45423db6bff", "shasum": "" }, "require": { "php": "^7.2 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^10", + "doctrine/coding-standard": "^11.0", "phpstan/phpstan": "^1.8", "phpstan/phpstan-phpunit": "^1.1", "phpstan/phpstan-strict-rules": "^1.3", "phpunit/phpunit": "^8.5 || ^9.5", - "vimeo/psalm": "^4.25" + "vimeo/psalm": "^4.25 || ^5.4" }, "type": "library", "autoload": { @@ -209,7 +209,7 @@ ], "support": { "issues": "https://github.com/doctrine/inflector/issues", - "source": "https://github.com/doctrine/inflector/tree/2.0.6" + "source": "https://github.com/doctrine/inflector/tree/2.0.8" }, "funding": [ { @@ -225,7 +225,7 @@ "type": "tidelift" } ], - "time": "2022-10-20T09:10:12+00:00" + "time": "2023-06-16T13:40:37+00:00" }, { "name": "doctrine/lexer", @@ -494,6 +494,331 @@ ], "time": "2023-02-25T20:23:15+00:00" }, + { + "name": "guzzlehttp/guzzle", + "version": "7.7.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "fb7566caccf22d74d1ab270de3551f72a58399f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/fb7566caccf22d74d1ab270de3551f72a58399f5", + "reference": "fb7566caccf22d74d1ab270de3551f72a58399f5", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.5.3 || ^2.0", + "guzzlehttp/psr7": "^1.9.1 || ^2.4.5", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.1", + "ext-curl": "*", + "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.29 || ^9.5.23", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.7.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2023-05-21T14:04:53+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "3a494dc7dc1d7d12e511890177ae2d0e6c107da6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/3a494dc7dc1d7d12e511890177ae2d0e6c107da6", + "reference": "3a494dc7dc1d7d12e511890177ae2d0e6c107da6", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.1", + "phpunit/phpunit": "^8.5.29 || ^9.5.23" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.0.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2023-05-21T13:50:22+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.5.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "b635f279edd83fc275f822a1188157ffea568ff6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/b635f279edd83fc275f822a1188157ffea568ff6", + "reference": "b635f279edd83fc275f822a1188157ffea568ff6", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.1", + "http-interop/http-factory-tests": "^0.9", + "phpunit/phpunit": "^8.5.29 || ^9.5.23" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.5.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2023-04-17T16:11:26+00:00" + }, { "name": "laravel/framework", "version": "v8.83.27", @@ -669,16 +994,16 @@ }, { "name": "laravel/serializable-closure", - "version": "v1.3.0", + "version": "v1.3.1", "source": { "type": "git", "url": "https://github.com/laravel/serializable-closure.git", - "reference": "f23fe9d4e95255dacee1bf3525e0810d1a1b0f37" + "reference": "e5a3057a5591e1cfe8183034b0203921abe2c902" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/f23fe9d4e95255dacee1bf3525e0810d1a1b0f37", - "reference": "f23fe9d4e95255dacee1bf3525e0810d1a1b0f37", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/e5a3057a5591e1cfe8183034b0203921abe2c902", + "reference": "e5a3057a5591e1cfe8183034b0203921abe2c902", "shasum": "" }, "require": { @@ -725,7 +1050,7 @@ "issues": "https://github.com/laravel/serializable-closure/issues", "source": "https://github.com/laravel/serializable-closure" }, - "time": "2023-01-30T18:31:20+00:00" + "time": "2023-07-14T13:56:28+00:00" }, { "name": "league/commonmark", @@ -1169,16 +1494,16 @@ }, { "name": "nesbot/carbon", - "version": "2.66.0", + "version": "2.68.1", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "496712849902241f04902033b0441b269effe001" + "reference": "4f991ed2a403c85efbc4f23eb4030063fdbe01da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/496712849902241f04902033b0441b269effe001", - "reference": "496712849902241f04902033b0441b269effe001", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/4f991ed2a403c85efbc4f23eb4030063fdbe01da", + "reference": "4f991ed2a403c85efbc4f23eb4030063fdbe01da", "shasum": "" }, "require": { @@ -1267,7 +1592,7 @@ "type": "tidelift" } ], - "time": "2023-01-29T18:53:47+00:00" + "time": "2023-06-20T18:29:04+00:00" }, { "name": "nette/schema", @@ -1333,20 +1658,20 @@ }, { "name": "nette/utils", - "version": "v4.0.0", + "version": "v4.0.1", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "cacdbf5a91a657ede665c541eda28941d4b09c1e" + "reference": "9124157137da01b1f5a5a22d6486cb975f26db7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/cacdbf5a91a657ede665c541eda28941d4b09c1e", - "reference": "cacdbf5a91a657ede665c541eda28941d4b09c1e", + "url": "https://api.github.com/repos/nette/utils/zipball/9124157137da01b1f5a5a22d6486cb975f26db7e", + "reference": "9124157137da01b1f5a5a22d6486cb975f26db7e", "shasum": "" }, "require": { - "php": ">=8.0 <8.3" + "php": ">=8.0 <8.4" }, "conflict": { "nette/finder": "<3", @@ -1354,7 +1679,7 @@ }, "require-dev": { "jetbrains/phpstorm-attributes": "dev-master", - "nette/tester": "^2.4", + "nette/tester": "^2.5", "phpstan/phpstan": "^1.0", "tracy/tracy": "^2.9" }, @@ -1414,9 +1739,9 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.0.0" + "source": "https://github.com/nette/utils/tree/v4.0.1" }, - "time": "2023-02-02T10:41:53+00:00" + "time": "2023-07-30T15:42:21+00:00" }, { "name": "opis/closure", @@ -1556,29 +1881,185 @@ "type": "tidelift" } ], - "time": "2023-02-25T19:38:58+00:00" + "time": "2023-02-25T19:38:58+00:00" + }, + { + "name": "psr/container", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.2" + }, + "time": "2021-11-05T16:50:12+00:00" + }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/0955afe48220520692d2d09f7ab7e0f93ffd6a31", + "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client/tree/1.0.2" + }, + "time": "2023-04-10T20:12:12+00:00" }, { - "name": "psr/container", - "version": "1.1.2", + "name": "psr/http-factory", + "version": "1.0.2", "source": { "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + "url": "https://github.com/php-fig/http-factory.git", + "reference": "e616d01114759c4c489f93b099585439f795fe35" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", + "reference": "e616d01114759c4c489f93b099585439f795fe35", "shasum": "" }, "require": { - "php": ">=7.4.0" + "php": ">=7.0.0", + "psr/http-message": "^1.0 || ^2.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, "autoload": { "psr-4": { - "Psr\\Container\\": "src/" + "Psr\\Http\\Message\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1591,47 +2072,48 @@ "homepage": "https://www.php-fig.org/" } ], - "description": "Common Container Interface (PHP FIG PSR-11)", - "homepage": "https://github.com/php-fig/container", + "description": "Common interfaces for PSR-7 HTTP message factories", "keywords": [ - "PSR-11", - "container", - "container-interface", - "container-interop", - "psr" + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" ], "support": { - "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/1.1.2" + "source": "https://github.com/php-fig/http-factory/tree/1.0.2" }, - "time": "2021-11-05T16:50:12+00:00" + "time": "2023-04-10T20:10:41+00:00" }, { - "name": "psr/event-dispatcher", - "version": "1.0.0", + "name": "psr/http-message", + "version": "2.0", "source": { "type": "git", - "url": "https://github.com/php-fig/event-dispatcher.git", - "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", - "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", "shasum": "" }, "require": { - "php": ">=7.2.0" + "php": "^7.2 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { "psr-4": { - "Psr\\EventDispatcher\\": "src/" + "Psr\\Http\\Message\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1641,20 +2123,23 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], - "description": "Standard interfaces for event handling.", + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", "keywords": [ - "events", + "http", + "http-message", "psr", - "psr-14" + "psr-7", + "request", + "response" ], "support": { - "issues": "https://github.com/php-fig/event-dispatcher/issues", - "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + "source": "https://github.com/php-fig/http-message/tree/2.0" }, - "time": "2019-01-08T18:20:26+00:00" + "time": "2023-04-04T09:54:51+00:00" }, { "name": "psr/log", @@ -1757,6 +2242,110 @@ }, "time": "2017-10-23T01:57:42+00:00" }, + { + "name": "quickemailverification/quickemailverification", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/quickemailverification/quickemailverification-php.git", + "reference": "c22a6fecee195d5c10c1c292b351630e2743e7b5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/quickemailverification/quickemailverification-php/zipball/c22a6fecee195d5c10c1c292b351630e2743e7b5", + "reference": "c22a6fecee195d5c10c1c292b351630e2743e7b5", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/guzzle": "^7.0.1" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.3", + "phpunit/phpunit": "^4.8 || ^5.4" + }, + "type": "library", + "autoload": { + "psr-0": { + "QuickEmailVerification\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "quickemailverification", + "email": "support@quickemailverification.com", + "homepage": "https://quickemailverification.com" + } + ], + "description": "Official QuickEmailVerification API library client for PHP", + "homepage": "https://quickemailverification.com", + "keywords": [ + "api", + "client", + "email", + "email verification api", + "free", + "library", + "quickemailverification", + "sandbox api", + "validation", + "verification", + "verify" + ], + "support": { + "issues": "https://github.com/quickemailverification/quickemailverification-php/issues", + "source": "https://github.com/quickemailverification/quickemailverification-php/tree/v1.0.3" + }, + "time": "2022-06-14T10:07:08+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, { "name": "ramsey/collection", "version": "2.0.0", @@ -2016,16 +2605,16 @@ }, { "name": "symfony/console", - "version": "v5.4.23", + "version": "v5.4.26", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "90f21e27d0d88ce38720556dd164d4a1e4c3934c" + "reference": "b504a3d266ad2bb632f196c0936ef2af5ff6e273" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/90f21e27d0d88ce38720556dd164d4a1e4c3934c", - "reference": "90f21e27d0d88ce38720556dd164d4a1e4c3934c", + "url": "https://api.github.com/repos/symfony/console/zipball/b504a3d266ad2bb632f196c0936ef2af5ff6e273", + "reference": "b504a3d266ad2bb632f196c0936ef2af5ff6e273", "shasum": "" }, "require": { @@ -2095,7 +2684,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.23" + "source": "https://github.com/symfony/console/tree/v5.4.26" }, "funding": [ { @@ -2111,20 +2700,20 @@ "type": "tidelift" } ], - "time": "2023-04-24T18:47:29+00:00" + "time": "2023-07-19T20:11:33+00:00" }, { "name": "symfony/css-selector", - "version": "v6.2.7", + "version": "v6.3.2", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "aedf3cb0f5b929ec255d96bbb4909e9932c769e0" + "reference": "883d961421ab1709877c10ac99451632a3d6fa57" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/aedf3cb0f5b929ec255d96bbb4909e9932c769e0", - "reference": "aedf3cb0f5b929ec255d96bbb4909e9932c769e0", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/883d961421ab1709877c10ac99451632a3d6fa57", + "reference": "883d961421ab1709877c10ac99451632a3d6fa57", "shasum": "" }, "require": { @@ -2160,7 +2749,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v6.2.7" + "source": "https://github.com/symfony/css-selector/tree/v6.3.2" }, "funding": [ { @@ -2176,20 +2765,20 @@ "type": "tidelift" } ], - "time": "2023-02-14T08:44:56+00:00" + "time": "2023-07-12T16:00:22+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.2.1", + "version": "v3.3.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e" + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e", - "reference": "e2d1534420bd723d0ef5aec58a22c5fe60ce6f5e", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", "shasum": "" }, "require": { @@ -2198,7 +2787,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.3-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", @@ -2227,7 +2816,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.2.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.3.0" }, "funding": [ { @@ -2243,20 +2832,20 @@ "type": "tidelift" } ], - "time": "2023-03-01T10:25:55+00:00" + "time": "2023-05-23T14:45:45+00:00" }, { "name": "symfony/error-handler", - "version": "v5.4.23", + "version": "v5.4.26", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "218206b4772d9f412d7d277980c020d06e9d8a4e" + "reference": "b26719213a39c9ba57520cbc5e52bfcc5e8d92f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/218206b4772d9f412d7d277980c020d06e9d8a4e", - "reference": "218206b4772d9f412d7d277980c020d06e9d8a4e", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/b26719213a39c9ba57520cbc5e52bfcc5e8d92f9", + "reference": "b26719213a39c9ba57520cbc5e52bfcc5e8d92f9", "shasum": "" }, "require": { @@ -2298,7 +2887,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v5.4.23" + "source": "https://github.com/symfony/error-handler/tree/v5.4.26" }, "funding": [ { @@ -2314,28 +2903,29 @@ "type": "tidelift" } ], - "time": "2023-04-17T10:03:27+00:00" + "time": "2023-07-16T16:48:57+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v6.2.8", + "version": "v6.3.2", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "04046f35fd7d72f9646e721fc2ecb8f9c67d3339" + "reference": "adb01fe097a4ee930db9258a3cc906b5beb5cf2e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/04046f35fd7d72f9646e721fc2ecb8f9c67d3339", - "reference": "04046f35fd7d72f9646e721fc2ecb8f9c67d3339", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/adb01fe097a4ee930db9258a3cc906b5beb5cf2e", + "reference": "adb01fe097a4ee930db9258a3cc906b5beb5cf2e", "shasum": "" }, "require": { "php": ">=8.1", - "symfony/event-dispatcher-contracts": "^2|^3" + "symfony/event-dispatcher-contracts": "^2.5|^3" }, "conflict": { - "symfony/dependency-injection": "<5.4" + "symfony/dependency-injection": "<5.4", + "symfony/service-contracts": "<2.5" }, "provide": { "psr/event-dispatcher-implementation": "1.0", @@ -2348,13 +2938,9 @@ "symfony/error-handler": "^5.4|^6.0", "symfony/expression-language": "^5.4|^6.0", "symfony/http-foundation": "^5.4|^6.0", - "symfony/service-contracts": "^1.1|^2|^3", + "symfony/service-contracts": "^2.5|^3", "symfony/stopwatch": "^5.4|^6.0" }, - "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" - }, "type": "library", "autoload": { "psr-4": { @@ -2381,7 +2967,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v6.2.8" + "source": "https://github.com/symfony/event-dispatcher/tree/v6.3.2" }, "funding": [ { @@ -2397,33 +2983,30 @@ "type": "tidelift" } ], - "time": "2023-03-20T16:06:02+00:00" + "time": "2023-07-06T06:56:43+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.2.1", + "version": "v3.3.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "0ad3b6f1e4e2da5690fefe075cd53a238646d8dd" + "reference": "a76aed96a42d2b521153fb382d418e30d18b59df" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/0ad3b6f1e4e2da5690fefe075cd53a238646d8dd", - "reference": "0ad3b6f1e4e2da5690fefe075cd53a238646d8dd", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/a76aed96a42d2b521153fb382d418e30d18b59df", + "reference": "a76aed96a42d2b521153fb382d418e30d18b59df", "shasum": "" }, "require": { "php": ">=8.1", "psr/event-dispatcher": "^1" }, - "suggest": { - "symfony/event-dispatcher-implementation": "" - }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.3-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", @@ -2460,7 +3043,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.2.1" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.3.0" }, "funding": [ { @@ -2476,20 +3059,20 @@ "type": "tidelift" } ], - "time": "2023-03-01T10:32:47+00:00" + "time": "2023-05-23T14:45:45+00:00" }, { "name": "symfony/finder", - "version": "v5.4.21", + "version": "v5.4.27", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "078e9a5e1871fcfe6a5ce421b539344c21afef19" + "reference": "ff4bce3c33451e7ec778070e45bd23f74214cd5d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/078e9a5e1871fcfe6a5ce421b539344c21afef19", - "reference": "078e9a5e1871fcfe6a5ce421b539344c21afef19", + "url": "https://api.github.com/repos/symfony/finder/zipball/ff4bce3c33451e7ec778070e45bd23f74214cd5d", + "reference": "ff4bce3c33451e7ec778070e45bd23f74214cd5d", "shasum": "" }, "require": { @@ -2523,7 +3106,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.4.21" + "source": "https://github.com/symfony/finder/tree/v5.4.27" }, "funding": [ { @@ -2539,20 +3122,20 @@ "type": "tidelift" } ], - "time": "2023-02-16T09:33:00+00:00" + "time": "2023-07-31T08:02:31+00:00" }, { "name": "symfony/http-foundation", - "version": "v5.4.23", + "version": "v5.4.26", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "af9fbb378f5f956c8f29d4886644c84c193780ac" + "reference": "e7793151e99dc2ac1352ff3735d100fb3b3bfc08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/af9fbb378f5f956c8f29d4886644c84c193780ac", - "reference": "af9fbb378f5f956c8f29d4886644c84c193780ac", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/e7793151e99dc2ac1352ff3735d100fb3b3bfc08", + "reference": "e7793151e99dc2ac1352ff3735d100fb3b3bfc08", "shasum": "" }, "require": { @@ -2599,7 +3182,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v5.4.23" + "source": "https://github.com/symfony/http-foundation/tree/v5.4.26" }, "funding": [ { @@ -2615,20 +3198,20 @@ "type": "tidelift" } ], - "time": "2023-04-18T06:30:11+00:00" + "time": "2023-07-21T11:30:15+00:00" }, { "name": "symfony/http-kernel", - "version": "v5.4.23", + "version": "v5.4.27", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "48ea17a7c65ef1ede0c3b2dbc35adace99071810" + "reference": "9f5624816c0b8d92f85666ac7ed2825a18fcd899" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/48ea17a7c65ef1ede0c3b2dbc35adace99071810", - "reference": "48ea17a7c65ef1ede0c3b2dbc35adace99071810", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/9f5624816c0b8d92f85666ac7ed2825a18fcd899", + "reference": "9f5624816c0b8d92f85666ac7ed2825a18fcd899", "shasum": "" }, "require": { @@ -2711,7 +3294,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v5.4.23" + "source": "https://github.com/symfony/http-kernel/tree/v5.4.27" }, "funding": [ { @@ -2727,20 +3310,20 @@ "type": "tidelift" } ], - "time": "2023-04-28T13:29:52+00:00" + "time": "2023-07-31T10:18:38+00:00" }, { "name": "symfony/mime", - "version": "v5.4.23", + "version": "v5.4.26", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "ae0a1032a450a3abf305ee44fc55ed423fbf16e3" + "reference": "2ea06dfeee20000a319d8407cea1d47533d5a9d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/ae0a1032a450a3abf305ee44fc55ed423fbf16e3", - "reference": "ae0a1032a450a3abf305ee44fc55ed423fbf16e3", + "url": "https://api.github.com/repos/symfony/mime/zipball/2ea06dfeee20000a319d8407cea1d47533d5a9d2", + "reference": "2ea06dfeee20000a319d8407cea1d47533d5a9d2", "shasum": "" }, "require": { @@ -2755,7 +3338,7 @@ "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", "symfony/mailer": "<4.4", - "symfony/serializer": "<5.4.14|>=6.0,<6.0.14|>=6.1,<6.1.6" + "symfony/serializer": "<5.4.26|>=6,<6.2.13|>=6.3,<6.3.2" }, "require-dev": { "egulias/email-validator": "^2.1.10|^3.1|^4", @@ -2763,7 +3346,7 @@ "symfony/dependency-injection": "^4.4|^5.0|^6.0", "symfony/property-access": "^4.4|^5.1|^6.0", "symfony/property-info": "^4.4|^5.1|^6.0", - "symfony/serializer": "^5.4.14|~6.0.14|^6.1.6" + "symfony/serializer": "^5.4.26|~6.2.13|^6.3.2" }, "type": "library", "autoload": { @@ -2795,7 +3378,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v5.4.23" + "source": "https://github.com/symfony/mime/tree/v5.4.26" }, "funding": [ { @@ -2811,7 +3394,7 @@ "type": "tidelift" } ], - "time": "2023-04-19T09:49:13+00:00" + "time": "2023-07-27T06:29:31+00:00" }, { "name": "symfony/polyfill-ctype", @@ -3553,16 +4136,16 @@ }, { "name": "symfony/process", - "version": "v5.4.23", + "version": "v5.4.26", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "4b842fc4b61609e0a155a114082bd94e31e98287" + "reference": "1a44dc377ec86a50fab40d066cd061e28a6b482f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/4b842fc4b61609e0a155a114082bd94e31e98287", - "reference": "4b842fc4b61609e0a155a114082bd94e31e98287", + "url": "https://api.github.com/repos/symfony/process/zipball/1a44dc377ec86a50fab40d066cd061e28a6b482f", + "reference": "1a44dc377ec86a50fab40d066cd061e28a6b482f", "shasum": "" }, "require": { @@ -3595,7 +4178,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.23" + "source": "https://github.com/symfony/process/tree/v5.4.26" }, "funding": [ { @@ -3611,20 +4194,20 @@ "type": "tidelift" } ], - "time": "2023-04-18T13:50:24+00:00" + "time": "2023-07-12T15:44:31+00:00" }, { "name": "symfony/routing", - "version": "v5.4.22", + "version": "v5.4.26", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "c2ac11eb34947999b7c38fb4c835a57306907e6d" + "reference": "853fc7df96befc468692de0a48831b38f04d2cb2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/c2ac11eb34947999b7c38fb4c835a57306907e6d", - "reference": "c2ac11eb34947999b7c38fb4c835a57306907e6d", + "url": "https://api.github.com/repos/symfony/routing/zipball/853fc7df96befc468692de0a48831b38f04d2cb2", + "reference": "853fc7df96befc468692de0a48831b38f04d2cb2", "shasum": "" }, "require": { @@ -3685,7 +4268,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v5.4.22" + "source": "https://github.com/symfony/routing/tree/v5.4.26" }, "funding": [ { @@ -3701,7 +4284,7 @@ "type": "tidelift" } ], - "time": "2023-03-14T14:59:20+00:00" + "time": "2023-07-24T13:28:37+00:00" }, { "name": "symfony/service-contracts", @@ -3788,16 +4371,16 @@ }, { "name": "symfony/string", - "version": "v6.2.8", + "version": "v6.3.2", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "193e83bbd6617d6b2151c37fff10fa7168ebddef" + "reference": "53d1a83225002635bca3482fcbf963001313fb68" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/193e83bbd6617d6b2151c37fff10fa7168ebddef", - "reference": "193e83bbd6617d6b2151c37fff10fa7168ebddef", + "url": "https://api.github.com/repos/symfony/string/zipball/53d1a83225002635bca3482fcbf963001313fb68", + "reference": "53d1a83225002635bca3482fcbf963001313fb68", "shasum": "" }, "require": { @@ -3808,13 +4391,13 @@ "symfony/polyfill-mbstring": "~1.0" }, "conflict": { - "symfony/translation-contracts": "<2.0" + "symfony/translation-contracts": "<2.5" }, "require-dev": { "symfony/error-handler": "^5.4|^6.0", "symfony/http-client": "^5.4|^6.0", "symfony/intl": "^6.2", - "symfony/translation-contracts": "^2.0|^3.0", + "symfony/translation-contracts": "^2.5|^3.0", "symfony/var-exporter": "^5.4|^6.0" }, "type": "library", @@ -3854,7 +4437,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.2.8" + "source": "https://github.com/symfony/string/tree/v6.3.2" }, "funding": [ { @@ -3870,32 +4453,35 @@ "type": "tidelift" } ], - "time": "2023-03-20T16:06:02+00:00" + "time": "2023-07-05T08:41:27+00:00" }, { "name": "symfony/translation", - "version": "v6.2.8", + "version": "v6.3.3", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "817535dbb1721df8b3a8f2489dc7e50bcd6209b5" + "reference": "3ed078c54bc98bbe4414e1e9b2d5e85ed5a5c8bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/817535dbb1721df8b3a8f2489dc7e50bcd6209b5", - "reference": "817535dbb1721df8b3a8f2489dc7e50bcd6209b5", + "url": "https://api.github.com/repos/symfony/translation/zipball/3ed078c54bc98bbe4414e1e9b2d5e85ed5a5c8bd", + "reference": "3ed078c54bc98bbe4414e1e9b2d5e85ed5a5c8bd", "shasum": "" }, "require": { "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/translation-contracts": "^2.3|^3.0" + "symfony/translation-contracts": "^2.5|^3.0" }, "conflict": { "symfony/config": "<5.4", "symfony/console": "<5.4", "symfony/dependency-injection": "<5.4", + "symfony/http-client-contracts": "<2.5", "symfony/http-kernel": "<5.4", + "symfony/service-contracts": "<2.5", "symfony/twig-bundle": "<5.4", "symfony/yaml": "<5.4" }, @@ -3909,20 +4495,14 @@ "symfony/console": "^5.4|^6.0", "symfony/dependency-injection": "^5.4|^6.0", "symfony/finder": "^5.4|^6.0", - "symfony/http-client-contracts": "^1.1|^2.0|^3.0", + "symfony/http-client-contracts": "^2.5|^3.0", "symfony/http-kernel": "^5.4|^6.0", "symfony/intl": "^5.4|^6.0", "symfony/polyfill-intl-icu": "^1.21", "symfony/routing": "^5.4|^6.0", - "symfony/service-contracts": "^1.1.2|^2|^3", + "symfony/service-contracts": "^2.5|^3", "symfony/yaml": "^5.4|^6.0" }, - "suggest": { - "nikic/php-parser": "To use PhpAstExtractor", - "psr/log-implementation": "To use logging capability in translator", - "symfony/config": "", - "symfony/yaml": "" - }, "type": "library", "autoload": { "files": [ @@ -3952,7 +4532,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v6.2.8" + "source": "https://github.com/symfony/translation/tree/v6.3.3" }, "funding": [ { @@ -3968,32 +4548,29 @@ "type": "tidelift" } ], - "time": "2023-03-31T09:14:44+00:00" + "time": "2023-07-31T07:08:24+00:00" }, { "name": "symfony/translation-contracts", - "version": "v3.2.1", + "version": "v3.3.0", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "dfec258b9dd17a6b24420d464c43bffe347441c8" + "reference": "02c24deb352fb0d79db5486c0c79905a85e37e86" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/dfec258b9dd17a6b24420d464c43bffe347441c8", - "reference": "dfec258b9dd17a6b24420d464c43bffe347441c8", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/02c24deb352fb0d79db5486c0c79905a85e37e86", + "reference": "02c24deb352fb0d79db5486c0c79905a85e37e86", "shasum": "" }, "require": { "php": ">=8.1" }, - "suggest": { - "symfony/translation-implementation": "" - }, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.3-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", @@ -4033,7 +4610,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.2.1" + "source": "https://github.com/symfony/translation-contracts/tree/v3.3.0" }, "funding": [ { @@ -4049,20 +4626,20 @@ "type": "tidelift" } ], - "time": "2023-03-01T10:32:47+00:00" + "time": "2023-05-30T17:17:10+00:00" }, { "name": "symfony/var-dumper", - "version": "v5.4.23", + "version": "v5.4.26", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "9a8a5b6d6508928174ded2109e29328a55342a42" + "reference": "e706c99b4a6f4d9383b52b80dd8c74880501e314" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/9a8a5b6d6508928174ded2109e29328a55342a42", - "reference": "9a8a5b6d6508928174ded2109e29328a55342a42", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/e706c99b4a6f4d9383b52b80dd8c74880501e314", + "reference": "e706c99b4a6f4d9383b52b80dd8c74880501e314", "shasum": "" }, "require": { @@ -4071,12 +4648,12 @@ "symfony/polyfill-php80": "^1.16" }, "conflict": { - "phpunit/phpunit": "<5.4.3", "symfony/console": "<4.4" }, "require-dev": { "ext-iconv": "*", "symfony/console": "^4.4|^5.0|^6.0", + "symfony/http-kernel": "^4.4|^5.0|^6.0", "symfony/process": "^4.4|^5.0|^6.0", "symfony/uid": "^5.1|^6.0", "twig/twig": "^2.13|^3.0.4" @@ -4122,7 +4699,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v5.4.23" + "source": "https://github.com/symfony/var-dumper/tree/v5.4.26" }, "funding": [ { @@ -4138,7 +4715,7 @@ "type": "tidelift" } ], - "time": "2023-04-18T09:26:27+00:00" + "time": "2023-07-13T07:32:46+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -4483,16 +5060,16 @@ }, { "name": "fakerphp/faker", - "version": "v1.21.0", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/FakerPHP/Faker.git", - "reference": "92efad6a967f0b79c499705c69b662f738cc9e4d" + "reference": "e3daa170d00fde61ea7719ef47bb09bb8f1d9b01" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/92efad6a967f0b79c499705c69b662f738cc9e4d", - "reference": "92efad6a967f0b79c499705c69b662f738cc9e4d", + "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/e3daa170d00fde61ea7719ef47bb09bb8f1d9b01", + "reference": "e3daa170d00fde61ea7719ef47bb09bb8f1d9b01", "shasum": "" }, "require": { @@ -4504,93 +5081,28 @@ "fzaninotto/faker": "*" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.4.1", - "doctrine/persistence": "^1.3 || ^2.0", - "ext-intl": "*", - "phpunit/phpunit": "^9.5.26", - "symfony/phpunit-bridge": "^5.4.16" - }, - "suggest": { - "doctrine/orm": "Required to use Faker\\ORM\\Doctrine", - "ext-curl": "Required by Faker\\Provider\\Image to download images.", - "ext-dom": "Required by Faker\\Provider\\HtmlLorem for generating random HTML.", - "ext-iconv": "Required by Faker\\Provider\\ru_RU\\Text::realText() for generating real Russian text.", - "ext-mbstring": "Required for multibyte Unicode string functionality." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "v1.21-dev" - } - }, - "autoload": { - "psr-4": { - "Faker\\": "src/Faker/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "François Zaninotto" - } - ], - "description": "Faker is a PHP library that generates fake data for you.", - "keywords": [ - "data", - "faker", - "fixtures" - ], - "support": { - "issues": "https://github.com/FakerPHP/Faker/issues", - "source": "https://github.com/FakerPHP/Faker/tree/v1.21.0" - }, - "time": "2022-12-13T13:54:32+00:00" - }, - { - "name": "guzzlehttp/psr7", - "version": "2.5.0", - "source": { - "type": "git", - "url": "https://github.com/guzzle/psr7.git", - "reference": "b635f279edd83fc275f822a1188157ffea568ff6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/b635f279edd83fc275f822a1188157ffea568ff6", - "reference": "b635f279edd83fc275f822a1188157ffea568ff6", - "shasum": "" - }, - "require": { - "php": "^7.2.5 || ^8.0", - "psr/http-factory": "^1.0", - "psr/http-message": "^1.1 || ^2.0", - "ralouphie/getallheaders": "^3.0" - }, - "provide": { - "psr/http-factory-implementation": "1.0", - "psr/http-message-implementation": "1.0" - }, - "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.1", - "http-interop/http-factory-tests": "^0.9", - "phpunit/phpunit": "^8.5.29 || ^9.5.23" + "bamarni/composer-bin-plugin": "^1.4.1", + "doctrine/persistence": "^1.3 || ^2.0", + "ext-intl": "*", + "phpunit/phpunit": "^9.5.26", + "symfony/phpunit-bridge": "^5.4.16" }, "suggest": { - "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + "doctrine/orm": "Required to use Faker\\ORM\\Doctrine", + "ext-curl": "Required by Faker\\Provider\\Image to download images.", + "ext-dom": "Required by Faker\\Provider\\HtmlLorem for generating random HTML.", + "ext-iconv": "Required by Faker\\Provider\\ru_RU\\Text::realText() for generating real Russian text.", + "ext-mbstring": "Required for multibyte Unicode string functionality." }, "type": "library", "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": false + "branch-alias": { + "dev-main": "v1.21-dev" } }, "autoload": { "psr-4": { - "GuzzleHttp\\Psr7\\": "src/" + "Faker\\": "src/Faker/" } }, "notification-url": "https://packagist.org/downloads/", @@ -4599,71 +5111,20 @@ ], "authors": [ { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - }, - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - }, - { - "name": "George Mponos", - "email": "gmponos@gmail.com", - "homepage": "https://github.com/gmponos" - }, - { - "name": "Tobias Nyholm", - "email": "tobias.nyholm@gmail.com", - "homepage": "https://github.com/Nyholm" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com", - "homepage": "https://github.com/sagikazarmark" - }, - { - "name": "Tobias Schultze", - "email": "webmaster@tubo-world.de", - "homepage": "https://github.com/Tobion" - }, - { - "name": "Márk Sági-Kazár", - "email": "mark.sagikazar@gmail.com", - "homepage": "https://sagikazarmark.hu" + "name": "François Zaninotto" } ], - "description": "PSR-7 message implementation that also provides common utility methods", + "description": "Faker is a PHP library that generates fake data for you.", "keywords": [ - "http", - "message", - "psr-7", - "request", - "response", - "stream", - "uri", - "url" + "data", + "faker", + "fixtures" ], "support": { - "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.5.0" + "issues": "https://github.com/FakerPHP/Faker/issues", + "source": "https://github.com/FakerPHP/Faker/tree/v1.23.0" }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://github.com/Nyholm", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", - "type": "tidelift" - } - ], - "time": "2023-04-17T16:11:26+00:00" + "time": "2023-06-12T08:44:38+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -4718,38 +5179,40 @@ }, { "name": "mockery/mockery", - "version": "1.5.1", + "version": "1.6.4", "source": { "type": "git", "url": "https://github.com/mockery/mockery.git", - "reference": "e92dcc83d5a51851baf5f5591d32cb2b16e3684e" + "reference": "d1413755e26fe56a63455f7753221c86cbb88f66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/e92dcc83d5a51851baf5f5591d32cb2b16e3684e", - "reference": "e92dcc83d5a51851baf5f5591d32cb2b16e3684e", + "url": "https://api.github.com/repos/mockery/mockery/zipball/d1413755e26fe56a63455f7753221c86cbb88f66", + "reference": "d1413755e26fe56a63455f7753221c86cbb88f66", "shasum": "" }, "require": { "hamcrest/hamcrest-php": "^2.0.1", "lib-pcre": ">=7.0", - "php": "^7.3 || ^8.0" + "php": ">=7.4,<8.3" }, "conflict": { "phpunit/phpunit": "<8.0" }, "require-dev": { - "phpunit/phpunit": "^8.5 || ^9.3" + "phpunit/phpunit": "^8.5 || ^9.3", + "psalm/plugin-phpunit": "^0.18.4", + "symplify/easy-coding-standard": "^11.5.0", + "vimeo/psalm": "^5.13.1" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4.x-dev" - } - }, "autoload": { - "psr-0": { - "Mockery": "library/" + "files": [ + "library/helpers.php", + "library/Mockery.php" + ], + "psr-4": { + "Mockery\\": "library/Mockery" } }, "notification-url": "https://packagist.org/downloads/", @@ -4760,12 +5223,20 @@ { "name": "Pádraic Brady", "email": "padraic.brady@gmail.com", - "homepage": "http://blog.astrumfutura.com" + "homepage": "https://github.com/padraic", + "role": "Author" }, { "name": "Dave Marshall", "email": "dave.marshall@atstsolutions.co.uk", - "homepage": "http://davedevelopment.co.uk" + "homepage": "https://davedevelopment.co.uk", + "role": "Developer" + }, + { + "name": "Nathanael Esayeas", + "email": "nathanael.esayeas@protonmail.com", + "homepage": "https://github.com/ghostwriter", + "role": "Lead Developer" } ], "description": "Mockery is a simple yet flexible PHP mock object framework", @@ -4783,10 +5254,13 @@ "testing" ], "support": { + "docs": "https://docs.mockery.io/", "issues": "https://github.com/mockery/mockery/issues", - "source": "https://github.com/mockery/mockery/tree/1.5.1" + "rss": "https://github.com/mockery/mockery/releases.atom", + "security": "https://github.com/mockery/mockery/security/advisories", + "source": "https://github.com/mockery/mockery" }, - "time": "2022-09-07T15:32:08+00:00" + "time": "2023-07-19T15:51:02+00:00" }, { "name": "myclabs/deep-copy", @@ -4849,16 +5323,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.15.4", + "version": "v4.16.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290" + "reference": "19526a33fb561ef417e822e85f08a00db4059c17" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6bb5176bc4af8bcb7d926f88718db9b96a2d4290", - "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/19526a33fb561ef417e822e85f08a00db4059c17", + "reference": "19526a33fb561ef417e822e85f08a00db4059c17", "shasum": "" }, "require": { @@ -4899,28 +5373,28 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.4" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.16.0" }, - "time": "2023-03-05T19:49:14+00:00" + "time": "2023-06-25T14:52:30+00:00" }, { "name": "orchestra/testbench", - "version": "v6.27.1", + "version": "v6.28.0", "source": { "type": "git", "url": "https://github.com/orchestral/testbench.git", - "reference": "b78f91f17bb86981e73dfbe786f055064c11539d" + "reference": "554949455a88e5afe31f3f7aa3c7104ab659995b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/orchestral/testbench/zipball/b78f91f17bb86981e73dfbe786f055064c11539d", - "reference": "b78f91f17bb86981e73dfbe786f055064c11539d", + "url": "https://api.github.com/repos/orchestral/testbench/zipball/554949455a88e5afe31f3f7aa3c7104ab659995b", + "reference": "554949455a88e5afe31f3f7aa3c7104ab659995b", "shasum": "" }, "require": { - "laravel/framework": "^8.83.26", + "laravel/framework": "^8.83.27", "mockery/mockery": "^1.4.4", - "orchestra/testbench-core": "^6.31.1", + "orchestra/testbench-core": "^6.32", "php": "^7.3 || ^8.0", "phpunit/phpunit": "^8.5.21 || ^9.5.10", "spatie/laravel-ray": "^1.29.7" @@ -4947,29 +5421,29 @@ "keywords": [ "BDD", "TDD", + "dev", "laravel", - "orchestra-platform", - "orchestral", + "laravel-packages", "testing" ], "support": { "issues": "https://github.com/orchestral/testbench/issues", - "source": "https://github.com/orchestral/testbench/tree/v6.27.1" + "source": "https://github.com/orchestral/testbench/tree/v6.28.0" }, - "time": "2023-04-03T01:20:40+00:00" + "time": "2023-06-13T05:41:28+00:00" }, { "name": "orchestra/testbench-core", - "version": "v6.31.2", + "version": "v6.32.0", "source": { "type": "git", "url": "https://github.com/orchestral/testbench-core.git", - "reference": "a630f963d45a4aeb6a8771093fa029bf2a8a4f15" + "reference": "12baf011c23e64bfe2a6c89f2eb07602e387f259" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/orchestral/testbench-core/zipball/a630f963d45a4aeb6a8771093fa029bf2a8a4f15", - "reference": "a630f963d45a4aeb6a8771093fa029bf2a8a4f15", + "url": "https://api.github.com/repos/orchestral/testbench-core/zipball/12baf011c23e64bfe2a6c89f2eb07602e387f259", + "reference": "12baf011c23e64bfe2a6c89f2eb07602e387f259", "shasum": "" }, "require": { @@ -4982,7 +5456,6 @@ "laravel/framework": "^8.83.27", "laravel/laravel": "8.x-dev", "mockery/mockery": "^1.4.4", - "orchestra/canvas": "^6.1", "phpunit/phpunit": "^8.5.21 || ^9.5.10", "spatie/laravel-ray": "^1.7.1", "symfony/process": "^5.0" @@ -5036,7 +5509,7 @@ "issues": "https://github.com/orchestral/testbench/issues", "source": "https://github.com/orchestral/testbench-core" }, - "time": "2023-04-11T07:42:07+00:00" + "time": "2023-06-13T04:58:55+00:00" }, { "name": "phar-io/manifest", @@ -5151,16 +5624,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.26", + "version": "9.2.27", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1" + "reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", - "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/b0a88255cb70d52653d80c890bd7f38740ea50d1", + "reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1", "shasum": "" }, "require": { @@ -5216,7 +5689,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26" + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.27" }, "funding": [ { @@ -5224,7 +5698,7 @@ "type": "github" } ], - "time": "2023-03-06T12:58:08+00:00" + "time": "2023-07-26T13:44:30+00:00" }, { "name": "phpunit/php-file-iterator", @@ -5469,16 +5943,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.7", + "version": "9.6.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "c993f0d3b0489ffc42ee2fe0bd645af1538a63b2" + "reference": "a6d351645c3fe5a30f5e86be6577d946af65a328" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c993f0d3b0489ffc42ee2fe0bd645af1538a63b2", - "reference": "c993f0d3b0489ffc42ee2fe0bd645af1538a63b2", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a6d351645c3fe5a30f5e86be6577d946af65a328", + "reference": "a6d351645c3fe5a30f5e86be6577d946af65a328", "shasum": "" }, "require": { @@ -5552,7 +6026,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.7" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.10" }, "funding": [ { @@ -5568,7 +6042,7 @@ "type": "tidelift" } ], - "time": "2023-04-14T08:58:40+00:00" + "time": "2023-07-10T04:04:23+00:00" }, { "name": "pimple/pimple", @@ -5623,158 +6097,6 @@ }, "time": "2021-10-28T11:13:42+00:00" }, - { - "name": "psr/http-factory", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-factory.git", - "reference": "e616d01114759c4c489f93b099585439f795fe35" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", - "reference": "e616d01114759c4c489f93b099585439f795fe35", - "shasum": "" - }, - "require": { - "php": ">=7.0.0", - "psr/http-message": "^1.0 || ^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interfaces for PSR-7 HTTP message factories", - "keywords": [ - "factory", - "http", - "message", - "psr", - "psr-17", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-factory/tree/1.0.2" - }, - "time": "2023-04-10T20:10:41+00:00" - }, - { - "name": "psr/http-message", - "version": "2.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP messages", - "homepage": "https://github.com/php-fig/http-message", - "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-message/tree/2.0" - }, - "time": "2023-04-04T09:54:51+00:00" - }, - { - "name": "ralouphie/getallheaders", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/ralouphie/getallheaders.git", - "reference": "120b605dfeb996808c31b6477290a714d356e822" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", - "reference": "120b605dfeb996808c31b6477290a714d356e822", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "require-dev": { - "php-coveralls/php-coveralls": "^2.1", - "phpunit/phpunit": "^5 || ^6.5" - }, - "type": "library", - "autoload": { - "files": [ - "src/getallheaders.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ralph Khattar", - "email": "ralph.khattar@gmail.com" - } - ], - "description": "A polyfill for getallheaders.", - "support": { - "issues": "https://github.com/ralouphie/getallheaders/issues", - "source": "https://github.com/ralouphie/getallheaders/tree/develop" - }, - "time": "2019-03-08T08:55:37+00:00" - }, { "name": "sebastian/cli-parser", "version": "1.0.1", @@ -6075,16 +6397,16 @@ }, { "name": "sebastian/diff", - "version": "4.0.4", + "version": "4.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", "shasum": "" }, "require": { @@ -6129,7 +6451,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" }, "funding": [ { @@ -6137,7 +6459,7 @@ "type": "github" } ], - "time": "2020-10-26T13:10:38+00:00" + "time": "2023-05-07T05:35:17+00:00" }, { "name": "sebastian/environment", @@ -6741,16 +7063,16 @@ }, { "name": "spatie/backtrace", - "version": "1.4.0", + "version": "1.5.3", "source": { "type": "git", "url": "https://github.com/spatie/backtrace.git", - "reference": "ec4dd16476b802dbdc6b4467f84032837e316b8c" + "reference": "483f76a82964a0431aa836b6ed0edde0c248e3ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/backtrace/zipball/ec4dd16476b802dbdc6b4467f84032837e316b8c", - "reference": "ec4dd16476b802dbdc6b4467f84032837e316b8c", + "url": "https://api.github.com/repos/spatie/backtrace/zipball/483f76a82964a0431aa836b6ed0edde0c248e3ab", + "reference": "483f76a82964a0431aa836b6ed0edde0c248e3ab", "shasum": "" }, "require": { @@ -6787,7 +7109,7 @@ "spatie" ], "support": { - "source": "https://github.com/spatie/backtrace/tree/1.4.0" + "source": "https://github.com/spatie/backtrace/tree/1.5.3" }, "funding": [ { @@ -6799,20 +7121,20 @@ "type": "other" } ], - "time": "2023-03-04T08:57:24+00:00" + "time": "2023-06-28T12:59:17+00:00" }, { "name": "spatie/laravel-ray", - "version": "1.32.4", + "version": "1.32.6", "source": { "type": "git", "url": "https://github.com/spatie/laravel-ray.git", - "reference": "2274653f0a90dd87fbb887437be1c1ea1388a47c" + "reference": "8526dd6c6c838b4bac4e0df2ea7896b688b0d43e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-ray/zipball/2274653f0a90dd87fbb887437be1c1ea1388a47c", - "reference": "2274653f0a90dd87fbb887437be1c1ea1388a47c", + "url": "https://api.github.com/repos/spatie/laravel-ray/zipball/8526dd6c6c838b4bac4e0df2ea7896b688b0d43e", + "reference": "8526dd6c6c838b4bac4e0df2ea7896b688b0d43e", "shasum": "" }, "require": { @@ -6872,7 +7194,7 @@ ], "support": { "issues": "https://github.com/spatie/laravel-ray/issues", - "source": "https://github.com/spatie/laravel-ray/tree/1.32.4" + "source": "https://github.com/spatie/laravel-ray/tree/1.32.6" }, "funding": [ { @@ -6884,7 +7206,7 @@ "type": "other" } ], - "time": "2023-03-23T08:04:54+00:00" + "time": "2023-07-19T12:30:16+00:00" }, { "name": "spatie/macroable", @@ -6938,16 +7260,16 @@ }, { "name": "spatie/ray", - "version": "1.37.1", + "version": "1.37.2", "source": { "type": "git", "url": "https://github.com/spatie/ray.git", - "reference": "a915e327f04c0fbed3bdd26e076e39feea091062" + "reference": "dea16182d4bc9d9833adec7e39fbb3d7b553425d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/ray/zipball/a915e327f04c0fbed3bdd26e076e39feea091062", - "reference": "a915e327f04c0fbed3bdd26e076e39feea091062", + "url": "https://api.github.com/repos/spatie/ray/zipball/dea16182d4bc9d9833adec7e39fbb3d7b553425d", + "reference": "dea16182d4bc9d9833adec7e39fbb3d7b553425d", "shasum": "" }, "require": { @@ -6998,7 +7320,7 @@ ], "support": { "issues": "https://github.com/spatie/ray/issues", - "source": "https://github.com/spatie/ray/tree/1.37.1" + "source": "https://github.com/spatie/ray/tree/1.37.2" }, "funding": [ { @@ -7010,25 +7332,25 @@ "type": "other" } ], - "time": "2023-03-06T07:22:28+00:00" + "time": "2023-05-17T06:35:47+00:00" }, { "name": "symfony/stopwatch", - "version": "v6.2.7", + "version": "v6.3.0", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "f3adc98c1061875dd2edcd45e5b04e63d0e29f8f" + "reference": "fc47f1015ec80927ff64ba9094dfe8b9d48fe9f2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/f3adc98c1061875dd2edcd45e5b04e63d0e29f8f", - "reference": "f3adc98c1061875dd2edcd45e5b04e63d0e29f8f", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/fc47f1015ec80927ff64ba9094dfe8b9d48fe9f2", + "reference": "fc47f1015ec80927ff64ba9094dfe8b9d48fe9f2", "shasum": "" }, "require": { "php": ">=8.1", - "symfony/service-contracts": "^1|^2|^3" + "symfony/service-contracts": "^2.5|^3" }, "type": "library", "autoload": { @@ -7056,7 +7378,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v6.2.7" + "source": "https://github.com/symfony/stopwatch/tree/v6.3.0" }, "funding": [ { @@ -7072,7 +7394,7 @@ "type": "tidelift" } ], - "time": "2023-02-14T08:44:56+00:00" + "time": "2023-02-16T10:14:28+00:00" }, { "name": "symfony/yaml", @@ -7345,16 +7667,16 @@ }, { "name": "zbateson/stream-decorators", - "version": "1.2.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/zbateson/stream-decorators.git", - "reference": "712b9e7d25dc665a6c64bdba65929bbb6f0932aa" + "reference": "783b034024fda8eafa19675fb2552f8654d3a3e9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zbateson/stream-decorators/zipball/712b9e7d25dc665a6c64bdba65929bbb6f0932aa", - "reference": "712b9e7d25dc665a6c64bdba65929bbb6f0932aa", + "url": "https://api.github.com/repos/zbateson/stream-decorators/zipball/783b034024fda8eafa19675fb2552f8654d3a3e9", + "reference": "783b034024fda8eafa19675fb2552f8654d3a3e9", "shasum": "" }, "require": { @@ -7396,7 +7718,7 @@ ], "support": { "issues": "https://github.com/zbateson/stream-decorators/issues", - "source": "https://github.com/zbateson/stream-decorators/tree/1.2.0" + "source": "https://github.com/zbateson/stream-decorators/tree/1.2.1" }, "funding": [ { @@ -7404,7 +7726,7 @@ "type": "github" } ], - "time": "2023-04-19T16:56:59+00:00" + "time": "2023-05-30T22:51:52+00:00" } ], "aliases": [], @@ -7413,7 +7735,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.4|^8.0" + "php": "^7.2|^7.4|^8.0" }, "platform-dev": [], "plugin-api-version": "2.3.0" diff --git a/config/laravel-spammail-checker.php b/config/laravel-spammail-checker.php new file mode 100644 index 0000000..4931656 --- /dev/null +++ b/config/laravel-spammail-checker.php @@ -0,0 +1,125 @@ + env('SPAM_MAIL_CHECKER_DRIVER', 'local'), + + /* + |-------------------------------------------------------------------------- + | Laravel Spam Email Drivers + |-------------------------------------------------------------------------- + | + | Here you may configure the settings for each driver that is used to check + | if an email address is a spam address. You can add as many drivers as + | you want. + | + */ + + 'drivers' => [ + 'local' => [ + 'path' => realpath(__DIR__ . '/../resources/config/emails.txt'), + 'cache_key' => 'spammailchecker_' . base64_encode(realpath(__DIR__ . '/../resources/config/emails.txt')), + 'cache_ttl' => 60 * 60 * 24 * 7, // 1 week + 'whitelists' => [ + // Email domains that should not be considered as spam, this excludes the domain from the spam check. + // Example: 'gmail.com', 'yahoo.com' + ], + 'blacklists' => [ + // Email domains that should be considered as spam, this includes the domain in the spam check. + // Example: 'mail.ru', 'yandex.ru' + ] + ], + 'remote' => [ + 'timeout' => 5, + 'check_dns' => true, + 'check_smtp' => true, + 'check_mx' => true, + ], + 'abstractapi' => [ + 'api_url' => 'https://emailvalidation.abstractapi.com/v1', + 'api_key' => env('ABSTRACTAPI_API_KEY'), + 'score' => 0.5, // The score threshold to consider an email address as spam. + 'accept_disposable_email' => true, // This option is to be used with caution, as it may block legitimate email addresses. + ], + 'quickemailverification' => [ + 'api_url' => 'https://api.quickemailverification.com/v1', + 'api_key' => env('QUICKEMAILVERIFICATION_API_KEY'), + 'accept_disposable_email' => true, // This option is to be used with caution, as it may block legitimate email addresses. + ], + 'verifalia' => [ + 'api_url' => 'https://api.verifalia.com/v2.4/email-validations', + 'username' => env('VERIFALIA_USERNAME'), + 'password' => env('VERIFALIA_PASSWORD'), + 'accept_disposable_email' => true, // This option is to be used with caution, as it may block legitimate email addresses. + ], + 'sendgrid' => [ + 'api_url' => 'https://api.sendgrid.com/v3/validations/email', + 'api_key' => env('SENDGRID_API_KEY'), + 'score' => 0.5, // The score threshold to consider an email address as spam. + 'accept_disposable_email' => true, // This option is to be used with caution, as it may block legitimate email addresses. + ], + ], + + /* + |-------------------------------------------------------------------------- + | Laravel Spam Email Rule + |-------------------------------------------------------------------------- + | + | Here you may configure the settings for each rule that is used to check + | if an email address is a spam address. You can change the rule to be + | used to check if an email address is a spam address. + | + */ + + 'rule' => 'spammail', // The rule to be used to check if an email address is a spam address. + + /* + |-------------------------------------------------------------------------- + | Laravel Spam Email Error Message + |-------------------------------------------------------------------------- + | + | Here you may configure the error message that is returned when an email + | address is considered as a spam address. + | + */ + + 'error_message' => 'The :attribute is considered as a spam address.', +]; diff --git a/src/Abstracts/Driver.php b/src/Abstracts/Driver.php new file mode 100644 index 0000000..7887040 --- /dev/null +++ b/src/Abstracts/Driver.php @@ -0,0 +1,40 @@ +config = new ConfigBuilder(); + } + + /** + * Validate the email. + * + * @return bool + */ + abstract public function validate(string $email): bool; + + /** + * Get the email domain. + * + * @param string $email + * @return string + */ + protected function getDomain(string $email): string + { + return strtolower(substr(strrchr($email, "@"), 1)); + } +} \ No newline at end of file diff --git a/src/Builders/ConfigBuilder.php b/src/Builders/ConfigBuilder.php new file mode 100644 index 0000000..abb2e0a --- /dev/null +++ b/src/Builders/ConfigBuilder.php @@ -0,0 +1,348 @@ +defaultDriver = Config::get('laravel-spammail-checker.driver'); + $this->drivers = Config::get('laravel-spammail-checker.drivers'); + $this->ruleName = Config::get('laravel-spammail-checker.rule_name'); + $this->errorMessage = Config::get('laravel-spammail-checker.error_message'); + } + + /** + * Get the default driver. + * + * @return string + */ + public function getDefaultDriver(): string + { + return $this->defaultDriver; + } + + /** + * Set the default driver. + * + * @param string $defaultDriver + * @return ConfigBuilder + */ + public function setDefaultDriver(string $defaultDriver): ConfigBuilder + { + $this->defaultDriver = $defaultDriver; + return $this; + } + + /** + * Get the drivers supported by the package. + * + * @return array + */ + public function getDrivers(): array + { + return array_keys($this->drivers); + } + + /** + * Get the api key for the selected driver. + * + * @param string $driver + * @return string + */ + public function getApiKeyForDriver(string $driver): string + { + if (!isset($this->drivers[$driver]['api_key'])) { + throw new SpamMailCheckerApiKeyNotSetException( + 'The selected driver ' . $driver . ' does not use an API key.' + ); + } + return $this->drivers[$driver]['api_key']; + } + + /** + * Get the api url for the selected driver. + * + * @param string $driver + * @return string + */ + public function getApiUrlForDriver(string $driver): string + { + if (!isset($this->drivers[$driver]['api_url'])) { + throw new SpamMailCheckerApiKeyNotSetException( + 'The selected driver ' . $driver . ' does not use an API url.' + ); + } + return $this->drivers[$driver]['api_url']; + } + + /** + * Get the credentials for the selected driver. + * + * @param string $driver + * @return array + */ + public function getCredentialsForDriver(string $driver): array + { + if (!isset($this->drivers[$driver]['username']) || !isset($this->drivers[$driver]['password'])) { + throw new SpamMailCheckerCredentialsNotSetException( + 'The selected driver ' . $driver . ' does not use credentials.' + ); + } + return [ + 'username' => $this->drivers[$driver]['username'], + 'password' => $this->drivers[$driver]['password'] + ]; + } + + /** + * Get the score for the selected driver. + * + * @param string $driver + * @return int + */ + public function getScoreForDriver(string $driver): int + { + if (!isset($this->drivers[$driver]['score'])) { + throw new SpamMailCheckerException( + 'The selected driver ' . $driver . ' does not use a score.' + ); + } + return $this->drivers[$driver]['score']; + } + + /** + * Get the accepts disposable email flag for the selected driver. + * + * @param string $driver + * @return bool + */ + public function getAcceptsDisposableEmailForDriver(string $driver): bool + { + if (!isset($this->drivers[$driver]['accept_disposable_email'])) { + throw new SpamMailCheckerException( + 'The selected driver ' . $driver . ' does not use a score.' + ); + } + return $this->drivers[$driver]['accept_disposable_email']; + } + + /** + * Get the API key for the selected driver. + * + * @return string + * @throws \Martian\SpamMailChecker\Exceptions\SpamMailCheckerApiKeyNotSetException + */ + public function getApiKey(): string + { + if (!array_key_exists('api_key', $this->drivers[$this->defaultDriver])) { + throw new SpamMailCheckerApiKeyNotSetException('The selected driver does not use an API key.'); + } + + $apiKey = $this->drivers[$this->defaultDriver]['api_key']; + + if (empty($apiKey)) { + throw new SpamMailCheckerApiKeyNotSetException('The API key for the selected driver' . $this->defaultDriver . ' is not set.'); + } + + return $apiKey; + } + + /** + * Get the Credentials (Username & Password) for Verifalia driver. + * + * @return array + * @throws \Martian\SpamMailChecker\Exceptions\SpamMailCheckerCredentialsNotSetException + */ + public function getVerifaliaCredentials(): array + { + if ($this->defaultDriver === 'verifalia') { + $username = $this->drivers[$this->defaultDriver]['username']; + $password = $this->drivers[$this->defaultDriver]['password']; + + if (empty($username) || empty($password)) { + throw new SpamMailCheckerCredentialsNotSetException('The credentials for the selected driver' . $this->defaultDriver . ' is not set.'); + } + + return [ + 'username' => $username, + 'password' => $password + ]; + } + + throw new SpamMailCheckerCredentialsNotSetException('The selected driver does not use credentials.'); + } + + /** + * Get the rule name. + * + * @return string + */ + public function getRuleName(): string + { + return $this->ruleName; + } + + /** + * Set the rule name. + * + * @param string $ruleName + * @return ConfigBuilder + */ + public function setRuleName(string $ruleName): ConfigBuilder + { + $this->ruleName = $ruleName; + return $this; + } + + /** + * Get the error message. + * + * @return string + */ + public function getErrorMessage(): string + { + return $this->errorMessage; + } + + /** + * Set the error message. + * + * @param string $errorMessage + * @return ConfigBuilder + */ + public function setErrorMessage(string $errorMessage): ConfigBuilder + { + $this->errorMessage = $errorMessage; + return $this; + } + + /** + * Get Local Cache Key. + * + * @return string + */ + public function getLocalCacheKey(): string + { + return $this->drivers['local']['cache_key']; + } + + /** + * Get Local Cache TTL. + * + * @return int + */ + public function getLocalCacheTTL(): int + { + return $this->drivers['local']['cache_ttl']; + } + + /** + * Get Local Whitelist. + * + * @return array + */ + public function getLocalWhitelist(): array + { + return array_map('strtolower', $this->drivers['local']['whitelist']); + } + + /** + * Get Local Blacklist. + * + * @return array + */ + public function getLocalBlacklist(): array + { + return array_map('strtolower', $this->drivers['local']['blacklist']); + } + + /** + * Get Local Resource Path + * + * @return string + */ + public function getLocalResourcePath(): string + { + return $this->drivers['local']['path']; + } + + /** + * Get Local Resource File Content. + * + * @return string + */ + public function getLocalResourceFileContent(): string + { + if (!file_exists($this->getLocalResourcePath())) { + throw new SpamMailCheckerNotFoundException( + 'The local resource file ' . $this->getLocalResourcePath() . ' was not found.' + ); + } + return file_get_contents($this->getLocalResourcePath()); + } + + /** + * Get Local Resource File Content as Array. + * + * @return array + */ + public function getLocalResourceFileContentAsArray(): array + { + return array_filter( + array_map('trim', explode("\n", $this->getLocalResourceFileContent())) + ); + } + + /** + * Get Local Domain List + * + * @return array + */ + public function getLocalDomainList(): array + { + return collect($this->getLocalResourceFileContentAsArray()) + ->reject(function ($domain) { + return in_array(strtolower($domain), $this->getLocalWhitelist()); + }) + ->merge($this->getLocalBlacklist()) + ->toArray(); + } + +} diff --git a/src/Contracts/DriverInterface.php b/src/Contracts/DriverInterface.php new file mode 100644 index 0000000..4ee6645 --- /dev/null +++ b/src/Contracts/DriverInterface.php @@ -0,0 +1,13 @@ +getDomain($email); + + $cacheKey = $this->config->getLocalCacheKey(); + $cacheTTL = $this->config->getLocalCacheTTL(); + + $domainList = Cache::remember($cacheKey, $cacheTTL, function () { + return $this->config->getLocalDomainList(); + }); + + return !in_array($emailDomain, $domainList); + } +} \ No newline at end of file diff --git a/src/Exceptions/SpamMailCheckerApiKeyNotSetException.php b/src/Exceptions/SpamMailCheckerApiKeyNotSetException.php new file mode 100644 index 0000000..afba0ee --- /dev/null +++ b/src/Exceptions/SpamMailCheckerApiKeyNotSetException.php @@ -0,0 +1,8 @@ + Date: Wed, 2 Aug 2023 16:13:38 +0100 Subject: [PATCH 02/12] added/remote driver setup --- src/Abstracts/Driver.php | 14 ++++++ src/Builders/ConfigBuilder.php | 40 +++++++++++++++++ src/Drivers/LocalDriver.php | 2 +- src/Drivers/RemoteDriver.php | 82 ++++++++++++++++++++++++++++++++++ 4 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 src/Drivers/RemoteDriver.php diff --git a/src/Abstracts/Driver.php b/src/Abstracts/Driver.php index 7887040..30b2cd8 100644 --- a/src/Abstracts/Driver.php +++ b/src/Abstracts/Driver.php @@ -2,8 +2,10 @@ namespace Martian\SpamMailChecker\Abstracts; +use GuzzleHttp\Client; use Martian\SpamMailChecker\Builders\ConfigBuilder; use Martian\SpamMailChecker\Contracts\DriverInterface; +use QuickEmailVerification\Client as QuickEmailVerificationClient; abstract class Driver implements DriverInterface { @@ -12,12 +14,24 @@ abstract class Driver implements DriverInterface */ protected $config; + /** + * @var Client + */ + protected $client; + + /** + * @var QuickEmailVerification + */ + protected $quickEmailVerification; + /** * Driver constructor. */ public function __construct() { $this->config = new ConfigBuilder(); + $this->client = new Client(); + $this->quickEmailVerification = new QuickEmailVerificationClient(); } /** diff --git a/src/Builders/ConfigBuilder.php b/src/Builders/ConfigBuilder.php index abb2e0a..7a32424 100644 --- a/src/Builders/ConfigBuilder.php +++ b/src/Builders/ConfigBuilder.php @@ -345,4 +345,44 @@ public function getLocalDomainList(): array ->toArray(); } + /** + * Get Remote Driver Timeout. + * + * @return int + */ + public function getRemoteDriverTimeout(): int + { + return $this->drivers['remote']['timeout']; + } + + /** + * Get Remote Driver Check DNS. + * + * @return bool + */ + public function getRemoteDriverCheckDNS(): bool + { + return $this->drivers['remote']['check_dns']; + } + + /** + * Get Remote Driver Check SMTP. + * + * @return bool + */ + public function getRemoteDriverCheckSMTP(): bool + { + return $this->drivers['remote']['check_smtp']; + } + + /** + * Get Remote Driver Check MX + * + * @return bool + */ + public function getRemoteDriverCheckMX(): bool + { + return $this->drivers['remote']['check_mx']; + } + } diff --git a/src/Drivers/LocalDriver.php b/src/Drivers/LocalDriver.php index 8c73edc..52a2ce1 100644 --- a/src/Drivers/LocalDriver.php +++ b/src/Drivers/LocalDriver.php @@ -8,7 +8,7 @@ class LocalDriver extends Driver { /** - * Validate the email. + * Validate the email using the local driver. * * @return bool */ diff --git a/src/Drivers/RemoteDriver.php b/src/Drivers/RemoteDriver.php new file mode 100644 index 0000000..1eb0c69 --- /dev/null +++ b/src/Drivers/RemoteDriver.php @@ -0,0 +1,82 @@ +getDomain($email); + + try { + $checkDNS = $this->config->getRemoteDriverCheckDNS(); + $checkSMTP = $this->config->getRemoteDriverCheckSMTP(); + $checkMX = $this->config->getRemoteDriverCheckMX(); + + if ($checkDNS && $this->isDNSValid($emailDomain)) { + return false; + } + + if ($checkSMTP && $this->isSMTPValid($emailDomain)) { + return false; + } + + if ($checkMX && $this->isMXValid($emailDomain)) { + return false; + } + + return true; + } catch (\Exception $e) { + throw new SpamMailCheckerException('Error occurred during email validation.'); + } + } + + /** + * Check if the DNS record is valid for the email domain. + * + * @param string $domain + * @return bool + */ + protected function isDNSValid(string $domain): bool + { + return checkdnsrr($domain, 'ANY'); + } + + /** + * Check if the SMTP server is valid for the email domain. + * + * @param string $domain + * @return bool + */ + protected function isSMTPValid(string $domain): bool + { + $timeout = $this->config->getRemoteDriverTimeout(); + $smtp = fsockopen($domain, 25, $errno, $errstr, $timeout); + if ($smtp) { + fclose($smtp); + return true; + } + return false; + } + + /** + * Check if the MX record is valid for the email domain. + * + * @param string $domain + * @return bool + */ + protected function isMXValid(string $domain): bool + { + return getmxrr($domain, $mxhosts); + } +} From c169c1f2535bc3dd3f5c87d0b788d5b7fc101f1f Mon Sep 17 00:00:00 2001 From: "Endurance, the Martian" Date: Wed, 2 Aug 2023 17:50:41 +0100 Subject: [PATCH 03/12] added/ abtractapi driver setup --- composer.json | 2 +- config/laravel-spammail-checker.php | 6 +- src/Builders/ConfigBuilder.php | 14 +-- src/Drivers/AbstractApiDriver.php | 99 +++++++++++++++++++ src/Drivers/LocalDriver.php | 25 ++++- src/Drivers/RemoteDriver.php | 63 ++++++++---- .../SpamMailCheckerServiceProvider.php | 73 ++++---------- src/SpamMailChecker.php | 8 ++ 8 files changed, 203 insertions(+), 87 deletions(-) create mode 100644 src/Drivers/AbstractApiDriver.php diff --git a/composer.json b/composer.json index a621c7d..e5ee2de 100644 --- a/composer.json +++ b/composer.json @@ -58,7 +58,7 @@ "extra": { "laravel": { "providers": [ - "Martian\\SpamMailChecker\\providers\\SpamMailCheckerServiceProvider" + "Martian\\SpamMailChecker\\Providers\\SpamMailCheckerServiceProvider" ], "aliases": { "SpamMailChecker": "Martian\\SpamMailChecker\\Facades\\SpamMailCheckerFacade" diff --git a/config/laravel-spammail-checker.php b/config/laravel-spammail-checker.php index 4931656..3bac1b3 100644 --- a/config/laravel-spammail-checker.php +++ b/config/laravel-spammail-checker.php @@ -28,7 +28,7 @@ | Supported: "local", "remote", "abstractapi", "quickemailverification", "verifalia", "sendgrid" | | - Local: This driver uses a local file `resources/config/emails.txt` to check if an email address is a spam address. - | - Remote: This driver uses php `getmxrr()` function to check if an email address is a spam address. + | - Remote: This driver uses php in-built functions to check if an email address is a spam address. | - AbstractAPI: This driver uses AbstractAPI to check if an email address is a spam address. | @see https://www.abstractapi.com/email-verification-validation-api | - QuickEmailVerification: This driver uses QuickEmailVerification to check if an email address is a spam address. @@ -58,11 +58,11 @@ 'path' => realpath(__DIR__ . '/../resources/config/emails.txt'), 'cache_key' => 'spammailchecker_' . base64_encode(realpath(__DIR__ . '/../resources/config/emails.txt')), 'cache_ttl' => 60 * 60 * 24 * 7, // 1 week - 'whitelists' => [ + 'whitelist' => [ // Email domains that should not be considered as spam, this excludes the domain from the spam check. // Example: 'gmail.com', 'yahoo.com' ], - 'blacklists' => [ + 'blacklist' => [ // Email domains that should be considered as spam, this includes the domain in the spam check. // Example: 'mail.ru', 'yandex.ru' ] diff --git a/src/Builders/ConfigBuilder.php b/src/Builders/ConfigBuilder.php index 7a32424..a17317c 100644 --- a/src/Builders/ConfigBuilder.php +++ b/src/Builders/ConfigBuilder.php @@ -88,7 +88,7 @@ public function getDrivers(): array */ public function getApiKeyForDriver(string $driver): string { - if (!isset($this->drivers[$driver]['api_key'])) { + if (!array_key_exists('api_key', $this->drivers[$driver])) { throw new SpamMailCheckerApiKeyNotSetException( 'The selected driver ' . $driver . ' does not use an API key.' ); @@ -104,7 +104,7 @@ public function getApiKeyForDriver(string $driver): string */ public function getApiUrlForDriver(string $driver): string { - if (!isset($this->drivers[$driver]['api_url'])) { + if (!array_key_exists('api_url', $this->drivers[$driver])) { throw new SpamMailCheckerApiKeyNotSetException( 'The selected driver ' . $driver . ' does not use an API url.' ); @@ -120,7 +120,7 @@ public function getApiUrlForDriver(string $driver): string */ public function getCredentialsForDriver(string $driver): array { - if (!isset($this->drivers[$driver]['username']) || !isset($this->drivers[$driver]['password'])) { + if (!array_key_exists('username', $this->drivers[$driver]) || !array_key_exists('password', $this->drivers[$driver])) { throw new SpamMailCheckerCredentialsNotSetException( 'The selected driver ' . $driver . ' does not use credentials.' ); @@ -135,11 +135,11 @@ public function getCredentialsForDriver(string $driver): array * Get the score for the selected driver. * * @param string $driver - * @return int + * @return float */ - public function getScoreForDriver(string $driver): int + public function getScoreForDriver(string $driver): float { - if (!isset($this->drivers[$driver]['score'])) { + if (!array_key_exists('score', $this->drivers[$driver])) { throw new SpamMailCheckerException( 'The selected driver ' . $driver . ' does not use a score.' ); @@ -155,7 +155,7 @@ public function getScoreForDriver(string $driver): int */ public function getAcceptsDisposableEmailForDriver(string $driver): bool { - if (!isset($this->drivers[$driver]['accept_disposable_email'])) { + if (!array_key_exists('accept_disposable_email', $this->drivers[$driver])) { throw new SpamMailCheckerException( 'The selected driver ' . $driver . ' does not use a score.' ); diff --git a/src/Drivers/AbstractApiDriver.php b/src/Drivers/AbstractApiDriver.php new file mode 100644 index 0000000..a71eff6 --- /dev/null +++ b/src/Drivers/AbstractApiDriver.php @@ -0,0 +1,99 @@ +apiKey = $this->config->getApiKeyForDriver($this->diverName); + $this->apiUrl = $this->config->getApiUrlForDriver($this->diverName); + $this->score = $this->config->getScoreForDriver($this->diverName); + $this->acceptDisposable = $this->config->getAcceptsDisposableEmailForDriver($this->diverName); + } + + /** + * Validate the email using the remote driver. + * + * @return bool + * @throws SpamMailCheckerValidationException + */ + public function validate(string $email): bool + { + try { + $response = $this->client->request('GET', $this->apiUrl, [ + 'query' => [ + 'email' => $email, + 'api_key' => $this->apiKey, + ], + ]); + + $response = json_decode($response->getBody()->getContents(), true); + + if (floatval($response['quality_score']) < $this->score) { + return false; + } + + if (!$this->acceptDisposable && $response['is_disposable_email']['value']) { + return false; + } + + return true; + } catch (\Exception $e) { + throw new SpamMailCheckerException($e->getMessage()); + } + + } + + public function val(string $email): float + { + try { + $response = $this->client->request('GET', $this->apiUrl, [ + 'query' => [ + 'email' => $email, + 'api_key' => $this->apiKey, + ], + ]); + + $response = json_decode($response->getBody()->getContents(), true); + + return $response['quality_score']; + + } catch (\Exception $e) { + throw new SpamMailCheckerException($e->getMessage()); + } + + } +} diff --git a/src/Drivers/LocalDriver.php b/src/Drivers/LocalDriver.php index 52a2ce1..a412d0d 100644 --- a/src/Drivers/LocalDriver.php +++ b/src/Drivers/LocalDriver.php @@ -7,6 +7,26 @@ class LocalDriver extends Driver { + /** + * @var string + */ + protected $cacheKey; + + /** + * @var int + */ + protected $cacheTTL; + + /** + * Local Driver Constructor. + */ + public function __construct() + { + parent::__construct(); + $this->cacheKey = $this->config->getLocalCacheKey(); + $this->cacheTTL = $this->config->getLocalCacheTTL(); + } + /** * Validate the email using the local driver. * @@ -16,10 +36,7 @@ public function validate(string $email): bool { $emailDomain = $this->getDomain($email); - $cacheKey = $this->config->getLocalCacheKey(); - $cacheTTL = $this->config->getLocalCacheTTL(); - - $domainList = Cache::remember($cacheKey, $cacheTTL, function () { + $domainList = Cache::remember($this->cacheKey, $this->cacheTTL, function () { return $this->config->getLocalDomainList(); }); diff --git a/src/Drivers/RemoteDriver.php b/src/Drivers/RemoteDriver.php index 1eb0c69..9e1de62 100644 --- a/src/Drivers/RemoteDriver.php +++ b/src/Drivers/RemoteDriver.php @@ -4,10 +4,41 @@ use Martian\SpamMailChecker\Abstracts\Driver; use Martian\SpamMailChecker\Exceptions\SpamMailCheckerException; -use Martian\SpamMailChecker\Exceptions\SpamMailCheckerValidationException; class RemoteDriver extends Driver { + /** + * @var bool + */ + protected $checkDNS; + + /** + * @var bool + */ + protected $checkSMTP; + + /** + * @var bool + */ + protected $checkMX; + + /** + * @var int + */ + protected $timeout; + + /** + * Remote Driver Constructor. + */ + public function __construct() + { + parent::__construct(); + $this->checkDNS = $this->config->getRemoteDriverCheckDNS(); + $this->checkSMTP = $this->config->getRemoteDriverCheckSMTP(); + $this->checkMX = $this->config->getRemoteDriverCheckMX(); + $this->timeout = $this->config->getRemoteDriverTimeout(); + } + /** * Validate the email using the remote driver. * @@ -19,21 +50,20 @@ public function validate(string $email): bool $emailDomain = $this->getDomain($email); try { - $checkDNS = $this->config->getRemoteDriverCheckDNS(); - $checkSMTP = $this->config->getRemoteDriverCheckSMTP(); - $checkMX = $this->config->getRemoteDriverCheckMX(); - - if ($checkDNS && $this->isDNSValid($emailDomain)) { - return false; - } + // Check DNS + if ($this->checkDNS && !$this->isDNSValid($emailDomain)) { + return false; + } - if ($checkSMTP && $this->isSMTPValid($emailDomain)) { - return false; - } + // Check SMTP + if ($this->checkSMTP && !$this->isSMTPValid($emailDomain)) { + return false; + } - if ($checkMX && $this->isMXValid($emailDomain)) { - return false; - } + // Check MX + if ($this->checkMX && !$this->isMXValid($emailDomain)) { + return false; + } return true; } catch (\Exception $e) { @@ -49,7 +79,7 @@ public function validate(string $email): bool */ protected function isDNSValid(string $domain): bool { - return checkdnsrr($domain, 'ANY'); + return checkdnsrr($domain, 'A'); } /** @@ -60,8 +90,7 @@ protected function isDNSValid(string $domain): bool */ protected function isSMTPValid(string $domain): bool { - $timeout = $this->config->getRemoteDriverTimeout(); - $smtp = fsockopen($domain, 25, $errno, $errstr, $timeout); + $smtp = fsockopen($domain, 25, $errno, $errstr, $this->timeout); if ($smtp) { fclose($smtp); return true; diff --git a/src/Providers/SpamMailCheckerServiceProvider.php b/src/Providers/SpamMailCheckerServiceProvider.php index b98ba86..58b2b46 100644 --- a/src/Providers/SpamMailCheckerServiceProvider.php +++ b/src/Providers/SpamMailCheckerServiceProvider.php @@ -1,80 +1,43 @@ - * - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ +namespace Martian\SpamMailChecker\Providers; -namespace Martian\SpamMailChecker; use Illuminate\Support\ServiceProvider; -use Illuminate\Support\Facades\Cache; -use Illuminate\Support\Facades\Validator; +use Martian\SpamMailChecker\SpamMailChecker; class SpamMailCheckerServiceProvider extends ServiceProvider { /** - * Indicate if loading of the provider is deferred. - * - */ - protected $defer = false; - - - /** - * Default error message. - * - * @var string - */ - protected $errorMessage = 'The email address is a spam address, please try another one.'; - - - /** - * Bootstrap services. - * - * @return void + * Bootstrap the application services. */ public function boot() { - Validator::extend('spammail', function ($attribute, $value, $parameters, $validator) { - $path = realpath(__DIR__ . '/../resources/config/emails.txt'); - $cacheKey = 'spammailchecker_' . base64_encode($path); - - $data = Cache::rememberForever($cacheKey, function () use ($path) { - return collect(explode("\n", file_get_contents($path))) - ->map(function ($item) { - return strtolower(trim($item)); - }); - }); - // check if the email address domain has any of the spam domains - $value = filter_var($value, FILTER_VALIDATE_EMAIL); - $domain = strtolower(substr(strrchr($value, "@"), 1)); - return !$data->contains($domain); - }, $this->errorMessage); + if ($this->app->runningInConsole()) { + $this->publishes([ + __DIR__ . '/../../config/laravel-spammail-checker.php' => config_path('laravel-spammail-checker.php'), + ], 'config'); + } } - /** - * Register services. - * - * @return void + * Register the application services. */ public function register() { - // - } + // Automatically apply the package configuration + $this->mergeConfigFrom(__DIR__ . '/../../config/laravel-spammail-checker.php', 'laravel-spammail-checker'); + // Register the main class to use with the facade + $this->app->singleton('spammailchecker', function () { + return new SpamMailChecker; + }); + } /** * Get the services provided by the provider. - * - * @return array */ public function provides() { - return ['laravel-spam-email']; + return ['spammailchecker']; } -} +} \ No newline at end of file diff --git a/src/SpamMailChecker.php b/src/SpamMailChecker.php index e69de29..fab76a2 100644 --- a/src/SpamMailChecker.php +++ b/src/SpamMailChecker.php @@ -0,0 +1,8 @@ + Date: Wed, 2 Aug 2023 20:15:00 +0100 Subject: [PATCH 04/12] added/ verifalia driver setup --- composer.json | 6 +- composer.lock | 2 +- config/laravel-spammail-checker.php | 8 +- src/Abstracts/Driver.php | 7 - src/Builders/ConfigBuilder.php | 32 ++++ src/Contracts/AuthenticateInterface.php | 13 ++ src/Drivers/AbstractApiDriver.php | 26 +--- src/Drivers/QuickEmailVerificationDriver.php | 82 ++++++++++ src/Drivers/VerifaliaDriver.php | 152 +++++++++++++++++++ 9 files changed, 293 insertions(+), 35 deletions(-) create mode 100644 src/Contracts/AuthenticateInterface.php create mode 100644 src/Drivers/QuickEmailVerificationDriver.php create mode 100644 src/Drivers/VerifaliaDriver.php diff --git a/composer.json b/composer.json index e5ee2de..4c83dd5 100644 --- a/composer.json +++ b/composer.json @@ -28,10 +28,10 @@ ], "require": { "php": "^7.2|^7.4|^8.0", - "laravel/framework": "^5.0|^6.0|^7.0|^8.0|^9.0|^10.0", "guzzlehttp/guzzle": "^6.0|^7.0", - "quickemailverification/quickemailverification": "*", - "illuminate/support": "^8.0|^9.0|^10.0" + "illuminate/support": "^8.0|^9.0|^10.0", + "laravel/framework": "^5.0|^6.0|^7.0|^8.0|^9.0|^10.0", + "quickemailverification/quickemailverification": "*" }, "require-dev": { "orchestra/testbench": "^6.0", diff --git a/composer.lock b/composer.lock index cfd3e03..8800d9a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "371d850807dbf67e8877900f850744b7", + "content-hash": "b98e14a9bdbe6fcbf714dccb453e1f5c", "packages": [ { "name": "brick/math", diff --git a/config/laravel-spammail-checker.php b/config/laravel-spammail-checker.php index 3bac1b3..ffff448 100644 --- a/config/laravel-spammail-checker.php +++ b/config/laravel-spammail-checker.php @@ -85,7 +85,13 @@ 'accept_disposable_email' => true, // This option is to be used with caution, as it may block legitimate email addresses. ], 'verifalia' => [ - 'api_url' => 'https://api.verifalia.com/v2.4/email-validations', + 'api_url' => 'https://api.verifalia.com/', // The base URL of the Verifalia API. + 'base_uris' => [ + 'https://api-1.verifalia.com/', + 'https://api-2.verifalia.com/', + 'https://api-3.verifalia.com/' + ], + 'version' => 'v2.4', // The version of the Verifalia API to use. 'username' => env('VERIFALIA_USERNAME'), 'password' => env('VERIFALIA_PASSWORD'), 'accept_disposable_email' => true, // This option is to be used with caution, as it may block legitimate email addresses. diff --git a/src/Abstracts/Driver.php b/src/Abstracts/Driver.php index 30b2cd8..eae7515 100644 --- a/src/Abstracts/Driver.php +++ b/src/Abstracts/Driver.php @@ -5,7 +5,6 @@ use GuzzleHttp\Client; use Martian\SpamMailChecker\Builders\ConfigBuilder; use Martian\SpamMailChecker\Contracts\DriverInterface; -use QuickEmailVerification\Client as QuickEmailVerificationClient; abstract class Driver implements DriverInterface { @@ -19,11 +18,6 @@ abstract class Driver implements DriverInterface */ protected $client; - /** - * @var QuickEmailVerification - */ - protected $quickEmailVerification; - /** * Driver constructor. */ @@ -31,7 +25,6 @@ public function __construct() { $this->config = new ConfigBuilder(); $this->client = new Client(); - $this->quickEmailVerification = new QuickEmailVerificationClient(); } /** diff --git a/src/Builders/ConfigBuilder.php b/src/Builders/ConfigBuilder.php index a17317c..055e1c8 100644 --- a/src/Builders/ConfigBuilder.php +++ b/src/Builders/ConfigBuilder.php @@ -163,6 +163,38 @@ public function getAcceptsDisposableEmailForDriver(string $driver): bool return $this->drivers[$driver]['accept_disposable_email']; } + /** + * Get the api version for the selected driver. + * + * @param string $driver + * @return string + */ + public function getApiVersionForDriver(string $driver): string + { + if (!array_key_exists('version', $this->drivers[$driver])) { + throw new SpamMailCheckerException( + 'The selected driver ' . $driver . ' does not use an api version.' + ); + } + return $this->drivers[$driver]['version']; + } + + /** + * Get the base uris for the selected driver. + * + * @param string $driver + * @return array + */ + public function getBaseUrisForDriver(string $driver): array + { + if (!array_key_exists('base_uris', $this->drivers[$driver])) { + throw new SpamMailCheckerException( + 'The selected driver ' . $driver . ' does not use base uris.' + ); + } + return $this->drivers[$driver]['base_uris']; + } + /** * Get the API key for the selected driver. * diff --git a/src/Contracts/AuthenticateInterface.php b/src/Contracts/AuthenticateInterface.php new file mode 100644 index 0000000..778cf19 --- /dev/null +++ b/src/Contracts/AuthenticateInterface.php @@ -0,0 +1,13 @@ +getBody()->getContents(), true); - if (floatval($response['quality_score']) < $this->score) { + if (is_numeric($response['quality_score']) && floatval($response['quality_score']) < $this->score) { return false; } @@ -71,29 +72,8 @@ public function validate(string $email): bool } return true; - } catch (\Exception $e) { + } catch (RequestException $e) { throw new SpamMailCheckerException($e->getMessage()); } - - } - - public function val(string $email): float - { - try { - $response = $this->client->request('GET', $this->apiUrl, [ - 'query' => [ - 'email' => $email, - 'api_key' => $this->apiKey, - ], - ]); - - $response = json_decode($response->getBody()->getContents(), true); - - return $response['quality_score']; - - } catch (\Exception $e) { - throw new SpamMailCheckerException($e->getMessage()); - } - } } diff --git a/src/Drivers/QuickEmailVerificationDriver.php b/src/Drivers/QuickEmailVerificationDriver.php new file mode 100644 index 0000000..36832c2 --- /dev/null +++ b/src/Drivers/QuickEmailVerificationDriver.php @@ -0,0 +1,82 @@ +apiKey = $this->config->getApiKeyForDriver($this->diverName); + $this->acceptDisposable = $this->config->getAcceptsDisposableEmailForDriver($this->diverName); + $this->client = new QuickEmailVerificationClient($this->apiKey); + } + + /** + * Validate the email using the quickemailverification driver. + * + * @return bool + * @throws SpamMailCheckerValidationException + */ + public function validate(string $email): bool + { + try { + $response = $this->getVerificationResponse($email); + + if($response['result'] !== 'valid') { + return false; + } + + if(!$this->acceptDisposable && $response['disposable']) { + return false; + } + + return true; + } catch (\Exception $e) { + throw new SpamMailCheckerException($e->getMessage()); + } + } + + + /** + * Get the email verification response from the client. + * + * @param string $email + * @return array|\stdClass + */ + protected function getVerificationResponse(string $email): array|\stdClass + { + if (function_exists('app') && app()->environment() !== 'production') { + return $this->client->quickemailverification()->sandbox($email)->body; + } else { + return $this->client->quickemailverification()->verify($email)->body; + } + } +} \ No newline at end of file diff --git a/src/Drivers/VerifaliaDriver.php b/src/Drivers/VerifaliaDriver.php new file mode 100644 index 0000000..c12fddd --- /dev/null +++ b/src/Drivers/VerifaliaDriver.php @@ -0,0 +1,152 @@ +credential = $this->config->getCredentialsForDriver($this->diverName); + $this->apiBaseUris = $this->config->getBaseUrisForDriver($this->diverName); + $this->apiUrl = $this->config->getApiUrlForDriver($this->diverName); + $this->allApiUrls = array_merge($this->apiBaseUris, [$this->apiUrl]); + $this->selectedApiUrl = $this->allApiUrls[array_rand($this->allApiUrls)]; + $this->version = $this->config->getApiVersionForDriver($this->diverName); + $this->bearerToken = $this->authenticate(); + $this->acceptDisposable = $this->config->getAcceptsDisposableEmailForDriver($this->diverName); + } + + /** + * Authenticate the driver using the credentials. + * + * @return string + */ + public function authenticate(): string + { + try { + $response = $this->client->request('POST', $this->selectedApiUrl . $this->version . '/auth/tokens', [ + 'json' => [ + 'username' => $this->credential['username'], + 'password' => $this->credential['password'], + ], + ]); + + $response = json_decode($response->getBody()->getContents(), true); + + return $response['accessToken']; + } catch (RequestException $e) { + throw new SpamMailCheckerException($e->getMessage()); + } + } + + /** + * Validate the email using the verifalia driver. + * + * @return bool + * @throws SpamMailCheckerValidationException + */ + public function validate(string $email): bool + { + try { + $response = $this->getVerificationResponse($email); + + if ($response['status'] !== 'Success') { + return false; + } + + if ($response['classification'] !== 'Deliverable') { + return false; + } + + if (!$this->acceptDisposable && $response['isDisposableEmailAddress']) { + return false; + } + + return true; + } catch (\Exception $e) { + throw new SpamMailCheckerException($e->getMessage()); + } + } + + /** + * Get the verification response from the verifalia api. + * + * @param string $email + * @return array + */ + public function getVerificationResponse(string $email): array + { + $response = $this->client->request('POST', $this->selectedApiUrl . $this->version . '/email-validations', [ + 'headers' => [ + 'Authorization' => 'Bearer ' . $this->bearerToken, + 'Accept' => 'application/json', + 'Content-Type' => 'application/json', + ], + 'json' => [ + 'entries' => [ + [ + 'inputData' => $email, + ], + ], + ], + ]); + + $response = json_decode($response->getBody()->getContents(), true); + + return $response['entries']['data'][0]; + } +} From fe5b6f0b168a8c6144d2cc6bab17dd739f81d2ce Mon Sep 17 00:00:00 2001 From: "Endurance, the Martian" Date: Wed, 2 Aug 2023 20:41:35 +0100 Subject: [PATCH 05/12] added/ sendgrid driver setup --- config/laravel-spammail-checker.php | 1 + src/Builders/ConfigBuilder.php | 15 +++++ src/Drivers/LocalDriver.php | 17 +++-- src/Drivers/SendGridDriver.php | 97 +++++++++++++++++++++++++++++ src/Drivers/VerifaliaDriver.php | 82 +++++++++--------------- 5 files changed, 152 insertions(+), 60 deletions(-) create mode 100644 src/Drivers/SendGridDriver.php diff --git a/config/laravel-spammail-checker.php b/config/laravel-spammail-checker.php index ffff448..ba9ff2f 100644 --- a/config/laravel-spammail-checker.php +++ b/config/laravel-spammail-checker.php @@ -101,6 +101,7 @@ 'api_key' => env('SENDGRID_API_KEY'), 'score' => 0.5, // The score threshold to consider an email address as spam. 'accept_disposable_email' => true, // This option is to be used with caution, as it may block legitimate email addresses. + 'source' => 'signup', // The source of the email address to be validated. ], ], diff --git a/src/Builders/ConfigBuilder.php b/src/Builders/ConfigBuilder.php index 055e1c8..0c645bc 100644 --- a/src/Builders/ConfigBuilder.php +++ b/src/Builders/ConfigBuilder.php @@ -179,6 +179,21 @@ public function getApiVersionForDriver(string $driver): string return $this->drivers[$driver]['version']; } + /** + * Get the source for the selected driver. + * + * @return string + */ + public function getSourceForDriver(string $driver): string + { + if (!array_key_exists('source', $this->drivers[$driver])) { + throw new SpamMailCheckerException( + 'The selected driver ' . $driver . ' does not use a source.' + ); + } + return $this->drivers[$driver]['source']; + } + /** * Get the base uris for the selected driver. * diff --git a/src/Drivers/LocalDriver.php b/src/Drivers/LocalDriver.php index a412d0d..2f48636 100644 --- a/src/Drivers/LocalDriver.php +++ b/src/Drivers/LocalDriver.php @@ -4,6 +4,7 @@ use Martian\SpamMailChecker\Abstracts\Driver; use Illuminate\Support\Facades\Cache; +use Martian\SpamMailChecker\Exceptions\SpamMailCheckerException; class LocalDriver extends Driver { @@ -34,12 +35,16 @@ public function __construct() */ public function validate(string $email): bool { - $emailDomain = $this->getDomain($email); + try { + $emailDomain = $this->getDomain($email); - $domainList = Cache::remember($this->cacheKey, $this->cacheTTL, function () { - return $this->config->getLocalDomainList(); - }); + $domainList = Cache::remember($this->cacheKey, $this->cacheTTL, function () { + return $this->config->getLocalDomainList(); + }); - return !in_array($emailDomain, $domainList); + return !in_array($emailDomain, $domainList); + } catch (\Exception $e) { + throw new SpamMailCheckerException($e->getMessage()); + } } -} \ No newline at end of file +} diff --git a/src/Drivers/SendGridDriver.php b/src/Drivers/SendGridDriver.php new file mode 100644 index 0000000..7dafd00 --- /dev/null +++ b/src/Drivers/SendGridDriver.php @@ -0,0 +1,97 @@ +apiKey = $this->config->getApiKeyForDriver($this->diverName); + $this->apiUrl = $this->config->getApiUrlForDriver($this->diverName); + $this->score = $this->config->getScoreForDriver($this->diverName); + $this->acceptDisposable = $this->config->getAcceptsDisposableEmailForDriver($this->diverName); + $this->source = $this->config->getSourceForDriver($this->diverName); + } + + /** + * Validate the email using the sendgrid driver. + * + * @return bool + */ + public function validate(string $email): bool + { + try { + $response = $this->getVerificationResponse($email); + + if ($response['result']['verdict'] !== 'Valid' || $response['result']['score'] > $this->score) { + return false; + } + + if ($response['result']['checks']['domain']['is_suspected_disposable_address'] && $this->acceptDisposable) { + return false; + } + + return true; + } catch (\Exception $e) { + throw new SpamMailCheckerException($e->getMessage()); + } + } + + /** + * Get the response from the sendgrid API. + * + * @return array + */ + protected function getVerificationResponse(string $email): array + { + $response = $this->client->request('GET', $this->apiUrl, [ + 'headers' => [ + 'Authorization' => 'Bearer ' . $this->apiKey, + 'Content-Type' => 'application/json' + ], + 'json' => [ + 'email' => $email, + 'source' => $this->source + ] + ]); + + return json_decode($response->getBody()->getContents(), true); + } +} diff --git a/src/Drivers/VerifaliaDriver.php b/src/Drivers/VerifaliaDriver.php index c12fddd..d4314f4 100644 --- a/src/Drivers/VerifaliaDriver.php +++ b/src/Drivers/VerifaliaDriver.php @@ -12,7 +12,7 @@ class VerifaliaDriver extends Driver implements IAuthenticator /** * @var string */ - protected $diverName = 'verifalia'; + protected $driverName = 'verifalia'; /** * @var string @@ -29,16 +29,6 @@ class VerifaliaDriver extends Driver implements IAuthenticator */ protected $apiUrl; - /** - * @var string - */ - protected $allApiUrls; - - /** - * @var string - */ - protected $selectedApiUrl; - /** * @var string */ @@ -54,61 +44,53 @@ class VerifaliaDriver extends Driver implements IAuthenticator */ protected $acceptDisposable; - /** - * Verifalia Driver Constructor. - */ public function __construct() { parent::__construct(); - $this->credential = $this->config->getCredentialsForDriver($this->diverName); - $this->apiBaseUris = $this->config->getBaseUrisForDriver($this->diverName); - $this->apiUrl = $this->config->getApiUrlForDriver($this->diverName); - $this->allApiUrls = array_merge($this->apiBaseUris, [$this->apiUrl]); - $this->selectedApiUrl = $this->allApiUrls[array_rand($this->allApiUrls)]; - $this->version = $this->config->getApiVersionForDriver($this->diverName); + $this->initializeConfig(); $this->bearerToken = $this->authenticate(); - $this->acceptDisposable = $this->config->getAcceptsDisposableEmailForDriver($this->diverName); + $this->acceptDisposable = $this->config->getAcceptsDisposableEmailForDriver($this->driverName); + } + + protected function initializeConfig() + { + $this->credential = $this->config->getCredentialsForDriver($this->driverName); + $this->apiBaseUris = $this->config->getBaseUrisForDriver($this->driverName); + $this->apiUrl = $this->config->getApiUrlForDriver($this->driverName); + $this->version = $this->config->getApiVersionForDriver($this->driverName); } - /** - * Authenticate the driver using the credentials. - * - * @return string - */ public function authenticate(): string { try { - $response = $this->client->request('POST', $this->selectedApiUrl . $this->version . '/auth/tokens', [ + $selectedApiUrl = $this->getRandomApiUrl(); + $response = $this->client->request('POST', $selectedApiUrl . $this->version . '/auth/tokens', [ 'json' => [ 'username' => $this->credential['username'], 'password' => $this->credential['password'], ], ]); - $response = json_decode($response->getBody()->getContents(), true); + $responseData = json_decode($response->getBody()->getContents(), true); - return $response['accessToken']; + return $responseData['accessToken']; } catch (RequestException $e) { throw new SpamMailCheckerException($e->getMessage()); } } - /** - * Validate the email using the verifalia driver. - * - * @return bool - * @throws SpamMailCheckerValidationException - */ + protected function getRandomApiUrl(): string + { + $allApiUrls = array_merge($this->apiBaseUris, [$this->apiUrl]); + return $allApiUrls[array_rand($allApiUrls)]; + } + public function validate(string $email): bool { try { $response = $this->getVerificationResponse($email); - if ($response['status'] !== 'Success') { - return false; - } - - if ($response['classification'] !== 'Deliverable') { + if ($response['status'] !== 'Success' || $response['classification'] !== 'Deliverable') { return false; } @@ -122,15 +104,11 @@ public function validate(string $email): bool } } - /** - * Get the verification response from the verifalia api. - * - * @param string $email - * @return array - */ - public function getVerificationResponse(string $email): array + protected function getVerificationResponse(string $email): array { - $response = $this->client->request('POST', $this->selectedApiUrl . $this->version . '/email-validations', [ + $selectedApiUrl = $this->getRandomApiUrl(); + + $response = $this->client->request('POST', $selectedApiUrl . $this->version . '/email-validations', [ 'headers' => [ 'Authorization' => 'Bearer ' . $this->bearerToken, 'Accept' => 'application/json', @@ -138,15 +116,11 @@ public function getVerificationResponse(string $email): array ], 'json' => [ 'entries' => [ - [ - 'inputData' => $email, - ], + ['inputData' => $email], ], ], ]); - $response = json_decode($response->getBody()->getContents(), true); - - return $response['entries']['data'][0]; + return json_decode($response->getBody()->getContents(), true)['entries']['data'][0]; } } From 55bcb14ebf47f2bb84d17b8d659588fc30f07513 Mon Sep 17 00:00:00 2001 From: "Endurance, the Martian" Date: Wed, 2 Aug 2023 20:51:19 +0100 Subject: [PATCH 06/12] setup/ spammailchecker class --- src/SpamMailChecker.php | 88 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 3 deletions(-) diff --git a/src/SpamMailChecker.php b/src/SpamMailChecker.php index fab76a2..edf4c78 100644 --- a/src/SpamMailChecker.php +++ b/src/SpamMailChecker.php @@ -2,7 +2,89 @@ namespace Martian\SpamMailChecker; -class SpamMailChecker +use Martian\SpamMailChecker\Builders\ConfigBuilder; +use Martian\SpamMailChecker\Contracts\DriverInterface; +use Martian\SpamMailChecker\Drivers\AbstractApiDriver; +use Martian\SpamMailChecker\Drivers\LocalDriver; +use Martian\SpamMailChecker\Drivers\QuickEmailVerificationDriver; +use Martian\SpamMailChecker\Drivers\RemoteDriver; +use Martian\SpamMailChecker\Drivers\SendGridDriver; +use Martian\SpamMailChecker\Drivers\VerifaliaDriver; +use Martian\SpamMailChecker\Exceptions\SpamMailCheckerException; + +class SpamMailChecker implements DriverInterface { - -} \ No newline at end of file + /** + * @var string + */ + protected $defaultDriver; + + /** + * @var array + */ + protected $drivers = []; + + /** + * SpamMailChecker constructor. + */ + public function __construct() + { + $this->defaultDriver = (new ConfigBuilder())->getDefaultDriver(); + $this->initializeDrivers(); + } + + /** + * Initialize the drivers. + * + * @return void + */ + protected function initializeDrivers() + { + $this->drivers = [ + 'local' => new LocalDriver(), + 'remote' => new RemoteDriver(), + 'abstractapi' => new AbstractApiDriver(), + 'quickemailverification' => new QuickEmailVerificationDriver(), + 'verifalia' => new VerifaliaDriver(), + 'sendgrid' => new SendGridDriver(), + ]; + } + + /** + * Validate the email using the default driver. + * + * @param string $email + * @return bool + */ + public function validate(string $email): bool + { + if (!isset($this->drivers[$this->defaultDriver])) { + throw new SpamMailCheckerException("Default driver '{$this->defaultDriver}' not found."); + } + return $this->drivers[$this->defaultDriver]->validate(filter_var($email, FILTER_SANITIZE_EMAIL)); + } + /** + * Set the default driver to use for email validation. + * + * @param string $driverName + * @throws SpamMailCheckerException + */ + public function setDefaultDriver(string $driverName) + { + if (!isset($this->drivers[$driverName])) { + throw new SpamMailCheckerException("Driver '{$driverName}' not found."); + } + + $this->defaultDriver = $driverName; + } + + /** + * Get the list of available drivers. + * + * @return array + */ + public function getAvailableDrivers(): array + { + return array_keys($this->drivers); + } +} From 33dbac9c6690fe212686f99ae0493e576d14757b Mon Sep 17 00:00:00 2001 From: "Endurance, the Martian" Date: Wed, 2 Aug 2023 20:53:38 +0100 Subject: [PATCH 07/12] changes/ facade to handle static method --- src/Facades/SpamMailCheckerFacade.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Facades/SpamMailCheckerFacade.php b/src/Facades/SpamMailCheckerFacade.php index 99d9e47..7ca9a4a 100644 --- a/src/Facades/SpamMailCheckerFacade.php +++ b/src/Facades/SpamMailCheckerFacade.php @@ -9,6 +9,14 @@ class SpamMailCheckerFacade extends Facade /** * Get the registered name of the component. * + * This method returns the key used to resolve the service from the Laravel container. + * In this case, it returns 'spammailchecker', which is the service container binding key + * for the `SpamMailChecker` class. + * + * @see \Martian\SpamMailChecker\SpamMailChecker + * + * @method static bool validate(string $email) + * * @return string */ protected static function getFacadeAccessor(): string From a9e0be47ea97bfad2e40a6d69b5949e1dca0d532 Mon Sep 17 00:00:00 2001 From: "Endurance, the Martian" Date: Wed, 2 Aug 2023 21:06:42 +0100 Subject: [PATCH 08/12] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20refactor/=20service?= =?UTF-8?q?=20provider=20to=20support=20drivers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SpamMailCheckerServiceProvider.php | 22 +++++++++++- tests/TestCase.php | 34 +++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 tests/TestCase.php diff --git a/src/Providers/SpamMailCheckerServiceProvider.php b/src/Providers/SpamMailCheckerServiceProvider.php index 58b2b46..b938260 100644 --- a/src/Providers/SpamMailCheckerServiceProvider.php +++ b/src/Providers/SpamMailCheckerServiceProvider.php @@ -2,9 +2,10 @@ namespace Martian\SpamMailChecker\Providers; +use Illuminate\Support\Facades\Validator; use Illuminate\Support\ServiceProvider; use Martian\SpamMailChecker\SpamMailChecker; - +use Martian\SpamMailChecker\Builders\ConfigBuilder; class SpamMailCheckerServiceProvider extends ServiceProvider { /** @@ -12,11 +13,17 @@ class SpamMailCheckerServiceProvider extends ServiceProvider */ public function boot() { + // Depreciation Notice + trigger_deprecation('martian/spammailchecker', '1.0.0', 'This package is deprecated and will no longer be maintained. Please use version 2.0.0 or higher.'); + if ($this->app->runningInConsole()) { $this->publishes([ __DIR__ . '/../../config/laravel-spammail-checker.php' => config_path('laravel-spammail-checker.php'), ], 'config'); } + + // Extend Validator + $this->extendValidator(); } /** @@ -33,6 +40,19 @@ public function register() }); } + /** + * Extend SpamMailChecker Validation Rule + * + * @return void + */ + protected function extendValidator() + { + $configBuilder = new ConfigBuilder; + Validator::extend($configBuilder->getRuleName(), function ($attribute, $value, $parameters, $validator) { + return app('spammailchecker')->validate($value); + }, $configBuilder->getErrorMessage()); + } + /** * Get the services provided by the provider. */ diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..4733c89 --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,34 @@ +SpamMailCheckerFacade::class, + ]; + } +} \ No newline at end of file From efe385aa44d320f2a5048fce22d625bb9f32e071 Mon Sep 17 00:00:00 2001 From: "Endurance, the Martian" Date: Wed, 2 Aug 2023 21:22:17 +0100 Subject: [PATCH 09/12] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20refactor/=20cleanups?= =?UTF-8?q?=20to=20main=20class=20--bug=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/laravel-spammail-checker.php | 2 +- src/Builders/ConfigBuilder.php | 6 +-- src/SpamMailChecker.php | 83 +++++++++++------------------ 3 files changed, 35 insertions(+), 56 deletions(-) diff --git a/config/laravel-spammail-checker.php b/config/laravel-spammail-checker.php index ba9ff2f..9d8429c 100644 --- a/config/laravel-spammail-checker.php +++ b/config/laravel-spammail-checker.php @@ -40,7 +40,7 @@ | */ - 'driver' => env('SPAM_MAIL_CHECKER_DRIVER', 'local'), + 'default' => env('SPAM_MAIL_CHECKER_DEFAULT_DRIVER', 'local'), /* |-------------------------------------------------------------------------- diff --git a/src/Builders/ConfigBuilder.php b/src/Builders/ConfigBuilder.php index 0c645bc..4ba65ac 100644 --- a/src/Builders/ConfigBuilder.php +++ b/src/Builders/ConfigBuilder.php @@ -10,8 +10,6 @@ class ConfigBuilder { - // Get all the required config setters and getters from the config file - /** * @var string */ @@ -42,9 +40,9 @@ class ConfigBuilder */ public function __construct() { - $this->defaultDriver = Config::get('laravel-spammail-checker.driver'); + $this->defaultDriver = Config::get('laravel-spammail-checker.default'); $this->drivers = Config::get('laravel-spammail-checker.drivers'); - $this->ruleName = Config::get('laravel-spammail-checker.rule_name'); + $this->ruleName = Config::get('laravel-spammail-checker.rule'); $this->errorMessage = Config::get('laravel-spammail-checker.error_message'); } diff --git a/src/SpamMailChecker.php b/src/SpamMailChecker.php index edf4c78..8ca6f88 100644 --- a/src/SpamMailChecker.php +++ b/src/SpamMailChecker.php @@ -2,52 +2,60 @@ namespace Martian\SpamMailChecker; -use Martian\SpamMailChecker\Builders\ConfigBuilder; use Martian\SpamMailChecker\Contracts\DriverInterface; +use Martian\SpamMailChecker\Exceptions\SpamMailCheckerException; +use Martian\SpamMailChecker\Builders\ConfigBuilder; use Martian\SpamMailChecker\Drivers\AbstractApiDriver; use Martian\SpamMailChecker\Drivers\LocalDriver; use Martian\SpamMailChecker\Drivers\QuickEmailVerificationDriver; use Martian\SpamMailChecker\Drivers\RemoteDriver; use Martian\SpamMailChecker\Drivers\SendGridDriver; use Martian\SpamMailChecker\Drivers\VerifaliaDriver; -use Martian\SpamMailChecker\Exceptions\SpamMailCheckerException; class SpamMailChecker implements DriverInterface { /** - * @var string - */ - protected $defaultDriver; - - /** - * @var array + * @var DriverInterface */ - protected $drivers = []; + protected $driver; /** * SpamMailChecker constructor. + * + * @throws SpamMailCheckerException */ public function __construct() { - $this->defaultDriver = (new ConfigBuilder())->getDefaultDriver(); - $this->initializeDrivers(); + $configBuilder = new ConfigBuilder(); + $defaultDriver = $configBuilder->getDefaultDriver(); + $this->driver = $this->initializeDriver($defaultDriver); } /** - * Initialize the drivers. - * - * @return void + * Initialize the driver based on the default driver configuration. + * + * @param string $defaultDriver + * @return DriverInterface + * @throws SpamMailCheckerException */ - protected function initializeDrivers() + protected function initializeDriver(string $defaultDriver): DriverInterface { - $this->drivers = [ - 'local' => new LocalDriver(), - 'remote' => new RemoteDriver(), - 'abstractapi' => new AbstractApiDriver(), - 'quickemailverification' => new QuickEmailVerificationDriver(), - 'verifalia' => new VerifaliaDriver(), - 'sendgrid' => new SendGridDriver(), - ]; + switch ($defaultDriver) { + case 'abstractapi': + return new AbstractApiDriver(); + case 'quickemailverification': + return new QuickEmailVerificationDriver(); + case 'verifalia': + return new VerifaliaDriver(); + case 'sendgrid': + return new SendGridDriver(); + case 'local': + return new LocalDriver(); + case 'remote': + return new RemoteDriver(); + default: + throw new SpamMailCheckerException("Driver '{$defaultDriver}' not found."); + } } /** @@ -58,33 +66,6 @@ protected function initializeDrivers() */ public function validate(string $email): bool { - if (!isset($this->drivers[$this->defaultDriver])) { - throw new SpamMailCheckerException("Default driver '{$this->defaultDriver}' not found."); - } - return $this->drivers[$this->defaultDriver]->validate(filter_var($email, FILTER_SANITIZE_EMAIL)); - } - /** - * Set the default driver to use for email validation. - * - * @param string $driverName - * @throws SpamMailCheckerException - */ - public function setDefaultDriver(string $driverName) - { - if (!isset($this->drivers[$driverName])) { - throw new SpamMailCheckerException("Driver '{$driverName}' not found."); - } - - $this->defaultDriver = $driverName; - } - - /** - * Get the list of available drivers. - * - * @return array - */ - public function getAvailableDrivers(): array - { - return array_keys($this->drivers); + return $this->driver->validate($email); } } From 32ca51c3896845b7af1de23b8a63d22900f97be8 Mon Sep 17 00:00:00 2001 From: "Endurance, the Martian" Date: Wed, 2 Aug 2023 22:11:12 +0100 Subject: [PATCH 10/12] =?UTF-8?q?=F0=9F=93=9A=20changes/=20changelog=20wit?= =?UTF-8?q?h=20current=20release=20&=20upcoming?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 39 ++++++++++++++++++++++++++++- config/laravel-spammail-checker.php | 4 +-- src/Builders/ConfigBuilder.php | 2 +- src/SpamMailChecker.php | 2 +- 4 files changed, 42 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad4fdc7..556983f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,43 @@ All notable changes to `spammailchecker` will be documented in this file -## 1.0.0 - 201X-XX-XX +## 1.0.0 - 2022-01-25 (Deprecated) - initial release +- [DEPRECATED] This package is deprecated and will no longer be maintained. Please use version 2.0.0 or higher. + +## 2.0.0 - 2023-07-02 +- [ADDED] Added Laravel 10 support. +- [IMPROVED] Improved compatibility with Laravel versions 5 and above. +- [IMPROVED] Improved the SpamMailChecker class to support multiple API drivers. +- [ADDED] Added driver support for the following email validation services: + - [x] [Local](/resources/config/emails.txt) + - [x] [Remote](https://www.php.net/manual/en/function.getmxrr.php) + - [x] [QuickEmailVerification](https://quickemailverification.com/) + - [x] [Verifalia](https://verifalia.com/) + - [x] [AbstractApi](https://www.abstractapi.com/api/email-verification-validation-api) + - [x] [SendGrid](https://sendgrid.com/solutions/email-validation-api/) + - [ ] [ZeroBounce](https://www.zerobounce.net/) + - [ ] [MailboxValidator](https://www.mailboxvalidator.com/) + - [ ] [EmailListVerify](https://www.emaillistverify.com/) + - [ ] [EmailChecker](https://www.emailchecker.com/) + +- [ADDED] Added the config file `config/laravel-spammail-checker.php` to handle package configuration. +- [ADDED] Added Abstract Driver class `Driver.php` to handle API driver configuration and validation using the `DriverInterface.php` interface. +- [ADDED] Added Config Builder class `ConfigBuilder.php` to handle package configuration building. +- [ADDED] Added Exception classes to handle package exceptions. +- [ADDED] Added SpamMailCheckerServiceProvider to handle package registration and validation rule extension. +- [CHANGED] The SpamMailChecker class now implements the DriverInterface. +- [DEPRECATED] Deprecated package versions less than 2.0.0. The package will no longer receive updates for versions 1.0.0 and below. + +## 2.1.0 (Upcoming) +- [ADDED] Added support for Laravel 11. +- [ADDED] Added support for the rest of the email validation services. + - [ ] [ZeroBounce](https://www.zerobounce.net/) + - [ ] [MailboxValidator](https://www.mailboxvalidator.com/) + - [ ] [EmailListVerify](https://www.emaillistverify.com/) + - [ ] [EmailChecker](https://www.emailchecker.com/) +- [IMPROVED] Enhanced error handling and exception messages for better debugging. +- [IMPROVED] Improved package documentation with more examples and usage guidelines. +- [FIXED] Addressed reported issues and bugs from previous versions. +- [IMPROVED] Optimized package code for reduced memory usage and increased speed. \ No newline at end of file diff --git a/config/laravel-spammail-checker.php b/config/laravel-spammail-checker.php index 9d8429c..5110c72 100644 --- a/config/laravel-spammail-checker.php +++ b/config/laravel-spammail-checker.php @@ -55,8 +55,8 @@ 'drivers' => [ 'local' => [ - 'path' => realpath(__DIR__ . '/../resources/config/emails.txt'), - 'cache_key' => 'spammailchecker_' . base64_encode(realpath(__DIR__ . '/../resources/config/emails.txt')), + 'path' => 'resources/config/emails.txt', + 'cache_key' => 'spammailchecker_' . base64_encode('resources/config/emails.txt'), 'cache_ttl' => 60 * 60 * 24 * 7, // 1 week 'whitelist' => [ // Email domains that should not be considered as spam, this excludes the domain from the spam check. diff --git a/src/Builders/ConfigBuilder.php b/src/Builders/ConfigBuilder.php index 4ba65ac..157ecd4 100644 --- a/src/Builders/ConfigBuilder.php +++ b/src/Builders/ConfigBuilder.php @@ -345,7 +345,7 @@ public function getLocalBlacklist(): array */ public function getLocalResourcePath(): string { - return $this->drivers['local']['path']; + return realpath(__DIR__ . '/../../' . $this->drivers['local']['path']); } /** diff --git a/src/SpamMailChecker.php b/src/SpamMailChecker.php index 8ca6f88..9aba9ab 100644 --- a/src/SpamMailChecker.php +++ b/src/SpamMailChecker.php @@ -66,6 +66,6 @@ protected function initializeDriver(string $defaultDriver): DriverInterface */ public function validate(string $email): bool { - return $this->driver->validate($email); + return $this->driver->validate(filter_var($email, FILTER_SANITIZE_EMAIL)); } } From 03b1cdb89980880d7b734dc252afcc0d1c7be413 Mon Sep 17 00:00:00 2001 From: "Endurance, the Martian" Date: Wed, 2 Aug 2023 23:43:27 +0100 Subject: [PATCH 11/12] =?UTF-8?q?=F0=9F=93=9A=20changes/=20readme=20doc=20?= =?UTF-8?q?aligns=20with=20current=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 5 +- README.md | 325 +++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 304 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 556983f..6e20f26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,14 +30,15 @@ All notable changes to `spammailchecker` will be documented in this file - [ADDED] Added SpamMailCheckerServiceProvider to handle package registration and validation rule extension. - [CHANGED] The SpamMailChecker class now implements the DriverInterface. - [DEPRECATED] Deprecated package versions less than 2.0.0. The package will no longer receive updates for versions 1.0.0 and below. +- [ADDED] Add tests for all supported email validation services. ## 2.1.0 (Upcoming) -- [ADDED] Added support for Laravel 11. +- [ADDED] Added support for Laravel ^10x. - [ADDED] Added support for the rest of the email validation services. - [ ] [ZeroBounce](https://www.zerobounce.net/) - [ ] [MailboxValidator](https://www.mailboxvalidator.com/) - [ ] [EmailListVerify](https://www.emaillistverify.com/) - - [ ] [EmailChecker](https://www.emailchecker.com/) + - [ ] [Emailable](https://emailable.com/) - [IMPROVED] Enhanced error handling and exception messages for better debugging. - [IMPROVED] Improved package documentation with more examples and usage guidelines. - [FIXED] Addressed reported issues and bugs from previous versions. diff --git a/README.md b/README.md index ba1055c..7c74108 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,22 @@ -# laravel-spam-email +# Laravel SpamMailChecker [![Latest Stable Version](http://poser.pugx.org/martian/spammailchecker/v)](https://packagist.org/packages/martian/spammailchecker) [![Total Downloads](http://poser.pugx.org/martian/spammailchecker/downloads)](https://packagist.org/packages/martian/spammailchecker) [![Latest Unstable Version](http://poser.pugx.org/martian/spammailchecker/v/unstable)](https://packagist.org/packages/martian/spammailchecker) [![License](http://poser.pugx.org/martian/spammailchecker/license)](https://packagist.org/packages/martian/spammailchecker) [![PHP Version Require](http://poser.pugx.org/martian/spammailchecker/require/php)](https://packagist.org/packages/martian/spammailchecker) [![Made in Nigeria](https://img.shields.io/badge/made%20in-nigeria-008751.svg?style=flat-square)](https://github.com/acekyd/made-in-nigeria) -This package is a Laravel package that checks if an email address is a spammer. It verifies your signups and form submissions to confirm that they are legitimate. + A powerful Laravel package designed to effortlessly validate email addresses against various spam mail providers using a diverse range of drivers. Seamlessly integrated with Laravel's validation system, this package offers comprehensive support for validating email inputs in forms and RESTful APIs + +## Supported Email Validation Services +| Service | Descriptions | Driver | Documentation | Supported | +| -------------------------- | ----------------------------------------------------------------------------------------------------------- | ------------------------ | ----------------------------------------------------------------------------------- | --------- | +| **Local** | A local text list of spam email domains. | *local* | [Read More](/resources/config/emails.txt) | ✅ Yes | +| **Remote** | Using PHP In-built functions `getmxrr()`, `checkdnsrr()`. `fsockopen()` to validate email domain | *remote* | [Read More](https://www.php.net/manual/en/function.getmxrr.php) | ✅ Yes | +| **AbstractApi** | Using Abstract's suite of API to validate email domains | *abstractapi* | [Read More](https://www.abstractapi.com/email-verification-validation-api) | ✅ Yes | +| **QuickEmailVerification** | A reliable, accurate, affordable, and advanced email verification service | *quickemailverification* | [Read More](https://quickemailverification.com/) | ✅ Yes | +| **Verifalia** | A web-based email validation service which allows to upload and validate lists of email addresses with ease | *verifalia* | [Read More](https://verifalia.com/) | ✅ Yes | +| **SendGrid** | A cloud-based SMTP provider that allows you to validate email addresses before you send. | *sendgrid* | [Read More](https://sendgrid.com/solutions/email-api/email-address-validation-api/) | ✅ Yes | + +> **NOTE:** More services will be added soon. (You can also contribute to this project by adding more services - ZeroBounce, Mailboxlayer, EmailListVerify, Emailable, etc) ## Installation @@ -13,16 +25,205 @@ You can install the package via composer: ```bash composer require martian/spammailchecker ``` -- If you are using Laravel 5.5 or higher, you can use the package directly: `composer require 'martian/spammailchecker'`. +- If you are using Laravel 5.5 or higher, you can use the package directly: `composer require 'martian/spammailchecker`. Check [Laravel 5.5 Package Discovery](https://laravel.com/docs/5.5/packages#package-discovery) for more information - If you're using Laravel 5.4 or lower, you'll need to register the service provider. Open `config/app.php` and add the following line to the `providers` array: ```php Martian\SpamMailChecker\SpamMailCheckerServiceProvider::class, ``` +- If you are going to be using the facade, you'll need to register it as well. Open `config/app.php` and add the following line to the `aliases` array: + +```php +'SpamMailChecker' => Martian\SpamMailChecker\Facades\SpamMailChecker::class, +``` + +## Publish Configuration File +Publish the configuration file using the following command: + +```bash +php artisan vendor:publish --provider="Martian\SpamMailChecker\Providers\SpamMailCheckerServiceProvider" +``` + +## Configuration +The configuration file is located at `config/laravel-spammail-checker.php`. You may configure the package to use any of the supported drivers. The default driver is `local` which uses a local text list of spam email domains. + +#### Local Driver Configuration +- In order to use `local`as your driver of choice, you need to set the `default` key in the `config/laravel-spammail-checker.php` configuration file to `local`: + + ```php + 'driver' => 'local', + ``` +- Or you can set the `SPAM_MAIL_CHECKER_DEFAULT_DRIVER` environment variable to `local` in your `.env` file. + + ```env + SPAM_MAIL_CHECKER_DEFAULT_DRIVER=local + ``` +- The local driver uses a local text list of spam email domains. The file is located at `resources/config/emails.txt`. You can include more domains by adding them to the `blacklist` array or exclude domains by adding them to the `whitelist` array. + + ```php + 'drivers' => [ + 'local' => [ + ... + 'whitelist' => [ + // Add domains you want the local driver to ignore here + 'gmail.com', + 'yahoo.com', + ], + 'blacklist' => [ + // Add domains you want the local driver to validate against here + 'mailinator.com', + 'spam.com', + ], + ] + ] + ``` +> **NOTE:** The local driver is case-insensitive. So, you don't need to worry about the case of the email domain. + +#### Remote Driver Configuration +- In order to use `remote` as your driver of choice, you need to set the `default` key in the `config/laravel-spammail-checker.php` configuration file to `remote`: + + ```php + 'driver' => 'remote', + ``` +- Or you can set the `SPAM_MAIL_CHECKER_DEFAULT_DRIVER` environment variable to `remote` in your `.env` file. + + ```env + SPAM_MAIL_CHECKER_DEFAULT_DRIVER=remote + ``` +- The remote driver uses PHP In-built functions `getmxrr()`, `checkdnsrr()`. `fsockopen()` to validate email domain. You can configure the remote driver on whether to check for MX - `getmxrr()`, DNS - `checkdnsrr()`, and SMTP -`fsockopen` or validate email domain. You can also configure the timeout value in seconds. + + ```php + 'drivers' => [ + ... + 'remote' => [ + ... + 'check_dns' => true, // When set to true, it will check for DNS + 'check_smtp' => false, // When set to true, it will check for SMTP + 'check_mx' => false, // When set to true, it will check for MX record + 'timeout' => 60 * 5, // 5 minutes + ] + ] + ``` + +#### AbstractApi Driver Configuration +- In order to use `abstractapi` as your driver of choice, you need to set the `default` key in the `config/laravel-spammail-checker.php` configuration file to `abstractapi`: + + ```env + 'driver' => 'abstractapi', + ``` +- Or you can set the `SPAM_MAIL_CHECKER_DEFAULT_DRIVER` environment variable to `abstractapi` in your `.env` file. + + ```env + SPAM_MAIL_CHECKER_DEFAULT_DRIVER=abstractapi + ``` +- Add your `ABSTRACTAPI_API_KEY` AbstractAPI key you got from [here](https://app.abstractapi.com/dashboard) to your `env` file. + + ``` + ABSTRACTAPI_API_KEY=abstractapi_api_key + ``` +- You can configure the `score` to determine the threshold for a valid email address. The score ranges from 0 to 1. The higher the score, the more likely the email address is valid. You can also accept disposable email addresses by setting `accept_disposable` to `true`. + + ```php + 'drivers' => [ + ... + 'abstractapi' => [ + ... + 'score' => 0.5, // 0.5 is the default score + 'accept_disposable_email' => true // When set to true, it will accept disposable email addresses + ] + ] + ``` + +#### QuickEmailVerification Driver Configuration +- In order to use `quickemailverification` as your driver of choice, you need to set the `default` key in the `config/laravel-spammail-checker.php` configuration file to `quickemailverification`: + + ```env + 'driver' => 'quickemailverification', + ``` +- Or you can set the `SPAM_MAIL_CHECKER_DEFAULT_DRIVER` environment variable to `quickemailverification` in your `.env` file. + + ```env + SPAM_MAIL_CHECKER_DEFAULT_DRIVER=quickemailverification + ``` +- Add your `QUICKEMAILVERIFICATION_API_KEY` QuickEmailVerification key you got from [here](https://quickemailverification.com/dashboard) to your `env` file. + ```env + QUICKEMAILVERIFICATION_API_KEY=quickemailverification_api_key + ``` +- You can configure the driver to accept disposable email addresses by setting `accept_disposable` to `true`. + + ```php + 'drivers' => [ + ... + 'quickemailverification' => [ + ... + 'accept_disposable' => true, // When set to true, it will accept disposable email addresses + ] + ] + ``` + +#### Verifalia Driver Configuration +- In order to use `verifalia` as your driver of choice, you need to set the `default` key in the `config/laravel-spammail-checker.php` configuration file to `verifalia`: + + ```env + 'driver' => 'verifalia', + ``` +- Or you can set the `SPAM_MAIL_CHECKER_DEFAULT_DRIVER` environment variable to `verifalia` in your `.env` file. + + ```env + SPAM_MAIL_CHECKER_DEFAULT_DRIVER=verifalia + ``` +- In order to use verifalia service, you need to set login credentials in your `env` file. You can get your credentials from after you create a user [here](https://verifalia.com/client-area#/users). + + ```env + VERIFALIA_USERNAME=verifalia_username + VERIFALIA_PASSWORD=verifalia_password + ``` + +- You can configure the driver to accept disposable email addresses by setting `accept_disposable` to `true`. + + ```php + 'drivers' => [ + ... + 'verifalia' => [ + ... + 'accept_disposable' => true, // When set to true, it will accept disposable email addresses + ] + ] + ``` +> **NOTE:** A user on verifalia needs to be granted permission to use the API. You can do this by going to [here](https://verifalia.com/client-area#/users) and clicking on the edit user you want to grant permission to. Then click on the `Permissions` tab and check the appropriate permissions on `Email validations` section. + +#### Sendgrid Driver Configuration +- In order to use `sendgrid` as your driver of choice, you need to set the `default` key in the `config/laravel-spammail-checker.php` configuration file to `sendgrid`: + + ```env + 'driver' => 'sendgrid', + ``` +- Or you can set the `SPAM_MAIL_CHECKER_DEFAULT_DRIVER` environment variable to `sendgrid` in your `.env` file. + + ```env + SPAM_MAIL_CHECKER_DEFAULT_DRIVER=sendgrid + ``` +- Add your `SENDGRID_API_KEY` Sendgrid key you got from [here](https://app.sendgrid.com/settings/api_keys) to your `env` file. + ```env + SENDGRID_API_KEY=sendgrid_api_key + ``` +- You can configure the driver to accept disposable email addresses by setting `accept_disposable` to `true`. Score can also be configured to determine the threshold for a valid email address. The score ranges from 0 to 1. The higher the score, the more likely the email address is valid. Source can also be configured to determine the source of the email address. The source can be `signup` or `contact`. + + ```php + 'drivers' => [ + ... + 'sendgrid' => [ + ... + 'score' => 0.5, // 0.5 is the default score + 'accept_disposable' => true, // When set to true, it will accept disposable email addresses + 'source' => 'signup' // The source is signup by default + ] + ] + ``` ## Usage -Make use of `spammail` in your validation rules: +In order to use the package, you need to call the `spammail` validation rule in your validation rules. You can also change the rule name to whatever you want in the `config/laravel-spammail-checker.php` configuration file under the `rule` key, likewise the error message under the `error_message` key. ```php /** @@ -34,7 +235,7 @@ Make use of `spammail` in your validation rules: protected function validator(array $data) { return Validator::make($data, [ - 'email' => 'required|email|spammail|max:255', + 'email' => 'required|spammail|max:255', ]); } ``` @@ -48,28 +249,111 @@ Or make use of `spammail` in your Requests file like this: public function rules() { return [ - 'email' => 'required|email|spammail|max:255', + 'email' => 'required|spammail|max:255', ]; } ``` -Error message shown when the email is a spam: -api screenshot error +#### Adding Custom Error Message +A custom error message can be added to the `spammail` validation rule. + +```php + 'email.spammail' => 'This email address is invalid.', // Custom error message +``` +Or you can change the error message in the `config/laravel-spammail-checker.php` configuration file under the `error_message` key. + +```php + 'error_message' => 'This email address is invalid.', // Custom error message +``` + +#### Using Classes Directly +You can also use the classes directly without using the `spammail` validation rule. This is useful when you want to use the package in your own custom validation rule or your own custom class. + +```php +use Martian\SpamMailChecker\SpamMailChecker; + +public function checkEmail($email) +{ + $spamMailChecker = new SpamMailChecker(); + $spamMailChecker->validate($email); +} +``` + +#### Using Facade + +You can also use the `SpamMailChecker` class directly without instantiating it. + +```php +use Martian\SpamMailChecker\Facades\SpamMailChecker; + +public function checkEmail($email) +{ + SpamMailChecker::validate($email); +} +``` + +#### Using Each Driver Individually +You can also use each driver individually without using the `spammail` validation rule. This is useful when you want to use the package in your own custom validation rule or your own custom class. +##### Using VerifaliaDriver +```php +use Martian\SpamMailChecker\Drivers\VerifaliaDriver; + +public function checkEmail($email) +{ + $verifaliaDriver = new VerifaliaDriver(); + $verifaliaDriver->validate($email); +} +``` +##### Using SendGridDriver +```php +use Martian\SpamMailChecker\Drivers\SendGridDriver; -By default, the error message is: -
-    "email": [
-        "The email address is a spam address, please try another one."
-    ]
-
+public function checkEmail($email) +{ + $sendGridDriver = new SendGridDriver(); + $sendGridDriver->validate($email); +} +``` +##### Using AbstractApiDriver +```php +use Martian\SpamMailChecker\Drivers\AbstractApiDriver; -You can customize the error message by opening `resources/lang/en/validation.php` and adding to the array like so: +public function checkEmail($email) +{ + $abstractApiDriver = new AbstractApiDriver(); + $abstractApiDriver->validate($email); +} +``` +##### Using RemoteDriver +```php +use Martian\SpamMailChecker\Drivers\RemoteDriver; +public function checkEmail($email) +{ + $remoteDriver = new RemoteDriver(); + $remoteDriver->validate($email); +} +``` +##### Using LocalDriver ```php - 'spammail' => 'You are using a spam email address nerd :-P', +use Martian\SpamMailChecker\Drivers\LocalDriver; + +public function checkEmail($email) +{ + $localDriver = new LocalDriver(); + $localDriver->validate($email); +} ``` +##### Using QuickEmailVerificationDriver +```php +use Martian\SpamMailChecker\Drivers\QuickEmailVerificationDriver; -screen shot 2016-07-02 at 2 12 14 pm +public function checkEmail($email) +{ + $quickEmailVerificationDriver = new QuickEmailVerificationDriver(); + $quickEmailVerificationDriver->validate($email); +} +``` ### Testing @@ -93,13 +377,6 @@ If you discover any security related issues, please email hendurhance.dev@gmail. ## Credits - [Josiah Endurance](https://github.com/hendurhance) -- [All Contributors](../../contributors) - -## How to appreciate the work - -Here are some ways you can give back to the project: -- [Star on GitHub](https://github.com/hendurhance/laravel-spam-email) -- Follow me on Twitter [@hendurhance](https://twitter.com/hendurhance) ## License From dadd7614dd23edae0592395500fd06e315319aee Mon Sep 17 00:00:00 2001 From: "Endurance, the Martian" Date: Wed, 2 Aug 2023 23:44:59 +0100 Subject: [PATCH 12/12] =?UTF-8?q?=F0=9F=93=9A=20changes/=20readme=20doc=20?= =?UTF-8?q?aligns=20with=20current=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7c74108..9711cfa 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,12 @@ The configuration file is located at `config/laravel-spammail-checker.php`. You ] ] ``` -> **NOTE:** The local driver is case-insensitive. So, you don't need to worry about the case of the email domain. +- Clear the config and cache using the following commands after making changes to the configuration file: + + ```bash + php artisan optimize:clear + ``` +> **NOTE:** The local driver is case-insensitive. So, you don't need to worry about the case of the email domain. Y #### Remote Driver Configuration - In order to use `remote` as your driver of choice, you need to set the `default` key in the `config/laravel-spammail-checker.php` configuration file to `remote`: