<?php
/**
 * @package     com_htprotect
 * @copyright   (C) 2026 Pascal Lohmann / website-bereinigung.de
 * @license     GNU General Public License version 2 or later
 *
 * Laedt die htprotect-Engine. Wird sowohl vom klassischen Einstieg
 * (Joomla 2.5/3.x) als auch vom Dispatcher (Joomla 4/5/6) eingebunden.
 */

defined('_JEXEC') or die;

if (!defined('HTP_CORE')) {
    define('HTP_CORE', __DIR__);
    define('HTP_VERSION', '2.7.4');

    // Engine-Dateien EINZELN und fehlertolerant laden. Grund: eine durch ein
    // ABGEBROCHENES Update leer geschriebene oder halbe Core-Datei (typische Ursachen:
    // volles Speicher-/Webspace-Kontingent, PHP-Timeout/Memory-Limit, gekappter FTP-/
    // Kopier-Vorgang) darf NIEMALS die ganze Seite mit einem Fatal abschiessen
    // ("Class Htp... not found" bei 0-Byte-Datei bzw. Parse-Fehler bei halber Datei).
    // try/catch faengt in PHP 7+ auch ParseError/Error; die Reihenfolge bleibt exakt
    // wie zuvor. Die Vollstaendigkeit wird danach ueber HTP_ENGINE_OK signalisiert,
    // damit die Aufrufer sauber degradieren statt zu crashen.
    // Datei => Kernklasse (Reihenfolge = Ladeordnung). compat.php liefert nur Funktionen
    // (leerer Wert -> Vollstaendigkeit dort ueber htp_load_lang statt einer Klasse).
    $htpFileClass = array(
        'compat' => '', 'config' => 'HtpConfig', 'auintent' => 'HtpAuIntent', 'defs' => 'HtpDefs', 'builder' => 'HtpBuilder',
        'nginx' => 'HtpNginx', 'iis' => 'HtpIis', 'storage' => 'HtpStorage', 'scanner' => 'HtpScanner', 'content' => 'HtpContent', 'corescan' => 'HtpCoreScan', 'compat_guard' => 'HtpCompat',
        'probe' => 'HtpProbe', 'guard' => 'HtpGuard', 'dirshield' => 'HtpDirShield',
        'watch' => 'HtpWatch', 'accounts' => 'HtpAccounts', 'seo' => 'HtpSeo', 'swarm' => 'HtpSwarm',
        'unsub' => 'HtpUnsub', 'feedback' => 'HtpFeedback', 'mail' => 'HtpMail', 'maillang' => 'HtpMailLang',
        'status' => 'HtpStatus',
        'helix' => 'HtpHelix', 'sppb' => 'HtpSppb', 'joomshaperpatch' => 'HtpJoomShaperPatch',
        'autoupdate_backup' => 'HtpUpdateBackup', 'autoupdate' => 'HtpAutoUpdate',
        'autoupdate_legacy' => 'HtpAutoUpdateLegacy',
        'autoupdate_ui' => 'HtpAutoUpdateUi', 'ui' => 'HtpUi', 'app' => 'HtpApp',
        'backup' => 'HtpBackup',
        'coreupdate_engine' => 'HtpCoreUpdateEngine',
        'coreupdate_j3' => 'HtpCoreUpdateJ3',
        'coreupdate' => 'HtpCoreUpdate',
        'corehotfix' => 'HtpCoreHotfix',
        'regclean' => 'HtpRegClean',
        'search' => 'HtpSearch',
        'files' => 'HtpFiles',
        'db' => 'HtpDb',
        'link' => 'HtpLink',
        'sso' => 'HtpSso',
        'ai' => 'HtpAi',
    );

    // Bis zu ZWEI Ladeversuche mit Cache-Auffrischung. Grund: DIREKT nach einem (auch
    // voellig normalen) Update kann eine gerade von Joomla kopierte Core-Datei im selben
    // Request TRANSIENT noch als "fehlt" (veralteter stat-Cache) oder "leer" (0-Byte-
    // Kopierfenster bei parallelem Request) erscheinen -> Klasse fehlt -> HTP_ENGINE_OK
    // waere FAELSCHLICH false und die Wiederherstellungs-Seite erschiene, obwohl das Paket
    // vollstaendig ist. Absicherung, damit das NIE faelschlich passiert:
    //   - vor jedem Versuch clearstatcache(true) (frischer Blick aufs Dateisystem);
    //   - je Datei "include" (bewusst NICHT _once) NUR solange ihre Klasse noch fehlt ->
    //     eine zuvor leer eingebundene Datei kann so nachgeladen werden; eine bereits
    //     geladene wird per Guard uebersprungen (kein "cannot redeclare");
    //   - im 2. Versuch zusaetzlich OPcache der noch fehlenden Datei invalidieren.
    // Erst wenn es DANN noch fehlt, ist die Engine ECHT kaputt (leere/fehlende Datei durch
    // ein abgebrochenes Update) -> dann degradieren die Aufrufer sauber statt zu crashen.
    $htpEngineComplete = false;

    for ($htpPass = 0; $htpPass < 2 && !$htpEngineComplete; $htpPass++) {
        if (function_exists('clearstatcache')) {
            clearstatcache(true);
        }

        foreach ($htpFileClass as $htpEngineFile => $htpEngineClass) {
            // Schon geladen? -> nicht erneut einbinden (verhindert "cannot redeclare").
            if ($htpEngineClass !== '') {
                if (class_exists($htpEngineClass, false)) {
                    continue;
                }
            } elseif (function_exists('htp_t') && function_exists('htp_load_lang')) {
                continue;
            }

            $htpEnginePath = HTP_CORE . '/' . $htpEngineFile . '.php';

            if ($htpPass === 1 && function_exists('opcache_invalidate') && @is_file($htpEnginePath)) {
                @opcache_invalidate($htpEnginePath, true);
            }

            try {
                if (is_file($htpEnginePath)) {
                    include $htpEnginePath;
                }
            } catch (Exception $htpEngineError) {
                // Beschaedigte Datei ueberspringen; Vollstaendigkeit faellt unten auf false.
            } catch (Throwable $htpEngineError) {
                // PHP 7+: faengt auch ParseError/Error einer halben Datei - dito.
            }
        }

        // Vollstaendig? (leere Datei = include ok, aber keine Klasse definiert)
        // HtpContent (isolierte Inhalts-Scanner-Engine) ist BEWUSST OPTIONAL: entfernt
        // ein Server-Virenscanner (Imunify o. ae.) NUR diese Datei, bleibt die Engine
        // vollstaendig - nur der Malware-Scan degradiert (die HtpStorage-Wrapper liefern
        // sichere Defaults, das Scan-UI meldet es klar). Darum hier NICHT gefordert.
        // HtpAutoUpdateLegacy (nur Joomla-3-Auto-Update-Pfad) ist ebenso BEWUSST OPTIONAL:
        // fehlt/entfernt sie, degradiert allein das J3-Auto-Update (5.4+ nutzt sie nie ausser
        // via class_exists-Guard) - die Engine bleibt vollstaendig, kein Recovery-Fehlalarm.
        $htpOptionalClasses = array('HtpContent' => 1, 'HtpScanner' => 1, 'HtpCoreScan' => 1, 'HtpLink' => 1, 'HtpAutoUpdateLegacy' => 1, 'HtpSso' => 1, 'HtpAi' => 1, 'HtpAuIntent' => 1, 'HtpCoreUpdate' => 1, 'HtpCoreUpdateEngine' => 1, 'HtpRegClean' => 1, 'HtpFiles' => 1, 'HtpDb' => 1);
        $htpEngineComplete  = function_exists('htp_t') && function_exists('htp_load_lang');

        if ($htpEngineComplete) {
            foreach ($htpFileClass as $htpEngineClass) {
                if ($htpEngineClass !== '' && !isset($htpOptionalClasses[$htpEngineClass]) && !class_exists($htpEngineClass, false)) {
                    $htpEngineComplete = false;
                    break;
                }
            }
        }
    }

    define('HTP_ENGINE_OK', $htpEngineComplete);
}
