Initial commit: Proyecto Portal ePromos completo con documentación unificada y seguridad base
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
// ruleta/admin/dashboard_landing_widget_data.php
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
// No HTML en errores:
|
||||
ini_set('display_errors', '0');
|
||||
ini_set('log_errors', '1');
|
||||
|
||||
// Captura warnings/notices para adjuntarlos al JSON:
|
||||
$php_warnings = [];
|
||||
set_error_handler(function($errno, $errstr, $errfile, $errline) use (&$php_warnings) {
|
||||
if (error_reporting() === 0) return true;
|
||||
$php_warnings[] = "$errstr in $errfile:$errline";
|
||||
return true;
|
||||
});
|
||||
|
||||
// Limpia cualquier output previo
|
||||
while (ob_get_level() > 0) { ob_end_clean(); }
|
||||
ob_start();
|
||||
|
||||
session_start();
|
||||
require_once __DIR__ . '/db.php';
|
||||
if (empty($_SESSION['admin_id'])) {
|
||||
http_response_code(401);
|
||||
echo json_encode(['ok'=>false, 'error'=>'auth']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Helper seguro para prepares
|
||||
function must_prepare(mysqli $conn, string $sql): mysqli_stmt {
|
||||
$st = $conn->prepare($sql);
|
||||
if (!$st) {
|
||||
throw new RuntimeException('prepare_failed: '. $conn->error .' | SQL='. preg_replace('/\s+/', ' ', $sql));
|
||||
}
|
||||
return $st;
|
||||
}
|
||||
function qcount(mysqli $conn, string $sql): int {
|
||||
$rs = $conn->query($sql);
|
||||
if (!$rs) throw new RuntimeException('query_failed: '. $conn->error .' | SQL='. preg_replace('/\s+/', ' ', $sql));
|
||||
$row = $rs->fetch_assoc();
|
||||
return (int)($row['c'] ?? 0);
|
||||
}
|
||||
|
||||
try {
|
||||
$from = trim($_GET['from'] ?? '');
|
||||
$to = trim($_GET['to'] ?? '');
|
||||
$landing_id = (int)($_GET['landing_id'] ?? 0);
|
||||
$want_meta = (int)($_GET['meta'] ?? 0);
|
||||
|
||||
if ($from === '' || $to === '') {
|
||||
$to = date('Y-m-d');
|
||||
$from = date('Y-m-d', strtotime($to.' -30 day'));
|
||||
}
|
||||
$from_dt = $from.' 00:00:00';
|
||||
$to_dt = $to.' 23:59:59';
|
||||
|
||||
// --- KPIs
|
||||
$kpis = [
|
||||
'landings' => qcount($conn, "SELECT COUNT(*) c FROM landing_pages"),
|
||||
'variants' => qcount($conn, "SELECT COUNT(*) c FROM landing_variants"),
|
||||
'blocks' => qcount($conn, "SELECT COUNT(*) c FROM landing_blocks"),
|
||||
'leads_window' => 0,
|
||||
'range_label' => date('d M', strtotime($from)).' - '.date('d M', strtotime($to)),
|
||||
'filtered' => $landing_id > 0
|
||||
];
|
||||
|
||||
if ($landing_id > 0) {
|
||||
$st = must_prepare($conn, "SELECT COUNT(*) c FROM landing_forms WHERE landing_id=? AND created_at BETWEEN ? AND ?");
|
||||
$st->bind_param('iss', $landing_id, $from_dt, $to_dt);
|
||||
} else {
|
||||
$st = must_prepare($conn, "SELECT COUNT(*) c FROM landing_forms WHERE created_at BETWEEN ? AND ?");
|
||||
$st->bind_param('ss', $from_dt, $to_dt);
|
||||
}
|
||||
$st->execute();
|
||||
$r = $st->get_result()->fetch_assoc();
|
||||
$kpis['leads_window'] = (int)($r['c'] ?? 0);
|
||||
|
||||
// --- Top + series
|
||||
$top = [];
|
||||
if ($landing_id > 0) {
|
||||
$st = must_prepare($conn, "
|
||||
SELECT lp.id AS landing_id, lp.titulo,
|
||||
SUM(lvs.event_type='impression') AS imps,
|
||||
SUM(lvs.event_type='conversion') AS conv,
|
||||
ROUND(SUM(lvs.event_type='conversion')/NULLIF(SUM(lvs.event_type='impression'),0)*100,2) AS cr
|
||||
FROM landing_pages lp
|
||||
LEFT JOIN landing_variant_stats lvs
|
||||
ON lvs.landing_id=lp.id
|
||||
AND lvs.created_at BETWEEN ? AND ?
|
||||
WHERE lp.id=?
|
||||
GROUP BY lp.id, lp.titulo
|
||||
");
|
||||
$st->bind_param('ssi', $from_dt, $to_dt, $landing_id);
|
||||
} else {
|
||||
// --- Top global (landing_id = 0): usar subquery para poder ordenar por 'cr'
|
||||
$st = must_prepare($conn, "
|
||||
SELECT landing_id, titulo, imps, conv, cr
|
||||
FROM (
|
||||
SELECT
|
||||
lp.id AS landing_id,
|
||||
lp.titulo,
|
||||
SUM(lvs.event_type='impression') AS imps,
|
||||
SUM(lvs.event_type='conversion') AS conv,
|
||||
ROUND(
|
||||
SUM(lvs.event_type='conversion') / NULLIF(SUM(lvs.event_type='impression'), 0) * 100, 2
|
||||
) AS cr
|
||||
FROM landing_pages lp
|
||||
LEFT JOIN landing_variant_stats lvs
|
||||
ON lvs.landing_id = lp.id
|
||||
AND lvs.created_at BETWEEN ? AND ?
|
||||
GROUP BY lp.id, lp.titulo
|
||||
) t
|
||||
ORDER BY (cr IS NULL), cr DESC, imps DESC
|
||||
LIMIT 10
|
||||
");
|
||||
$st->bind_param('ss', $from_dt, $to_dt);
|
||||
}
|
||||
$st->execute();
|
||||
$rs = $st->get_result();
|
||||
|
||||
while($row = $rs->fetch_assoc()){
|
||||
$row['imps'] = (int)($row['imps'] ?? 0);
|
||||
$row['conv'] = (int)($row['conv'] ?? 0);
|
||||
$row['cr'] = $row['imps'] ? (float)$row['cr'] : null;
|
||||
|
||||
// Serie diaria
|
||||
$st2 = must_prepare($conn, "
|
||||
SELECT DATE(created_at) d,
|
||||
SUM(event_type='impression') imp,
|
||||
SUM(event_type='conversion') conv
|
||||
FROM landing_variant_stats
|
||||
WHERE landing_id=? AND created_at BETWEEN ? AND ?
|
||||
GROUP BY DATE(created_at)
|
||||
ORDER BY d ASC
|
||||
");
|
||||
$lid = (int)$row['landing_id'];
|
||||
$st2->bind_param('iss', $lid, $from_dt, $to_dt);
|
||||
$st2->execute();
|
||||
$ser = $st2->get_result()->fetch_all(MYSQLI_ASSOC);
|
||||
$row['series'] = array_map(function($p){
|
||||
return ['d'=>$p['d'], 'imp'=>(int)$p['imp'], 'conv'=>(int)$p['conv']];
|
||||
}, $ser);
|
||||
|
||||
$top[] = $row;
|
||||
}
|
||||
|
||||
// Lista para el select (si meta=1)
|
||||
$landings_list = [];
|
||||
if ($want_meta === 1) {
|
||||
$q = $conn->query("SELECT id, titulo FROM landing_pages ORDER BY titulo ASC");
|
||||
if (!$q) throw new RuntimeException('query_failed: '. $conn->error .' | SQL=SELECT id,titulo FROM landing_pages ORDER BY titulo ASC');
|
||||
while($L = $q->fetch_assoc()){
|
||||
$landings_list[] = ['id'=>(int)$L['id'], 'titulo'=>$L['titulo']];
|
||||
}
|
||||
}
|
||||
|
||||
$warnings = $php_warnings;
|
||||
ob_end_clean();
|
||||
echo json_encode([
|
||||
'ok'=>true,
|
||||
'kpis'=>$kpis,
|
||||
'top'=>$top,
|
||||
'landings_list'=>$landings_list,
|
||||
'warnings'=>$warnings
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
|
||||
} catch (Throwable $e) {
|
||||
ob_end_clean();
|
||||
http_response_code(500);
|
||||
echo json_encode(['ok'=>false, 'error'=>$e->getMessage()], JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
Reference in New Issue
Block a user