- WordPress core y plugins - Tema Twenty Twenty-Four configurado - Plugin allow-unfiltered-html.php simplificado - .gitignore configurado para excluir wp-config.php y uploads 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
310 lines
12 KiB
PHP
Executable File
310 lines
12 KiB
PHP
Executable File
<?php
|
||
// public_html/buscar-apus/index.php
|
||
$cfg = require __DIR__ . '/config.php';
|
||
require __DIR__ . '/app/Db.php';
|
||
require __DIR__ . '/app/Logger.php';
|
||
require __DIR__ . '/app/Search.php';
|
||
require __DIR__ . '/menu.php';
|
||
require __DIR__ . '/app/Analytics.php';
|
||
|
||
if (session_status() !== PHP_SESSION_ACTIVE) @session_start();
|
||
|
||
Logger::log($cfg['log'], 'peticion', [
|
||
'uri' => $_SERVER['REQUEST_URI'] ?? '',
|
||
'ua' => $_SERVER['HTTP_USER_AGENT'] ?? '',
|
||
'get' => $_GET
|
||
]);
|
||
|
||
/**
|
||
* =========================
|
||
* Config de anuncios
|
||
* =========================
|
||
* - $ADS_BETWEEN_MAX: máximo de anuncios entre resultados.
|
||
* - $ALLOWED_AD_UNITS: tipos permitidos para los anuncios intermedios.
|
||
* - $TOP_FIXED_AD_SIZE: tamaño fijo del anuncio bajo el buscador ('300x250' | '728x90' | '320x100' | '970x250').
|
||
* - $TOP_FIXED_AD_SLOT: SLOT de AdSense para ese tamaño fijo (reemplázalo por el tuyo).
|
||
*/
|
||
$ADS_BETWEEN_MAX = 1; // 1..n
|
||
$ALLOWED_AD_UNITS = ['auto', 'autorelaxed', 'in-article'];
|
||
$TOP_FIXED_AD_SIZE = '1100x315';
|
||
$TOP_FIXED_AD_SLOT = '2873062302'; // <-- pon aquí tu data-ad-slot (numérico)
|
||
|
||
// Parámetros
|
||
$raw = isset($_GET['s']) ? trim((string)$_GET['s']) : '';
|
||
$page = (isset($_GET['pagina']) && ctype_digit($_GET['pagina']) && (int)$_GET['pagina'] > 0) ? (int)$_GET['pagina'] : 1;
|
||
$pp = max(1, min(100, (int)$cfg['limits']['per_page']));
|
||
$off = ($page - 1) * $pp;
|
||
|
||
[$valid, $term, $err] = Search::sanitizeTerm($raw, $cfg['limits']['min_len'], $cfg['limits']['max_len']);
|
||
|
||
$results = ['total'=>0,'rows'=>[],'modo'=>'NONE','time_ms'=>0];
|
||
$pdo = null; $searchId = null;
|
||
|
||
if ($valid) {
|
||
$pdo = Db::pdo($cfg);
|
||
$search = new Search($pdo, $cfg['db']['prefix'], $cfg['log']);
|
||
$results = $search->run($term, $pp, $off);
|
||
|
||
$analyticsCfg = $cfg['analytics'] ?? ['enabled' => false];
|
||
// al terminar la búsqueda:
|
||
$searchId = Analytics::logSearch(
|
||
$pdo, $cfg['db']['prefix'], $analyticsCfg,
|
||
$raw, $term, $results, $page, $pp
|
||
);
|
||
|
||
} else if ($raw !== '') {
|
||
Logger::log($cfg['log'], 'consulta_invalida', ['error' => $err]);
|
||
}
|
||
|
||
/** ===== Helpers ===== **/
|
||
|
||
// Resalta el texto (sin snippet). Útil para títulos.
|
||
function apu_highlight(string $text, string $term): string {
|
||
$safe = htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
|
||
foreach (array_filter(explode(' ', $term)) as $t) {
|
||
if (mb_strlen($t, 'UTF-8') >= 2) {
|
||
$safe = preg_replace('/' . preg_quote($t, '/') . '/iu', '<mark>$0</mark>', $safe);
|
||
}
|
||
}
|
||
return $safe;
|
||
}
|
||
|
||
/**
|
||
* Anuncio fijo (display) para el bloque bajo el buscador.
|
||
* Usa un slot de tamaño específico para mantener altura constante.
|
||
*
|
||
* @param string $size '300x250' | '728x90' | '320x100' | '970x250'
|
||
* @param string $slot Tu data-ad-slot para ese tamaño
|
||
*/
|
||
function apu_top_fixed_ad_html(string $size, string $slot): string {
|
||
$client = 'ca-pub-8476420265998726';
|
||
// whitelist de tamaños (incluye 970x250)
|
||
$allowed = ['300x250','728x90','320x100','970x250','1100x315'];
|
||
if (!in_array($size, $allowed, true)) $size = '300x250';
|
||
|
||
[$w,$h] = array_map('intval', explode('x', $size));
|
||
$w = max(1,$w); $h = max(1,$h);
|
||
$slot = preg_match('/^\d+$/', $slot) ? $slot : '0000000000'; // placeholder seguro (no muestra anuncio)
|
||
|
||
return '<div class="apu-top-ad d-flex justify-content-center">'.
|
||
'<ins class="adsbygoogle" style="display:inline-block;width:'.$w.'px;height:'.$h.'px" '.
|
||
'data-ad-client="'.$client.'" data-ad-slot="'.$slot.'"></ins>'.
|
||
'<script>(adsbygoogle = window.adsbygoogle || []).push({});</script>'.
|
||
'</div>';
|
||
}
|
||
|
||
/**
|
||
* Solo anuncios AUTO (responsive). Ignora $allowed y fuerza 'auto'.
|
||
* Puedes fijar una altura para evitar CLS: 250–320 suele ir bien.
|
||
*/
|
||
function apu_random_ad_html(array $allowed = ['auto']): string {
|
||
// Alturas sugeridas: elige una fija o deja una lista si quieres variar
|
||
$heights = [100, 200, 250, 280, 300, 315, 320, 350, 400]; // puedes cambiarlo por [300] para altura constante
|
||
$h = $heights[array_rand($heights)];
|
||
|
||
return '<ins class="adsbygoogle" style="display:block; min-height:'.$h.'px"
|
||
data-ad-client="ca-pub-8476420265998726"
|
||
data-ad-slot="8471732096"
|
||
data-ad-format="auto"
|
||
data-full-width-responsive="true"></ins>
|
||
<script>(adsbygoogle = window.adsbygoogle || []).push({});</script>';
|
||
}
|
||
|
||
/**
|
||
* HTML de un anuncio AdSense aleatorio, restringido a tipos permitidos (intermedios).
|
||
*
|
||
* @param array $allowed tipos permitidos: 'auto','autorelaxed','in-article'
|
||
* @return string
|
||
*/
|
||
/*
|
||
function apu_random_ad_html(array $allowed = ['auto']): string {
|
||
$allowed = array_values(array_intersect(
|
||
array_map('strval', $allowed),
|
||
['auto','autorelaxed','in-article']
|
||
));
|
||
if (empty($allowed)) $allowed = ['auto','autorelaxed','in-article'];
|
||
|
||
$unit = $allowed[array_rand($allowed)];
|
||
|
||
if ($unit === 'auto') { // AUTO
|
||
$heights = [100, 150, 200, 250, 280, 300, 350, 400, 500, 600];
|
||
$h = $heights[array_rand($heights)];
|
||
return '<ins class="adsbygoogle" style="display:block; min-height:'.$h.'px"
|
||
data-ad-client="ca-pub-8476420265998726"
|
||
data-ad-slot="8471732096"
|
||
data-ad-format="auto"
|
||
data-full-width-responsive="true"></ins>
|
||
<script>(adsbygoogle = window.adsbygoogle || []).push({});</script>';
|
||
}
|
||
|
||
if ($unit === 'autorelaxed') { // AUTORELAXED (feed)
|
||
$heights = [280, 300, 320, 360];
|
||
$h = $heights[array_rand($heights)];
|
||
return '<ins class="adsbygoogle" style="display:block; min-height:'.$h.'px"
|
||
data-ad-format="autorelaxed"
|
||
data-ad-client="ca-pub-8476420265998726"
|
||
data-ad-slot="9205569855"></ins>
|
||
<script>(adsbygoogle = window.adsbygoogle || []).push({});</script>';
|
||
}
|
||
|
||
// IN-ARTICLE (fluid)
|
||
$heights = [180, 200, 220, 240];
|
||
$h = $heights[array_rand($heights)];
|
||
return '<ins class="adsbygoogle" style="display:block; text-align:center; min-height:'.$h.'px"
|
||
data-ad-layout="in-article"
|
||
data-ad-format="fluid"
|
||
data-ad-client="ca-pub-8476420265998726"
|
||
data-ad-slot="7285187368"></ins>
|
||
<script>(adsbygoogle = window.adsbygoogle || []).push({});</script>';
|
||
}
|
||
*/
|
||
?>
|
||
<!DOCTYPE html>
|
||
<html lang="es">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
<meta name="robots" content="noindex,nofollow">
|
||
<title>Buscador APU</title>
|
||
|
||
<!-- AdSense loader (una sola vez) -->
|
||
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-8476420265998726" crossorigin="anonymous"></script>
|
||
|
||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
|
||
|
||
<style>
|
||
:root { --apu-max-width: 1150px; }
|
||
.apu-wrap { max-width: var(--apu-max-width); width: 100%; margin: 0 auto; padding-inline: 12px; }
|
||
.container { max-width: var(--apu-max-width) !important; }
|
||
body{background:#fafafa}
|
||
mark{background:#fff3cd;padding:0;border-radius:2px}
|
||
.apu-top-ad { margin-top: .5rem; margin-bottom: .75rem; } /* espacio del anuncio fijo */
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<main class="apu-wrap">
|
||
|
||
<section class="container my-4">
|
||
<div class="p-3 border rounded-3 bg-light">
|
||
<form method="get" action="" class="row g-2 align-items-center">
|
||
<div class="col-12 col-md-9">
|
||
<input
|
||
type="text"
|
||
name="s"
|
||
class="form-control<?php echo (!$valid && $raw!=='') ? ' is-invalid' : ''; ?>"
|
||
placeholder="Buscar análisis… (cantidad mínima de caracteres para buscar. <?php echo (int)$cfg['limits']['min_len']; ?>)"
|
||
value="<?php echo htmlspecialchars($term ?: $raw, ENT_QUOTES, 'UTF-8'); ?>"
|
||
maxlength="<?php echo (int)$cfg['limits']['max_len']; ?>">
|
||
<?php if(!$valid && $raw!==''): ?>
|
||
<div class="invalid-feedback"><?php echo htmlspecialchars($err, ENT_QUOTES, 'UTF-8'); ?></div>
|
||
<?php endif; ?>
|
||
</div>
|
||
<div class="col-12 col-md-3 d-grid"><button class="btn btn-primary" type="submit">Buscar</button></div>
|
||
</form>
|
||
</div>
|
||
|
||
<?php
|
||
// ===== Anuncio FIJO debajo del buscador (tamaño constante) =====
|
||
echo apu_top_fixed_ad_html($TOP_FIXED_AD_SIZE, $TOP_FIXED_AD_SLOT);
|
||
?>
|
||
</section>
|
||
|
||
<?php if ($valid): ?>
|
||
<section class="container my-4">
|
||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||
<h2 class="h5 mb-0">
|
||
Resultados para "<strong><?php echo htmlspecialchars($term, ENT_QUOTES, 'UTF-8'); ?></strong>":
|
||
<?php echo number_format($results['total']); ?>
|
||
</h2>
|
||
<small class="text-muted"><?php echo htmlspecialchars($results['modo']); ?> (<?php echo $results['time_ms']; ?>ms)</small>
|
||
</div>
|
||
|
||
<?php if (!empty($results['rows'])): ?>
|
||
<div class="list-group mb-4">
|
||
|
||
<?php
|
||
// ===== Anuncios entre resultados =====
|
||
$rows = $results['rows'];
|
||
$n = count($rows);
|
||
|
||
// Máximo permitido por configuración (no puede superar los huecos disponibles)
|
||
$adsBetween = min((int)$ADS_BETWEEN_MAX, max(0, $n - 1));
|
||
|
||
// Elegimos $adsBetween huecos aleatorios únicos (entre item i y i+1)
|
||
$adPos = [];
|
||
if ($adsBetween > 0) {
|
||
$pool = range(1, $n - 1); // huecos posibles
|
||
shuffle($pool);
|
||
$adPos = array_flip(array_slice($pool, 0, $adsBetween)); // set de posiciones
|
||
}
|
||
|
||
$i = 0;
|
||
foreach ($rows as $r):
|
||
$i++;
|
||
$permalink = '/?p='.(int)$r['ID'];
|
||
$clk = ($searchId)
|
||
? '/buscar-apus/clk.php?sid='.$searchId.'&pid='.(int)$r['ID'].'&pos='.$i.'&page='.$page
|
||
: $permalink; // fallback seguro
|
||
|
||
$title = (string)$r['post_title'];
|
||
$dateStr = htmlspecialchars(substr($r['post_date'],0,10), ENT_QUOTES, 'UTF-8');
|
||
?>
|
||
|
||
<a class="list-group-item list-group-item-action py-3"
|
||
href="<?php echo htmlspecialchars($clk, ENT_QUOTES, 'UTF-8'); ?>"
|
||
target="_blank" rel="noopener noreferrer">
|
||
<div class="d-flex w-100 justify-content-between mb-1">
|
||
<h3 class="h6 mb-0"><?php echo apu_highlight($title, $term); ?></h3>
|
||
</div>
|
||
</a>
|
||
|
||
<?php
|
||
// ¿Insertar anuncio después de este ítem?
|
||
if (isset($adPos[$i])) {
|
||
echo '<div class="list-group-item py-3">'.apu_random_ad_html($ALLOWED_AD_UNITS).'</div>';
|
||
}
|
||
?>
|
||
|
||
<?php endforeach; ?>
|
||
</div>
|
||
|
||
<?php
|
||
$total_pages = (int)ceil($results['total'] / $pp);
|
||
if ($total_pages > 1):
|
||
$base = $_GET; unset($base['pagina']);
|
||
?>
|
||
<nav aria-label="Paginación">
|
||
<ul class="pagination justify-content-center flex-wrap gap-1">
|
||
<?php if ($page > 1): ?>
|
||
<li class="page-item"><a class="page-link" href="?<?php echo http_build_query($base + ['pagina'=>1]); ?>">« Primera</a></li>
|
||
<li class="page-item"><a class="page-link" href="?<?php echo http_build_query($base + ['pagina'=>$page-1]); ?>">‹ Anterior</a></li>
|
||
<?php endif; ?>
|
||
|
||
<?php
|
||
$start = max(1, $page - 5);
|
||
$end = min($total_pages, $start + 9);
|
||
if ($end - $start < 9) $start = max(1, $end - 9);
|
||
for ($i = $start; $i <= $end; $i++):
|
||
?>
|
||
<li class="page-item<?php echo ($i === $page) ? ' active' : ''; ?>">
|
||
<a class="page-link" href="?<?php echo http_build_query($base + ['pagina'=>$i]); ?>"><?php echo $i; ?></a>
|
||
</li>
|
||
<?php endfor; ?>
|
||
|
||
<?php if ($page < $total_pages): ?>
|
||
<li class="page-item"><a class="page-link" href="?<?php echo http_build_query($base + ['pagina'=>$page+1]); ?>">Siguiente ›</a></li>
|
||
<li class="page-item"><a class="page-link" href="?<?php echo http_build_query($base + ['pagina'=>$total_pages]); ?>">Última »</a></li>
|
||
<?php endif; ?>
|
||
</ul>
|
||
</nav>
|
||
<?php endif; ?>
|
||
|
||
<?php else: ?>
|
||
<div class="alert alert-secondary"><strong>Sin resultados.</strong> Prueba con términos más generales.</div>
|
||
<?php endif; ?>
|
||
</section>
|
||
<?php endif; ?>
|
||
</main>
|
||
</body>
|
||
</html>
|
||
<?php Logger::log($cfg['log'], 'fin_peticion', []); ?>
|