3 * @file src/Core/Addon.php
5 namespace Friendica\Core;
8 use Friendica\BaseObject;
9 use Friendica\Database\DBA;
12 * Some functions to handle addons
14 class Addon extends BaseObject
17 * List of the names of enabled addons
21 private static $addons = [];
24 * @brief Synchronize addons:
26 * system.addon contains a comma-separated list of names
27 * of addons which are used on this system.
28 * Go through the database list of already installed addons, and if we have
29 * an entry, but it isn't in the config list, call the uninstall procedure
30 * and mark it uninstalled in the database (for now we'll remove it).
31 * Then go through the config list and if we have a addon that isn't installed,
32 * call the install procedure and add it to the database.
35 public static function loadAddons()
37 $installed_addons = [];
39 $r = DBA::select('addon', [], ['installed' => 1]);
40 if (DBA::isResult($r)) {
41 $installed_addons = DBA::toArray($r);
44 $addons = Config::get('system', 'addon');
48 $addons_arr = explode(',', str_replace(' ', '', $addons));
51 self::$addons = $addons_arr;
55 foreach ($installed_addons as $addon) {
56 if (!self::isEnabled($addon['name'])) {
57 self::uninstall($addon['name']);
59 $installed_arr[] = $addon['name'];
63 foreach (self::$addons as $p) {
64 if (!in_array($p, $installed_arr)) {
71 * @brief uninstalls an addon.
73 * @param string $addon name of the addon
76 public static function uninstall($addon)
78 logger("Addons: uninstalling " . $addon);
79 DBA::delete('addon', ['name' => $addon]);
81 @include_once('addon/' . $addon . '/' . $addon . '.php');
82 if (function_exists($addon . '_uninstall')) {
83 $func = $addon . '_uninstall';
87 unset(self::$addons[$idx]);
91 * @brief installs an addon.
93 * @param string $addon name of the addon
96 public static function install($addon)
98 // silently fail if addon was removed
100 if (!file_exists('addon/' . $addon . '/' . $addon . '.php')) {
103 logger("Addons: installing " . $addon);
104 $t = @filemtime('addon/' . $addon . '/' . $addon . '.php');
105 @include_once('addon/' . $addon . '/' . $addon . '.php');
106 if (function_exists($addon . '_install')) {
107 $func = $addon . '_install';
110 $addon_admin = (function_exists($addon . "_addon_admin") ? 1 : 0);
112 DBA::insert('addon', ['name' => $addon, 'installed' => true,
113 'timestamp' => $t, 'plugin_admin' => $addon_admin]);
115 // we can add the following with the previous SQL
116 // once most site tables have been updated.
117 // This way the system won't fall over dead during the update.
119 if (file_exists('addon/' . $addon . '/.hidden')) {
120 DBA::update('addon', ['hidden' => true], ['name' => $addon]);
123 if (!self::isEnabled($addon)) {
124 self::$addons[] = $addon;
128 logger("Addons: FAILED installing " . $addon);
134 * reload all updated addons
136 public static function reload()
138 $addons = Config::get('system', 'addon');
139 if (strlen($addons)) {
140 $r = DBA::select('addon', [], ['installed' => 1]);
141 if (DBA::isResult($r)) {
142 $installed = DBA::toArray($r);
147 $addon_list = explode(',', $addons);
149 if (count($addon_list)) {
150 foreach ($addon_list as $addon) {
151 $addon = trim($addon);
152 $fname = 'addon/' . $addon . '/' . $addon . '.php';
154 if (file_exists($fname)) {
155 $t = @filemtime($fname);
156 foreach ($installed as $i) {
157 if (($i['name'] == $addon) && ($i['timestamp'] != $t)) {
158 logger('Reloading addon: ' . $i['name']);
159 @include_once($fname);
161 if (function_exists($addon . '_uninstall')) {
162 $func = $addon . '_uninstall';
165 if (function_exists($addon . '_install')) {
166 $func = $addon . '_install';
169 DBA::update('addon', ['timestamp' => $t], ['id' => $i['id']]);
179 * @brief Parse addon comment in search of addon infos.
184 * * Description: An addon which plugs in
186 * * Author: John <profile url>
187 * * Author: Jane <email>
188 * * Maintainer: Jess <email>
191 * @param string $addon the name of the addon
192 * @return array with the addon information
194 public static function getInfo($addon)
207 if (!is_file("addon/$addon/$addon.php")) {
211 $stamp1 = microtime(true);
212 $f = file_get_contents("addon/$addon/$addon.php");
213 $a->saveTimestamp($stamp1, "file");
215 $r = preg_match("|/\*.*\*/|msU", $f, $m);
218 $ll = explode("\n", $m[0]);
219 foreach ($ll as $l) {
220 $l = trim($l, "\t\n\r */");
222 $addon_info = array_map("trim", explode(":", $l, 2));
223 if (count($addon_info) < 2) {
227 list($type, $v) = $addon_info;
228 $type = strtolower($type);
229 if ($type == "author" || $type == "maintainer") {
230 $r = preg_match("|([^<]+)<([^>]+)>|", $v, $m);
232 $info[$type][] = ['name' => $m[1], 'link' => $m[2]];
234 $info[$type][] = ['name' => $v];
237 if (array_key_exists($type, $info)) {
248 * Checks if the provided addon is enabled
250 * @param string $addon
253 public static function isEnabled($addon)
255 return in_array($addon, self::$addons);
259 * Returns a list of the enabled addon names
263 public static function getEnabledList()
265 return self::$addons;
269 * Saves the current enabled addon list in the system.addon config key
273 public static function saveEnabledList()
275 return Config::set("system", "addon", implode(", ", self::$addons));
279 * Returns the list of non-hidden enabled addon names
283 public static function getVisibleList()
285 $visible_addons = [];
286 $stmt = DBA::select('addon', ['name'], ['hidden' => false, 'installed' => true]);
287 if (DBA::isResult($stmt)) {
288 foreach (DBA::toArray($stmt) as $addon) {
289 $visible_addons[] = $addon['name'];
293 return $visible_addons;
297 * Shim of Hook::register left for backward compatibility purpose.
299 * @see Hook::register
300 * @deprecated since version 2018.12
301 * @param string $hook the name of the hook
302 * @param string $file the name of the file that hooks into
303 * @param string $function the name of the function that the hook will call
304 * @param int $priority A priority (defaults to 0)
307 public static function registerHook($hook, $file, $function, $priority = 0)
309 return Hook::register($hook, $file, $function, $priority);
313 * Shim of Hook::unregister left for backward compatibility purpose.
315 * @see Hook::unregister
316 * @deprecated since version 2018.12
317 * @param string $hook the name of the hook
318 * @param string $file the name of the file that hooks into
319 * @param string $function the name of the function that the hook called
322 public static function unregisterHook($hook, $file, $function)
324 return Hook::unregister($hook, $file, $function);
328 * Shim of Hook::callAll left for backward-compatibility purpose.
331 * @deprecated since version 2018.12
332 * @param string $name of the hook to call
333 * @param string|array &$data to transmit to the callback handler
335 public static function callHooks($name, &$data = null)
337 Hook::callAll($name, $data);