source: trunk/admin/include/plugins.class.php @ 2299

Last change on this file since 2299 was 2299, checked in by plg, 16 years ago

Bug fixed: as rvelices notified me by email, my header replacement script was
bugged (r2297 was repeating new and old header).

By the way, I've also removed the replacement keywords. We were using them
because it was a common usage with CVS but it is advised not to use them with
Subversion. Personnaly, it is a problem when I search differences between 2
Piwigo installations outside Subversion.

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Author Date Id Revision
File size: 13.6 KB
Line 
1<?php
2// +-----------------------------------------------------------------------+
3// | Piwigo - a PHP based picture gallery                                  |
4// +-----------------------------------------------------------------------+
5// | Copyright(C) 2008      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
24class plugins
25{
26  var $fs_plugins = array();
27  var $db_plugins_by_id = array();
28  var $server_plugins;
29
30  /**
31   * Initialize $fs_plugins and $db_plugins_by_id
32  */
33  function plugins()
34  {
35    $this->get_fs_plugins();
36
37    foreach (get_db_plugins() as $db_plugin)
38    {
39      $this->db_plugins_by_id[$db_plugin['id']] = $db_plugin;
40    }
41  }
42
43 /**
44   * Perform requested actions
45  *  @param string - action
46  * @param string - plugin id
47  * @param array - errors
48  */
49  function perform_action($action, $plugin_id)
50  {
51    if (isset($this->db_plugins_by_id[$plugin_id]))
52    {
53      $crt_db_plugin = $this->db_plugins_by_id[$plugin_id];
54    }
55    $file_to_include = PHPWG_PLUGINS_PATH . $plugin_id . '/maintain.inc.php';
56
57    $errors = array();
58
59    switch ($action)
60    {
61      case 'install':
62        if (!empty($crt_db_plugin))
63        {
64          array_push($errors, 'CANNOT INSTALL - ALREADY INSTALLED');
65          break;
66        }
67        if (!isset($this->fs_plugins[$plugin_id]))
68        {
69          array_push($errors, 'CANNOT INSTALL - NO SUCH PLUGIN');
70          break;
71        }
72        if (file_exists($file_to_include))
73        {
74          include_once($file_to_include);
75          if (function_exists('plugin_install'))
76          {
77            plugin_install($plugin_id, $this->fs_plugins[$plugin_id]['version'], $errors);
78          }
79        }
80        if (empty($errors))
81        {
82          $query = '
83INSERT INTO ' . PLUGINS_TABLE . ' (id,version) VALUES ("'
84. $plugin_id . '","' . $this->fs_plugins[$plugin_id]['version'] . '"
85)';
86          pwg_query($query);
87        }
88        break;
89
90      case 'activate':
91        if (!isset($crt_db_plugin))
92        {
93          array_push($errors, 'CANNOT ACTIVATE - NOT INSTALLED');
94          break;
95        }
96        if ($crt_db_plugin['state'] != 'inactive')
97        {
98          array_push($errors, 'invalid current state ' . $crt_db_plugin['state']);
99          break;
100        }
101        if (file_exists($file_to_include))
102        {
103          include_once($file_to_include);
104          if (function_exists('plugin_activate'))
105          {
106            plugin_activate($plugin_id, $crt_db_plugin['version'], $errors);
107          }
108        }
109        if (empty($errors))
110        {
111          $query = '
112UPDATE ' . PLUGINS_TABLE . ' SET state="active" WHERE id="' . $plugin_id . '"';
113          pwg_query($query);
114        }
115        break;
116
117      case 'deactivate':
118        if (!isset($crt_db_plugin))
119        {
120          die ('CANNOT DEACTIVATE - NOT INSTALLED');
121        }
122        if ($crt_db_plugin['state'] != 'active')
123        {
124          die('invalid current state ' . $crt_db_plugin['state']);
125        }
126        $query = '
127UPDATE ' . PLUGINS_TABLE . ' SET state="inactive" WHERE id="' . $plugin_id . '"';
128        pwg_query($query);
129        if (file_exists($file_to_include))
130        {
131          include_once($file_to_include);
132          if (function_exists('plugin_deactivate'))
133          {
134            plugin_deactivate($plugin_id);
135          }
136        }
137        break;
138
139      case 'uninstall':
140        if (!isset($crt_db_plugin))
141        {
142          die ('CANNOT UNINSTALL - NOT INSTALLED');
143        }
144        $query = '
145DELETE FROM ' . PLUGINS_TABLE . ' WHERE id="' . $plugin_id . '"';
146        pwg_query($query);
147        if (file_exists($file_to_include))
148        {
149          include_once($file_to_include);
150          if (function_exists('plugin_uninstall'))
151          {
152            plugin_uninstall($plugin_id);
153          }
154        }
155        break;
156
157      case 'delete':
158        if (!empty($crt_db_plugin))
159        {
160          array_push($errors, 'CANNOT DELETE - PLUGIN IS INSTALLED');
161          break;
162        }
163        if (!isset($this->fs_plugins[$plugin_id]))
164        {
165          array_push($errors, 'CANNOT DELETE - NO SUCH PLUGIN');
166          break;
167        }
168        if (!$this->deltree(PHPWG_PLUGINS_PATH . $plugin_id))
169        {
170          $this->send_to_trash(PHPWG_PLUGINS_PATH . $plugin_id);
171        }
172        break;
173    }
174    return $errors;
175  }
176
177  /**
178  *  Get plugins defined in the plugin directory
179  */ 
180  function get_fs_plugins()
181  {
182    $dir = opendir(PHPWG_PLUGINS_PATH);
183    while ($file = readdir($dir))
184    {
185      if ($file!='.' and $file!='..')
186      {
187        $path = PHPWG_PLUGINS_PATH.$file;
188        if (is_dir($path) and !is_link($path)
189            and preg_match('/^[a-zA-Z0-9-_]+$/', $file )
190            and file_exists($path.'/main.inc.php')
191            )
192        {
193          $plugin = array(
194              'name'=>$file,
195              'version'=>'0',
196              'uri'=>'',
197              'description'=>'',
198              'author'=>'',
199            );
200          $plg_data = implode( '', file($path.'/main.inc.php') );
201
202          if ( preg_match("|Plugin Name: (.*)|", $plg_data, $val) )
203          {
204            $plugin['name'] = trim( $val[1] );
205          }
206          if (preg_match("|Version: (.*)|", $plg_data, $val))
207          {
208            $plugin['version'] = trim($val[1]);
209          }
210          if ( preg_match("|Plugin URI: (.*)|", $plg_data, $val) )
211          {
212            $plugin['uri'] = trim($val[1]);
213          }
214          if ( preg_match("|Description: (.*)|", $plg_data, $val) )
215          {
216            $plugin['description'] = trim($val[1]);
217          }
218          if ( preg_match("|Author: (.*)|", $plg_data, $val) )
219          {
220            $plugin['author'] = trim($val[1]);
221          }
222          if ( preg_match("|Author URI: (.*)|", $plg_data, $val) )
223          {
224            $plugin['author uri'] = trim($val[1]);
225          }
226          if (!empty($plugin['uri']) and strpos($plugin['uri'] , 'extension_view.php?eid='))
227          {
228            list( , $extension) = explode('extension_view.php?eid=', $plugin['uri']);
229            if (is_numeric($extension)) $plugin['extension'] = $extension;
230          }
231          // IMPORTANT SECURITY !
232          $plugin = array_map('htmlspecialchars', $plugin);
233          $this->fs_plugins[$file] = $plugin;
234        }
235      }
236    }
237    closedir($dir);
238  }
239
240  /**
241   * Sort fs_plugins
242   */
243  function sort_fs_plugins($order='name')
244  {
245    switch ($order)
246    {
247      case 'name':
248        uasort($this->fs_plugins, 'name_compare');
249        break;
250      case 'status':
251        $this->sort_plugins_by_state();
252        break;
253      case 'author':
254        uasort($this->fs_plugins, array($this, 'plugin_author_compare'));
255        break;
256      case 'id':
257        uksort($this->fs_plugins, 'strcasecmp');
258        break;
259    }
260  }
261
262  /**
263   * Retrieve PEM server datas to $server_plugins
264   */
265  function get_server_plugins($new=false)
266  {
267    foreach($this->fs_plugins as $fs_plugin)
268    {
269      if (isset($fs_plugin['extension']))
270      {
271        $plugins_to_check[] = $fs_plugin['extension'];
272      }
273    }
274    $url = PEM_URL . '/uptodate.php?version=' . rawurlencode(PHPWG_VERSION) . '&extensions=' . implode(',', $plugins_to_check);
275    $url .= $new ? '&newext=Plugin' : '';
276
277    if (!empty($plugins_to_check) and $source = @file_get_contents($url))
278    {
279      $this->server_plugins = @unserialize($source);
280    }
281  }
282 
283  /**
284   * Sort $server_plugins
285   */
286  function sort_server_plugins($order='date')
287  {
288    switch ($order)
289    {
290      case 'date':
291        krsort($this->server_plugins);
292        break;
293      case 'revision':
294        usort($this->server_plugins, array($this, 'extension_revision_compare'));
295        break;
296      case 'name':
297        uasort($this->server_plugins, array($this, 'extension_name_compare'));
298        break;
299      case 'author':
300        uasort($this->server_plugins, array($this, 'extension_author_compare'));
301        break;
302    }
303  }
304
305  /**
306   * Extract plugin files from archive
307   * @param string - install or upgrade
308   *  @param string - archive URL
309    * @param string - destination path
310   */
311  function extract_plugin_files($action, $source, $dest)
312  {
313    if ($archive = tempnam( PHPWG_PLUGINS_PATH, 'zip'))
314    {
315      if (@copy(PEM_URL . str_replace(' ', '%20', $source), $archive))
316      {
317        include(PHPWG_ROOT_PATH.'admin/include/pclzip.lib.php');
318        $zip = new PclZip($archive);
319        if ($list = $zip->listContent())
320        {
321          foreach ($list as $file)
322          {
323            // we search main.inc.php in archive
324            if (basename($file['filename']) == 'main.inc.php'
325              and (!isset($main_filepath)
326              or strlen($file['filename']) < strlen($main_filepath)))
327            {
328              $main_filepath = $file['filename'];
329            }
330          }
331          if (isset($main_filepath))
332          {
333            $root = dirname($main_filepath); // main.inc.php path in archive
334            if ($action == 'upgrade')
335            {
336              $extract_path = PHPWG_PLUGINS_PATH.$dest;
337            }
338            else
339            {
340              $extract_path = PHPWG_PLUGINS_PATH
341                  . ($root == '.' ? 'extension_' . $dest : basename($root));
342            }
343            if($result = $zip->extract(PCLZIP_OPT_PATH, $extract_path,
344                                       PCLZIP_OPT_REMOVE_PATH, $root,
345                                       PCLZIP_OPT_REPLACE_NEWER))
346            {
347              foreach ($result as $file)
348              {
349                if ($file['stored_filename'] == $main_filepath)
350                {
351                  $status = $file['status'];
352                  break;
353                }
354              }
355            }
356            else $status = 'extract_error';
357          }
358          else $status = 'archive_error';
359        }
360        else $status = 'archive_error';
361      }
362      else $status = 'dl_archive_error';
363    }
364    else $status = 'temp_path_error';
365
366    @unlink($archive);
367    return $status;
368  }
369 
370  /**
371   * delete $path directory
372   * @param string - path
373   */
374  function deltree($path)
375  {
376    if (is_dir($path))
377    {
378      $fh = opendir($path);
379      while ($file = readdir($fh))
380      {
381        if ($file != '.' and $file != '..')
382        {
383          $pathfile = $path . '/' . $file;
384          if (is_dir($pathfile))
385          {
386            $this->deltree($pathfile);
387          }
388          else
389          {
390            @unlink($pathfile);
391          }
392        }
393      }
394      closedir($fh);
395      return @rmdir($path);
396    }
397  }
398
399  /**
400   * send $path to trash directory
401   * @param string - path
402   */
403  function send_to_trash($path)
404  {
405    $trash_path = PHPWG_PLUGINS_PATH . 'trash';
406    if (!is_dir($trash_path))
407    {
408      @mkdir($trash_path);
409      $file = @fopen($trash_path . '/.htaccess', 'w');
410      @fwrite($file, 'deny from all');
411      @fclose($file);
412    }
413    while ($r = $trash_path . '/' . md5(uniqid(rand(), true)))
414    {
415      if (!is_dir($r))
416      {
417        @rename($path, $r);
418        break;
419      }
420    }
421  }
422
423  /**
424   * Sort functions
425   */
426  function plugin_version_compare($a, $b)
427  {
428    $pattern = array('/([a-z])/ei', '/\.+/', '/\.\Z|\A\./');
429    $replacement = array( "'.'.intval('\\1', 36).'.'", '.', '');
430
431    $array = preg_replace($pattern, $replacement, array($a['version'], $b['version']));
432
433    return version_compare($array[0], $array[1], '>=');
434  }
435
436  function extension_revision_compare($a, $b)
437  {
438    if ($a['date'] < $b['date']) return 1;
439    else return -1;
440  }
441
442  function extension_name_compare($a, $b)
443  {
444    return strcmp(strtolower($a['ext_name']), strtolower($b['ext_name']));
445  }
446
447  function extension_author_compare($a, $b)
448  {
449    $r = strcasecmp($a['author'], $b['author']);
450    if ($r == 0) return $this->extension_name_compare($a, $b);
451    else return $r;
452  }
453
454  function plugin_author_compare($a, $b)
455  {
456    $r = strcasecmp($a['author'], $b['author']);
457    if ($r == 0) return name_compare($a, $b);
458    else return $r;
459  }
460
461  function sort_plugins_by_state()
462  {
463    uasort($this->fs_plugins, 'name_compare');
464
465    $active_plugins = array();
466    $inactive_plugins = array();
467    $not_installed = array();
468
469    foreach($this->fs_plugins as $plugin_id => $plugin)
470    {
471      if (isset($this->db_plugins_by_id[$plugin_id]))
472      {
473        $this->db_plugins_by_id[$plugin_id]['state'] == 'active' ?
474          $active_plugins[$plugin_id] = $plugin : $inactive_plugins[$plugin_id] = $plugin;
475      }
476      else
477      {
478        $not_installed[$plugin_id] = $plugin;
479      }
480    }
481    $this->fs_plugins = $active_plugins + $inactive_plugins + $not_installed;
482  }
483}
484?>
Note: See TracBrowser for help on using the repository browser.