3 * @file src/Core/Addon.php
5 namespace Friendica\Core;
8 use Friendica\BaseObject;
9 use Friendica\Core\Logger;
10 use Friendica\Database\DBA;
13 * Some functions to handle addons
15 class Addon extends BaseObject
18 * List of the names of enabled addons
22 private static $addons = [];
25 * @brief Synchronize addons:
27 * system.addon contains a comma-separated list of names
28 * of addons which are used on this system.
29 * Go through the database list of already installed addons, and if we have
30 * an entry, but it isn't in the config list, call the uninstall procedure
31 * and mark it uninstalled in the database (for now we'll remove it).
32 * Then go through the config list and if we have a addon that isn't installed,
33 * call the install procedure and add it to the database.
36 public static function loadAddons()
38 $installed_addons = [];
40 $r = DBA::select('addon', [], ['installed' => 1]);
41 if (DBA::isResult($r)) {
42 $installed_addons = DBA::toArray($r);
45 $addons = Config::get('system', 'addon');
49 $addons_arr = explode(',', str_replace(' ', '', $addons));
52 self::$addons = $addons_arr;
56 foreach ($installed_addons as $addon) {
57 if (!self::isEnabled($addon['name'])) {
58 self::uninstall($addon['name']);
60 $installed_arr[] = $addon['name'];
64 foreach (self::$addons as $p) {
65 if (!in_array($p, $installed_arr)) {
72 * @brief uninstalls an addon.
74 * @param string $addon name of the addon
77 public static function uninstall($addon)
79 Logger::log("Addons: uninstalling " . $addon);
80 DBA::delete('addon', ['name' => $addon]);
82 @include_once('addon/' . $addon . '/' . $addon . '.php');
83 if (function_exists($addon . '_uninstall')) {
84 $func = $addon . '_uninstall';
88 unset(self::$addons[array_search($addon, self::$addons)]);
92 * @brief installs an addon.
94 * @param string $addon name of the addon
97 public static function install($addon)
99 // silently fail if addon was removed
101 if (!file_exists('addon/' . $addon . '/' . $addon . '.php')) {
104 Logger::log("Addons: installing " . $addon);
105 $t = @filemtime('addon/' . $addon . '/' . $addon . '.php');
106 @include_once('addon/' . $addon . '/' . $addon . '.php');
107 if (function_exists($addon . '_install')) {
108 $func = $addon . '_install';
111 $addon_admin = (function_exists($addon . "_addon_admin") ? 1 : 0);
113 DBA::insert('addon', ['name' => $addon, 'installed' => true,
114 'timestamp' => $t, 'plugin_admin' => $addon_admin]);
116 // we can add the following with the previous SQL
117 // once most site tables have been updated.
118 // This way the system won't fall over dead during the update.
120 if (file_exists('addon/' . $addon . '/.hidden')) {
121 DBA::update('addon', ['hidden' => true], ['name' => $addon]);
124 if (!self::isEnabled($addon)) {
125 self::$addons[] = $addon;
129 Logger::log("Addons: FAILED installing " . $addon);
135 * reload all updated addons
137 public static function reload()
139 $addons = Config::get('system', 'addon');
140 if (strlen($addons)) {
141 $r = DBA::select('addon', [], ['installed' => 1]);
142 if (DBA::isResult($r)) {
143 $installed = DBA::toArray($r);
148 $addon_list = explode(',', $addons);
150 if (count($addon_list)) {
151 foreach ($addon_list as $addon) {
152 $addon = trim($addon);
153 $fname = 'addon/' . $addon . '/' . $addon . '.php';
155 if (file_exists($fname)) {
156 $t = @filemtime($fname);
157 foreach ($installed as $i) {
158 if (($i['name'] == $addon) && ($i['timestamp'] != $t)) {
159 Logger::log('Reloading addon: ' . $i['name']);
160 @include_once($fname);
162 if (function_exists($addon . '_uninstall')) {
163 $func = $addon . '_uninstall';
166 if (function_exists($addon . '_install')) {
167 $func = $addon . '_install';
170 DBA::update('addon', ['timestamp' => $t], ['id' => $i['id']]);
180 * @brief Parse addon comment in search of addon infos.
185 * * Description: An addon which plugs in
187 * * Author: John <profile url>
188 * * Author: Jane <email>
189 * * Maintainer: Jess <email>
192 * @param string $addon the name of the addon
193 * @return array with the addon information
195 public static function getInfo($addon)
208 if (!is_file("addon/$addon/$addon.php")) {
212 $stamp1 = microtime(true);
213 $f = file_get_contents("addon/$addon/$addon.php");
214 $a->saveTimestamp($stamp1, "file");
216 $r = preg_match("|/\*.*\*/|msU", $f, $m);
219 $ll = explode("\n", $m[0]);
220 foreach ($ll as $l) {
221 $l = trim($l, "\t\n\r */");
223 $addon_info = array_map("trim", explode(":", $l, 2));
224 if (count($addon_info) < 2) {
228 list($type, $v) = $addon_info;
229 $type = strtolower($type);
230 if ($type == "author" || $type == "maintainer") {
231 $r = preg_match("|([^<]+)<([^>]+)>|", $v, $m);
233 $info[$type][] = ['name' => $m[1], 'link' => $m[2]];
235 $info[$type][] = ['name' => $v];
238 if (array_key_exists($type, $info)) {
249 * Checks if the provided addon is enabled
251 * @param string $addon
254 public static function isEnabled($addon)
256 return in_array($addon, self::$addons);
260 * Returns a list of the enabled addon names
264 public static function getEnabledList()
266 return self::$addons;
270 * Saves the current enabled addon list in the system.addon config key
274 public static function saveEnabledList()
276 return Config::set("system", "addon", implode(", ", self::$addons));
280 * Returns the list of non-hidden enabled addon names
284 public static function getVisibleList()
286 $visible_addons = [];
287 $stmt = DBA::select('addon', ['name'], ['hidden' => false, 'installed' => true]);
288 if (DBA::isResult($stmt)) {
289 foreach (DBA::toArray($stmt) as $addon) {
290 $visible_addons[] = $addon['name'];
294 return $visible_addons;
298 * Shim of Hook::register left for backward compatibility purpose.
300 * @see Hook::register
301 * @deprecated since version 2018.12
302 * @param string $hook the name of the hook
303 * @param string $file the name of the file that hooks into
304 * @param string $function the name of the function that the hook will call
305 * @param int $priority A priority (defaults to 0)
308 public static function registerHook($hook, $file, $function, $priority = 0)
310 return Hook::register($hook, $file, $function, $priority);
314 * Shim of Hook::unregister left for backward compatibility purpose.
316 * @see Hook::unregister
317 * @deprecated since version 2018.12
318 * @param string $hook the name of the hook
319 * @param string $file the name of the file that hooks into
320 * @param string $function the name of the function that the hook called
323 public static function unregisterHook($hook, $file, $function)
325 return Hook::unregister($hook, $file, $function);
329 * Shim of Hook::callAll left for backward-compatibility purpose.
332 * @deprecated since version 2018.12
333 * @param string $name of the hook to call
334 * @param string|array &$data to transmit to the callback handler
336 public static function callHooks($name, &$data = null)
338 Hook::callAll($name, $data);