source: branches/2.0/admin/include/plugins.class.php @ 3206

Last change on this file since 3206 was 3206, checked in by patdenice, 15 years ago

merge r3205 from trunk to branch 2.0.
Update version in plugins table during plugin activation.

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Author Date Id Revision
File size: 15.3 KB
Line 
1<?php
2// +-----------------------------------------------------------------------+
3// | Piwigo - a PHP based picture gallery                                  |
4// +-----------------------------------------------------------------------+
5// | Copyright(C) 2008-2009 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 = array();
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 . '
113SET state="active", version="'.$this->fs_plugins[$plugin_id]['version'].'"
114WHERE id="' . $plugin_id . '"';
115          pwg_query($query);
116        }
117        break;
118
119      case 'deactivate':
120        if (!isset($crt_db_plugin))
121        {
122          die ('CANNOT DEACTIVATE - NOT INSTALLED');
123        }
124        if ($crt_db_plugin['state'] != 'active')
125        {
126          die('invalid current state ' . $crt_db_plugin['state']);
127        }
128        $query = '
129UPDATE ' . PLUGINS_TABLE . ' SET state="inactive" WHERE id="' . $plugin_id . '"';
130        pwg_query($query);
131        if (file_exists($file_to_include))
132        {
133          include_once($file_to_include);
134          if (function_exists('plugin_deactivate'))
135          {
136            plugin_deactivate($plugin_id);
137          }
138        }
139        break;
140
141      case 'uninstall':
142        if (!isset($crt_db_plugin))
143        {
144          die ('CANNOT UNINSTALL - NOT INSTALLED');
145        }
146        $query = '
147DELETE FROM ' . PLUGINS_TABLE . ' WHERE id="' . $plugin_id . '"';
148        pwg_query($query);
149        if (file_exists($file_to_include))
150        {
151          include_once($file_to_include);
152          if (function_exists('plugin_uninstall'))
153          {
154            plugin_uninstall($plugin_id);
155          }
156        }
157        break;
158
159      case 'delete':
160        if (!empty($crt_db_plugin))
161        {
162          array_push($errors, 'CANNOT DELETE - PLUGIN IS INSTALLED');
163          break;
164        }
165        if (!isset($this->fs_plugins[$plugin_id]))
166        {
167          array_push($errors, 'CANNOT DELETE - NO SUCH PLUGIN');
168          break;
169        }
170        if (!$this->deltree(PHPWG_PLUGINS_PATH . $plugin_id))
171        {
172          $this->send_to_trash(PHPWG_PLUGINS_PATH . $plugin_id);
173        }
174        break;
175    }
176    return $errors;
177  }
178
179  /**
180  *  Get plugins defined in the plugin directory
181  */ 
182  function get_fs_plugins()
183  {
184    $dir = opendir(PHPWG_PLUGINS_PATH);
185    while ($file = readdir($dir))
186    {
187      if ($file!='.' and $file!='..')
188      {
189        $path = PHPWG_PLUGINS_PATH.$file;
190        if (is_dir($path) and !is_link($path)
191            and preg_match('/^[a-zA-Z0-9-_]+$/', $file )
192            and file_exists($path.'/main.inc.php')
193            )
194        {
195          $plugin = array(
196              'name'=>$file,
197              'version'=>'0',
198              'uri'=>'',
199              'description'=>'',
200              'author'=>'',
201            );
202          $plg_data = implode( '', file($path.'/main.inc.php') );
203
204          if ( preg_match("|Plugin Name: (.*)|", $plg_data, $val) )
205          {
206            $plugin['name'] = trim( $val[1] );
207          }
208          if (preg_match("|Version: (.*)|", $plg_data, $val))
209          {
210            $plugin['version'] = trim($val[1]);
211          }
212          if ( preg_match("|Plugin URI: (.*)|", $plg_data, $val) )
213          {
214            $plugin['uri'] = trim($val[1]);
215          }
216          if ( preg_match("|Description: (.*)|", $plg_data, $val) )
217          {
218            $plugin['description'] = trim($val[1]);
219          }
220          if ( preg_match("|Author: (.*)|", $plg_data, $val) )
221          {
222            $plugin['author'] = trim($val[1]);
223          }
224          if ( preg_match("|Author URI: (.*)|", $plg_data, $val) )
225          {
226            $plugin['author uri'] = trim($val[1]);
227          }
228          if (!empty($plugin['uri']) and strpos($plugin['uri'] , 'extension_view.php?eid='))
229          {
230            list( , $extension) = explode('extension_view.php?eid=', $plugin['uri']);
231            if (is_numeric($extension)) $plugin['extension'] = $extension;
232          }
233          // IMPORTANT SECURITY !
234          $plugin = array_map('htmlspecialchars', $plugin);
235          $this->fs_plugins[$file] = $plugin;
236        }
237      }
238    }
239    closedir($dir);
240  }
241
242  /**
243   * Sort fs_plugins
244   */
245  function sort_fs_plugins($order='name')
246  {
247    switch ($order)
248    {
249      case 'name':
250        uasort($this->fs_plugins, 'name_compare');
251        break;
252      case 'status':
253        $this->sort_plugins_by_state();
254        break;
255      case 'author':
256        uasort($this->fs_plugins, array($this, 'plugin_author_compare'));
257        break;
258      case 'id':
259        uksort($this->fs_plugins, 'strcasecmp');
260        break;
261    }
262  }
263
264  /**
265   * Retrieve PEM server datas to $server_plugins
266   */
267  function get_server_plugins($new=false)
268  {
269    global $user;
270
271    // Retrieve PEM versions
272    $version = PHPWG_VERSION;
273    $versions_to_check = array();
274    $url = PEM_URL . '/api/get_version_list.php?category_id=12&format=php';
275    if (fetchRemote($url, $result) and $pem_versions = @unserialize($result))
276    {
277      if (!preg_match('/^\d+\.\d+\.\d+/', $version))
278      {
279        $version = $pem_versions[0]['name'];
280      }
281      $branch = substr($version, 0, strrpos($version, '.'));
282      foreach ($pem_versions as $pem_version)
283      {
284        if (strpos($pem_version['name'], $branch) === 0)
285        {
286          $versions_to_check[] = $pem_version['id'];
287        }
288      }
289    }
290    if (empty($versions_to_check))
291    {
292      return false;
293    }
294
295    // Plugins to check
296    $plugins_to_check = array();
297    foreach($this->fs_plugins as $fs_plugin)
298    {
299      if (isset($fs_plugin['extension']))
300      {
301        $plugins_to_check[] = $fs_plugin['extension'];
302      }
303    }
304
305    // Retrieve PEM plugins infos
306    $url = PEM_URL . '/api/get_revision_list.php?category_id=12&format=php&last_revision_only=true';
307    $url .= '&version=' . implode(',', $versions_to_check);
308    $url .= '&lang=' . substr($user['language'], 0, 2);
309    $url .= '&get_nb_downloads=true';
310
311    if (!empty($plugins_to_check))
312    {
313      $url .= $new ? '&extension_exclude=' : '&extension_include=';
314      $url .= implode(',', $plugins_to_check);
315    }
316    if (fetchRemote($url, $result))
317    {
318      $pem_plugins = @unserialize($result);
319      if (!is_array($pem_plugins))
320      {
321        return false;
322      }
323      foreach ($pem_plugins as $plugin)
324      {
325        $this->server_plugins[$plugin['extension_id']] = $plugin;
326      }
327      return true;
328    }
329    return false;
330  }
331 
332  /**
333   * Sort $server_plugins
334   */
335  function sort_server_plugins($order='date')
336  {
337    switch ($order)
338    {
339      case 'date':
340        krsort($this->server_plugins);
341        break;
342      case 'revision':
343        usort($this->server_plugins, array($this, 'extension_revision_compare'));
344        break;
345      case 'name':
346        uasort($this->server_plugins, array($this, 'extension_name_compare'));
347        break;
348      case 'author':
349        uasort($this->server_plugins, array($this, 'extension_author_compare'));
350        break;
351      case 'downloads':
352        usort($this->server_plugins, array($this, 'extension_downloads_compare'));
353        break;
354    }
355  }
356
357  /**
358   * Extract plugin files from archive
359   * @param string - install or upgrade
360   *  @param string - archive URL
361    * @param string - plugin id or extension id
362   */
363  function extract_plugin_files($action, $revision, $dest)
364  {
365    if ($archive = tempnam( PHPWG_PLUGINS_PATH, 'zip'))
366    {
367      $url = PEM_URL . '/download.php?rid=' . $revision;
368      $url .= '&origin=piwigo_' . $action;
369
370      if ($handle = @fopen($archive, 'wb') and fetchRemote($url, $handle))
371      {
372        fclose($handle);
373        include(PHPWG_ROOT_PATH.'admin/include/pclzip.lib.php');
374        $zip = new PclZip($archive);
375        if ($list = $zip->listContent())
376        {
377          foreach ($list as $file)
378          {
379            // we search main.inc.php in archive
380            if (basename($file['filename']) == 'main.inc.php'
381              and (!isset($main_filepath)
382              or strlen($file['filename']) < strlen($main_filepath)))
383            {
384              $main_filepath = $file['filename'];
385            }
386          }
387          if (isset($main_filepath))
388          {
389            $root = dirname($main_filepath); // main.inc.php path in archive
390            if ($action == 'upgrade')
391            {
392              $extract_path = PHPWG_PLUGINS_PATH . $dest;
393            }
394            else
395            {
396              $extract_path = PHPWG_PLUGINS_PATH
397                  . ($root == '.' ? 'extension_' . $dest : basename($root));
398            }
399            if($result = $zip->extract(PCLZIP_OPT_PATH, $extract_path,
400                                       PCLZIP_OPT_REMOVE_PATH, $root,
401                                       PCLZIP_OPT_REPLACE_NEWER))
402            {
403              foreach ($result as $file)
404              {
405                if ($file['stored_filename'] == $main_filepath)
406                {
407                  $status = $file['status'];
408                  break;
409                }
410              }
411            }
412            else $status = 'extract_error';
413          }
414          else $status = 'archive_error';
415        }
416        else $status = 'archive_error';
417      }
418      else $status = 'dl_archive_error';
419    }
420    else $status = 'temp_path_error';
421
422    @unlink($archive);
423    return $status;
424  }
425 
426  /**
427   * delete $path directory
428   * @param string - path
429   */
430  function deltree($path)
431  {
432    if (is_dir($path))
433    {
434      $fh = opendir($path);
435      while ($file = readdir($fh))
436      {
437        if ($file != '.' and $file != '..')
438        {
439          $pathfile = $path . '/' . $file;
440          if (is_dir($pathfile))
441          {
442            $this->deltree($pathfile);
443          }
444          else
445          {
446            @unlink($pathfile);
447          }
448        }
449      }
450      closedir($fh);
451      return @rmdir($path);
452    }
453  }
454
455  /**
456   * send $path to trash directory
457   * @param string - path
458   */
459  function send_to_trash($path)
460  {
461    $trash_path = PHPWG_PLUGINS_PATH . 'trash';
462    if (!is_dir($trash_path))
463    {
464      @mkdir($trash_path);
465      $file = @fopen($trash_path . '/.htaccess', 'w');
466      @fwrite($file, 'deny from all');
467      @fclose($file);
468    }
469    while ($r = $trash_path . '/' . md5(uniqid(rand(), true)))
470    {
471      if (!is_dir($r))
472      {
473        @rename($path, $r);
474        break;
475      }
476    }
477  }
478
479  /**
480   * Sort functions
481   */
482  function plugin_version_compare($a, $b)
483  {
484    $pattern = array('/([a-z])/ei', '/\.+/', '/\.\Z|\A\./');
485    $replacement = array( "'.'.intval('\\1', 36).'.'", '.', '');
486
487    $array = preg_replace($pattern, $replacement, array($a, $b));
488
489    return version_compare($array[0], $array[1], '>=');
490  }
491
492  function extension_revision_compare($a, $b)
493  {
494    if ($a['revision_date'] < $b['revision_date']) return 1;
495    else return -1;
496  }
497
498  function extension_name_compare($a, $b)
499  {
500    return strcmp(strtolower($a['extension_name']), strtolower($b['extension_name']));
501  }
502
503  function extension_author_compare($a, $b)
504  {
505    $r = strcasecmp($a['author_name'], $b['author_name']);
506    if ($r == 0) return $this->extension_name_compare($a, $b);
507    else return $r;
508  }
509
510  function plugin_author_compare($a, $b)
511  {
512    $r = strcasecmp($a['author'], $b['author']);
513    if ($r == 0) return name_compare($a, $b);
514    else return $r;
515  }
516
517  function extension_downloads_compare($a, $b)
518  {
519    if ($a['extension_nb_downloads'] < $b['extension_nb_downloads']) return 1;
520    else return -1;
521  }
522
523  function sort_plugins_by_state()
524  {
525    uasort($this->fs_plugins, 'name_compare');
526
527    $active_plugins = array();
528    $inactive_plugins = array();
529    $not_installed = array();
530
531    foreach($this->fs_plugins as $plugin_id => $plugin)
532    {
533      if (isset($this->db_plugins_by_id[$plugin_id]))
534      {
535        $this->db_plugins_by_id[$plugin_id]['state'] == 'active' ?
536          $active_plugins[$plugin_id] = $plugin : $inactive_plugins[$plugin_id] = $plugin;
537      }
538      else
539      {
540        $not_installed[$plugin_id] = $plugin;
541      }
542    }
543    $this->fs_plugins = $active_plugins + $inactive_plugins + $not_installed;
544  }
545}
546?>
Note: See TracBrowser for help on using the repository browser.