streams/Code/Lib/Addon.php

358 lines
10 KiB
PHP
Raw Normal View History

<?php
2022-02-16 04:08:28 +00:00
namespace Code\Lib;
2022-03-07 00:03:26 +00:00
use Exception;
2022-07-15 08:14:44 +00:00
class Addon {
2022-07-15 08:14:44 +00:00
/**
* @brief Handle errors in plugin calls
*
* @param string $addon name of the addon
* @param string $error_text text of error
* @param bool $uninstall uninstall plugin
*/
2022-08-23 10:15:05 +00:00
public static function ErrorHandler($addon, $notice, $log, $uninstall = false): void
{
2022-08-20 23:11:42 +00:00
logger("Addons: [" . $addon . "] Error: ". $log);
if ($notice != '') {
2022-08-20 23:11:42 +00:00
notice("[" . $addon . "] Error: ". $notice);
}
if ($uninstall) {
self::uninstall($addon);
}
}
/**
* @brief Unloads an addon.
*
* @param string $addon name of the addon
*/
public static function unload($addon)
{
logger("Addons: unloading " . $addon, LOGGER_DEBUG);
@include_once('addon/' . $addon . '/' . $addon . '.php');
if (function_exists($addon . '_unload')) {
$func = $addon . '_unload';
try {
$func();
} catch (Exception $e) {
self::ErrorHandler($addon, "Unable to unload.", $e->getMessage());
}
}
}
/**
* @brief Uninstalls an addon.
*
* @param string $addon name of the addon
* @return bool
*/
public static function uninstall($addon)
{
self::unload($addon);
if (! file_exists('addon/' . $addon . '/' . $addon . '.php')) {
2022-07-21 05:32:00 +00:00
q("DELETE FROM addon WHERE aname = '%s' ",
dbesc($addon)
);
return false;
}
logger("Addons: uninstalling " . $addon);
2022-08-22 10:28:48 +00:00
@include_once('addon/' . $addon . '/' . $addon . '.php');
if (function_exists($addon . '_uninstall')) {
$func = $addon . '_uninstall';
try {
$func();
} catch (Exception $e) {
self::ErrorHandler($addon, "Unable to uninstall.", "Unable to run _uninstall : ".$e->getMessage());
}
}
2022-07-21 05:32:00 +00:00
q("DELETE FROM addon WHERE aname = '%s' ",
dbesc($addon)
);
2022-08-23 10:15:05 +00:00
return true;
}
/**
* @brief Installs an addon.
*
* This function is called once to install the addon (either from the cli or via
* the web admin). This will also call load_plugin() once.
*
* @param string $addon name of the addon
* @return bool
*/
public static function install($addon)
{
if (! file_exists('addon/' . $addon . '/' . $addon . '.php')) {
return false;
}
logger("Addons: installing " . $addon);
$t = @filemtime('addon/' . $addon . '/' . $addon . '.php');
@include_once('addon/' . $addon . '/' . $addon . '.php');
if (function_exists($addon . '_install')) {
$func = $addon . '_install';
try {
$func();
} catch (Exception $e) {
self::ErrorHandler($addon, "Install failed.", "Install failed : ".$e->getMessage());
2022-08-23 10:15:05 +00:00
return false;
}
}
$addon_admin = (function_exists($addon . '_plugin_admin') ? 1 : 0);
$d = q(
"select * from addon where aname = '%s' limit 1",
dbesc($addon)
);
if (! $d) {
q(
"INSERT INTO addon (aname, installed, tstamp, plugin_admin) VALUES ( '%s', 1, %d , %d ) ",
dbesc($addon),
intval($t),
$addon_admin
);
}
self::load($addon);
2022-08-23 10:15:05 +00:00
return true;
}
/**
2022-08-13 10:57:14 +00:00
* @brief loads an addon by name.
*
* @param string $addon name of the addon
* @return bool
*/
2022-02-12 19:22:42 +00:00
public static function load($addon)
{
// silently fail if plugin was removed
if (! file_exists('addon/' . $addon . '/' . $addon . '.php')) {
return false;
}
logger("Addons: loading " . $addon, LOGGER_DEBUG);
@include_once('addon/' . $addon . '/' . $addon . '.php');
if (function_exists($addon . '_load')) {
$func = $addon . '_load';
try {
$func();
} catch (Exception $e) {
self::ErrorHandler($addon, "Unable to load.", "FAILED loading : ".$e->getMessage(), true);
2022-08-23 10:15:05 +00:00
return false;
}
// we can add the following with the previous SQL
// once most site tables have been updated.
// This way the system won't fall over dead during the update.
if (file_exists('addon/' . $addon . '/.hidden')) {
q(
"update addon set hidden = 1 where name = '%s'",
dbesc($addon)
);
}
return true;
} else {
logger("Addons: FAILED loading " . $addon . " (missing _load function)");
return false;
}
}
/**
* @brief Check if addon is installed.
*
2022-07-21 05:32:00 +00:00
* @param string $addon
* @return bool
*/
2022-07-21 05:32:00 +00:00
public static function is_installed($addon)
{
2022-07-15 08:14:44 +00:00
$r = q("select aname from addon where aname = '%s' and installed = 1 limit 1",
2022-07-21 05:32:00 +00:00
dbesc($addon)
);
2022-10-11 07:59:26 +00:00
return (bool)$r;
}
/**
* @brief Reload all updated plugins.
*/
public static function reload_all()
{
2022-07-21 05:32:00 +00:00
$installed = q("SELECT * FROM addon WHERE installed = 1");
if (!$installed) {
return;
}
2022-07-21 05:32:00 +00:00
foreach ($installed as $i) {
$addon = $i['aname'];
$fname = 'addon/' . $addon . '/' . $addon . '.php';
if (file_exists($fname)) {
$t = @filemtime($fname);
if ($t && intval($i['tstamp']) !== $t) {
logger('Reloading plugin: ' . $addon, LOGGER_DEBUG);
@include_once($fname);
if (function_exists($addon . '_unload')) {
$func = $addon . '_unload';
try {
$func();
} catch (Exception $e) {
self::ErrorHandler($addon, "", "UNLOAD FAILED (uninstalling) : ".$e->getMessage(), true);
continue;
}
}
2022-07-21 05:32:00 +00:00
if (function_exists($addon . '_load')) {
$func = $addon . '_load';
try {
$func();
} catch (Exception $e) {
self::ErrorHandler($addon, "", "LOAD FAILED (uninstalling): ".$e->getMessage(), true);
continue;
}
}
q("UPDATE addon SET tstamp = %d WHERE id = %d",
intval($t),
intval($i['id'])
);
}
}
}
}
public static function list_installed()
{
$r = q("select * from addon where installed = 1 order by aname asc");
return(($r) ? ids_to_array($r, 'aname') : []);
}
/**
2022-08-13 10:57:14 +00:00
* @brief Get a list of non-hidden addons.
*
* @return array
*/
public static function list_visible()
{
2022-07-15 08:14:44 +00:00
$r = q("select * from addon where hidden = 0 order by aname asc");
$x = (($r) ? ids_to_array($r, 'aname') : []);
$y = [];
if ($x) {
foreach ($x as $xv) {
if (is_dir('addon/' . $xv)) {
$y[] = $xv;
}
}
}
return $y;
}
2022-02-12 19:22:42 +00:00
/**
* @brief Parse plugin comment in search of plugin infos.
*
* like
* \code
* * Name: Plugin
* * Description: A plugin which plugs in
* * Version: 1.2.3
* * Author: John <profile url>
* * Author: Jane <email>
* *
*\endcode
* @param string $plugin the name of the plugin
* @return array with the plugin information
*/
2022-08-13 10:57:14 +00:00
public static function get_info(string $plugin): array
2022-02-12 19:22:42 +00:00
{
$info = null;
2022-03-07 00:03:26 +00:00
$has_yaml = true;
2022-07-15 08:14:44 +00:00
2022-02-12 19:22:42 +00:00
if (is_file("addon/$plugin/$plugin.yml")) {
$info = Infocon::from_file("addon/$plugin/$plugin.yml");
}
elseif (is_file("addon/$plugin/$plugin.php")) {
2022-03-07 00:03:26 +00:00
$has_yaml = false;
2022-02-12 19:22:42 +00:00
$info = Infocon::from_c_comment("addon/$plugin/$plugin.php");
}
2022-03-07 00:03:26 +00:00
if ($info && ! $has_yaml) {
try {
2022-07-21 05:32:00 +00:00
file_put_contents("addon/$plugin/$plugin.yml", Yaml::encode($info));
2022-03-07 00:03:26 +00:00
}
catch (Exception $e) {
2022-10-11 07:59:26 +00:00
logger('Exception:' . $e->getMessage());
2022-03-07 00:03:26 +00:00
}
}
2022-07-15 08:14:44 +00:00
2022-08-13 10:57:14 +00:00
return $info ?: [ 'name' => $plugin ] ;
2022-02-12 19:22:42 +00:00
}
2022-07-15 08:14:44 +00:00
2022-08-13 10:57:14 +00:00
public static function check_versions($info): bool
2022-02-12 20:43:29 +00:00
{
if (! is_array($info)) {
return true;
}
if (array_key_exists('minversion', $info) && $info['minversion']) {
if (! version_compare(STD_VERSION, trim($info['minversion']), '>=')) {
logger('minversion limit: ' . $info['name'], LOGGER_NORMAL, LOG_WARNING);
return false;
}
}
if (array_key_exists('maxversion', $info) && $info['maxversion']) {
if (! version_compare(STD_VERSION, trim($info['maxversion']), '<')) {
logger('maxversion limit: ' . $info['name'], LOGGER_NORMAL, LOG_WARNING);
return false;
}
}
if (array_key_exists('minphpversion', $info) && $info['minphpversion']) {
if (! version_compare(PHP_VERSION, trim($info['minphpversion']), '>=')) {
logger('minphpversion limit: ' . $info['name'], LOGGER_NORMAL, LOG_WARNING);
return false;
}
}
if (array_key_exists('requires', $info)) {
$arr = explode(',', $info['requires']);
$found = true;
if ($arr) {
foreach ($arr as $test) {
$test = trim($test);
if (! $test) {
continue;
}
if (strpos($test, '.')) {
$conf = explode('.', $test);
if (get_config(trim($conf[0]), trim($conf[1]))) {
return true;
} else {
return false;
}
}
if (! in_array($test, Addon::list_installed())) {
$found = false;
}
}
}
if (! $found) {
return false;
}
}
return true;
}
2022-10-11 07:59:26 +00:00
}