--- a/install.php +++ b/install.php @@ -19,6 +19,8 @@ } $before=json_decode(IPS_GetConfiguration($manager),true,128,JSON_THROW_ON_ERROR); $report['files']=v4StageInstall(__DIR__,'/var/lib/symcon/modules/Enelix-EMS'); + require_once __DIR__.'/installed_capture_bootstrap.php'; + $report['classLoading']=v4ApplicationLoadInstalledCapture('/var/lib/symcon/modules/Enelix-EMS',__DIR__.'/MANIFEST.json'); $controls=[]; foreach (IPS_GetModuleList() as $mid) if ((IPS_GetModule($mid)['Prefix']??'')==='MC') $controls=array_merge($controls,IPS_GetInstanceListByModuleID($mid)); if (count($controls)!==1||!function_exists('MC_ReloadModule')) throw new RuntimeException('Module Control nicht eindeutig.'); @@ -38,7 +40,7 @@ $marker=$dir.'/observer-import.json'; if (!is_file($marker)&&!IPS_GetProperty($manager,'NetzfahrplanV4MessdatenAktiv')) { if (glob($dir.'/raw-*.jsonl')!==[]) throw new RuntimeException('Messdaten ohne Importabschluss vorhanden; nicht doppelt importieren.'); - require_once __DIR__.'/source/libs/NetzfahrplanV4Messaufnahme.php'; + // Reuse the hash-checked installed class; never load the staged copy. $count=0;$last=0;$cutoff=time()-172800; $files=glob('/srv/agent/netplan-v4-separated-observer-stage/data/raw-*.jsonl');sort($files,SORT_STRING); foreach ($files as $file) { --- /dev/null +++ b/installed_capture_bootstrap.php @@ -0,0 +1,48 @@ + 'libs/NetzfahrplanV4Bilanzierung.php', + 'Belevo\\EnelixEMS\\NetzfahrplanV4Messaufnahme' => 'libs/NetzfahrplanV4Messaufnahme.php', + ]; + // Check BOTH origins before loading either file, including the transitive dependency. + foreach ($classes as $class => $relative) { + $path = $target . '/' . $relative; + $expected = $manifest['files'][$relative]['after'] ?? null; + if (!is_string($expected) || !preg_match('/^[a-f0-9]{64}$/D', $expected) + || is_link($path) || !is_file($path) || realpath($path) !== $path + || hash_file('sha256', $path) !== $expected) { + throw new RuntimeException('Installierte Messbibliothek weicht vom geprueften Paket ab: ' . $relative); + } + if (class_exists($class, false)) { + $origin = (new ReflectionClass($class))->getFileName(); + if ($origin !== $path) { + throw new RuntimeException('Messbibliothek bereits aus anderem Pfad geladen. Installationsaufruf separat ausfuehren, ohne weitere Sammler-Includes.'); + } + } + } + foreach ($classes as $class => $relative) { + $path = $target . '/' . $relative; + if (!class_exists($class, false)) { + require_once $path; + } + if (!class_exists($class, false) || (new ReflectionClass($class))->getFileName() !== $path) { + throw new RuntimeException('Installierte Messbibliothek konnte nicht eindeutig geladen werden.'); + } + } + return ['source' => 'installed_module_only', 'stagedClassesLoaded' => false, + 'files' => array_values($classes)]; +}