PriviMetrics
Version 1.0.9 • 43 files • 278.98 KB
Files
.last_check
admin.php
assets/.htaccess
assets/dashboard-chart.php
assets/dashboard-logic.php
assets/dashboard-modals.php
assets/dashboard-tables.php
assets/dashboard-template.php
assets/trends-template.php
chosen-limits.php
dashboard.php
data/.htaccess
extensions-load.php
extensions.php
extensions.xml
extensions/.htaccess
extensions/extensions_off.txt
functions.php
getCountryFrom/db-ip.php
getCountryFrom/geo-lite.php
getCountryFrom/ip-api-com.php
getCountryFrom/ip-info.php
getCountryFrom/ip-stack.php
getCountryFrom/ip2location-io.php
getCountryFrom/privacy-friendly.php
index.html
install.php
limits-options.php
new_version.php
privimetrics-div.js
privimetrics.php
public.php
scripts.js
settings-config.php
settings.php
signup.php
storage.php
styles-mobile.css
styles.css
trends.css
trends.php
updater/index.php
version.txt
extensions-load.php
<?php
// ===============================================================================
// PriviMetrics - Extensions Loader
// ===============================================================================
/**
* Extension Loading System for PriviMetrics
* * Hook points available for extensions:
* - before_dashboard_init, after_dashboard_init
* - before_analytics_save, after_analytics_save
* - before_render, after_render
* - custom_dashboard_widget, custom_settings_tab
**/
// EMERGENCY DISABLE: Create a file named 'extensions_off.txt' (path: extensions/) with content 'true'
class ExtensionLoader {
private static $instance = null;
private $extensions = [];
private $hooks = [];
private $extensionsDir;
private $extensionsFile;
private $killSwitchFile;
private function __construct() {
$this->extensionsDir = __DIR__ . '/extensions';
$this->extensionsFile = __DIR__ . '/extensions.xml';
$this->killSwitchFile = __DIR__ . '/extensions/extensions_off.txt';
$this->loadExtensions();
}
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
private function loadExtensions() {
if (file_exists($this->killSwitchFile) && strtolower(trim(file_get_contents($this->killSwitchFile))) === 'true') {
error_log("PriviMetrics: Extensions system is globally disabled via extensions_off.txt");
return;
}
if (!file_exists($this->extensionsFile)) return;
try {
$xml = simplexml_load_file($this->extensionsFile);
if (!$xml) return;
foreach ($xml->extension as $ext) {
if ((string)$ext->enabled === 'true') {
$this->loadExtension((string)$ext->id);
}
}
} catch (Exception $e) {
error_log('Extension loading error: ' . $e->getMessage());
}
}
private function loadExtension($extId) {
$extDir = $this->extensionsDir . '/' . $extId;
$mainFile = $extDir . '/main.php';
if (!is_dir($extDir) || !file_exists($mainFile)) return;
$manifestFile = $extDir . '/manifest.json';
if (!file_exists($manifestFile)) return;
$manifest = json_decode(file_get_contents($manifestFile), true);
if (!$manifest || !isset($manifest['id']) || $manifest['id'] !== $extId) return;
try {
$this->executeExtension($mainFile, $extId);
$this->extensions[$extId] = $manifest;
} catch (Exception $e) {
error_log("Failed to load extension {$extId}: " . $e->getMessage());
}
}
private function executeExtension($file, $extId) {
$ext = [
'id' => $extId,
'dir' => $this->extensionsDir . '/' . $extId,
'registerHook' => function($hook, $callback) use ($extId) {
$this->registerHook($hook, $callback, $extId);
},
'getData' => function($key) use ($extId) {
return $this->getExtensionData($extId, $key);
},
'setData' => function($key, $value) use ($extId) {
return $this->setExtensionData($extId, $key, $value);
}
];
require_once $file;
}
private function registerHook($hook, $callback, $extId) {
if (!isset($this->hooks[$hook])) $this->hooks[$hook] = [];
$this->hooks[$hook][] = ['callback' => $callback, 'extension' => $extId];
}
public function runHook($hook, $data = null) {
if (!isset($this->hooks[$hook])) return $data;
foreach ($this->hooks[$hook] as $hookData) {
try {
$result = call_user_func($hookData['callback'], $data);
if ($result !== null) $data = $result;
} catch (Exception $e) {
error_log("Extension {$hookData['extension']} hook {$hook} error: " . $e->getMessage());
}
}
return $data;
}
private function getExtensionData($extId, $key) {
$dataFile = $this->extensionsDir . '/' . $extId . '/data.json';
if (!file_exists($dataFile)) return null;
$data = json_decode(file_get_contents($dataFile), true);
return $data[$key] ?? null;
}
private function setExtensionData($extId, $key, $value) {
$dataFile = $this->extensionsDir . '/' . $extId . '/data.json';
$data = file_exists($dataFile) ? json_decode(file_get_contents($dataFile), true) ?? [] : [];
$data[$key] = $value;
return file_put_contents($dataFile, json_encode($data, JSON_PRETTY_PRINT), LOCK_EX);
}
public function getLoadedExtensions() {
return $this->extensions;
}
public function isExtensionLoaded($extId) {
return isset($this->extensions[$extId]);
}
}
$GLOBALS['extensionLoader'] = ExtensionLoader::getInstance();
function ext_hook($hook, $data = null) {
global $extensionLoader;
if (!$extensionLoader) return $data;
return $extensionLoader->runHook($hook, $data);
}
function ext_loaded($extId) {
global $extensionLoader;
return $extensionLoader ? $extensionLoader->isExtensionLoaded($extId) : false;
}
function ext_list() {
global $extensionLoader;
return $extensionLoader ? $extensionLoader->getLoadedExtensions() : [];
}