Files
breadcrumb-the-shire/modules/security/pages/security/checks/report($id).php

83 lines
2.8 KiB
PHP

<?php
use MintyPHP\Http\SessionStoreInterface;
use MintyPHP\I18n;
use MintyPHP\Module\Security\SecurityAuthorizationPolicy;
use MintyPHP\Module\Security\Service\SecurityCheckProcess;
use MintyPHP\Module\Security\Service\SecurityCheckService;
use MintyPHP\Module\Security\Service\SecurityReportPdfService;
use MintyPHP\Router;
use MintyPHP\Support\Flash;
use MintyPHP\Support\Guard;
// Streams the generated PDF directly — no view template for this route.
define('MINTY_ALLOW_OUTPUT', true);
Guard::requireLogin();
Guard::requireAbilityOrForbidden(SecurityAuthorizationPolicy::ABILITY_CHECKS_VIEW);
$checkId = (int) ($id ?? 0);
$closeTarget = requestResolveReturnTarget('security/checks');
$editTarget = requestPathWithReturnTarget('security/checks/edit/' . $checkId, requestResolveReturnTarget());
$session = app(SessionStoreInterface::class)->all();
$tenantId = (int) ($session['current_tenant']['id'] ?? 0);
$service = app(SecurityCheckService::class);
$process = app(SecurityCheckProcess::class);
$check = $service->findById($tenantId, $checkId);
if ($check === null) {
Flash::error(t('Security check not found'), $closeTarget, 'security_check_not_found');
Router::redirect($closeTarget);
return;
}
// Re-enforce the gate server-side: the report can only be produced once the
// check has actually been carried out (all preceding steps complete). The UI
// hides the button, but it must not be the only line of defence.
$prerequisitesMet = $process->reportPrerequisitesMet(
is_array($check['process_state'] ?? null) ? $check['process_state'] : [],
is_array($check['tech_schema_snapshot'] ?? null) ? $check['tech_schema_snapshot'] : [],
is_array($check['tech_state'] ?? null) ? $check['tech_state'] : []
);
if (!$prerequisitesMet) {
Flash::error(t('Complete all previous steps before generating the customer report.'), $editTarget, 'security_report_gated');
Router::redirect($editTarget);
return;
}
$pdfService = app(SecurityReportPdfService::class);
$pdf = $pdfService->renderCustomerReportPdf($check, [
'locale' => strtolower((string) (I18n::$locale ?? I18n::$defaultLocale)),
'app_name' => appTitle(),
'tenant_uuid' => (string) ($session['current_tenant']['uuid'] ?? ''),
]);
if ($pdf === '') {
// Concrete renderer/template failures are handled inside the service.
http_response_code(500);
return;
}
$filename = $pdfService->buildReportFilename($check);
header('Content-Type: application/pdf');
header('Content-Disposition: inline; filename="' . $filename . '"');
header('Cache-Control: private, no-store, max-age=0');
header('Pragma: no-cache');
header('X-Content-Type-Options: nosniff');
header('Content-Length: ' . strlen($pdf));
$output = fopen('php://output', 'wb');
if ($output === false) {
http_response_code(500);
return;
}
fwrite($output, $pdf);
fclose($output);