[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/lib/plugins/plugin/ -> admin.php (source)

   1  <?php
   2  /**
   3   * Plugin management functions
   4   *
   5   * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
   6   * @author     Christopher Smith <chris@jalakai.co.uk>
   7   */
   8  // must be run within Dokuwiki
   9  if(!defined('DOKU_INC')) die();
  10  
  11  // todo
  12  // - maintain a history of file modified
  13  // - allow a plugin to contain extras to be copied to the current template (extra/tpl/)
  14  // - to images (lib/images/) [ not needed, should go in lib/plugin/images/ ]
  15  
  16  if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
  17  require_once (DOKU_PLUGIN.'admin.php');
  18  
  19      //--------------------------[ GLOBALS ]------------------------------------------------
  20      // note: probably should be dokuwiki wide globals, where they can be accessed by pluginutils.php
  21      // global $plugin_types;
  22      // $plugin_types = array('syntax', 'admin');
  23  
  24      // plugins that are an integral part of dokuwiki, they shouldn't be disabled or deleted
  25      global $plugin_protected;
  26      $plugin_protected = array('acl','plugin','config','info','usermanager','revert');
  27  
  28  /**
  29   * All DokuWiki plugins to extend the admin function
  30   * need to inherit from this class
  31   */
  32  class admin_plugin_plugin extends DokuWiki_Admin_Plugin {
  33  
  34      var $disabled = 0;
  35      var $plugin = '';
  36      var $cmd = '';
  37      var $handler = NULL;
  38  
  39      var $functions = array('delete','update',/*'settings',*/'info');  // require a plugin name
  40      var $commands = array('manage','download','enable');              // don't require a plugin name
  41      var $plugin_list = array();
  42  
  43      var $msg = '';
  44      var $error = '';
  45  
  46      function admin_plugin_plugin() {
  47        global $conf;
  48        $this->disabled = (isset($conf['pluginmanager']) && ($conf['pluginmanager'] == 0));
  49      }
  50  
  51      /**
  52       * return some info
  53       */
  54      function getInfo(){
  55        $disabled = ($this->disabled) ? '(disabled)' : '';
  56  
  57        return array(
  58          'author' => 'Christopher Smith',
  59          'email'  => 'chris@jalakai.co.uk',
  60          'date'   => '2005-08-10',
  61          'name'   => 'Plugin Manager',
  62          'desc'   => "Manage Plugins, including automated plugin installer $disabled",
  63          'url'    => 'http://dokuwiki.org/plugin:plugin',
  64        );
  65      }
  66  
  67      /**
  68       * return prompt for admin menu
  69       */
  70      function getMenuText($language) {
  71  
  72          if (!$this->disabled)
  73            return parent::getMenuText($language);
  74  
  75          return '';
  76      }
  77  
  78      /**
  79       * return sort order for position in admin menu
  80       */
  81      function getMenuSort() {
  82        return 20;
  83      }
  84  
  85      /**
  86       * handle user request
  87       */
  88      function handle() {
  89  
  90        if ($this->disabled) return;
  91  
  92        // enable direct access to language strings
  93        $this->setupLocale();
  94  
  95  //      $this->plugin = $_REQUEST['plugin'];
  96  //      $this->cmd = $_REQUEST['fn'];
  97  //      if (is_array($this->cmd)) $this->cmd = key($this->cmd);
  98  
  99        $fn = $_REQUEST['fn'];
 100        if (is_array($fn)) {
 101            $this->cmd = key($fn);
 102            $this->plugin = is_array($fn[$this->cmd]) ? key($fn[$this->cmd]) : null;
 103        } else {
 104            $this->cmd = $fn;
 105            $this->plugin = null;
 106        }
 107  
 108        $this->plugin_list = plugin_list('', true);
 109        sort($this->plugin_list);
 110  
 111        // verify $_REQUEST vars
 112        if (in_array($this->cmd, $this->commands)) {
 113          $this->plugin = '';
 114        } else if (!in_array($this->cmd, $this->functions) || !in_array($this->plugin, $this->plugin_list)) {
 115          $this->cmd = 'manage';
 116          $this->plugin = '';
 117        }
 118  
 119        if(($this->cmd != 'manage' || $this->plugin != '') && !checkSecurityToken()){
 120          $this->cmd = 'manage';
 121          $this->plugin = '';
 122        }
 123  
 124        // create object to handle the command
 125        $class = "ap_".$this->cmd;
 126        if (!class_exists($class)) $class = 'ap_manage';
 127  
 128        $this->handler = & new $class($this, $this->plugin);
 129        $this->msg = $this->handler->process();
 130      }
 131  
 132      /**
 133       * output appropriate html
 134       */
 135      function html() {
 136  
 137        if ($this->disabled) return;
 138  
 139        // enable direct access to language strings
 140        $this->setupLocale();
 141  
 142        if ($this->handler === NULL) $this->handler = & new ap_manage($this, $this->plugin);
 143        if (!$this->plugin_list) {
 144          $this->plugin_list = plugin_list('',true);
 145          sort($this->plugin_list);
 146        }
 147  
 148        ptln('<div id="plugin__manager">');
 149        $this->handler->html();
 150        ptln('</div><!-- #plugin_manager -->');
 151      }
 152  
 153  }
 154  
 155  class ap_manage {
 156  
 157          var $manager = NULL;
 158          var $lang = array();
 159          var $plugin = '';
 160          var $downloaded = array();
 161  
 162          function ap_manage(&$manager, $plugin) {
 163              $this->manager = & $manager;
 164              $this->plugin = $plugin;
 165              $this->lang = & $manager->lang;
 166          }
 167  
 168          function process() {
 169              return '';
 170          }
 171  
 172          function html() {
 173            print $this->manager->locale_xhtml('admin_plugin');
 174            $this->html_menu();
 175          }
 176  
 177          // build our standard menu
 178          function html_menu($listPlugins = true) {
 179            global $ID;
 180  
 181            ptln('<div class="pm_menu">');
 182  
 183            ptln('<div class="common">');
 184            ptln('  <h2>'.$this->lang['download'].'</h2>');
 185            ptln('  <form action="'.wl($ID).'" method="post">');
 186            ptln('    <fieldset class="hidden">',4);
 187            ptln('      <input type="hidden" name="do"   value="admin" />');
 188            ptln('      <input type="hidden" name="page" value="plugin" />');
 189            formSecurityToken();
 190            ptln('    </fieldset>');
 191            ptln('    <fieldset>');
 192            ptln('      <legend>'.$this->lang['download'].'</legend>');
 193            ptln('      <label for="dw__url">'.$this->lang['url'].'<input name="url" id="dw__url" class="edit" type="text" maxlength="200" /></label>');
 194            ptln('      <input type="submit" class="button" name="fn[download]" value="'.$this->lang['btn_download'].'" />');
 195            ptln('    </fieldset>');
 196            ptln('  </form>');
 197            ptln('</div>');
 198  
 199            if ($listPlugins) {
 200              ptln('<h2>'.$this->lang['manage'].'</h2>');
 201  
 202              ptln('<form action="'.wl($ID).'" method="post" class="plugins">');
 203  //            ptln('  <div class="plugins">');
 204  
 205              ptln('  <fieldset class="hidden">');
 206              ptln('    <input type="hidden" name="do"     value="admin" />');
 207              ptln('    <input type="hidden" name="page"   value="plugin" />');
 208              formSecurityToken();
 209              ptln('  </fieldset>');
 210  
 211              $this->html_pluginlist();
 212  
 213              ptln('  <fieldset class="buttons">');
 214              ptln('    <input type="submit" class="button" name="fn[enable]" value="'.$this->lang['btn_enable'].'" />');
 215              ptln('  </fieldset>');
 216  
 217  //            ptln('  </div>');
 218              ptln('</form>');
 219            }
 220  
 221            ptln('</div>');
 222          }
 223  
 224          function html_pluginlist() {
 225            global $ID;
 226            global $plugin_protected;
 227  
 228            foreach ($this->manager->plugin_list as $plugin) {
 229  
 230              $disabled = plugin_isdisabled($plugin);
 231              $protected = in_array($plugin,$plugin_protected);
 232  
 233              $checked = ($disabled) ? '' : ' checked="checked"';
 234              $check_disabled = ($protected) ? ' disabled="disabled"' : '';
 235  
 236              // determine display class(es)
 237              $class = array();
 238              if (in_array($plugin, $this->downloaded)) $class[] = 'new';
 239              if ($disabled) $class[] = 'disabled';
 240              if ($protected) $class[] = 'protected';
 241  
 242              $class = count($class) ? ' class="'.join(' ', $class).'"' : '';
 243  
 244              ptln('    <fieldset'.$class.'>');
 245              ptln('      <legend>'.$plugin.'</legend>');
 246              ptln('      <input type="checkbox" class="enable" name="enabled[]" value="'.$plugin.'"'.$checked.$check_disabled.' />');
 247              ptln('      <h3 class="legend">'.$plugin.'</h3>');
 248  
 249              $this->html_button($plugin, 'info', false, 6);
 250              if (in_array('settings', $this->manager->functions)) {
 251                $this->html_button($plugin, 'settings', !@file_exists(DOKU_PLUGIN.$plugin.'/settings.php'), 6);
 252              }
 253              $this->html_button($plugin, 'update', !$this->plugin_readlog($plugin, 'url'), 6);
 254              $this->html_button($plugin, 'delete', $protected, 6);
 255  
 256              ptln('    </fieldset>');
 257              }
 258          }
 259  
 260          function html_button($plugin, $btn, $disabled=false, $indent=0) {
 261              $disabled = ($disabled) ? 'disabled="disabled"' : '';
 262              ptln('<input type="submit" class="button" '.$disabled.' name="fn['.$btn.']['.$plugin.']" value="'.$this->lang['btn_'.$btn].'" />',$indent);
 263          }
 264  
 265          /**
 266           *  Refresh plugin list
 267           */
 268          function refresh() {
 269  
 270              $this->manager->plugin_list = plugin_list('',true);
 271              sort($this->manager->plugin_list);
 272  
 273              // expire dokuwiki caches
 274              // touching local.php expires wiki page, JS and CSS caches
 275              @touch(DOKU_CONF.'local.php');
 276  
 277              // update latest plugin date - FIXME
 278              return (!$this->manager->error);
 279          }
 280  
 281          function download($url, $overwrite=false) {
 282            global $lang;
 283  
 284            // check the url
 285            $matches = array();
 286            if (!preg_match("/[^\/]*$/", $url, $matches) || !$matches[0]) {
 287              $this->manager->error = $this->lang['error_badurl']."\n";
 288              return false;
 289            }
 290  
 291            $file = $matches[0];
 292  
 293            if (!($tmp = io_mktmpdir())) {
 294              $this->manager->error = $this->lang['error_dircreate']."\n";
 295              return false;
 296            }
 297  
 298            if (!$file = io_download($url, "$tmp/", true, $file)) {
 299              $this->manager->error = sprintf($this->lang['error_download'],$url)."\n";
 300            }
 301  
 302            if (!$this->manager->error && !ap_decompress("$tmp/$file", $tmp)) {
 303              $this->manager->error = sprintf($this->lang['error_decompress'],$file)."\n";
 304            }
 305  
 306            // search $tmp for the folder(s) that has been created
 307            // move the folder(s) to lib/plugins/
 308            if (!$this->manager->error) {
 309              if ($dh = @opendir("$tmp/")) {
 310                while (false !== ($f = readdir($dh))) {
 311                  if ($f == '.' || $f == '..' || $f == 'tmp') continue;
 312                  if (!is_dir("$tmp/$f")) continue;
 313  
 314                  // check to make sure we aren't overwriting anything
 315                  if (!$overwrite && @file_exists(DOKU_PLUGIN.$f)) {
 316                     // remember our settings, ask the user to confirm overwrite, FIXME
 317                     continue;
 318                  }
 319  
 320                  $instruction = @file_exists(DOKU_PLUGIN.$f) ? 'update' : 'install';
 321  
 322                  if (ap_copy("$tmp/$f", DOKU_PLUGIN.$f)) {
 323                    $this->downloaded[] = $f;
 324                    $this->plugin_writelog($f, $instruction, array($url));
 325                  } else {
 326                    $this->manager->error .= sprintf($this->lang['error_copy']."\n", $f);
 327                  }
 328                }
 329                closedir($dh);
 330              } else {
 331                $this->manager->error = $this->lang['error']."\n";
 332              }
 333            }
 334  
 335            // cleanup
 336            if ($tmp) ap_delete($tmp);
 337  
 338            if (!$this->manager->error) {
 339                $this->refresh();
 340                return true;
 341            }
 342  
 343            return false;
 344          }
 345  
 346          // log
 347          function plugin_writelog($plugin, $cmd, $data) {
 348  
 349              $file = DOKU_PLUGIN.$plugin.'/manager.dat';
 350  
 351              switch ($cmd) {
 352                case 'install' :
 353                  $url = $data[0];
 354                  $date = date('r');
 355                  if (!$fp = @fopen($file, 'w')) return;
 356                  fwrite($fp, "installed=$date\nurl=$url\n");
 357                  fclose($fp);
 358                  break;
 359  
 360                case 'update' :
 361                  $date = date('r');
 362                  if (!$fp = @fopen($file, 'a')) return;
 363                  fwrite($fp, "updated=$date\n");
 364                  fclose($fp);
 365                  break;
 366              }
 367          }
 368  
 369          function plugin_readlog($plugin, $field) {
 370              static $log = array();
 371              $file = DOKU_PLUGIN.$plugin.'/manager.dat';
 372  
 373              if (!isset($log[$plugin])) {
 374                  $tmp = @file_get_contents($file);
 375                  if (!$tmp) return '';
 376                  $log[$plugin] = & $tmp;
 377              }
 378  
 379              if ($field == 'ALL') {
 380                  return $log[$plugin];
 381              }
 382  
 383                          $match = array();
 384              if (preg_match_all('/'.$field.'=(.*)$/m',$log[$plugin], $match))
 385                  return implode("\n", $match[1]);
 386  
 387              return '';
 388          }
 389      }
 390  
 391      class ap_download extends ap_manage {
 392  
 393          var $overwrite = false;
 394  
 395          function process() {
 396            global $lang;
 397  
 398            $plugin_url = $_REQUEST['url'];
 399            $this->download($plugin_url, $this->overwrite);
 400            return '';
 401          }
 402  
 403          function html() {
 404              parent::html();
 405  
 406              ptln('<div class="pm_info">');
 407              ptln('<h2>'.$this->lang['downloading'].'</h2>');
 408  
 409              if ($this->manager->error) {
 410                  ptln('<div class="error">'.str_replace("\n","<br />",$this->manager->error).'</div>');
 411              } else if (count($this->downloaded) == 1) {
 412                  ptln('<p>'.sprintf($this->lang['downloaded'],$this->downloaded[0]).'</p>');
 413              } else if (count($this->downloaded)) {   // more than one plugin in the download
 414                  ptln('<p>'.$this->lang['downloads'].'</p>');
 415                  ptln('<ul>');
 416                  foreach ($this->downloaded as $plugin) {
 417                      ptln('<li><div class="li">'.$plugin.'</div></li>',2);
 418                  }
 419                  ptln('</ul>');
 420              } else {        // none found in download
 421                  ptln('<p>'.$this->lang['download_none'].'</p>');
 422              }
 423              ptln('</div>');
 424          }
 425  
 426      }
 427  
 428      class ap_delete extends ap_manage {
 429  
 430          function process() {
 431  
 432              if (!ap_delete(DOKU_PLUGIN.$this->manager->plugin)) {
 433                $this->manager->error = sprintf($this->lang['error_delete'],$this->manager->plugin);
 434              } else {
 435                $this->refresh();
 436              }
 437          }
 438  
 439          function html() {
 440              parent::html();
 441  
 442              ptln('<div class="pm_info">');
 443              ptln('<h2>'.$this->lang['deleting'].'</h2>');
 444  
 445              if ($this->manager->error) {
 446                ptln('<div class="error">'.str_replace("\n","<br />",$this->manager->error).'</div>');
 447              } else {
 448                ptln('<p>'.sprintf($this->lang['deleted'],$this->plugin).'</p>');
 449              }
 450              ptln('</div>');
 451          }
 452      }
 453  
 454      class ap_info extends ap_manage {
 455  
 456          var $plugin_info = array();        // the plugin itself
 457          var $details = array();            // any component plugins
 458  
 459          function process() {
 460  
 461            // sanity check
 462            if (!$this->manager->plugin) { return; }
 463  
 464            $component_list = ap_plugin_components($this->manager->plugin);
 465            usort($component_list, 'ap_component_sort');
 466  
 467            foreach ($component_list as $component) {
 468                if ($obj = & plugin_load($component['type'],$component['name']) === NULL) continue;
 469  
 470              $this->details[] = array_merge($obj->getInfo(), array('type' => $component['type']));
 471              unset($obj);
 472            }
 473  
 474            // review details to simplify things
 475            foreach($this->details as $info) {
 476              foreach($info as