Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

R medvedev/hw7 #594

Open
wants to merge 10 commits into
base: RMedvedev/main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/vendor/
27 changes: 27 additions & 0 deletions app/Actions/CheckEmailAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace Rofflexor\Hw\Actions;

use Exception;
use Rofflexor\Hw\Tasks\CheckEmailDomainWithDoHTask;
use Rofflexor\Hw\Tasks\CheckEmailTask;

class CheckEmailAction
{
/**
* @throws Exception
*/
public function run(string $email): array
{
$emails = explode(',', $email);
$validatedEmails = [];
foreach($emails as $emailItem) {

Check failure on line 18 in app/Actions/CheckEmailAction.php

View workflow job for this annotation

GitHub Actions / phpcs

Expected 1 space(s) after FOREACH keyword; 0 found
$isValidFormat = (new CheckEmailTask())->run($emailItem);
if($isValidFormat && (new CheckEmailDomainWithDoHTask())->run($emailItem)) {

Check failure on line 20 in app/Actions/CheckEmailAction.php

View workflow job for this annotation

GitHub Actions / phpcs

Expected 1 space(s) after IF keyword; 0 found
$validatedEmails[] = $emailItem;
}
}
return $validatedEmails;
}

}

Check failure on line 27 in app/Actions/CheckEmailAction.php

View workflow job for this annotation

GitHub Actions / phpcs

Expected 1 newline at end of file; 0 found

Check failure on line 27 in app/Actions/CheckEmailAction.php

View workflow job for this annotation

GitHub Actions / phpcs

The closing brace for the class must go on the next line after the body
34 changes: 34 additions & 0 deletions app/Application.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace Rofflexor\Hw;

Check failure on line 3 in app/Application.php

View workflow job for this annotation

GitHub Actions / phpcs

Header blocks must be separated by a single blank line
use Laminas\Diactoros\Response\HtmlResponse;
use MiladRahimi\PhpContainer\Container;
use MiladRahimi\PhpRouter\Exceptions\RouteNotFoundException;
use MiladRahimi\PhpRouter\Router;
use Rofflexor\Hw\Helpers\FileHelper;
use Throwable;

class Application
{

Check failure on line 12 in app/Application.php

View workflow job for this annotation

GitHub Actions / phpcs

Opening brace must not be followed by a blank line

public function run(): void
{
$router = Router::create();
$routes = FileHelper::getDirContents(__DIR__.'/Routes/');

Check failure on line 17 in app/Application.php

View workflow job for this annotation

GitHub Actions / phpcs

Expected at least 1 space before &quot;.&quot;; 0 found

Check failure on line 17 in app/Application.php

View workflow job for this annotation

GitHub Actions / phpcs

Expected at least 1 space after &quot;.&quot;; 0 found
if(!empty($routes)) {

Check failure on line 18 in app/Application.php

View workflow job for this annotation

GitHub Actions / phpcs

Expected 1 space(s) after IF keyword; 0 found
foreach ($routes as $route) {
require_once $route;
}
try {
$router->dispatch();
} catch (RouteNotFoundException $e) {
$router->getPublisher()->publish(new HtmlResponse('Not found.', 404));
} catch (Throwable $e) {
echo $e->getMessage();
$router->getPublisher()->publish(new HtmlResponse('Internal error.', 500));
}
}

}

Check failure on line 32 in app/Application.php

View workflow job for this annotation

GitHub Actions / phpcs

Function closing brace must go on the next line following the body; found 1 blank lines before brace

}
26 changes: 26 additions & 0 deletions app/Controllers/CheckEmailController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace Rofflexor\Hw\Controllers;

use Laminas\Diactoros\Response\JsonResponse;
use MiladRahimi\PhpContainer\Container;
use Rofflexor\Hw\Actions\CheckEmailAction;

class CheckEmailController
{
/**
* @throws \Exception
*/
public function handle(): JsonResponse
{
if(isset($_POST['email'])) {
$validateEmails = (new CheckEmailAction())->run($_POST['string']);
if(count($validateEmails) > 0) {
return new JsonResponse($validateEmails);
}
return new JsonResponse(['message' => 'Нет валидных Email'], 400);
}
return new JsonResponse(['message' => 'Bad request'], 400);
}

}
166 changes: 166 additions & 0 deletions app/Helpers/FileHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
<?php

namespace Rofflexor\Hw\Helpers;

