]> git.mxchange.org Git - friendica.git/blob - src/Core/Addon.php
Fix types in doc blocks/prototypes
[friendica.git] / src / Core / Addon.php
1 <?php
2 /**
3  * @file src/Core/Addon.php
4  */
5 namespace Friendica\Core;
6
7 use Friendica\BaseObject;
8 use Friendica\Database\DBA;
9
10 /**
11  * Some functions to handle addons
12  */
13 class Addon extends BaseObject
14 {
15         /**
16          * List of the names of enabled addons
17          *
18          * @var array
19          */
20         private static $addons = [];
21
22         /**
23          * @brief Synchronize addons:
24          *
25          * system.addon contains a comma-separated list of names
26          * of addons which are used on this system.
27          * Go through the database list of already installed addons, and if we have
28          * an entry, but it isn't in the config list, call the uninstall procedure
29          * and mark it uninstalled in the database (for now we'll remove it).
30          * Then go through the config list and if we have a addon that isn't installed,
31          * call the install procedure and add it to the database.
32          *
33          */
34         public static function loadAddons()
35         {
36                 $installed_addons = [];
37
38                 $r = DBA::select('addon', [], ['installed' => 1]);
39                 if (DBA::isResult($r)) {
40                         $installed_addons = DBA::toArray($r);
41                 }
42
43                 $addons = Config::get('system', 'addon');
44                 $addons_arr = [];
45
46                 if ($addons) {
47                         $addons_arr = explode(',', str_replace(' ', '', $addons));
48                 }
49
50                 self::$addons = $addons_arr;
51
52                 $installed_arr = [];
53
54                 foreach ($installed_addons as $addon) {
55                         if (!self::isEnabled($addon['name'])) {
56                                 self::uninstall($addon['name']);
57                         } else {
58                                 $installed_arr[] = $addon['name'];
59                         }
60                 }
61
62                 foreach (self::$addons as $p) {
63                         if (!in_array($p, $installed_arr)) {
64                                 self::install($p);
65                         }
66                 }
67         }
68
69         /**
70          * @brief uninstalls an addon.
71          *
72          * @param string $addon name of the addon
73          * @return void
74          * @throws \Exception
75          */
76         public static function uninstall($addon)
77         {
78                 Logger::notice("Addon {addon}: {action}", ['action' => 'uninstall', 'addon' => $addon]);
79                 DBA::delete('addon', ['name' => $addon]);
80
81                 @include_once('addon/' . $addon . '/' . $addon . '.php');
82                 if (function_exists($addon . '_uninstall')) {
83                         $func = $addon . '_uninstall';
84                         $func();
85                 }
86
87                 unset(self::$addons[array_search($addon, self::$addons)]);
88         }
89
90         /**
91          * @brief installs an addon.
92          *
93          * @param string $addon name of the addon
94          * @return bool
95          * @throws \Exception
96          */
97         public static function install($addon)
98         {
99                 // silently fail if addon was removed
100
101                 if (!file_exists('addon/' . $addon . '/' . $addon . '.php')) {
102                         return false;
103                 }
104                 Logger::notice("Addon {addon}: {action}", ['action' => 'install', 'addon' => $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';
109                         $func();
110
111                         $addon_admin = (function_exists($addon . "_addon_admin") ? 1 : 0);
112
113                         DBA::insert('addon', ['name' => $addon, 'installed' => true,
114                                 'timestamp' => $t, 'plugin_admin' => $addon_admin]);
115
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.
119
120                         if (file_exists('addon/' . $addon . '/.hidden')) {
121                                 DBA::update('addon', ['hidden' => true], ['name' => $addon]);
122                         }
123
124                         if (!self::isEnabled($addon)) {
125                                 self::$addons[] = $addon;
126                         }
127                         return true;
128                 } else {
129                         Logger::error("Addon {addon}: {action} failed", ['action' => 'uninstall', 'addon' => $addon]);
130                         return false;
131                 }
132         }
133
134         /**
135          * reload all updated addons
136          */
137         public static function reload()
138         {
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);
144                         } else {
145                                 $installed = [];
146                         }
147
148                         $addon_list = explode(',', $addons);
149
150                         if (count($addon_list)) {
151                                 foreach ($addon_list as $addon) {
152                                         $addon = trim($addon);
153                                         $fname = 'addon/' . $addon . '/' . $addon . '.php';
154
155                                         if (file_exists($fname)) {
156                                                 $t = @filemtime($fname);
157                                                 foreach ($installed as $i) {
158                                                         if (($i['name'] == $addon) && ($i['timestamp'] != $t)) {
159
160                                                                 Logger::notice("Addon {addon}: {action}", ['action' => 'reload', 'addon' => $i['name']]);
161                                                                 @include_once($fname);
162
163                                                                 if (function_exists($addon . '_uninstall')) {
164                                                                         $func = $addon . '_uninstall';
165                                                                         $func();
166                                                                 }
167                                                                 if (function_exists($addon . '_install')) {
168                                                                         $func = $addon . '_install';
169                                                                         $func();
170                                                                 }
171                                                                 DBA::update('addon', ['timestamp' => $t], ['id' => $i['id']]);
172                                                         }
173                                                 }
174                                         }
175                                 }
176                         }
177                 }
178         }
179
180         /**
181          * @brief Parse addon comment in search of addon infos.
182          *
183          * like
184          * \code
185          *   * Name: addon
186          *   * Description: An addon which plugs in
187          * . * Version: 1.2.3
188          *   * Author: John <profile url>
189          *   * Author: Jane <email>
190          *   * Maintainer: Jess <email>
191          *   *
192          *   *\endcode
193          * @param string $addon the name of the addon
194          * @return array with the addon information
195          * @throws \Exception
196          */
197         public static function getInfo($addon)
198         {
199                 $a = self::getApp();
200
201                 $info = [
202                         'name' => $addon,
203                         'description' => "",
204                         'author' => [],
205                         'maintainer' => [],
206                         'version' => "",
207                         'status' => ""
208                 ];
209
210                 if (!is_file("addon/$addon/$addon.php")) {
211                         return $info;
212                 }
213
214                 $stamp1 = microtime(true);
215                 $f = file_get_contents("addon/$addon/$addon.php");
216                 $a->saveTimestamp($stamp1, "file");
217
218                 $r = preg_match("|/\*.*\*/|msU", $f, $m);
219
220                 if ($r) {
221                         $ll = explode("\n", $m[0]);
222                         foreach ($ll as $l) {
223                                 $l = trim($l, "\t\n\r */");
224                                 if ($l != "") {
225                                         $addon_info = array_map("trim", explode(":", $l, 2));
226                                         if (count($addon_info) < 2) {
227                                                 continue;
228                                         }
229
230                                         list($type, $v) = $addon_info;
231                                         $type = strtolower($type);
232                                         if ($type == "author" || $type == "maintainer") {
233                                                 $r = preg_match("|([^<]+)<([^>]+)>|", $v, $m);
234                                                 if ($r) {
235                                                         $info[$type][] = ['name' => $m[1], 'link' => $m[2]];
236                                                 } else {
237                                                         $info[$type][] = ['name' => $v];
238                                                 }
239                                         } else {
240                                                 if (array_key_exists($type, $info)) {
241                                                         $info[$type] = $v;
242                                                 }
243                                         }
244                                 }
245                         }
246                 }
247                 return $info;
248         }
249
250         /**
251          * Checks if the provided addon is enabled
252          *
253          * @param string $addon
254          * @return boolean
255          */
256         public static function isEnabled($addon)
257         {
258                 return in_array($addon, self::$addons);
259         }
260
261         /**
262          * Returns a list of the enabled addon names
263          *
264          * @return array
265          */
266         public static function getEnabledList()
267         {
268                 return self::$addons;
269         }
270
271         /**
272          * Saves the current enabled addon list in the system.addon config key
273          *
274          * @return boolean
275          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
276          */
277         public static function saveEnabledList()
278         {
279                 return Config::set("system", "addon", implode(", ", self::$addons));
280         }
281
282         /**
283          * Returns the list of non-hidden enabled addon names
284          *
285          * @return array
286          * @throws \Exception
287          */
288         public static function getVisibleList()
289         {
290                 $visible_addons = [];
291                 $stmt = DBA::select('addon', ['name'], ['hidden' => false, 'installed' => true]);
292                 if (DBA::isResult($stmt)) {
293                         foreach (DBA::toArray($stmt) as $addon) {
294                                 $visible_addons[] = $addon['name'];
295                         }
296                 }
297
298                 return $visible_addons;
299         }
300
301         /**
302          * Shim of Hook::register left for backward compatibility purpose.
303          *
304          * @see        Hook::register
305          * @deprecated since version 2018.12
306          * @param string $hook     the name of the hook
307          * @param string $file     the name of the file that hooks into
308          * @param string $function the name of the function that the hook will call
309          * @param int    $priority A priority (defaults to 0)
310          * @return mixed|bool
311          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
312          */
313         public static function registerHook($hook, $file, $function, $priority = 0)
314         {
315                 return Hook::register($hook, $file, $function, $priority);
316         }
317
318         /**
319          * Shim of Hook::unregister left for backward compatibility purpose.
320          *
321          * @see        Hook::unregister
322          * @deprecated since version 2018.12
323          * @param string $hook     the name of the hook
324          * @param string $file     the name of the file that hooks into
325          * @param string $function the name of the function that the hook called
326          * @return boolean
327          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
328          */
329         public static function unregisterHook($hook, $file, $function)
330         {
331                 return Hook::unregister($hook, $file, $function);
332         }
333
334         /**
335          * Shim of Hook::callAll left for backward-compatibility purpose.
336          *
337          * @see        Hook::callAll
338          * @deprecated since version 2018.12
339          * @param string        $name of the hook to call
340          * @param string|array &$data to transmit to the callback handler
341          * @throws \Friendica\Network\HTTPException\InternalServerErrorException
342          */
343         public static function callHooks($name, &$data = null)
344         {
345                 Hook::callAll($name, $data);
346         }
347 }