Security: verwijder hardcoded wachtwoord, voeg random-wachtwoord-generator toe bij eerste installatie

This commit is contained in:
2026-08-27 08:57:05 +00:00
parent 6485f693dc
commit 74612aefbb
55 changed files with 6019 additions and 876 deletions
+242 -37
View File
@@ -1,15 +1,82 @@
<?php
/**
* Beheert het laden en hooks-systeem van plugins.
*
* Laadt ingeschakelde plugins uit de pluginsdirectory, registreert automatisch
* action- en filter-hooks, en biedt methoden voor plugin-configuratie,
* vertalingen, admin-routes en sidebar-content.
*
* @since 2.6.4
*/
class PluginManager
{
/**
* Geladen plugin-instanties, geïndexeerd op plugin-naam.
*
* @since 2.6.4
* @var array<string,object>
*/
private array $plugins = [];
/**
* Het absolute pad naar de pluginsdirectory.
*
* @since 2.6.4
* @var string
*/
private string $pluginsPath;
/**
* De geïnjecteerde plugin-API-instantie (CMSAPI of AdminPluginAPI).
*
* @since 2.6.4
* @var PluginAPIInterface|null
*/
private $api = null;
/**
* Lijst met ingeschakelde plugin-namen.
*
* @since 2.6.4
* @var array<int,string>
*/
private array $enabledPlugins = [];
/**
* Geregistreerde action-hooks, gegroepeerd per hook-naam en prioriteit.
*
* @since 2.6.4
* @var array<string,array<int,array<int,callable>>>
*/
private array $actions = [];
/**
* Geregistreerde filter-hooks, gegroepeerd per hook-naam en prioriteit.
*
* @since 2.6.4
* @var array<string,array<int,array<int,callable>>>
*/
private array $filters = [];
/**
* De standaardtaal van de site, gebruikt als fallback voor plugins
* zonder eigen default_language in plugin.json.
*
* @since 2.6.4
* @var string
*/
private string $siteDefaultLanguage = 'nl';
/**
* Construeer een PluginManager en laadt direct de ingeschakelde plugins.
*
* @since 2.6.4
*
* @param string $pluginsPath Absoluut pad naar de pluginsdirectory.
* @param array<int,string> $enabledPlugins Lijst met ingeschakelde plugin-namen.
* @param string $siteDefaultLanguage Standaardtaal van de site.
*/
public function __construct(string $pluginsPath, array $enabledPlugins = [], string $siteDefaultLanguage = 'nl')
{
$this->pluginsPath = $pluginsPath;
@@ -19,14 +86,31 @@ class PluginManager
}
/**
* Set the CMS site default language. Used as a fallback when a plugin
* does not declare its own `default_language` in plugin.json.
* Stel de standaardtaal van de site in.
*
* Wordt gebruikt als fallback wanneer een plugin geen eigen `default_language`
* declareert in plugin.json.
*
* @since 2.6.4
*
* @param string $lang Taalcode (bijv. 'nl', 'en').
* @return void
*/
public function setSiteDefaultLanguage(string $lang): void
{
$this->siteDefaultLanguage = $lang !== '' ? $lang : 'nl';
}
/**
* Stel de plugin-API in en geef deze door aan alle geladen plugins.
*
* Plugins die een setAPI()-methode implementeren, ontvangen de API-instantie.
*
* @since 2.6.4
*
* @param PluginAPIInterface $api De plugin-API-instantie.
* @return void
*/
public function setAPI($api): void
{
$this->api = $api;
@@ -38,6 +122,16 @@ class PluginManager
}
}
/**
* Laad alle ingeschakelde plugins uit de pluginsdirectory.
*
* Per plugin wordt het hoofdbestand (<naam>.php) geïncludeerd, de plugin-class
* geïnstantieerd, en action- en filter-hooks automatisch geregistreerd.
*
* @since 2.6.4
*
* @return void
*/
private function loadPlugins(): void
{
if (!is_dir($this->pluginsPath)) {
@@ -82,16 +176,45 @@ class PluginManager
}
}
/**
* Registreer een action-callback voor een hook.
*
* @since 2.6.4
*
* @param string $hook Naam van de action-hook.
* @param callable $callback De callback die bij de hook wordt uitgevoerd.
* @param int $priority Uitvoer-volgorde; lager wordt eerder uitgevoerd.
* @return void
*/
public function addAction(string $hook, callable $callback, int $priority = 10): void
{
$this->actions[$hook][$priority][] = $callback;
}
/**
* Registreer een filter-callback voor een hook.
*
* @since 2.6.4
*
* @param string $hook Naam van de filter-hook.
* @param callable $callback De callback die de waarde filtert.
* @param int $priority Uitvoer-volgorde; lager wordt eerder uitgevoerd.
* @return void
*/
public function addFilter(string $hook, callable $callback, int $priority = 10): void
{
$this->filters[$hook][$priority][] = $callback;
}
/**
* Voer alle geregistreerde callbacks voor een action-hook uit.
*
* @since 2.6.4
*
* @param string $hook Naam van de action-hook.
* @param mixed ...$args Argumenten die aan elke callback worden doorgegeven.
* @return void
*/
public function doAction(string $hook, ...$args): void
{
if (!isset($this->actions[$hook])) return;
@@ -103,6 +226,16 @@ class PluginManager
}
}
/**
* Pas alle geregistreerde filter-callbacks toe op een waarde.
*
* @since 2.6.4
*
* @param string $hook Naam van de filter-hook.
* @param mixed $value De initiële waarde die wordt gefilterd.
* @param mixed ...$args Extra argumenten voor elke filter-callback.
* @return mixed De gefilterde waarde.
*/
public function applyFilters(string $hook, $value, ...$args)
{
if (!isset($this->filters[$hook])) return $value;
@@ -115,32 +248,66 @@ class PluginManager
return $value;
}
/**
* Haal een specifieke plugin-instantie op.
*
* @since 2.6.4
*
* @param string $name Plugin-naam (directorynaam).
* @return object|null De plugin-instantie of null indien niet geladen.
*/
public function getPlugin(string $name): ?object
{
return $this->plugins[$name] ?? null;
}
/**
* Haal alle geladen plugin-instanties op.
*
* @since 2.6.4
*
* @return array<string,object> Plugin-instanties geïndexeerd op naam.
*/
public function getAllPlugins(): array
{
return $this->plugins;
}
/**
* Haal de lijst met ingeschakelde plugin-namen op.
*
* @since 2.6.4
*
* @return array<int,string> Lijst met ingeschakelde plugin-namen.
*/
public function getEnabledPlugins(): array
{
return $this->enabledPlugins;
}
/**
* Controleer of een plugin is ingeschakeld.
*
* @since 2.6.4
*
* @param string $pluginName Plugin-naam (directorynaam).
* @return bool True indien de plugin is ingeschakeld.
*/
public function isEnabled(string $pluginName): bool
{
return in_array($pluginName, $this->enabledPlugins, true);
}
/**
* Get the runtime config for a plugin: defaults from plugin.json `settings`
* merged with overrides from the plugin's config.json.
* Haal de runtime-configuratie van een plugin op.
*
* @param string $pluginName Plugin name (directory name)
* @return array Resolved config: [key => value, ...]
* Standaardwaarden uit plugin.json `settings` worden samengevoegd met
* overrides uit het config.json van de plugin.
*
* @since 2.6.4
*
* @param string $pluginName Plugin-naam (directorynaam).
* @return array<string,mixed> Opgeloste configuratie als [key => value].
*/
public function getPluginConfig(string $pluginName): array
{
@@ -167,15 +334,17 @@ class PluginManager
}
/**
* Get the default (fallback) language declared by a plugin.
* Haal de standaard (fallback) taal van een plugin op.
*
* Resolved from (in order):
* Resolved in volgorde van:
* 1. plugin.json `default_language`
* 2. CMS site config `language.default`
* 2. CMS site-config `language.default`
* 3. 'nl'
*
* @param string $pluginName Plugin directory name
* @return string Language code (e.g. 'nl', 'en')
* @since 2.6.4
*
* @param string $pluginName Plugin-directorynaam.
* @return string Taalcode (bijv. 'nl', 'en').
*/
public function getPluginDefaultLanguage(string $pluginName): string
{
@@ -190,15 +359,17 @@ class PluginManager
}
/**
* Load the translations for a plugin for the requested language.
* Laad de vertalingen voor een plugin voor de aangevraagde taal.
*
* Fallback chain: requested language -> plugin default language -> empty array.
* Fallback-keten: aangevraagde taal -> standaardtaal van de plugin -> lege array.
*
* @param string $pluginName Plugin directory name
* @param string $lang Requested language code
* @param string $context Translation context: 'admin' or 'site' (front-end).
* Defaults to 'admin' for system plugins, 'site' for content plugins.
* @return array Translations [key => value]
* @since 2.6.4
*
* @param string $pluginName Plugin-directorynaam.
* @param string $lang Aangevraagde taalcode.
* @param string $context Vertaalcontext: 'admin' of 'site' (front-end).
* Standaard 'admin' voor system-plugins, 'site' voor content-plugins.
* @return array<string,string> Vertalingen als [key => value].
*/
public function getPluginTranslations(string $pluginName, string $lang, string $context = 'admin'): array
{
@@ -232,14 +403,16 @@ class PluginManager
}
/**
* Collect translations for every loaded plugin for the requested language.
* Verzamel vertalingen voor alle geladen plugins voor de aangevraagde taal.
*
* Returns an associative array keyed by plugin name:
* Geeft een associatieve array terug, geïndexeerd op plugin-naam:
* ['Statistics' => [...], 'Logs' => [...], ...]
*
* @param string $lang Requested language code
* @param string $context 'admin' or 'site'
* @return array Plugin translations keyed by plugin name
* @since 2.6.4
*
* @param string $lang Aangevraagde taalcode.
* @param string $context 'admin' of 'site'.
* @return array<string,array<string,string>> Plugin-vertalingen geïndexeerd op plugin-naam.
*/
public function getAllPluginTranslations(string $lang, string $context = 'admin'): array
{
@@ -252,6 +425,16 @@ class PluginManager
return $all;
}
/**
* Controleer of een plugin viewable is.
*
* Een plugin is viewable tenzij zijn configuratie 'viewable' expliciet op false zet.
*
* @since 2.6.4
*
* @param object $plugin De plugin-instantie.
* @return bool True indien de plugin viewable is.
*/
public function isPluginViewable(object $plugin): bool
{
if (method_exists($plugin, 'getConfig')) {
@@ -261,6 +444,17 @@ class PluginManager
return true;
}
/**
* Haal de samengevoegde sidebar-content van alle viewable plugins op.
*
* Elke plugin met een getSidebarContent()-methode levert HTML die wordt
* ingepakt in een Bootstrap-card met de plugin-titel.
*
* @since 2.6.4
*
* @param array<int,string>|null $allowedPlugins Optionele whitelist van plugin-namen.
* @return string De samengevoegde sidebar-HTML.
*/
public function getSidebarContent(?array $allowedPlugins = null): string
{
$sidebarContent = '';
@@ -300,9 +494,11 @@ class PluginManager
}
/**
* Get CSS URLs from all enabled plugins that provide getCssUrl().
* Haal CSS-URL's op van alle ingeschakelde plugins die getCssUrl() implementeren.
*
* @return array List of CSS URLs
* @since 2.6.4
*
* @return array<int,string> Lijst met CSS-URL's.
*/
public function getPluginCssUrls(): array
{
@@ -319,10 +515,13 @@ class PluginManager
}
/**
* Collect admin menu items from all enabled plugins that implement getAdminMenu().
* Each plugin returns [['route' => 'plugin-name/action', 'label' => 'Label', 'icon' => 'bi-icon']].
* Verzamel admin-menu-items van alle plugins die getAdminMenu() implementeren.
*
* @return array Admin menu items from all plugins
* Elke plugin levert [['route' => 'plugin-name/action', 'label' => 'Label', 'icon' => 'bi-icon']].
*
* @since 2.6.4
*
* @return array<int,array<string,mixed>> Admin-menu-items van alle plugins.
*/
public function getAdminMenuItems(): array
{
@@ -341,12 +540,16 @@ class PluginManager
}
/**
* Dispatch an admin route to a plugin that handles it.
* Plugins implement handleAdminRoute(string $action): ?string (returns rendered HTML or null).
* Dispatch een admin-route naar de plugin die deze afhandelt.
*
* @param string $pluginName Plugin name
* @param string $action Action/sub-route within the plugin
* @return string|null Rendered HTML, or null if plugin doesn't handle it
* Plugins implementeren handleAdminRoute(string $action): ?string
* (geeft gerenderde HTML of null terug).
*
* @since 2.6.4
*
* @param string $pluginName Plugin-naam.
* @param string $action Actie/sub-route binnen de plugin.
* @return string|null Gerenderde HTML, of null indien de plugin deze niet afhandelt.
*/
public function dispatchAdminRoute(string $pluginName, string $action): ?string
{
@@ -361,10 +564,12 @@ class PluginManager
}
/**
* Find which plugin handles a given admin route.
* Bepaal welke plugin een opgegeven admin-route afhandelt.
*
* @param string $route The admin route (e.g. 'statistics' or 'statistics/details')
* @return array|null ['plugin' => name, 'action' => action, 'permission' => required permission] or null
* @since 2.6.4
*
* @param string $route De admin-route (bijv. 'statistics' of 'statistics/details').
* @return array<string,mixed>|null ['plugin' => naam, 'action' => actie, 'permission' => vereiste permissie] of null.
*/
public function resolveAdminRoute(string $route): ?array
{
@@ -382,4 +587,4 @@ class PluginManager
}
return null;
}
}
}