File: /home/storage/5/78/dd/wicomm2/public_html/clientes/performance-healthcheck/result.php
<?php
declare(strict_types=1);
// Debug defensivo: mostra o erro real quando o Apache devolve 500 genérico.
error_reporting(E_ALL);
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
register_shutdown_function(function () {
$e = error_get_last();
if (!$e) return;
if (!in_array($e['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR], true)) return;
// Alguns setups do Apache substituem o corpo quando o status é 500.
// Para não perder a mensagem, respondemos 200 e imprimimos o erro em texto puro.
http_response_code(200);
header('Content-Type: text/plain; charset=utf-8');
echo "PHP fatal error (status forçado 200 para não ser substituído pelo Apache)\n";
echo "Type: {$e['type']}\n";
echo "Message: {$e['message']}\n";
echo "File: {$e['file']}\n";
echo "Line: {$e['line']}\n";
});
set_exception_handler(function (Throwable $e) {
http_response_code(200);
header('Content-Type: text/plain; charset=utf-8');
echo "Uncaught exception (status 200)\n";
echo "Class: " . get_class($e) . "\n";
echo "Message: " . $e->getMessage() . "\n";
echo "File: " . $e->getFile() . "\n";
echo "Line: " . $e->getLine() . "\n";
echo "Trace:\n" . $e->getTraceAsString() . "\n";
exit;
});
set_error_handler(function (int $severity, string $message, string $file, int $line) {
// Converte warnings/notices em exceção para ficar visível.
throw new ErrorException($message, 0, $severity, $file, $line);
});
// Log local para casos em que o browser ainda não mostra.
ini_set('log_errors', '1');
ini_set('error_log', __DIR__ . '/php-error.log');
require __DIR__ . '/config.php';
$config = app_config();
function h(string $v): string {
return htmlspecialchars($v, ENT_QUOTES, 'UTF-8');
}
$id = (string)($_GET['id'] ?? '');
$reportId = (string)($_GET['report_id'] ?? '');
if ($id === '') {
http_response_code(400);
?><!doctype html><html lang="pt-br"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Erro</title><link rel="stylesheet" href="styles.css"></head><body><main class="wrap"><section class="card"><h2>id ausente</h2><p class="muted">Abra esta página como <b>result.php?id=...</b></p><a class="btn" href="./">Voltar</a></section></main></body></html><?php
exit;
}
$error = null;
$client = [];
$history = [];
function md_get_client_strict(array $config, string $id): array {
// 1) Try the standard getter
$client = md_get_client($config, $id);
$name = (string)($client['client_name'] ?? '');
$url = (string)($client['client_url'] ?? '');
if ($name !== '' || $url !== '') return $client;
// 2) Fallback: force _fields on the documents endpoint (some accounts return a minimal doc)
$entity = md_entity($config);
$fields = 'id,client_name,client_url,client_plataform,client_plataforma,performance_history';
$docUrl = vtex_base($config) . "/api/dataentities/{$entity}/documents/{$id}?_fields={$fields}";
$r = http_request('GET', $docUrl, vtex_headers($config), null, 60);
if ($r['ok'] && is_array($r['data'])) {
$client2 = $r['data'];
$name2 = (string)($client2['client_name'] ?? '');
$url2 = (string)($client2['client_url'] ?? '');
if ($name2 !== '' || $url2 !== '') return $client2;
}
// 3) Fallback: locate the record via search and then return it
$rows = md_search_clients($config, 200);
foreach ($rows as $row) {
$rid = (string)($row['id'] ?? ($row['Id'] ?? ($row['documentId'] ?? '')));
if ($rid !== '' && $rid === $id) return $row;
}
return $client;
}
try {
$client = md_get_client_strict($config, $id);
$history = md_history_as_array($client);
} catch (Throwable $e) {
$error = $e->getMessage();
}
// Rodar uma nova análise e salvar no histórico
if (!$error && $_SERVER['REQUEST_METHOD'] === 'POST' && (string)($_POST['action'] ?? '') === 'run') {
$strategy = (string)($_POST['strategy'] ?? 'mobile');
$strategy = in_array($strategy, ['mobile', 'desktop'], true) ? $strategy : 'mobile';
try {
$targetUrl = (string)($client['client_url'] ?? ($client['clientUrl'] ?? ($client['url'] ?? '')));
if ($targetUrl === '') throw new RuntimeException('client_url ausente');
$psi = run_lighthouse($config, $targetUrl, $strategy);
$summary = extract_lighthouse_summary($psi);
$report = gemini_report($config, $client, $summary, $strategy);
$newReportId = bin2hex(random_bytes(8));
$item = [
'report_id' => $newReportId,
'created_at' => now_iso((string)($config['app']['timezone'] ?? 'America/Sao_Paulo')),
'strategy' => $strategy,
'scores' => $summary['scores'] ?? [],
'metrics' => $summary['metrics'] ?? [],
'lighthouse_raw' => $summary['lighthouse_raw'] ?? new stdClass(),
'gemini_report' => $report,
];
$history[] = $item;
md_patch_client($config, $id, ['performance_history' => $history]);
header('Location: result.php?id=' . rawurlencode($id) . '&report_id=' . rawurlencode($newReportId));
exit;
} catch (Throwable $e) {
$error = $e->getMessage();
}
}
// Selecionar item do histórico
$selected = null;
if (!$error && $history) {
if ($reportId !== '') {
foreach ($history as $hitem) {
if (($hitem['report_id'] ?? '') === $reportId) {
$selected = $hitem;
break;
}
}
}
if ($selected === null) {
$selected = $history[count($history) - 1];
}
}
$clientName = (string)($client['client_name'] ?? '');
$clientUrl = (string)($client['client_url'] ?? ($client['clientUrl'] ?? ($client['url'] ?? '')));
$platformRaw = $client['client_plataform'] ?? ($client['client_plataforma'] ?? '');
$platform = is_array($platformRaw) ? json_encode($platformRaw, JSON_UNESCAPED_UNICODE) : (string)$platformRaw;
$scores = $selected['scores'] ?? [];
$scorePerf = isset($scores['performance']) ? (int)$scores['performance'] : null;
$scoreAcc = isset($scores['accessibility']) ? (int)$scores['accessibility'] : null;
$scoreBp = isset($scores['best-practices']) ? (int)$scores['best-practices'] : null;
$scoreSeo = isset($scores['seo']) ? (int)$scores['seo'] : null;
$scorePwa = isset($scores['pwa']) ? (int)$scores['pwa'] : null;
$report = $selected['gemini_report'] ?? [];
$summaryText = (string)($report['summary'] ?? '');
$priority = is_array($report['priority_actions'] ?? null) ? $report['priority_actions'] : [];
$risks = is_array($report['risks'] ?? null) ? $report['risks'] : [];
$notes = is_array($report['notes'] ?? null) ? $report['notes'] : [];
$createdAt = (string)($selected['created_at'] ?? '');
$strategySel = (string)($selected['strategy'] ?? '');
?>
<!doctype html>
<html lang="pt-br">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title><?php echo h($clientName !== '' ? $clientName : 'Histórico'); ?></title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="wrap">
<header class="top">
<div>
<h1><?php echo h($clientName !== '' ? $clientName : 'Cliente'); ?></h1>
<p class="muted">
<?php if ($clientUrl !== ''): ?><?php echo h($clientUrl); ?><?php endif; ?>
<?php if ($platform !== ''): ?> <span class="dot">•</span> <?php echo h($platform); ?><?php endif; ?>
<?php if ($createdAt !== ''): ?> <span class="dot">•</span> <?php echo h($createdAt); ?><?php endif; ?>
<?php if ($strategySel !== ''): ?> <span class="dot">•</span> <?php echo h($strategySel); ?><?php endif; ?>
</p>
</div>
<div class="row">
<a class="btn" href="./">Voltar</a>
</div>
</header>
<?php if ($error): ?>
<section class="card">
<h2>Erro</h2>
<p class="muted"><?php echo h($error); ?></p>
<p class="muted">Se a listagem do index funciona e aqui falha, o ID pode não existir ou o documento pode estar restrito.</p>
</section>
<?php else: ?>
<section class="card">
<h2>Nova análise</h2>
<form method="post" class="row" style="align-items:flex-end; flex-wrap:wrap; gap:12px;">
<input type="hidden" name="action" value="run">
<div style="min-width:220px;">
<label class="muted" for="strategy">Strategy</label>
<select id="strategy" name="strategy" class="input" style="margin-top:6px;">
<option value="mobile">mobile</option>
<option value="desktop">desktop</option>
</select>
</div>
<div>
<button class="btn" type="submit">Rodar e salvar</button>
</div>
<div class="muted" style="padding-bottom:2px;">
A execução chama Lighthouse, depois gera leitura com Gemini, e por fim adiciona um novo objeto no performance_history.
</div>
</form>
</section>
<section class="card" style="margin-top:12px;">
<h2>Histórico</h2>
<?php if (!$history): ?>
<p class="muted">Sem análises salvas ainda.</p>
<?php else: ?>
<div style="overflow:auto;">
<table class="table">
<thead>
<tr>
<th>Data</th>
<th>Strategy</th>
<th>Perf</th>
<th>A11y</th>
<th>BP</th>
<th>SEO</th>
<th>PWA</th>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach (array_reverse($history) as $it): ?>
<?php
$itId = (string)($it['report_id'] ?? '');
$itAt = (string)($it['created_at'] ?? '');
$itSt = (string)($it['strategy'] ?? '');
$itScores = is_array($it['scores'] ?? null) ? $it['scores'] : [];
$itPerf = isset($itScores['performance']) ? (int)$itScores['performance'] : null;
$itAcc = isset($itScores['accessibility']) ? (int)$itScores['accessibility'] : null;
$itBp = isset($itScores['best-practices']) ? (int)$itScores['best-practices'] : null;
$itSeo = isset($itScores['seo']) ? (int)$itScores['seo'] : null;
$itPwa = isset($itScores['pwa']) ? (int)$itScores['pwa'] : null;
$isActive = ($reportId !== '' && $itId === $reportId) || ($reportId === '' && $selected && ($selected['report_id'] ?? '') === $itId);
?>
<tr>
<td><?php echo h($itAt); ?></td>
<td><?php echo h($itSt); ?></td>
<td><?php echo $itPerf === null ? '—' : (int)$itPerf; ?></td>
<td><?php echo $itAcc === null ? '—' : (int)$itAcc; ?></td>
<td><?php echo $itBp === null ? '—' : (int)$itBp; ?></td>
<td><?php echo $itSeo === null ? '—' : (int)$itSeo; ?></td>
<td><?php echo $itPwa === null ? '—' : (int)$itPwa; ?></td>
<td style="white-space:nowrap;">
<a class="btn" style="padding:8px 10px;" href="result.php?id=<?php echo rawurlencode($id); ?>&report_id=<?php echo rawurlencode($itId); ?>"><?php echo $isActive ? 'Aberto' : 'Abrir'; ?></a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</section>
<?php if ($selected): ?>
<section class="cards" style="margin-top:12px;">
<div class="card">
<h2>Scores</h2>
<div class="grid">
<div class="pill"><span>Performance</span><b><?php echo $scorePerf === null ? '—' : (int)$scorePerf; ?></b></div>
<div class="pill"><span>Acessibilidade</span><b><?php echo $scoreAcc === null ? '—' : (int)$scoreAcc; ?></b></div>
<div class="pill"><span>Boas práticas</span><b><?php echo $scoreBp === null ? '—' : (int)$scoreBp; ?></b></div>
<div class="pill"><span>SEO</span><b><?php echo $scoreSeo === null ? '—' : (int)$scoreSeo; ?></b></div>
<div class="pill"><span>PWA</span><b><?php echo $scorePwa === null ? '—' : (int)$scorePwa; ?></b></div>
</div>
</div>
<div class="card">
<h2>Leitura executiva</h2>
<?php if ($summaryText === ''): ?>
<p class="muted">Sem resumo gerado.</p>
<?php else: ?>
<p class="text"><?php echo h($summaryText); ?></p>
<?php endif; ?>
</div>
</section>
<section class="card" style="margin-top:12px;">
<h2>Ações prioritárias</h2>
<?php if (!$priority): ?>
<p class="muted">Sem itens retornados.</p>
<?php else: ?>
<ul class="list">
<?php foreach ($priority as $item): ?>
<?php
$t = (string)($item['title'] ?? '');
$w = (string)($item['why'] ?? '');
$how = (string)($item['how'] ?? '');
$imp = (string)($item['expected_impact'] ?? '');
?>
<li>
<b><?php echo h($t); ?></b>
<?php if ($w !== ''): ?><div class="muted"><?php echo h($w); ?></div><?php endif; ?>
<?php if ($how !== ''): ?><div class="text"><?php echo h($how); ?></div><?php endif; ?>
<?php if ($imp !== ''): ?><div class="tag">Impacto: <?php echo h($imp); ?></div><?php endif; ?>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</section>
<section class="card" style="margin-top:12px;">
<h2>Riscos e observações</h2>
<div class="cols">
<div>
<h3>Riscos</h3>
<?php if (!$risks): ?>
<p class="muted">Sem itens retornados.</p>
<?php else: ?>
<ul class="list">
<?php foreach ($risks as $r): ?>
<?php $rt = (string)($r['title'] ?? ''); $rc = (string)($r['context'] ?? ''); ?>
<li>
<b><?php echo h($rt); ?></b>
<?php if ($rc !== ''): ?><div class="muted"><?php echo h($rc); ?></div><?php endif; ?>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</div>
<div>
<h3>Notas</h3>
<?php if (!$notes): ?>
<p class="muted">Sem itens retornados.</p>
<?php else: ?>
<ul class="list">
<?php foreach ($notes as $n): ?>
<li><?php echo h((string)$n); ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</div>
</div>
</section>
<section class="card" style="margin-top:12px;">
<h2>JSON bruto</h2>
<details>
<summary>Ver Lighthouse completo salvo</summary>
<pre class="code"><?php echo h(json_encode($selected['lighthouse_raw'] ?? new stdClass(), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); ?></pre>
</details>
</section>
<?php endif; ?>
<?php endif; ?>
</main>
</body>
</html>