Skip to content

Commit

Permalink
Merge branch '5.x' into feat/no_redirect-http_handler
Browse files Browse the repository at this point in the history
  • Loading branch information
theus77 authored Oct 7, 2023
2 parents 3ba5e7e + b76808f commit 18c9dfc
Show file tree
Hide file tree
Showing 9 changed files with 254 additions and 50 deletions.
4 changes: 3 additions & 1 deletion EMS/helpers/src/File/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@
class File
{
public string $name;
public string $extension;
public string $mimeType;
public int $size;

public const DEFAULT_CHUNK_SIZE = 8 * 1024 * 1024;

private function __construct(private readonly \SplFileInfo $file)
public function __construct(private readonly \SplFileInfo $file)
{
$this->name = $this->file->getFilename();
$this->extension = $this->file->getExtension();
$this->size = Type::integer($this->file->getSize());
$this->mimeType = MimeTypes::getDefault()->guessMimeType($file->getPathname()) ?? 'application/octet-stream';
}
Expand Down
79 changes: 31 additions & 48 deletions elasticms-cli/src/Client/Audit/Report.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@
namespace App\CLI\Client\Audit;

use App\CLI\Client\HttpClient\UrlReport;
use App\CLI\Client\Report\AbstractReport;
use App\CLI\Client\WebToElasticms\Helper\Url;
use EMS\CommonBundle\Common\SpreadsheetGeneratorService;
use EMS\CommonBundle\Contracts\SpreadsheetGeneratorServiceInterface;
use Symfony\Component\HttpFoundation\HeaderUtils;

class Report
class Report extends AbstractReport
{
/** @var string[][] */
private array $accessibilityErrors = [['URL', 'WCAG2AA', 'Accessibility\'s score']];
Expand All @@ -22,50 +20,6 @@ class Report
private array $ignoredLinks = [['URL', 'Error message', 'Referrers']];
/** @var string[][] */
private array $warnings = [['URL', 'Warning message', 'Referrer']];
private readonly SpreadsheetGeneratorService $spreadsheetGeneratorService;

public function __construct()
{
$this->spreadsheetGeneratorService = new SpreadsheetGeneratorService();
}

public function generateXslxReport(): string
{
$config = [
SpreadsheetGeneratorServiceInterface::CONTENT_DISPOSITION => HeaderUtils::DISPOSITION_ATTACHMENT,
SpreadsheetGeneratorServiceInterface::WRITER => SpreadsheetGeneratorServiceInterface::XLSX_WRITER,
SpreadsheetGeneratorServiceInterface::CONTENT_FILENAME => 'Audit-Report.xlsx',
SpreadsheetGeneratorServiceInterface::SHEETS => [
[
'name' => 'Broken links',
'rows' => \array_values($this->brokenLinks),
],
[
'name' => 'Ignored links',
'rows' => \array_values($this->ignoredLinks),
],
[
'name' => 'Warnings',
'rows' => \array_values($this->warnings),
],
[
'name' => 'Accessibility',
'rows' => \array_values($this->accessibilityErrors),
],
[
'name' => 'Security',
'rows' => \array_values($this->securityErrors),
],
],
];
$tmpFilename = \tempnam(\sys_get_temp_dir(), 'WebReport');
if (!\is_string($tmpFilename)) {
throw new \RuntimeException('Not able to generate a temporary filename');
}
$this->spreadsheetGeneratorService->generateSpreadsheetFile($config, $tmpFilename);

return $tmpFilename;
}

public function addAccessibilityError(string $url, int $errorCount, ?float $score): void
{
Expand Down Expand Up @@ -211,4 +165,33 @@ public function setIgnoredLinks(array $ignoredLinks): void
{
$this->ignoredLinks = $ignoredLinks;
}

/**
* @return array{array{name: string, rows: string[][]}}
*/
protected function getSheets(): array
{
return [
[
'name' => 'Broken links',
'rows' => \array_values($this->brokenLinks),
],
[
'name' => 'Ignored links',
'rows' => \array_values($this->ignoredLinks),
],
[
'name' => 'Warnings',
'rows' => \array_values($this->warnings),
],
[
'name' => 'Accessibility',
'rows' => \array_values($this->accessibilityErrors),
],
[
'name' => 'Security',
'rows' => \array_values($this->securityErrors),
],
];
}
}
43 changes: 43 additions & 0 deletions elasticms-cli/src/Client/File/Report.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

declare(strict_types=1);

namespace App\CLI\Client\File;

use App\CLI\Client\Report\AbstractReport;

class Report extends AbstractReport
{
/** @var string[][] */
private array $warnings = [['type', 'file', 'message']];

public function addWarning(string $type, string $filename, string $message): void
{
$this->warnings[] = [
$type,
$filename,
$message,
];
}

/**
* @return string[][]
*/
public function getWarnings(): array
{
return $this->warnings;
}

/**
* @return array{array{name: string, rows: string[][]}}
*/
protected function getSheets(): array
{
return [
[
'name' => 'Warnings',
'rows' => \array_values($this->warnings),
],
];
}
}
41 changes: 41 additions & 0 deletions elasticms-cli/src/Client/Report/AbstractReport.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

namespace App\CLI\Client\Report;

use EMS\CommonBundle\Common\SpreadsheetGeneratorService;
use EMS\CommonBundle\Contracts\SpreadsheetGeneratorServiceInterface;
use Symfony\Component\HttpFoundation\HeaderUtils;

abstract class AbstractReport
{
private readonly SpreadsheetGeneratorService $spreadsheetGeneratorService;

public function __construct()
{
$this->spreadsheetGeneratorService = new SpreadsheetGeneratorService();
}

public function generateXslxReport(): string
{
$config = [
SpreadsheetGeneratorServiceInterface::CONTENT_DISPOSITION => HeaderUtils::DISPOSITION_ATTACHMENT,
SpreadsheetGeneratorServiceInterface::WRITER => SpreadsheetGeneratorServiceInterface::XLSX_WRITER,
SpreadsheetGeneratorServiceInterface::CONTENT_FILENAME => 'Audit-Report.xlsx',
SpreadsheetGeneratorServiceInterface::SHEETS => $this->getSheets(),
];
$tmpFilename = \tempnam(\sys_get_temp_dir(), 'Audit-Report-').'.xlsx';
if (!\is_string($tmpFilename)) {
throw new \RuntimeException('Not able to generate a temporary filename');
}
$this->spreadsheetGeneratorService->generateSpreadsheetFile($config, $tmpFilename);

return $tmpFilename;
}

/**
* @return array{array{name: string, rows: string[][]}}
*/
abstract protected function getSheets(): array;
}
33 changes: 33 additions & 0 deletions elasticms-cli/src/Client/WebToElasticms/Config/ConfigManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ class ConfigManager
/** @var string[] */
private array $validClasses = [];
/** @var string[] */
private array $styleValidTags = [];
/** @var string[] */
private array $locales = [];
/** @var string[] */
private array $linkToClean = [];
Expand Down Expand Up @@ -264,6 +266,22 @@ public function setValidClasses(array $validClasses): void
$this->validClasses = $validClasses;
}

/**
* @return string[]
*/
public function getStyleValidTags(): array
{
return $this->styleValidTags;
}

/**
* @param string[] $styleValidTags
*/
public function setStyleValidTags(array $styleValidTags): void
{
$this->styleValidTags = $styleValidTags;
}

public function findInDocuments(Url $url): ?string
{
foreach ($this->documents as $document) {
Expand Down Expand Up @@ -435,6 +453,11 @@ public function getExpressionLanguage(): ExpressionLanguage
fn ($arguments, $pattern, $str, $limit = -1, $flags = PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY) => (null === $pattern || null === $str) ? null : \preg_split($pattern, (string) $str, $limit, $flags)
);

$this->expressionLanguage->register('match',
fn ($pattern, $str, $flags = 0) => \sprintf('((null === %1$s || null === %2$s) ? null : \\preg_match(%1$s, %2$s, %3$d))', $pattern, $str, $flags),
fn ($arguments, $pattern, $str, $flags = 0) => (null === $pattern || null === $str) ? null : $this->matches($pattern, (string) $str, $flags)
);

$this->expressionLanguage->register('datalinks',
fn ($value, $type) => \sprintf('((null === %1$s || null === %2$s) ? null : (is_array($value) ? \\$this->findDataLinksArray(%1$s, %2$s): $this->findDataLinkString(%1$s, %2$s)))', \strval($value), $type),
fn ($arguments, $value, $type) => (null === $value || null === $type) ? null : (\is_array($value) ? $this->findDataLinksArray($value, $type) : $this->findDataLinkString($value, $type))
Expand All @@ -458,6 +481,16 @@ public function getExpressionLanguage(): ExpressionLanguage
return $this->expressionLanguage;
}

/**
* @return string[]
*/
public function matches(string $pattern, string $str, int $flags): array
{
\preg_match_all($pattern, $str, $matches, $flags);

return $matches['matches'] ?? $matches[0];
}

public function getHashResourcesField(): string
{
return $this->hashResourcesField;
Expand Down
2 changes: 1 addition & 1 deletion elasticms-cli/src/Client/WebToElasticms/Extract/Html.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ private function applyFilters(WebResource $resource, Crawler $content, Extractor
$filter = new InternalLink($this->config, $rapport, $resource->getUrl());
break;
case StyleCleaner::TYPE:
$filter = new StyleCleaner();
$filter = new StyleCleaner($this->config);
break;
case ClassCleaner::TYPE:
$filter = new ClassCleaner($this->config);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,29 @@

namespace App\CLI\Client\WebToElasticms\Filter\Html;

use App\CLI\Client\WebToElasticms\Config\ConfigManager;
use App\CLI\Client\WebToElasticms\Config\WebResource;
use Symfony\Component\DomCrawler\Crawler;

class StyleCleaner implements HtmlInterface
{
final public const TYPE = 'style-cleaner';

public function __construct(private readonly ConfigManager $config)
{
}

public function process(WebResource $resource, Crawler $content): void
{
foreach ($content->filter('[style]') as $item) {
if (!$item instanceof \DOMElement) {
throw new \RuntimeException('Unexpected non DOMElement object');
}

if (\in_array($item->nodeName, $this->config->getStyleValidTags())) {
continue;
}

$item->removeAttribute('style');
}
}
Expand Down
91 changes: 91 additions & 0 deletions elasticms-cli/src/Command/File/AuditFileCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php

declare(strict_types=1);

namespace App\CLI\Command\File;

use App\CLI\Client\File\Report;
use App\CLI\Commands;
use EMS\CommonBundle\Common\Command\AbstractCommand;
use EMS\Helpers\File\File;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Logger\ConsoleLogger;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Mime\MimeTypes;

class AuditFileCommand extends AbstractCommand
{
protected static $defaultName = Commands::FILE_AUDIT;
final public const UPPERCASE_EXTENSION = 'ExtensionWithUppercase';
final public const EXTENSION_MISMATCH = 'ExtensionMismatch';

private const ARG_FOLDER = 'folder';
private ConsoleLogger $logger;
private string $folder;
private MimeTypes $mimeTypes;
private Report $report;

public function __construct()
{
$this->mimeTypes = new MimeTypes();
$this->report = new Report();
parent::__construct();
}

protected function configure(): void
{
$this
->setDescription('Audit files in a folder structure')
->addArgument(
self::ARG_FOLDER,
InputArgument::REQUIRED,
'Path of the folder structure'
);
}

protected function initialize(InputInterface $input, OutputInterface $output): void
{
parent::initialize($input, $output);
$this->logger = new ConsoleLogger($output);
$this->folder = $this->getArgumentString(self::ARG_FOLDER);
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$this->io->title(\sprintf('Audit files in %s', $this->folder));
$finder = new Finder();
$finder->files()->in($this->folder);

if (!$finder->hasResults()) {
throw new \RuntimeException('No files found!');
}
$this->io->comment(\sprintf('%d files located', $finder->count()));
$progressBar = $this->io->createProgressBar($finder->count());
foreach ($finder as $file) {
$pathInStructure = \substr($file->getPathname(), \strlen($this->folder));
$info = new File($file);
$extension = \strtolower($info->extension);
if ($extension !== $info->extension) {
$this->log(self::UPPERCASE_EXTENSION, $pathInStructure, \sprintf('The extension %s contains uppercase', $info->extension));
}
if (!\in_array($extension, $this->mimeTypes->getExtensions($info->mimeType))) {
$this->log(self::EXTENSION_MISMATCH, $pathInStructure, \sprintf('The extension %s mismatch with the mime type %s', $info->extension, $info->mimeType));
}
$progressBar->advance();
}

$progressBar->finish();
$this->io->newLine();
$this->io->writeln(\sprintf('Audit report: %s', $this->report->generateXslxReport()));

return self::EXECUTE_SUCCESS;
}

private function log(string $type, string $filename, string $message): void
{
$this->report->addWarning($type, $filename, $message);
$this->logger->warning(\sprintf('%s: %s', $filename, $message));
}
}
Loading

0 comments on commit 18c9dfc

Please sign in to comment.