class FileHelper
{
/**
* Check if a file exists in a path or url.
*
* @since 1.1.3
*
* @param string $file → path or file url
*
* @return bool
*/
public static function exists($file)
{
if (filter_var($file, FILTER_VALIDATE_URL)) {
$stream = stream_context_create(['http' => ['method' => 'HEAD']]);
if ($content = @fopen($file, 'r', null, $stream)) {
$headers = stream_get_meta_data($content);
fclose($content);
$status = substr($headers['wrapper_data'][0], 9, 3);

return $status >= 200 && $status < 400;
}

return false;
}

return file_exists($file) && is_file($file);
}

/**
* Delete file.
*
* @since 1.1.3
*
* @param string $file → file path
*
* @return bool
*/
public static function delete($file)
{
return self::exists($file) && @unlink($file);
}

/**
* Create directory.
*
* @since 1.1.3
*
* @param string $path → path where to create directory
*
* @return bool
*/
public static function createDir($path): bool
{
return !is_dir($path) && !mkdir($path, 0777, true) && !is_dir($path);
}

/**
* Copy directory recursively.
*
* @param string $from
* @param string $to
* @return bool
* @since 1.1.4
*
*/
public static function copyDirRecursively(string $from, string $to): bool
{
if (! $path = self::getFilesFromDir($from)) {
return false;
}

self::createDir($to = rtrim($to, '/') . '/');

foreach ($path as $file) {
if ($file->isFile()) {
if (! copy($file->getRealPath(), $to . $file->getFilename())) {
return false;
}
} elseif (! $file->isDot() && $file->isDir()) {
self::copyDirRecursively($file->getRealPath(), $to . $path);
}
}

return true;
}

/**
* Delete empty directory.
*
* @param string $path → path to delete
*
* @return bool
*@since 1.1.3
*
*/
public static function deleteEmptyDir(string $path): bool
{
return is_dir($path) && @rmdir($path);
}

/**
* Delete directory recursively.
*
* @since 1.1.3
*
* @param string $path → path to delete
*
* @return bool
*/
public static function deleteDirRecursively($path): bool
{
if (! $paths = self::getFilesFromDir($path)) {
return false;
}

foreach ($paths as $file) {
if ($file->isFile()) {
if (! self::delete($file->getRealPath())) {
return false;
}
} elseif (! $file->isDot() && $file->isDir()) {
self::deleteDirRecursively($file->getRealPath());
self::deleteEmptyDir($file->getRealPath());
}
}

return self::deleteEmptyDir($path);
}

/**
* Get files from directory.
*
* @param string $path → path where get files
*
* @return object|false →
*@since 1.1.3
*
*/
public static function getFilesFromDir(string $path): false|\DirectoryIterator
{
if (! is_dir($path)) {
return false;
}

return new \DirectoryIterator(rtrim($path, '/') . '/');
}

public static function getDirContents($dir, &$results = array()) {
$files = scandir($dir);
foreach ($files as $key => $value) {
$path = realpath($dir . DIRECTORY_SEPARATOR . $value);
if (!is_dir($path)) {
$results[] = $path;
} else if ($value !== "." && $value !== "..") {
self::getDirContents($path, $results);
$results[] = $path;
}
}
return $results;
}
}
8 changes: 8 additions & 0 deletions app/Routes/route.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

/** @var Router $router */

use MiladRahimi\PhpRouter\Router;
use Rofflexor\Hw\Controllers\CheckEmailController;

$router->post('/', CheckEmailController::class);
65 changes: 65 additions & 0 deletions app/Tasks/CheckEmailDomainWithDoHTask.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

namespace Rofflexor\Hw\Tasks;

use Exception;

class CheckEmailDomainWithDoHTask
{

protected array $defaultServers = [
'Quad9 Foundation' => 'https://dns.quad9.net:5053/dns-query',
'Cloudflare for Teams' => 'https://security.cloudflare-dns.com/dns-query',
'Cloudflare' => 'https://cloudflare-dns.com/dns-query',
'Google' => 'https://dns.google/resolve',
];

/**
* @throws Exception
*/
public function run(string $email): bool
{
$domain = explode('@', $email)[1];

foreach ($this->defaultServers as $serverName => $urlPrefix) {
$url = "$urlPrefix?name={$domain}&type=MX";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['accept: application/dns-json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);

$result = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

curl_close($ch);

if ($result === false || $httpCode !== 200) {
continue;
}

$json = json_decode($result, false, 512, JSON_THROW_ON_ERROR);

if (json_last_error() !== JSON_ERROR_NONE) {
continue;
}

if ($json->Status === 5) {
return false;
}

if ($json->Status !== 0) {
return false;
}

if (!isset($json->Answer) || (isset($json->Answer[0]) && $json->Answer[0]->data === '0.0.0.0')) {
return false;
}
return true;
}

throw new \RuntimeException("The DNS queries to all servers failed while validating domain of email: {$email}. Not sure what's happening but it's likely a problem on our side.");

}

}
11 changes: 11 additions & 0 deletions app/Tasks/CheckEmailTask.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Rofflexor\Hw\Tasks;

class CheckEmailTask
{
public function run(string $email): false|int
{
return filter_var($email, FILTER_VALIDATE_EMAIL);
}
}
19 changes: 19 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "rofflexor/framework",
"type": "project",
"autoload": {
"psr-4": {
"Rofflexor\\Hw\\": "app/"
}
},
"authors": [
{
"name": "Rudolf Medvedev",
"email": "[email protected]"
}
],
"require": {
"miladrahimi/phprouter": "5.*",
"ext-curl": "*"
}
}
Loading
Loading