[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/lib/exe/ -> xmlrpc.php (source)

   1  <?php
   2  if(!defined('DOKU_INC')) define('DOKU_INC',dirname(__FILE__).'/../../');
   3  
   4  // fix when '<?xml' isn't on the very first line
   5  if(isset($HTTP_RAW_POST_DATA)) $HTTP_RAW_POST_DATA = trim($HTTP_RAW_POST_DATA);
   6  
   7  
   8  require_once (DOKU_INC.'inc/init.php');
   9  require_once (DOKU_INC.'inc/common.php');
  10  require_once (DOKU_INC.'inc/auth.php');
  11  session_write_close();  //close session
  12  
  13  if(!$conf['xmlrpc']) {
  14      die('XML-RPC server not enabled.');
  15      // FIXME check for groups allowed
  16  }
  17  
  18  require_once (DOKU_INC.'inc/IXR_Library.php');
  19  
  20  
  21  /**
  22   * Contains needed wrapper functions and registers all available
  23   * XMLRPC functions.
  24   */
  25  class dokuwiki_xmlrpc_server extends IXR_IntrospectionServer {
  26      var $methods = array();
  27  
  28      /**
  29       * Constructor. Register methods and run Server
  30       */
  31      function dokuwiki_xmlrpc_server(){
  32          $this->IXR_IntrospectionServer();
  33  
  34          /* DokuWiki's own methods */
  35          $this->addCallback(
  36              'dokuwiki.getVersion',
  37              'getVersion',
  38              array('string'),
  39              'Returns the running DokuWiki version.'
  40          );
  41  
  42          /* Wiki API v2 http://www.jspwiki.org/wiki/WikiRPCInterface2 */
  43          $this->addCallback(
  44              'wiki.getRPCVersionSupported',
  45              'this:wiki_RPCVersion',
  46              array('int'),
  47              'Returns 2 with the supported RPC API version.'
  48          );
  49          $this->addCallback(
  50              'wiki.getPage',
  51              'this:rawPage',
  52              array('string','string'),
  53              'Get the raw Wiki text of page, latest version.'
  54          );
  55          $this->addCallback(
  56              'wiki.getPageVersion',
  57              'this:rawPage',
  58              array('string','string','int'),
  59              'Get the raw Wiki text of page.'
  60          );
  61          $this->addCallback(
  62              'wiki.getPageHTML',
  63              'this:htmlPage',
  64              array('string','string'),
  65              'Return page in rendered HTML, latest version.'
  66          );
  67          $this->addCallback(
  68              'wiki.getPageHTMLVersion',
  69              'this:htmlPage',
  70              array('string','string','int'),
  71              'Return page in rendered HTML.'
  72          );
  73          $this->addCallback(
  74              'wiki.getAllPages',
  75              'this:listPages',
  76              array('struct'),
  77              'Returns a list of all pages. The result is an array of utf8 pagenames.'
  78          );
  79          $this->addCallback(
  80              'wiki.getAttachments',
  81              'this:listAttachments',
  82              array('struct', 'string', 'struct'),
  83              'Returns a list of all media files.'
  84          );
  85          $this->addCallback(
  86              'wiki.getBackLinks',
  87              'this:listBackLinks',
  88              array('struct','string'),
  89              'Returns the pages that link to this page.'
  90          );
  91          $this->addCallback(
  92              'wiki.getPageInfo',
  93              'this:pageInfo',
  94              array('struct','string'),
  95              'Returns a struct with infos about the page.'
  96          );
  97          $this->addCallback(
  98              'wiki.getPageInfoVersion',
  99              'this:pageInfo',
 100              array('struct','string','int'),
 101              'Returns a struct with infos about the page.'
 102          );
 103          $this->addCallback(
 104              'wiki.getPageVersions',
 105              'this:pageVersions',
 106              array('struct','string','int'),
 107              'Returns the available revisions of the page.'
 108          );
 109          $this->addCallback(
 110              'wiki.putPage',
 111              'this:putPage',
 112              array('int', 'string', 'string', 'struct'),
 113              'Saves a wiki page.'
 114          );
 115          $this->addCallback(
 116              'wiki.listLinks',
 117              'this:listLinks',
 118              array('struct','string'),
 119              'Lists all links contained in a wiki page.'
 120          );
 121          $this->addCallback(
 122              'wiki.getRecentChanges',
 123              'this:getRecentChanges',
 124              array('struct','int'),
 125              'Returns a strukt about all recent changes since given timestamp.'
 126          );
 127          $this->addCallback(
 128              'wiki.aclCheck',
 129              'this:aclCheck',
 130              array('int', 'string'),
 131              'Returns the permissions of a given wiki page.'
 132          );
 133          $this->addCallback(
 134              'wiki.putAttachment',
 135              'this:putAttachment',
 136              array('struct', 'string', 'base64', 'struct'),
 137              'Upload a file to the wiki.'
 138          );
 139          $this->addCallback(
 140              'wiki.deleteAttachment',
 141              'this:deleteAttachment',
 142              array('int', 'string'),
 143              'Delete a file from the wiki.'
 144          );
 145          $this->addCallback(
 146              'wiki.getAttachment',
 147              'this:getAttachment',
 148              array('base64', 'string'),
 149              'Download a file from the wiki.'
 150          );
 151          $this->addCallback(
 152              'wiki.getAttachmentInfo',
 153              'this:getAttachmentInfo',
 154              array('struct', 'string'),
 155              'Returns a struct with infos about the attachment.'
 156          );
 157  
 158          /**
 159           * Trigger XMLRPC_CALLBACK_REGISTER, action plugins can use this event 
 160           * to extend the XMLRPC interface and register their own callbacks.
 161           *
 162           * Event data:
 163           *  The XMLRPC server object:
 164           *
 165           *  $event->data->addCallback() - register a callback, the second 
 166           *  paramter has to be of the form "plugin:<pluginname>:<plugin 
 167           *  method>"
 168           *
 169           *  $event->data->callbacks - an array which holds all awaylable 
 170           *  callbacks
 171           */
 172          trigger_event('XMLRPC_CALLBACK_REGISTER', $this);
 173  
 174          $this->serve();
 175      }
 176  
 177      /**
 178       * Return a raw wiki page
 179       */
 180      function rawPage($id,$rev=''){
 181          if(auth_quickaclcheck($id) < AUTH_READ){
 182              return new IXR_Error(1, 'You are not allowed to read this page');
 183          }
 184          $text = rawWiki($id,$rev);
 185          if(!$text) {
 186              $data = array($id);
 187              return trigger_event('HTML_PAGE_FROMTEMPLATE',$data,'pageTemplate',true);
 188          } else {
 189              return $text;
 190          }
 191      }
 192      
 193      /**
 194       * Return a media file encoded in base64
 195       * 
 196       * @author Gina Haeussge <osd@foosel.net>
 197       */
 198      function getAttachment($id){
 199          $id = cleanID($id);
 200          if (auth_quickaclcheck(getNS($id).':*') < AUTH_READ)
 201              return new IXR_Error(1, 'You are not allowed to read this file');
 202          
 203          $file = mediaFN($id);
 204          if (!@ file_exists($file))
 205              return new IXR_Error(1, 'The requested file does not exist');
 206          
 207          $data = io_readFile($file, false);
 208          $base64 = base64_encode($data);
 209          return $base64;
 210      }
 211      
 212      /**
 213       * Return info about a media file
 214       * 
 215       * @author Gina Haeussge <osd@foosel.net>
 216       */
 217      function getAttachmentInfo($id){
 218          $id = cleanID($id);
 219          $info = array(
 220              'lastModified' => 0,
 221              'size' => 0,
 222          );
 223          
 224          $file = mediaFN($id);
 225          if ((auth_quickaclcheck(getNS($id).':*') >= AUTH_READ) && file_exists($file)){
 226              $info['lastModified'] = new IXR_Date(filemtime($file));
 227              $info['size'] = filesize($file);
 228          }
 229  
 230          return $info;
 231      }
 232  
 233      /**
 234       * Return a wiki page rendered to html
 235       */
 236      function htmlPage($id,$rev=''){
 237          if(auth_quickaclcheck($id) < AUTH_READ){
 238              return new IXR_Error(1, 'You are not allowed to read this page');
 239          }
 240          return p_wiki_xhtml($id,$rev,false);
 241      }
 242  
 243      /**
 244       * List all pages - we use the indexer list here
 245       */
 246      function listPages(){
 247          global $conf;
 248  
 249          $list  = array();
 250          $pages = file($conf['indexdir'] . '/page.idx');
 251          $pages = array_filter($pages, 'isVisiblePage');
 252  
 253          foreach(array_keys($pages) as $idx) {
 254              if(page_exists($pages[$idx])) {
 255                  $perm = auth_quickaclcheck($pages[$idx]);
 256                  if($perm >= AUTH_READ) {
 257                      $page = array();
 258                      $page['id'] = trim($pages[$idx]);
 259                      $page['perms'] = $perm;
 260                      $page['size'] = @filesize(wikiFN($pages[$idx]));
 261                      $page['lastModified'] = new IXR_Date(@filemtime(wikiFN($pages[$idx])));
 262                      $list[] = $page;
 263                  }
 264              }
 265          }
 266  
 267          return $list;
 268      }
 269  
 270      /**
 271       * List all media files.
 272       * 
 273       * Available options are 'recursive' for also including the subnamespaces
 274       * in the listing, and 'pattern' for filtering the returned files against
 275       * a regular expression matching their name.
 276       * 
 277       * @author Gina Haeussge <osd@foosel.net>
 278       */
 279      function listAttachments($ns, $options = array()) {
 280          global $conf;
 281          global $lang;
 282  
 283          $ns = cleanID($ns);
 284  
 285          if (!is_array($options))
 286              $options = array();
 287  
 288          if (!isset($options['recursive'])) $options['recursive'] = false;
 289  
 290          if(auth_quickaclcheck($ns.':*') >= AUTH_READ) {
 291              $dir = utf8_encodeFN(str_replace(':', '/', $ns));
 292  
 293              $data = array();
 294              require_once (DOKU_INC.'inc/search.php');
 295              search($data, $conf['mediadir'], 'search_media', array('recursive' => $options['recursive']), $dir);
 296  
 297              if(!count($data)) {
 298                  return array();
 299              }
 300  
 301              $files = array();
 302              foreach($data as $item) {
 303                  if (isset($options['pattern']) && !@preg_match($options['pattern'], $item['id']))
 304                      continue;
 305                  $file = array();
 306                  $file['id']       = $item['id'];
 307                  $file['size']     = $item['size'];
 308                  $file['lastModified'] = new IXR_Date($item['mtime']);
 309                  $file['isimg']    = $item['isimg'];
 310                  $file['writable'] = $item['writeable'];
 311                  $file['perms'] = auth_quickaclcheck(getNS($item['id']).':*');
 312                  array_push($files, $file);
 313              }
 314  
 315              return $files;
 316  
 317          } else {
 318              return new IXR_Error(1, 'You are not allowed to list media files.');
 319          }
 320      }
 321  
 322      /**
 323       * Return a list of backlinks
 324       */
 325      function listBackLinks($id){
 326          require_once (DOKU_INC.'inc/fulltext.php');
 327          return ft_backlinks($id);
 328      }
 329  
 330      /**
 331       * Return some basic data about a page
 332       */
 333      function pageInfo($id,$rev=''){
 334          if(auth_quickaclcheck($id) < AUTH_READ){
 335              return new IXR_Error(1, 'You are not allowed to read this page');
 336          }
 337          $file = wikiFN($id,$rev);
 338          $time = @filemtime($file);
 339          if(!$time){
 340              return new IXR_Error(10, 'The requested page does not exist');
 341          }
 342  
 343          $info = getRevisionInfo($id, $time, 1024);
 344  
 345          $data = array(
 346              'name'         => $id,
 347              'lastModified' => new IXR_Date($time),
 348              'author'       => (($info['user']) ? $info['user'] : $info['ip']),
 349              'version'      => $time
 350          );
 351  
 352          return ($data);
 353      }
 354  
 355      /**
 356       * Save a wiki page
 357       *
 358       * @author Michael Klier <chi@chimeric.de> 
 359       */
 360      function putPage($id, $text, $params) {
 361          global $TEXT;
 362          global $lang;
 363          global $conf;
 364  
 365          $id    = cleanID($id);
 366          $TEXT  = trim($text);
 367          $sum   = $params['sum'];
 368          $minor = $params['minor'];
 369  
 370          if(empty($id))
 371              return new IXR_Error(1, 'Empty page ID');
 372  
 373          if(!page_exists($id) && empty($TEXT)) {
 374              return new IXR_ERROR(1, 'Refusing to write an empty new wiki page');
 375          }
 376  
 377          if(auth_quickaclcheck($id) < AUTH_EDIT)
 378              return new IXR_Error(1, 'You are not allowed to edit this page');
 379  
 380          // Check, if page is locked
 381          if(checklock($id))
 382              return new IXR_Error(1, 'The page is currently locked');
 383  
 384          // SPAM check
 385          if(checkwordblock()) 
 386              return new IXR_Error(1, 'Positive wordblock check');
 387  
 388          // autoset summary on new pages
 389          if(!page_exists($id) && empty($sum)) {
 390              $sum = $lang['created'];
 391          }
 392  
 393          // autoset summary on deleted pages
 394          if(page_exists($id) && empty($TEXT) && empty($sum)) {
 395              $sum = $lang['deleted'];
 396          }
 397  
 398          lock($id);
 399  
 400          saveWikiText($id,$TEXT,$sum,$minor);
 401  
 402          unlock($id);
 403  
 404          // run the indexer if page wasn't indexed yet
 405          if(!@file_exists(metaFN($id, '.indexed'))) {
 406              // try to aquire a lock
 407              $lock = $conf['lockdir'].'/_indexer.lock';
 408              while(!@mkdir($lock,$conf['dmode'])){
 409                  usleep(50);
 410                  if(time()-@filemtime($lock) > 60*5){
 411                      // looks like a stale lock - remove it
 412                      @rmdir($lock);
 413                  }else{
 414                      return false;
 415                  }
 416              }
 417              if($conf['dperm']) chmod($lock, $conf['dperm']);
 418  
 419              require_once (DOKU_INC.'inc/indexer.php');
 420  
 421              // do the work
 422              idx_addPage($id);
 423  
 424              // we're finished - save and free lock
 425              io_saveFile(metaFN($id,'.indexed'),INDEXER_VERSION);
 426              @rmdir($lock);
 427          }
 428  
 429          return 0;
 430      }
 431  
 432      /**
 433       * Uploads a file to the wiki.
 434       *
 435       * Michael Klier <chi@chimeric.de>
 436       */
 437      function putAttachment($id, $file, $params) {
 438          global $conf;
 439          global $lang;
 440  
 441          $auth = auth_quickaclcheck(getNS($id).':*');
 442          if($auth >= AUTH_UPLOAD) {
 443              if(!isset($id)) {
 444                  return new IXR_ERROR(1, 'Filename not given.');
 445              }
 446  
 447              $ftmp = $conf['tmpdir'] . '/' . $id;
 448  
 449              // save temporary file
 450              @unlink($ftmp);
 451              $buff = base64_decode($file);
 452              io_saveFile($ftmp, $buff);
 453  
 454              // get filename
 455              list($iext, $imime) = mimetype($id);
 456              $id = cleanID($id);
 457              $fn = mediaFN($id);
 458  
 459              // get filetype regexp
 460              $types = array_keys(getMimeTypes());
 461              $types = array_map(create_function('$q','return preg_quote($q,"/");'),$types);
 462              $regex = join('|',$types);
 463  
 464              // because a temp file was created already
 465              if(preg_match('/\.('.$regex.')$/i',$fn)) {
 466                  //check for overwrite
 467                  if(@file_exists($fn) && (!$params['ow'] || $auth < AUTH_DELETE)) {
 468                      return new IXR_ERROR(1, $lang['uploadexist']);
 469                  }
 470                  // check for valid content
 471                  @require_once (DOKU_INC.'inc/media.php');
 472                  $ok = media_contentcheck($ftmp, $imime);
 473                  if($ok == -1) {
 474                      return new IXR_ERROR(1, sprintf($lang['uploadexist'], ".$iext"));
 475                  } elseif($ok == -2) {
 476                      return new IXR_ERROR(1, $lang['uploadspam']);
 477                  } elseif($ok == -3) {
 478                      return new IXR_ERROR(1, $lang['uploadxss']);
 479                  }
 480  
 481                  // prepare event data
 482                  $data[0] = $ftmp;
 483                  $data[1] = $fn;
 484                  $data[2] = $id;
 485                  $data[3] = $imime;
 486  
 487                  // trigger event
 488                  require_once (DOKU_INC.'inc/events.php');
 489                  return trigger_event('MEDIA_UPLOAD_FINISH', $data, array($this, '_media_upload_action'), true);
 490  
 491              } else {
 492                  return new IXR_ERROR(1, $lang['uploadwrong']);
 493              }
 494          } else {
 495              return new IXR_ERROR(1, "You don't have permissions to upload files.");
 496          }
 497      }
 498      
 499      /**
 500       * Deletes a file from the wiki.
 501       * 
 502       * @author Gina Haeussge <osd@foosel.net>
 503       */
 504      function deleteAttachment($id){
 505          $auth = auth_quickaclcheck(getNS($id).':*');
 506          if($auth < AUTH_DELETE) return new IXR_ERROR(1, "You don't have permissions to delete files.");
 507          global $conf;
 508          global $lang;
 509      
 510          // check for references if needed
 511          $mediareferences = array();
 512          if($conf['refcheck']){
 513              require_once (DOKU_INC.'inc/fulltext.php');
 514              $mediareferences = ft_mediause($id,$conf['refshow']);
 515          }
 516      
 517          if(!count($mediareferences)){
 518              $file = mediaFN($id);
 519              if(@unlink($file)){
 520                  msg(str_replace('%s',noNS($id),$lang['deletesucc']),1);
 521                  io_sweepNS($id,'mediadir');
 522                  return 0;
 523              }
 524              //something went wrong
 525                 return new IXR_ERROR(1, 'Could not delete file');
 526          } else {
 527              return new IXR_ERROR(1, 'File is still referenced');
 528          }
 529      }
 530  
 531      /**
 532       * Moves the temporary file to its final destination.
 533       *
 534       * Michael Klier <chi@chimeric.de>
 535       */
 536      function _media_upload_action($data) {
 537          global $conf;
 538  
 539          if(is_array($data) && count($data)===4) {
 540              io_createNamespace($data[2], 'media');
 541              if(rename($data[0], $data[1])) {
 542                  chmod($data[1], $conf['fmode']);
 543                  media_notify($data[2], $data[1], $data[3]);
 544                  return $data[2];
 545              } else {
 546                  return new IXR_ERROR(1, 'Upload failed.');
 547              }
 548          } else {
 549              return new IXR_ERROR(1, 'Upload failed.');
 550          }
 551      }
 552  
 553      /**
 554      * Returns the permissions of a given wiki page
 555      */
 556      function aclCheck($id) {
 557          return auth_quickaclcheck($id);
 558      }
 559  
 560      /**
 561       * Lists all links contained in a wiki page
 562       *
 563       * @author Michael Klier <chi@chimeric.de>
 564       */
 565      function listLinks($id) {
 566          if(auth_quickaclcheck($id) < AUTH_READ){
 567              return new IXR_Error(1, 'You are not allowed to read this page');
 568          }
 569          $links = array();
 570  
 571          // resolve page instructions
 572          $ins   = p_cached_instructions(wikiFN(cleanID($id)));
 573  
 574          // instantiate new Renderer - needed for interwiki links
 575          include (DOKU_INC.'inc/parser/xhtml.php');
 576          $Renderer = new Doku_Renderer_xhtml();
 577          $Renderer->interwiki = getInterwiki();
 578  
 579          // parse parse instructions
 580          foreach($ins as $in) {
 581