* * @author LibreNMS Group * * @link https://www.librenms.org * * @copyright 2016 */ namespace LibreNMS; use App\Models\Plugin; use LibreNMS\Util\Notifications; use Log; /** * Handles loading of plugins * * @author LibreNMS Group * * @link https://www.librenms.org * * @copyright 2016 * * Supported hooks * */ class Plugins { /** * Array of plugin hooks * * @var array|null */ private static $plugins = null; /** * Start loading active plugins * * @return bool */ public static function start() { if (! is_null(self::$plugins)) { return false; } self::$plugins = []; $plugin_dir = Config::get('plugin_dir'); if (! file_exists($plugin_dir)) { return false; } $plugin_files = Plugin::isActive()->get()->toArray(); foreach ($plugin_files as $plugins) { $plugin_file = $plugin_dir . '/' . $plugins['plugin_name'] . '/' . $plugins['plugin_name'] . '.php'; $plugin_info = pathinfo($plugin_file); if ($plugin_info['extension'] !== 'php') { continue; } if (! is_file($plugin_file)) { continue; } self::load($plugin_file, $plugin_info['filename']); } return true; } /** * Load plugin * * @param string $file Full path and filename of plugin * @param string $pluginName Plugin name without any namespace * @return object|null */ public static function load($file, $pluginName) { chdir(Config::get('install_dir') . '/html'); $plugin = self::getInstance($file, $pluginName); if (! is_null($plugin)) { $class = get_class($plugin); $hooks = get_class_methods($class); foreach ((array) $hooks as $hookName) { if ($hookName[0] != '_') { self::$plugins[$hookName][] = $plugin; } } } chdir(Config::get('install_dir')); return $plugin; } /** * Get an instance of this plugin * Search various namespaces and include files if needed. * * @param string $file * @param string $pluginName * @return object|null */ private static function getInstance($file, $pluginName) { $ns_prefix = 'LibreNMS\\Plugins\\'; $ns_psr4 = $ns_prefix . $pluginName . '\\' . $pluginName; $ns_plugin = $ns_prefix . $pluginName; $ns_global = $pluginName; if (class_exists($ns_psr4)) { return new $ns_psr4; } if (class_exists($ns_plugin)) { return new $ns_plugin; } // Include file because it's not psr4 (may have been included by previous class_exists calls include_once $file; if (class_exists($ns_global)) { return new $ns_global; } return null; } /** * Get all plugins implementing a specific hook. * * @param string $hook Name of the hook to get count for * @return int|bool */ public static function countHooks($hook) { // count all plugins implementing a specific hook self::start(); if (! empty(self::$plugins[$hook])) { return count(self::$plugins[$hook]); } else { return false; } } /** * Call hook for plugin. * * @param string $hook Name of hook to call * @param array|false $params Optional array of parameters for hook * @return string */ public static function call($hook, $params = false) { chdir(Config::get('install_dir') . '/html'); self::start(); ob_start(); if (! empty(self::$plugins[$hook])) { foreach (self::$plugins[$hook] as $plugin) { try { if (! is_array($params)) { @call_user_func([$plugin, $hook]); } else { @call_user_func_array([$plugin, $hook], $params); } } catch (\Exception|\Error $e) { Log::error($e); $class = (string) get_class($plugin); $name = property_exists($class, 'name') ? $class::$name : basename(str_replace('\\', '/', $class)); Notifications::create("Plugin $name disabled", "$name caused an error and was disabled, please check with the plugin creator to fix the error. The error can be found in logs/librenms.log", 'plugins', 2); Plugin::where('plugin_name', $name)->update(['plugin_active' => 0]); } } } $output = ob_get_contents(); ob_end_clean(); chdir(Config::get('install_dir')); return $output; } /** * Get count of hooks. * * @return int */ public static function count() { self::start(); return count(self::$plugins); } public static function scanNew() { $countInstalled = 0; if (file_exists(\LibreNMS\Config::get('plugin_dir'))) { $plugin_files = array_diff(scandir(\LibreNMS\Config::get('plugin_dir')), ['..', '.']); $plugin_files = array_diff($plugin_files, Plugin::versionOne()->pluck('plugin_name')->toArray()); foreach ($plugin_files as $name) { if (is_dir(\LibreNMS\Config::get('plugin_dir') . '/' . $name) && is_file(\LibreNMS\Config::get('plugin_dir') . '/' . $name . '/' . $name . '.php')) { Plugin::create(['plugin_name' => $name, 'plugin_active' => false, 'version' => 1]); $countInstalled++; } } } return $countInstalled; } public static function scanRemoved() { $countRemoved = 0; if (file_exists(\LibreNMS\Config::get('plugin_dir'))) { $plugin_files = array_diff(scandir(\LibreNMS\Config::get('plugin_dir')), ['.', '..', '.gitignore']); $plugins = Plugin::versionOne()->whereNotIn('plugin_name', $plugin_files)->select('plugin_id')->get(); foreach ($plugins as $plugin) { if ($plugin->delete()) { $countRemoved++; } } } return $countRemoved; } }