46 lines
2.8 KiB
PHP
46 lines
2.8 KiB
PHP
<?php
|
|
|
|
use App\Services\LegacyContent;
|
|
|
|
// Exercise the existing presentation adapter against staged originals; no app/DB bootstrap.
|
|
require dirname(__DIR__).'/vendor/autoload.php';
|
|
$root = dirname(__DIR__).'/storage/app/private/investmoz-v2/portal-audit/legacy-sector-reconciliation-20261010';
|
|
$reconciliation = json_decode(file_get_contents($root.'/reconciliation.json'), true, 512, JSON_THROW_ON_ERROR);
|
|
$stage = dirname(__DIR__).'/storage/app/private/document-import-staging/legacy-setores-20261010';
|
|
$adapter = new LegacyContent;
|
|
$checks = [];
|
|
foreach ($reconciliation['articles'] as $article) {
|
|
$bytes = file_get_contents($stage.'/'.$article['file']);
|
|
if (hash('sha256', $bytes) !== $article['library_bytes_sha256']) {
|
|
throw new RuntimeException('Staged source bytes changed.');
|
|
}
|
|
$source = json_decode($bytes, true, 512, JSON_THROW_ON_ERROR);
|
|
$projected = $adapter->sanitize($source['content_html']);
|
|
$doc = new DOMDocument;
|
|
$old = libxml_use_internal_errors(true);
|
|
$doc->loadHTML('<?xml encoding="UTF-8"><html><body>'.$source['content_html'].'</body></html>', LIBXML_NONET);
|
|
libxml_clear_errors();
|
|
libxml_use_internal_errors($old);
|
|
$headings = [];
|
|
foreach ($doc->getElementsByTagName('h1') as $heading) {
|
|
$headings[] = str_contains(html_entity_decode(strip_tags($projected), ENT_QUOTES | ENT_HTML5, 'UTF-8'), $heading->textContent);
|
|
}
|
|
$checks[] = ['legacy_id' => $article['id'], 'original_sha256_preserved' => true,
|
|
'source_h1_count' => count($headings), 'heading_text_preserved' => ! in_array(false, $headings, true),
|
|
'projected_h1_count' => preg_match_all('/<h1\b/i', $projected), 'projection_sha256' => hash('sha256', $projected)];
|
|
}
|
|
$malicious = $adapter->sanitize('<h1 onmouseover="bad()">Título<script>bad()</script><a href="javascript:bad()">Fonte</a></h1>');
|
|
$security = ! preg_match('/<script|javascript:|onmouseover/i', $malicious);
|
|
$passed = $security && ! in_array(false, array_column($checks, 'heading_text_preserved'), true);
|
|
$phase = $argv[1] ?? 'after';
|
|
if (! in_array($phase, ['before', 'after'], true)) {
|
|
exit(2);
|
|
}
|
|
$proof = ['result' => $passed ? 'passed' : 'failed', 'phase' => $phase, 'checks' => $checks,
|
|
'active_markup_removed' => $security, 'database_access' => false, 'interface_accepted' => false];
|
|
file_put_contents($root.'/content-check-'.$phase.'.json', json_encode($proof, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
|
|
echo json_encode(['result' => $proof['result'], 'phase' => $phase, 'articles' => count($checks),
|
|
'missing_heading_articles' => array_values(array_column(array_filter($checks, fn ($c) => ! $c['heading_text_preserved']), 'legacy_id')),
|
|
'active_markup_removed' => $security, 'database_access' => false, 'interface_accepted' => false], JSON_THROW_ON_ERROR).PHP_EOL;
|
|
exit($passed ? 0 : 1);
|