source: trunk/include/functions_plugins.inc.php @ 30353

Last change on this file since 30353 was 29779, checked in by mistic100, 10 years ago

final fix for plugins update ?

  • plugins.version is not updated in "activate" action
  • plugins.version is updated in "update" action and "load_plugin()" function (not only for plugins using maintain.class.php)

cases covered:

  • autoupdate while active or inactive
  • FTP update while active or inactive
  • Property svn:eol-style set to LF
File size: 11.1 KB
Line 
1<?php
2// +-----------------------------------------------------------------------+
3// | Piwigo - a PHP based photo gallery                                    |
4// +-----------------------------------------------------------------------+
5// | Copyright(C) 2008-2014 Piwigo Team                  http://piwigo.org |
6// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
7// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
8// +-----------------------------------------------------------------------+
9// | This program is free software; you can redistribute it and/or modify  |
10// | it under the terms of the GNU General Public License as published by  |
11// | the Free Software Foundation                                          |
12// |                                                                       |
13// | This program is distributed in the hope that it will be useful, but   |
14// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
15// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
16// | General Public License for more details.                              |
17// |                                                                       |
18// | You should have received a copy of the GNU General Public License     |
19// | along with this program; if not, write to the Free Software           |
20// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
21// | USA.                                                                  |
22// +-----------------------------------------------------------------------+
23
24/**
25 * @package functions\plugins
26 */
27
28
29/** base directory of plugins */
30define('PHPWG_PLUGINS_PATH', PHPWG_ROOT_PATH.'plugins/');
31/** default priority for plugins handlers */
32define('EVENT_HANDLER_PRIORITY_NEUTRAL', 50);
33
34
35/**
36 * Used to declare maintenance methods of a plugin.
37 */
38class PluginMaintain
39{
40  /** @var string $plugin_id */
41  protected $plugin_id;
42
43  /**
44   * @param string $id
45   */
46  function __construct($id)
47  {
48    $this->plugin_id = $id;
49  }
50
51  /**
52   * @param string $plugin_version
53   * @param array &$errors - used to return error messages
54   */
55  function install($plugin_version, &$errors=array()) {}
56
57  /**
58   * @param string $plugin_version
59   * @param array &$errors - used to return error messages
60   */
61  function activate($plugin_version, &$errors=array()) {}
62
63  function deactivate() {}
64
65  function uninstall() {}
66
67  /**
68   * @param string $old_version
69   * @param string $new_version
70   * @param array &$errors - used to return error messages
71   */
72  function update($old_version, $new_version, &$errors=array()) {}
73 
74  /**
75   * @removed 2.7
76   */
77  function autoUpdate()
78  {
79    if (is_admin() && !defined('IN_WS'))
80    {
81      trigger_error('Function PluginMaintain::autoUpdate deprecated', E_USER_WARNING);
82    }
83  }
84}
85
86/**
87 * Used to declare maintenance methods of a theme.
88 */
89class ThemeMaintain
90{
91  /** @var string $theme_id */
92  protected $theme_id;
93
94  /**
95   * @param string $id
96   */
97  function __construct($id)
98  {
99    $this->theme_id = $id;
100  }
101
102  /**
103   * @param string $theme_version
104   * @param array &$errors - used to return error messages
105   */
106  function activate($theme_version, &$errors=array()) {}
107
108  function deactivate() {}
109
110  function delete() {}
111}
112
113
114/**
115 * Register an event handler.
116 *
117 * @param string $event the name of the event to listen to
118 * @param Callable $func the callback function
119 * @param int $priority greater priority will be executed at last
120 * @param string $include_path file to include before executing the callback
121 * @return bool false is handler already exists
122 */
123function add_event_handler($event, $func,
124    $priority=EVENT_HANDLER_PRIORITY_NEUTRAL, $include_path=null)
125{
126  global $pwg_event_handlers;
127
128  if (isset($pwg_event_handlers[$event][$priority]))
129  {
130    foreach ($pwg_event_handlers[$event][$priority] as $handler)
131    {
132      if ($handler['function'] == $func)
133      {
134        return false;
135      }
136    }
137  }
138
139  $pwg_event_handlers[$event][$priority][] = array(
140    'function' => $func,
141    'include_path' => is_string($include_path) ? $include_path : null,
142    );
143
144  ksort($pwg_event_handlers[$event]);
145  return true;
146}
147
148/**
149 * Removes an event handler.
150 * @see add_event_handler()
151 *
152 * @param string $event
153 * @param Callable $func
154 * @param int $priority
155 */
156function remove_event_handler($event, $func,
157   $priority=EVENT_HANDLER_PRIORITY_NEUTRAL)
158{
159  global $pwg_event_handlers;
160
161  if (!isset($pwg_event_handlers[$event][$priority]))
162  {
163    return false;
164  }
165  for ($i=0; $i<count($pwg_event_handlers[$event][$priority]); $i++)
166  {
167    if ($pwg_event_handlers[$event][$priority][$i]['function']==$func)
168    {
169      unset($pwg_event_handlers[$event][$priority][$i]);
170      $pwg_event_handlers[$event][$priority] =
171        array_values($pwg_event_handlers[$event][$priority]);
172
173      if (empty($pwg_event_handlers[$event][$priority]))
174      {
175        unset($pwg_event_handlers[$event][$priority]);
176        if (empty($pwg_event_handlers[$event]))
177        {
178          unset($pwg_event_handlers[$event]);
179        }
180      }
181      return true;
182    }
183  }
184  return false;
185}
186
187/**
188 * Triggers a modifier event and calls all registered event handlers.
189 * trigger_change() is used as a modifier: it allows to transmit _$data_
190 * through all handlers, thus each handler MUST return a value,
191 * optional _$args_ are not transmitted.
192 *
193 * @since 2.6
194 *
195 * @param string $event
196 * @param mixed $data data to transmit to all handlers
197 * @param mixed $args,... optional arguments
198 * @return mixed $data
199 */
200function trigger_change($event, $data=null)
201{
202  global $pwg_event_handlers;
203
204  if (isset($pwg_event_handlers['trigger']))
205  {// debugging
206    trigger_notify('trigger',
207      array('type'=>'event', 'event'=>$event, 'data'=>$data)
208      );
209  }
210
211  if (!isset($pwg_event_handlers[$event]))
212  {
213    return $data;
214  }
215  $args = func_get_args();
216  array_shift($args);
217
218  foreach ($pwg_event_handlers[$event] as $priority => $handlers)
219  {
220    foreach ($handlers as $handler)
221    {
222      $args[0] = $data;
223
224      if (!empty($handler['include_path']))
225      {
226        include_once($handler['include_path']);
227      }
228
229      $data = call_user_func_array($handler['function'], $args);
230    }
231  }
232
233  if (isset($pwg_event_handlers['trigger']))
234  {// debugging
235    trigger_notify('trigger',
236      array('type'=>'post_event', 'event'=>$event, 'data'=>$data)
237      );
238  }
239
240  return $data;
241}
242
243/**
244 * Triggers a notifier event and calls all registered event handlers.
245 * trigger_notify() is only used as a notifier, no modification of data is possible
246 *
247 * @since 2.6
248 *
249 * @param string $event
250 * @param mixed $args,... optional arguments
251 */
252function trigger_notify($event)
253{
254  global $pwg_event_handlers;
255
256  if (isset($pwg_event_handlers['trigger']) and $event!='trigger')
257  {// debugging - avoid recursive calls
258    trigger_notify('trigger',
259      array('type'=>'action', 'event'=>$event, 'data'=>null)
260      );
261  }
262
263  if (!isset($pwg_event_handlers[$event]))
264  {
265    return;
266  }
267  $args = func_get_args();
268  array_shift($args);
269
270  foreach ($pwg_event_handlers[$event] as $priority => $handlers)
271  {
272    foreach ($handlers as $handler)
273    {
274      if (!empty($handler['include_path']))
275      {
276        include_once($handler['include_path']);
277      }
278
279      call_user_func_array($handler['function'], $args);
280    }
281  }
282}
283
284/**
285 * Saves some data with the associated plugin id, data are only available
286 * during script lifetime.
287 * @depracted 2.6
288 *
289 * @param string $plugin_id
290 * @param mixed &$data
291 * @return bool
292 */
293function set_plugin_data($plugin_id, &$data)
294{
295  global $pwg_loaded_plugins;
296  if ( isset($pwg_loaded_plugins[$plugin_id]) )
297  {
298    $pwg_loaded_plugins[$plugin_id]['plugin_data'] = &$data;
299    return true;
300  }
301  return false;
302}
303
304/**
305 * Retrieves plugin data saved previously with set_plugin_data.
306 * @see set_plugin_data()
307 * @depracted 2.6
308 *
309 * @param string $plugin_id
310 * @return mixed
311 */
312function &get_plugin_data($plugin_id)
313{
314  global $pwg_loaded_plugins;
315  if ( isset($pwg_loaded_plugins[$plugin_id]['plugin_data']) )
316  {
317    return $pwg_loaded_plugins[$plugin_id]['plugin_data'];
318  }
319  return null;
320}
321
322/**
323 * Returns an array of plugins defined in the database.
324 *
325 * @param string $state optional filter
326 * @param string $id returns only data about given plugin
327 * @return array
328 */
329function get_db_plugins($state='', $id='')
330{
331  $query = '
332SELECT * FROM '.PLUGINS_TABLE;
333  $clauses = array();
334  if (!empty($state))
335  {
336    $clauses[] = 'state=\''.$state.'\'';
337  }
338  if (!empty($id))
339  {
340    $clauses[] = 'id="'.$id.'"';
341  }
342  if (count($clauses))
343  {
344    $query .= '
345  WHERE '. implode(' AND ', $clauses);
346  }
347
348  return query2array($query);
349}
350
351/**
352 * Loads a plugin in memory.
353 * It performs autoupdate, includes the main.inc.php file and updates *$pwg_loaded_plugins*.
354 *
355 * @param string $plugin
356 */
357function load_plugin($plugin)
358{
359  $file_name = PHPWG_PLUGINS_PATH.$plugin['id'].'/main.inc.php';
360  if (file_exists($file_name))
361  {
362    autoupdate_plugin($plugin);
363    global $pwg_loaded_plugins;
364    $pwg_loaded_plugins[ $plugin['id'] ] = $plugin;
365    include_once($file_name);
366  }
367}
368
369/**
370 * Performs update task of a plugin.
371 * Autoupdate is only performed if the plugin has a maintain.class.php file.
372 *
373 * @since 2.7
374 *
375 * @param array &$plugin (id, version, state) will be updated if version changes
376 */
377function autoupdate_plugin(&$plugin)
378{
379  // try to find the filesystem version in lines 2 to 10 of main.inc.php
380  $fh = fopen(PHPWG_PLUGINS_PATH.$plugin['id'].'/main.inc.php', 'r');
381  $fs_version = null;
382  $i = -1;
383
384  while (($line = fgets($fh))!==false && $fs_version==null && $i<10)
385  {
386    $i++;
387    if ($i < 2) continue; // first lines are typically "<?php" and "/*"
388
389    if (preg_match('/Version:\\s*([\\w.-]+)/', $line, $matches))
390    {
391      $fs_version = $matches[1];
392    }
393  }
394
395  fclose($fh);
396
397  // if version is auto (dev) or superior
398  if ($fs_version != null && (
399        $fs_version == 'auto' || $plugin['version'] == 'auto' ||
400        safe_version_compare($plugin['version'], $fs_version, '<')
401      )
402  ) {
403    $plugin['version'] = $fs_version;
404
405    $maintain_file = PHPWG_PLUGINS_PATH.$plugin['id'].'/maintain.class.php';
406
407    // autoupdate is applicable only to plugins with 2.7 architecture
408    if (file_exists($maintain_file))
409    {
410      global $page;
411
412      // call update method
413      include_once($maintain_file);
414
415      $classname = $plugin['id'].'_maintain';
416      $plugin_maintain = new $classname($plugin['id']);
417      $plugin_maintain->update($plugin['version'], $fs_version, $page['errors']);
418    }
419
420    // update database (only on production)
421    if ($plugin['version'] != 'auto')
422    {
423      $query = '
424UPDATE '. PLUGINS_TABLE .'
425  SET version = "'. $plugin['version'] .'"
426  WHERE id = "'. $plugin['id'] .'"
427;';
428      pwg_query($query);
429    }
430  }
431}
432
433/**
434 * Loads all the registered plugins.
435 */
436function load_plugins()
437{
438  global $conf, $pwg_loaded_plugins;
439  $pwg_loaded_plugins = array();
440  if ($conf['enable_plugins'])
441  {
442    $plugins = get_db_plugins('active');
443    foreach( $plugins as $plugin)
444    {// include main from a function to avoid using same function context
445      load_plugin($plugin);
446    }
447    trigger_notify('plugins_loaded');
448  }
449}
450
451?>
Note: See TracBrowser for help on using the repository browser.