]> git.mxchange.org Git - friendica.git/blob - src/Core/Addon.php
Fewer Defaults
[friendica.git] / src / Core / Addon.php
1 <?php
2 /**
3  * @file src/Core/Addon.php
4  */
5 namespace Friendica\Core;
6
7 use Friendica\Core\Config;
8 use Friendica\Database\DBM;
9 use Friendica\Core\Worker;
10
11 use dba;
12
13 require_once 'include/dba.php';
14
15 /**
16  * Some functions to handle addons
17  */
18 class Addon
19 {
20         /**
21          * @brief uninstalls an addon.
22          *
23          * @param string $addon name of the addon
24          * @return boolean
25          */
26         public static function uninstall($addon)
27         {
28                 logger("Addons: uninstalling " . $addon);
29                 dba::delete('addon', ['name' => $addon]);
30
31                 @include_once('addon/' . $addon . '/' . $addon . '.php');
32                 if (function_exists($addon . '_uninstall')) {
33                         $func = $addon . '_uninstall';
34                         $func();
35                 }
36         }
37
38         /**
39          * @brief installs an addon.
40          *
41          * @param string $addon name of the addon
42          * @return bool
43          */
44         public static function install($addon)
45         {
46                 // silently fail if addon was removed
47
48                 if (!file_exists('addon/' . $addon . '/' . $addon . '.php')) {
49                         return false;
50                 }
51                 logger("Addons: installing " . $addon);
52                 $t = @filemtime('addon/' . $addon . '/' . $addon . '.php');
53                 @include_once('addon/' . $addon . '/' . $addon . '.php');
54                 if (function_exists($addon . '_install')) {
55                         $func = $addon . '_install';
56                         $func();
57
58                         $addon_admin = (function_exists($addon."_addon_admin") ? 1 : 0);
59
60                         dba::insert('addon', ['name' => $addon, 'installed' => true,
61                                                 'timestamp' => $t, 'plugin_admin' => $addon_admin]);
62
63                         // we can add the following with the previous SQL
64                         // once most site tables have been updated.
65                         // This way the system won't fall over dead during the update.
66
67                         if (file_exists('addon/' . $addon . '/.hidden')) {
68                                 dba::update('addon', ['hidden' => true], ['name' => $addon]);
69                         }
70                         return true;
71                 } else {
72                         logger("Addons: FAILED installing " . $addon);
73                         return false;
74                 }
75         }
76
77         /**
78          * reload all updated addons
79          */
80         public static function reload()
81         {
82                 $addons = Config::get('system', 'addon');
83                 if (strlen($addons)) {
84                         $r = dba::select('addon', [], ['installed' => 1]);
85                         if (DBM::is_result($r)) {
86                                 $installed = dba::inArray($r);
87                         } else {
88                                 $installed = [];
89                         }
90
91                         $addon_list = explode(',', $addons);
92
93                         if (count($addon_list)) {
94                                 foreach ($addon_list as $addon) {
95                                         $addon = trim($addon);
96                                         $fname = 'addon/' . $addon . '/' . $addon . '.php';
97
98                                         if (file_exists($fname)) {
99                                                 $t = @filemtime($fname);
100                                                 foreach ($installed as $i) {
101                                                         if (($i['name'] == $addon) && ($i['timestamp'] != $t)) {
102                                                                 logger('Reloading addon: ' . $i['name']);
103                                                                 @include_once($fname);
104
105                                                                 if (function_exists($addon . '_uninstall')) {
106                                                                         $func = $addon . '_uninstall';
107                                                                         $func();
108                                                                 }
109                                                                 if (function_exists($addon . '_install')) {
110                                                                         $func = $addon . '_install';
111                                                                         $func();
112                                                                 }
113                                                                 dba::update('addon', ['timestamp' => $t], ['id' => $i['id']]);
114                                                         }
115                                                 }
116                                         }
117                                 }
118                         }
119                 }
120         }
121
122         /**
123          * @brief check if addon is enabled
124          *
125          * @param string $addon
126          * @return boolean
127          */
128         public static function isEnabled($addon)
129         {
130                 return dba::exists('addon', ['installed' => true, 'name' => $addon]);
131         }
132
133
134         /**
135          * @brief registers a hook.
136          *
137          * @param string $hook the name of the hook
138          * @param string $file the name of the file that hooks into
139          * @param string $function the name of the function that the hook will call
140          * @param int $priority A priority (defaults to 0)
141          * @return mixed|bool
142          */
143         public static function registerHook($hook, $file, $function, $priority = 0)
144         {
145                 $condition = ['hook' => $hook, 'file' => $file, 'function' => $function];
146                 $exists = dba::exists('hook', $condition);
147                 if ($exists) {
148                         return true;
149                 }
150
151                 $r = dba::insert('hook', ['hook' => $hook, 'file' => $file, 'function' => $function, 'priority' => $priority]);
152
153                 return $r;
154         }
155
156         /**
157          * @brief unregisters a hook.
158          *
159          * @param string $hook the name of the hook
160          * @param string $file the name of the file that hooks into
161          * @param string $function the name of the function that the hook called
162          * @return array
163          */
164         public static function unregisterHook($hook, $file, $function)
165         {
166                 $condition = ['hook' => $hook, 'file' => $file, 'function' => $function];
167                 $r = dba::delete('hook', $condition);
168                 return $r;
169         }
170
171         /**
172          * Load hooks
173          */
174         public static function loadHooks()
175         {
176                 $a = get_app();
177                 $a->hooks = [];
178                 $r = dba::select('hook', ['hook', 'file', 'function'], [], ['order' => ['priority' => 'desc', 'file']]);
179
180                 while ($rr = dba::fetch($r)) {
181                         if (! array_key_exists($rr['hook'], $a->hooks)) {
182                                 $a->hooks[$rr['hook']] = [];
183                         }
184                         $a->hooks[$rr['hook']][] = [$rr['file'],$rr['function']];
185                 }
186                 dba::close($r);
187         }
188
189         /**
190          * @brief Forks a hook.
191          *
192          * Use this function when you want to fork a hook via the worker.
193          *
194          * @param string $name of the hook to call
195          * @param string|array $data to transmit to the callback handler
196          */
197         public static function forkHooks($priority, $name, $data = null)
198         {
199                 $a = get_app();
200
201                 if (is_array($a->hooks) && array_key_exists($name, $a->hooks)) {
202                         foreach ($a->hooks[$name] as $hook) {
203                                 Worker::add($priority, 'ForkHook', $name, $hook, $data);
204                         }
205                 }
206         }
207
208         /**
209          * @brief Calls a hook.
210          *
211          * Use this function when you want to be able to allow a hook to manipulate
212          * the provided data.
213          *
214          * @param string $name of the hook to call
215          * @param string|array &$data to transmit to the callback handler
216          */
217         public static function callHooks($name, &$data = null)
218         {
219                 $a = get_app();
220
221                 if (is_array($a->hooks) && array_key_exists($name, $a->hooks)) {
222                         foreach ($a->hooks[$name] as $hook) {
223                                 self::callSingleHook($a, $name, $hook, $data);
224                         }
225                 }
226         }
227
228         /**
229          * @brief Calls a single hook.
230          *
231          * @param string $name of the hook to call
232          * @param array $hook Hook data
233          * @param string|array &$data to transmit to the callback handler
234          */
235         public static function callSingleHook($a, $name, $hook, &$data = null)
236         {
237                 // Don't run a theme's hook if the user isn't using the theme
238                 if (strpos($hook[0], 'view/theme/') !== false && strpos($hook[0], 'view/theme/'.current_theme()) === false) {
239                         return;
240                 }
241
242                 @include_once($hook[0]);
243                 if (function_exists($hook[1])) {
244                         $func = $hook[1];
245                         $func($a, $data);
246                 } else {
247                         // remove orphan hooks
248                         $condition = ['hook' => $name, 'file' => $hook[0], 'function' => $hook[1]];
249                         dba::delete('hook', $condition);
250                 }
251         }
252
253         /**
254          * check if an app_menu hook exist for addon $name.
255          * Return true if the addon is an app
256          */
257         public static function isApp($name)
258         {
259                 $a = get_app();
260
261                 if (is_array($a->hooks) && (array_key_exists('app_menu', $a->hooks))) {
262                         foreach ($a->hooks['app_menu'] as $hook) {
263                                 if ($hook[0] == 'addon/'.$name.'/'.$name.'.php') {
264                                         return true;
265                                 }
266                         }
267                 }
268
269                 return false;
270         }
271
272         /**
273          * @brief Parse addon comment in search of addon infos.
274          *
275          * like
276          * \code
277          *   * Name: addon
278          *   * Description: An addon which plugs in
279          * . * Version: 1.2.3
280          *   * Author: John <profile url>
281          *   * Author: Jane <email>
282          *   * Maintainer: Jess <email>
283          *   *
284          *   *\endcode
285          * @param string $addon the name of the addon
286          * @return array with the addon information
287          */
288         public static function getInfo($addon)
289         {
290                 $a = get_app();
291
292                 $info = [
293                         'name' => $addon,
294                         'description' => "",
295                         'author' => [],
296                         'maintainer' => [],
297                         'version' => "",
298                         'status' => ""
299                 ];
300
301                 if (!is_file("addon/$addon/$addon.php")) {
302                         return $info;
303                 }
304
305                 $stamp1 = microtime(true);
306                 $f = file_get_contents("addon/$addon/$addon.php");
307                 $a->save_timestamp($stamp1, "file");
308
309                 $r = preg_match("|/\*.*\*/|msU", $f, $m);
310
311                 if ($r) {
312                         $ll = explode("\n", $m[0]);
313                         foreach ($ll as $l) {
314                                 $l = trim($l, "\t\n\r */");
315                                 if ($l != "") {
316                                         list($type, $v) = array_map("trim", explode(":", $l, 2));
317                                         $type = strtolower($type);
318                                         if ($type == "author" || $type == "maintainer") {
319                                                 $r = preg_match("|([^<]+)<([^>]+)>|", $v, $m);
320                                                 if ($r) {
321                                                         $info[$type][] = ['name' => $m[1], 'link' => $m[2]];
322                                                 } else {
323                                                         $info[$type][] = ['name' => $v];
324                                                 }
325                                         } else {
326                                                 if (array_key_exists($type, $info)) {
327                                                         $info[$type] = $v;
328                                                 }
329                                         }
330                                 }
331                         }
332                 }
333                 return $info;
334         }
335 }