4 Ruta ExpertoLección 1 de 8 8 min de lectura

La arquitectura de Éclair

  1. 1. La arquitectura de Éclair
  2. 2. Desarrollo local y pruebas
  3. 3. Personalizar las plantillas del tema
  4. 4. Nginx, VPS, proxy y CDN: desplegar Éclair
  5. 5. Rendimiento de Éclair: mantener 100 sobre 100
  6. 6. Migrar desde WordPress o Wix
  7. 7. Seguridad avanzada y mantenimiento
  8. 8. Industrializar Éclair en una agencia
Índice
  1. ¿Cómo atraviesa una petición la arquitectura de Éclair?
  2. El almacenamiento en archivos planos: la clase Store
  3. Los archivos de la carpeta data/
  4. Las clases principales de app/lib/
  5. ¿Por qué se vacía la caché con cada cambio?
  6. Cabeceras de seguridad y CSP
  7. Las traducciones
  8. Para recordar
  9. Para saber más
  10. Preguntas frecuentes

La arquitectura de Éclair se resume en una regla: hacer trabajar a PHP solo cuando hace falta. Esta lección sigue una petición de principio a fin, del servidor web a la caché estática, y muestra cómo se guardan los datos sin base de datos y qué clase hace cada cosa. Después podrás depurar, personalizar o alojar Éclair sabiendo cómo funciona por dentro.

Lo que sabrás hacer

Seguir una petición

Del servidor web a index.php y, de ahí, a la caché o a la aplicación.

Leer la carpeta data/

Qué contiene cada archivo y cómo está protegido.

Encontrar la clase adecuada

Saber en pocos segundos dónde actuar dentro de app/lib/.

¿Cómo atraviesa una petición la arquitectura de Éclair?

Esquema del ciclo de una petición: respuesta desde la caché estática o paso por la aplicación Éclair
La vía rápida sirve las páginas ya generadas; todo lo demás pasa por App::run.

Todo parte de una constatación: la mayoría de las visitas piden una página que no ha cambiado. Por eso la arquitectura de Éclair la devuelve tal cual, sin leer ni un solo contenido. Este es el recorrido de una petición.

  1. El servidor web. En Apache o LiteSpeed, el .htaccess envía a index.php cualquier dirección que no sea un archivo existente. Responde 404 para app/, data/, cache/, los archivos ocultos (salvo .well-known) y cualquier .php distinto de index.php, y transmite la cabecera Authorization al conector MCP.
  2. La vía rápida de index.php. Para un GET o un HEAD, index.php lee cache/runtime.php y busca en cache/pages/ la página guardada con el md5 de la ruta. Si la encuentra, devuelve sus cabeceras guardadas, su ETag y X-Cache: HIT, o un 304 Not Modified si el navegador ya tiene esa versión.
  3. El arranque. Si no, app/bootstrap.php comprueba la versión de PHP (8.1 como mínimo), carga eclair-config.php si existe, define ECLAIR_DATA y ECLAIR_DEBUG, registra la carga automática de las clases Eclair\… y llama a Eclair\App::run().
  4. El enrutamiento. App::run() instala la gestión de errores y entrega la petición al módulo adecuado (tabla de abajo).
  5. El renderizado. Site::handle() solo acepta GET y HEAD, impone una sola dirección por contenido (barra final, mayúsculas, index.php: redirección 301), sirve los archivos generados (robots.txt, sitemap.xml, llms.txt, feeds, versiones .md) y después busca el contenido. Cache::put() guarda cada página renderizada con el código 200.
Ruta solicitadaMódulo que responde
/__eclair/pingcomprobación de la reescritura, prueba de identidad (Loopback)
cualquier ruta, antes de la instalaciónInstaller::handle()
la dirección de la administración y sus subpáginasAdmin::handle()
/_eclair/contactContact::handle(), el formulario de contacto
/_eclair/edit/<id>redirección al editor, si hay una sesión iniciada
/_eclair/… y /.well-known/…Mcp::handle(), mudo mientras el conector esté desactivado
todo lo demásSite::handle()

La búsqueda, la página 404, la vista previa de la apariencia, el modo Visual y la administración nunca se guardan en caché. Para ver la vía rápida en acción, consulta dos veces la misma página:

# 1.ª llamada: la aplicación genera la página y la guarda
curl -sI https://exemple.fr/contact | grep -i -E 'etag|x-cache'
# ETag: "0745734655e7d523"

# 2.ª llamada: index.php la sirve desde cache/pages/, sin cargar la aplicación
curl -sI https://exemple.fr/contact | grep -i -E 'etag|x-cache'
# ETag: "0745734655e7d523"
# X-Cache: HIT

# El archivo de caché lleva el md5 de la ruta solicitada
php -r 'echo md5("/contact"), PHP_EOL;'   # 90609cfd31a32bdbd3d81843c57d356b

El almacenamiento en archivos planos: la clase Store

La arquitectura de Éclair prescinde de la base de datos: cada dato es un archivo data/<nom>.php que empieza por la línea <?php exit; ?>, seguida de JSON legible. Si se llama desde la web, no devuelve nada, incluso en un servidor que ignorara los .htaccess. Este es el principio de un archivo de menús real:

<?php exit; ?>
{
    "main": [
        {
            "type": "content",
            "id": "af59e5ba0a",
            "label": "",
            "url": ""
        }
    ]
}

Cuatro mecanismos hacen que este almacenamiento sea seguro, incluso en un hosting compartido muy cargado:

Todas las clases que escriben siguen este patrón, por ejemplo Redirects::add():

use Eclair\Store;

$menus = Store::read('menus', []);           // lectura, con un valor por defecto
Store::locked(function (): void {            // leer, modificar y escribir sin condiciones de carrera
    $list = Store::read('redirects', []);
    // … modificar $list …
    Store::write('redirects', $list);        // archivo temporal, 0600, renombrado
});

Los archivos de la carpeta data/

La última columna indica lo que conserva la copia de seguridad ZIP de la página Seguridad: los secretos y los datos temporales quedan fuera.

Archivo o carpetaContenidoCopia ZIP
site.phpajustes, combinados con Settings::DEFAULTSsí
users.phpcuentas, hashes Argon2id, verificación en dos pasossí
keys.phpsecreto del sitio y clave de IndexNow, creados en la instalaciónsí
index.phpresumen de cada contenido, para listar y enrutar rápidosí
content/<id>.phpuna página, un artículo o un producto, con sus bloquessí
revisions/<id>/las 20 últimas versiones de ese contenidosí
search.php, media.phptexto de búsqueda, registro de la biblioteca de mediossí
menus.php, categories.php, redirects.php, custom-css.phpmenús, categorías, redirecciones, CSS personalizadosí
messages/, inbox.phpmensajes del formulario, 500 como máximosí
logs/registros de errores y de seguridad, limitados a 1 MBsí
vault.phpclaves de API cifradasno
ai/conversaciones del asistente, propuestas, conexiones MCPno
sessions/, limits/sesiones de la administración, contadores contra la fuerza brutano

Las actualizaciones nunca tocan data/, que la constante ECLAIR_DATA puede incluso situar fuera de la carpeta pública.

Las clases principales de app/lib/

Todas las clases viven en el espacio de nombres Eclair\, un archivo por clase, sin framework ni Composer:

ClaseFunción
Appenrutamiento de las peticiones que no sirve la caché
Req, Httplectura de la petición, respuestas y redirecciones
Store, Settingsalmacenamiento en archivos planos, ajustes y valores por defecto
Content, Blockscontenidos, índice, revisiones; renderizado de los 18 bloques
Site, Themeenrutador público; plantillas y CSS en línea
Cachepáginas estáticas y cache/runtime.php
Seo, Analyzerdatos estructurados, sitemap, llms.txt; puntuaciones
Security, Session, Authcabeceras, tokens CSRF, sesiones, inicio de sesión
Mediabiblioteca de medios, recodificación y WebP
Admin y Admin…pantallas y acciones de la administración
Ai, AiChat, AiTools, Mcpasistente IA, herramientas, conector MCP y OAuth
Integrity, Log, Keys, Vault, Loopbackintegridad, registros, secretos, caja fuerte, verificación de la dirección
I18ntraducciones de la administración

¿Por qué se vacía la caché con cada cambio?

Un título modificado aparece también en un menú, en una tarjeta de artículo o en las migas de pan. En lugar de adivinar esas dependencias, la arquitectura de Éclair lo vacía todo: Cache::purge() se ejecuta tras cada guardado de un contenido, de los ajustes, los menús, las categorías, los medios, un perfil o el CSS personalizado. Borra los archivos de cache/pages/ y reescribe cache/runtime.php; cada página se regenera en su primera visita.

<?php exit; ?>
{"on":true,"expires":0,"host":"exemple.fr","https":true}

index.php lee este pequeño archivo en cada petición:

Cabeceras de seguridad y CSP

Security::headers() produce tres juegos de cabeceras: site, admin y text (sitemap, llms.txt, feeds). Dependen de los ajustes, nunca de la petición: nadie puede envenenar la caché con una cabecera falsificada. Estas son las de una página pública servida por HTTP, tomadas de Éclair 1.8:

Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'sha256-…'; img-src 'self' data: https:; media-src 'self' https:; frame-src https://www.youtube-nocookie.com https://player.vimeo.com; connect-src 'self'; form-action 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'self'
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=(), browsing-topics=()
Cross-Origin-Opener-Policy: same-origin

Theme::hash() calcula la huella sha256 sobre el CSS insertado en la página: solo se autoriza esa etiqueta <style>, no se permite ningún script en línea y el único script público es assets/site/site.js. Con HTTPS se añaden upgrade-insecure-requests y, si la opción HSTS está marcada, Strict-Transport-Security. La administración es aún más estricta: ningún estilo en línea, frame-ancestors 'none', noindex y Cache-Control: no-store, private.

Las traducciones

Para recordar

Para saber más

Preguntas frecuentes

¿Puede funcionar Éclair sin su caché estática?

Sí: desmarca Caché estática de páginas en Ajustes › Avanzado, o activa el modo de depuración. Cada visita genera entonces la página, lo que consume más tiempo de servidor.

¿Por qué guardar JSON en archivos .php?

Para que la línea <?php exit; ?> proteja cada archivo aunque el servidor ignore el .htaccess. Si se llama desde la web, no muestra nada, mientras que Éclair lee el JSON que sigue a esa primera línea.

¿Qué pasa si dos personas guardan a la vez?

Las escrituras pasan por Store::locked(), que pone un bloqueo exclusivo sobre data/.lock. Los dos guardados se ejecutan uno detrás de otro, y la versión anterior pasa al historial de revisiones.

¿Se puede colocar la carpeta data/ fuera de la carpeta pública?

Sí. Primero mueve la carpeta y después indica su nueva ubicación con define('ECLAIR_DATA', '/chemin/vers/eclair-data'); en eclair-config.php, junto a index.php. La vía rápida no depende de ella: solo lee cache/.

Todas las lecciones de la ruta