[ Index ] |
PHP Cross Reference of DokuWiki |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * Increased whenever the API is changed 5 */ 6 define('DOKU_API_VERSION', 10); 7 8 /** 9 * Provides the core methods for the remote API. 10 * The methods are ordered in 'wiki.<method>' and 'dokuwiki.<method>' namespaces 11 */ 12 class RemoteAPICore { 13 14 private $api; 15 16 /** 17 * @param RemoteAPI $api 18 */ 19 public function __construct(RemoteAPI $api) { 20 $this->api = $api; 21 } 22 23 /** 24 * Returns details about the core methods 25 * 26 * @return array 27 */ 28 public function __getRemoteInfo() { 29 return array( 30 'dokuwiki.getVersion' => array( 31 'args' => array(), 32 'return' => 'string', 33 'doc' => 'Returns the running DokuWiki version.' 34 ), 'dokuwiki.login' => array( 35 'args' => array('string', 'string'), 36 'return' => 'int', 37 'doc' => 'Tries to login with the given credentials and sets auth cookies.', 38 'public' => '1' 39 ), 'dokuwiki.logoff' => array( 40 'args' => array(), 41 'return' => 'int', 42 'doc' => 'Tries to logoff by expiring auth cookies and the associated PHP session.' 43 ), 'dokuwiki.getPagelist' => array( 44 'args' => array('string', 'array'), 45 'return' => 'array', 46 'doc' => 'List all pages within the given namespace.', 47 'name' => 'readNamespace' 48 ), 'dokuwiki.search' => array( 49 'args' => array('string'), 50 'return' => 'array', 51 'doc' => 'Perform a fulltext search and return a list of matching pages' 52 ), 'dokuwiki.getTime' => array( 53 'args' => array(), 54 'return' => 'int', 55 'doc' => 'Returns the current time at the remote wiki server as Unix timestamp.', 56 ), 'dokuwiki.setLocks' => array( 57 'args' => array('array'), 58 'return' => 'array', 59 'doc' => 'Lock or unlock pages.' 60 ), 'dokuwiki.getTitle' => array( 61 'args' => array(), 62 'return' => 'string', 63 'doc' => 'Returns the wiki title.', 64 'public' => '1' 65 ), 'dokuwiki.appendPage' => array( 66 'args' => array('string', 'string', 'array'), 67 'return' => 'bool', 68 'doc' => 'Append text to a wiki page.' 69 ), 'dokuwiki.deleteUsers' => array( 70 'args' => array('array'), 71 'return' => 'bool', 72 'doc' => 'Remove one or more users from the list of registered users.' 73 ), 'wiki.getPage' => array( 74 'args' => array('string'), 75 'return' => 'string', 76 'doc' => 'Get the raw Wiki text of page, latest version.', 77 'name' => 'rawPage', 78 ), 'wiki.getPageVersion' => array( 79 'args' => array('string', 'int'), 80 'name' => 'rawPage', 81 'return' => 'string', 82 'doc' => 'Return a raw wiki page' 83 ), 'wiki.getPageHTML' => array( 84 'args' => array('string'), 85 'return' => 'string', 86 'doc' => 'Return page in rendered HTML, latest version.', 87 'name' => 'htmlPage' 88 ), 'wiki.getPageHTMLVersion' => array( 89 'args' => array('string', 'int'), 90 'return' => 'string', 91 'doc' => 'Return page in rendered HTML.', 92 'name' => 'htmlPage' 93 ), 'wiki.getAllPages' => array( 94 'args' => array(), 95 'return' => 'array', 96 'doc' => 'Returns a list of all pages. The result is an array of utf8 pagenames.', 97 'name' => 'listPages' 98 ), 'wiki.getAttachments' => array( 99 'args' => array('string', 'array'), 100 'return' => 'array', 101 'doc' => 'Returns a list of all media files.', 102 'name' => 'listAttachments' 103 ), 'wiki.getBackLinks' => array( 104 'args' => array('string'), 105 'return' => 'array', 106 'doc' => 'Returns the pages that link to this page.', 107 'name' => 'listBackLinks' 108 ), 'wiki.getPageInfo' => array( 109 'args' => array('string'), 110 'return' => 'array', 111 'doc' => 'Returns a struct with info about the page, latest version.', 112 'name' => 'pageInfo' 113 ), 'wiki.getPageInfoVersion' => array( 114 'args' => array('string', 'int'), 115 'return' => 'array', 116 'doc' => 'Returns a struct with info about the page.', 117 'name' => 'pageInfo' 118 ), 'wiki.getPageVersions' => array( 119 'args' => array('string', 'int'), 120 'return' => 'array', 121 'doc' => 'Returns the available revisions of the page.', 122 'name' => 'pageVersions' 123 ), 'wiki.putPage' => array( 124 'args' => array('string', 'string', 'array'), 125 'return' => 'bool', 126 'doc' => 'Saves a wiki page.' 127 ), 'wiki.listLinks' => array( 128 'args' => array('string'), 129 'return' => 'array', 130 'doc' => 'Lists all links contained in a wiki page.' 131 ), 'wiki.getRecentChanges' => array( 132 'args' => array('int'), 133 'return' => 'array', 134 'Returns a struct about all recent changes since given timestamp.' 135 ), 'wiki.getRecentMediaChanges' => array( 136 'args' => array('int'), 137 'return' => 'array', 138 'Returns a struct about all recent media changes since given timestamp.' 139 ), 'wiki.aclCheck' => array( 140 'args' => array('string', 'string', 'array'), 141 'return' => 'int', 142 'doc' => 'Returns the permissions of a given wiki page. By default, for current user/groups' 143 ), 'wiki.putAttachment' => array( 144 'args' => array('string', 'file', 'array'), 145 'return' => 'array', 146 'doc' => 'Upload a file to the wiki.' 147 ), 'wiki.deleteAttachment' => array( 148 'args' => array('string'), 149 'return' => 'int', 150 'doc' => 'Delete a file from the wiki.' 151 ), 'wiki.getAttachment' => array( 152 'args' => array('string'), 153 'doc' => 'Return a media file', 154 'return' => 'file', 155 'name' => 'getAttachment', 156 ), 'wiki.getAttachmentInfo' => array( 157 'args' => array('string'), 158 'return' => 'array', 159 'doc' => 'Returns a struct with info about the attachment.' 160 ), 'dokuwiki.getXMLRPCAPIVersion' => array( 161 'args' => array(), 162 'name' => 'getAPIVersion', 163 'return' => 'int', 164 'doc' => 'Returns the XMLRPC API version.', 165 'public' => '1', 166 ), 'wiki.getRPCVersionSupported' => array( 167 'args' => array(), 168 'name' => 'wiki_RPCVersion', 169 'return' => 'int', 170 'doc' => 'Returns 2 with the supported RPC API version.', 171 'public' => '1' 172 ), 173 174 ); 175 } 176 177 /** 178 * @return string 179 */ 180 public function getVersion() { 181 return getVersion(); 182 } 183 184 /** 185 * @return int unix timestamp 186 */ 187 public function getTime() { 188 return time(); 189 } 190 191 /** 192 * Return a raw wiki page 193 * 194 * @param string $id wiki page id 195 * @param int|string $rev revision timestamp of the page or empty string 196 * @return string page text. 197 * @throws RemoteAccessDeniedException if no permission for page 198 */ 199 public function rawPage($id,$rev=''){ 200 $id = $this->resolvePageId($id); 201 if(auth_quickaclcheck($id) < AUTH_READ){ 202 throw new RemoteAccessDeniedException('You are not allowed to read this file', 111); 203 } 204 $text = rawWiki($id,$rev); 205 if(!$text) { 206 return pageTemplate($id); 207 } else { 208 return $text; 209 } 210 } 211 212 /** 213 * Return a media file 214 * 215 * @author Gina Haeussge <osd@foosel.net> 216 * 217 * @param string $id file id 218 * @return mixed media file 219 * @throws RemoteAccessDeniedException no permission for media 220 * @throws RemoteException not exist 221 */ 222 public function getAttachment($id){ 223 $id = cleanID($id); 224 if (auth_quickaclcheck(getNS($id).':*') < AUTH_READ) { 225 throw new RemoteAccessDeniedException('You are not allowed to read this file', 211); 226 } 227 228 $file = mediaFN($id); 229 if (!@ file_exists($file)) { 230 throw new RemoteException('The requested file does not exist', 221); 231 } 232 233 $data = io_readFile($file, false); 234 return $this->api->toFile($data); 235 } 236 237 /** 238 * Return info about a media file 239 * 240 * @author Gina Haeussge <osd@foosel.net> 241 * 242 * @param string $id page id 243 * @return array 244 */ 245 public function getAttachmentInfo($id){ 246 $id = cleanID($id); 247 $info = array( 248 'lastModified' => $this->api->toDate(0), 249 'size' => 0, 250 ); 251 252 $file = mediaFN($id); 253 if(auth_quickaclcheck(getNS($id) . ':*') >= AUTH_READ) { 254 if(file_exists($file)) { 255 $info['lastModified'] = $this->api->toDate(filemtime($file)); 256 $info['size'] = filesize($file); 257 } else { 258 //Is it deleted media with changelog? 259 $medialog = new MediaChangeLog($id); 260 $revisions = $medialog->getRevisions(0, 1); 261 if(!empty($revisions)) { 262 $info['lastModified'] = $this->api->toDate($revisions[0]); 263 } 264 } 265 } 266 267 return $info; 268 } 269 270 /** 271 * Return a wiki page rendered to html 272 * 273 * @param string $id page id 274 * @param string|int $rev revision timestamp or empty string 275 * @return null|string html 276 * @throws RemoteAccessDeniedException no access to page 277 */ 278 public function htmlPage($id,$rev=''){ 279 $id = $this->resolvePageId($id); 280 if(auth_quickaclcheck($id) < AUTH_READ){ 281 throw new RemoteAccessDeniedException('You are not allowed to read this page', 111); 282 } 283 return p_wiki_xhtml($id,$rev,false); 284 } 285 286 /** 287 * List all pages - we use the indexer list here 288 * 289 * @return array 290 */ 291 public function listPages(){ 292 $list = array(); 293 $pages = idx_get_indexer()->getPages(); 294 $pages = array_filter(array_filter($pages,'isVisiblePage'),'page_exists'); 295 296 foreach(array_keys($pages) as $idx) { 297 $perm = auth_quickaclcheck($pages[$idx]); 298 if($perm < AUTH_READ) { 299 continue; 300 } 301 $page = array(); 302 $page['id'] = trim($pages[$idx]); 303 $page['perms'] = $perm; 304 $page['size'] = @filesize(wikiFN($pages[$idx])); 305 $page['lastModified'] = $this->api->toDate(@filemtime(wikiFN($pages[$idx]))); 306 $list[] = $page; 307 } 308 309 return $list; 310 } 311 312 /** 313 * List all pages in the given namespace (and below) 314 * 315 * @param string $ns 316 * @param array $opts 317 * $opts['depth'] recursion level, 0 for all 318 * $opts['hash'] do md5 sum of content? 319 * @return array 320 */ 321 public function readNamespace($ns,$opts){ 322 global $conf; 323 324 if(!is_array($opts)) $opts=array(); 325 326 $ns = cleanID($ns); 327 $dir = utf8_encodeFN(str_replace(':', '/', $ns)); 328 $data = array(); 329 $opts['skipacl'] = 0; // no ACL skipping for XMLRPC 330 search($data, $conf['datadir'], 'search_allpages', $opts, $dir); 331 return $data; 332 } 333 334 /** 335 * List all pages in the given namespace (and below) 336 * 337 * @param string $query 338 * @return array 339 */ 340 public function search($query){ 341 $regex = array(); 342 $data = ft_pageSearch($query,$regex); 343 $pages = array(); 344 345 // prepare additional data 346 $idx = 0; 347 foreach($data as $id => $score){ 348 $file = wikiFN($id); 349 350 if($idx < FT_SNIPPET_NUMBER){ 351 $snippet = ft_snippet($id,$regex); 352 $idx++; 353 }else{ 354 $snippet = ''; 355 } 356 357 $pages[] = array( 358 'id' => $id, 359 'score' => intval($score), 360 'rev' => filemtime($file), 361 'mtime' => filemtime($file), 362 'size' => filesize($file), 363 'snippet' => $snippet, 364 'title' => useHeading('navigation') ? p_get_first_heading($id) : $id 365 ); 366 } 367 return $pages; 368 } 369 370 /** 371 * Returns the wiki title. 372 * 373 * @return string 374 */ 375 public function getTitle(){ 376 global $conf; 377 return $conf['title']; 378 } 379 380 /** 381 * List all media files. 382 * 383 * Available options are 'recursive' for also including the subnamespaces 384 * in the listing, and 'pattern' for filtering the returned files against 385 * a regular expression matching their name. 386 * 387 * @author Gina Haeussge <osd@foosel.net> 388 * 389 * @param string $ns 390 * @param array $options 391 * $options['depth'] recursion level, 0 for all 392 * $options['showmsg'] shows message if invalid media id is used 393 * $options['pattern'] check given pattern 394 * $options['hash'] add hashes to result list 395 * @return array 396 * @throws RemoteAccessDeniedException no access to the media files 397 */ 398 public function listAttachments($ns, $options = array()) { 399 global $conf; 400 401 $ns = cleanID($ns); 402 403 if (!is_array($options)) $options = array(); 404 $options['skipacl'] = 0; // no ACL skipping for XMLRPC 405 406 if(auth_quickaclcheck($ns.':*') >= AUTH_READ) { 407 $dir = utf8_encodeFN(str_replace(':', '/', $ns)); 408 409 $data = array(); 410 search($data, $conf['mediadir'], 'search_media', $options, $dir); 411 $len = count($data); 412 if(!$len) return array(); 413 414 for($i=0; $i<$len; $i++) { 415 unset($data[$i]['meta']); 416 $data[$i]['perms'] = $data[$i]['perm']; 417 unset($data[$i]['perm']); 418 $data[$i]['lastModified'] = $this->api->toDate($data[$i]['mtime']); 419 } 420 return $data; 421 } else { 422 throw new RemoteAccessDeniedException('You are not allowed to list media files.', 215); 423 } 424 } 425 426 /** 427 * Return a list of backlinks 428 * 429 * @param string $id page id 430 * @return array 431 */ 432 function listBackLinks($id){ 433 return ft_backlinks($this->resolvePageId($id)); 434 } 435 436 /** 437 * Return some basic data about a page 438 * 439 * @param string $id page id 440 * @param string|int $rev revision timestamp or empty string 441 * @return array 442 * @throws RemoteAccessDeniedException no access for page 443 * @throws RemoteException page not exist 444 */ 445 public function pageInfo($id,$rev=''){ 446 $id = $this->resolvePageId($id); 447 if(auth_quickaclcheck($id) < AUTH_READ){ 448 throw new RemoteAccessDeniedException('You are not allowed to read this page', 111); 449 } 450 $file = wikiFN($id,$rev); 451 $time = @filemtime($file); 452 if(!$time){ 453 throw new RemoteException('The requested page does not exist', 121); 454 } 455 456 // set revision to current version if empty, use revision otherwise 457 // as the timestamps of old files are not necessarily correct 458 if($rev === '') { 459 $rev = $time; 460 } 461 462 $pagelog = new PageChangeLog($id, 1024); 463 $info = $pagelog->getRevisionInfo($rev); 464 465 $data = array( 466 'name' => $id, 467 'lastModified' => $this->api->toDate($rev), 468 'author' => (($info['user']) ? $info['user'] : $info['ip']), 469 'version' => $rev 470 ); 471 472 return ($data); 473 } 474 475 /** 476 * Save a wiki page 477 * 478 * @author Michael Klier <chi@chimeric.de> 479 * 480 * @param string $id page id 481 * @param string $text wiki text 482 * @param array $params parameters: summary, minor edit 483 * @return bool 484 * @throws RemoteAccessDeniedException no write access for page 485 * @throws RemoteException no id, empty new page or locked 486 */ 487 public function putPage($id, $text, $params) { 488 global $TEXT; 489 global $lang; 490 491 $id = $this->resolvePageId($id); 492 $TEXT = cleanText($text); 493 $sum = $params['sum']; 494 $minor = $params['minor']; 495 496 if(empty($id)) { 497 throw new RemoteException('Empty page ID', 131); 498 } 499 500 if(!page_exists($id) && trim($TEXT) == '' ) { 501 throw new RemoteException('Refusing to write an empty new wiki page', 132); 502 } 503 504 if(auth_quickaclcheck($id) < AUTH_EDIT) { 505 throw new RemoteAccessDeniedException('You are not allowed to edit this page', 112); 506 } 507 508 // Check, if page is locked 509 if(checklock($id)) { 510 throw new RemoteException('The page is currently locked', 133); 511 } 512 513 // SPAM check 514 if(checkwordblock()) { 515 throw new RemoteException('Positive wordblock check', 134); 516 } 517 518 // autoset summary on new pages 519 if(!page_exists($id) && empty($sum)) { 520 $sum = $lang['created']; 521 } 522 523 // autoset summary on deleted pages 524 if(page_exists($id) && empty($TEXT) && empty($sum)) { 525 $sum = $lang['deleted']; 526 } 527 528 lock($id); 529 530 saveWikiText($id,$TEXT,$sum,$minor); 531 532 unlock($id); 533 534 // run the indexer if page wasn't indexed yet 535 idx_addPage($id); 536 537 return true; 538 } 539 540 /** 541 * Appends text to a wiki page. 542 * 543 * @param string $id page id 544 * @param string $text wiki text 545 * @param array $params such as summary,minor 546 * @return bool|string 547 */ 548 public function appendPage($id, $text, $params) { 549 $currentpage = $this->rawPage($id); 550 if (!is_string($currentpage)) { 551 return $currentpage; 552 } 553 return $this->putPage($id, $currentpage.$text, $params); 554 } 555 556 /** 557 * Remove one or more users from the list of registered users 558 * 559 * @param string[] $usernames List of usernames to remove 560 * 561 * @return bool 562 * 563 * @throws RemoteAccessDeniedException 564 */ 565 public function deleteUsers($usernames) 566 { 567 if (!auth_isadmin()) { 568 throw new RemoteAccessDeniedException('Only admins are allowed to delete users', 114); 569 } 570 /** @var DokuWiki_Auth_Plugin $auth */ 571 global $auth; 572 return (bool)$auth->triggerUserMod('delete', array($usernames)); 573 } 574 575 /** 576 * Uploads a file to the wiki. 577 * 578 * Michael Klier <chi@chimeric.de> 579 * 580 * @param string $id page id 581 * @param string $file 582 * @param array $params such as overwrite 583 * @return false|string 584 * @throws RemoteException 585 */ 586 public function putAttachment($id, $file, $params) { 587 $id = cleanID($id); 588 $auth = auth_quickaclcheck(getNS($id).':*'); 589 590 if(!isset($id)) { 591 throw new RemoteException('Filename not given.', 231); 592 } 593 594 global $conf; 595 596 $ftmp = $conf['tmpdir'] . '/' . md5($id.clientIP()); 597 598 // save temporary file 599 @unlink($ftmp); 600 io_saveFile($ftmp, $file); 601 602 $res = media_save(array('name' => $ftmp), $id, $params['ow'], $auth, 'rename'); 603 if (is_array($res)) { 604 throw new RemoteException($res[0], -$res[1]); 605 } else { 606 return $res; 607 } 608 } 609 610 /** 611 * Deletes a file from the wiki. 612 * 613 * @author Gina Haeussge <osd@foosel.net> 614 * 615 * @param string $id page id 616 * @return int 617 * @throws RemoteAccessDeniedException no permissions 618 * @throws RemoteException file in use or not deleted 619 */ 620 public function deleteAttachment($id){ 621 $id = cleanID($id); 622 $auth = auth_quickaclcheck(getNS($id).':*'); 623 $res = media_delete($id, $auth); 624 if ($res & DOKU_MEDIA_DELETED) { 625 return 0; 626 } elseif ($res & DOKU_MEDIA_NOT_AUTH) { 627 throw new RemoteAccessDeniedException('You don\'t have permissions to delete files.', 212); 628 } elseif ($res & DOKU_MEDIA_INUSE) { 629 throw new RemoteException('File is still referenced', 232); 630 } else { 631 throw new RemoteException('Could not delete file', 233); 632 } 633 } 634 635 /** 636 * Returns the permissions of a given wiki page for the current user or another user 637 * 638 * @param string $id page id 639 * @param string|null $user username 640 * @param array|null $groups array of groups 641 * @return int permission level 642 */ 643 public function aclCheck($id, $user = null, $groups = null) { 644 /** @var DokuWiki_Auth_Plugin $auth */ 645 global $auth; 646 647 $id = $this->resolvePageId($id); 648 if($user === null) { 649 return auth_quickaclcheck($id); 650 } else { 651 if($groups === null) { 652 $userinfo = $auth->getUserData($user); 653 if($userinfo === false) { 654 $groups = array(); 655 } else { 656 $groups = $userinfo['grps']; 657 } 658 } 659 return auth_aclcheck($id, $user, $groups); 660 } 661 } 662 663 /** 664 * Lists all links contained in a wiki page 665 * 666 * @author Michael Klier <chi@chimeric.de> 667 * 668 * @param string $id page id 669 * @return array 670 * @throws RemoteAccessDeniedException no read access for page 671 */ 672 public function listLinks($id) { 673 $id = $this->resolvePageId($id); 674 if(auth_quickaclcheck($id) < AUTH_READ){ 675 throw new RemoteAccessDeniedException('You are not allowed to read this page', 111); 676 } 677 $links = array(); 678 679 // resolve page instructions 680 $ins = p_cached_instructions(wikiFN($id)); 681 682 // instantiate new Renderer - needed for interwiki links 683 $Renderer = new Doku_Renderer_xhtml(); 684 $Renderer->interwiki = getInterwiki(); 685 686 // parse parse instructions 687 foreach($ins as $in) { 688 $link = array(); 689 switch($in[0]) { 690 case 'internallink': 691 $link['type'] = 'local'; 692 $link['page'] = $in[1][0]; 693 $link['href'] = wl($in[1][0]); 694 array_push($links,$link); 695 break; 696 case 'externallink': 697 $link['type'] = 'extern'; 698 $link['page'] = $in[1][0]; 699 $link['href'] = $in[1][0]; 700 array_push($links,$link); 701 break; 702 case 'interwikilink': 703 $url = $Renderer->_resolveInterWiki($in[1][2],$in[1][3]); 704 $link['type'] = 'extern'; 705 $link['page'] = $url; 706 $link['href'] = $url; 707 array_push($links,$link); 708 break; 709 } 710 } 711 712 return ($links); 713 } 714 715 /** 716 * Returns a list of recent changes since give timestamp 717 * 718 * @author Michael Hamann <michael@content-space.de> 719 * @author Michael Klier <chi@chimeric.de> 720 * 721 * @param int $timestamp unix timestamp 722 * @return array 723 * @throws RemoteException no valid timestamp 724 */ 725 public function getRecentChanges($timestamp) { 726 if(strlen($timestamp) != 10) { 727 throw new RemoteException('The provided value is not a valid timestamp', 311); 728 } 729 730 $recents = getRecentsSince($timestamp); 731 732 $changes = array(); 733 734 foreach ($recents as $recent) { 735 $change = array(); 736 $change['name'] = $recent['id']; 737 $change['lastModified'] = $this->api->toDate($recent['date']); 738 $change['author'] = $recent['user']; 739 $change['version'] = $recent['date']; 740 $change['perms'] = $recent['perms']; 741 $change['size'] = @filesize(wikiFN($recent['id'])); 742 array_push($changes, $change); 743 } 744 745 if (!empty($changes)) { 746 return $changes; 747 } else { 748 // in case we still have nothing at this point 749 throw new RemoteException('There are no changes in the specified timeframe', 321); 750 } 751 } 752 753 /** 754 * Returns a list of recent media changes since give timestamp 755 * 756 * @author Michael Hamann <michael@content-space.de> 757 * @author Michael Klier <chi@chimeric.de> 758 * 759 * @param int $timestamp unix timestamp 760 * @return array 761 * @throws RemoteException no valid timestamp 762 */ 763 public function getRecentMediaChanges($timestamp) { 764 if(strlen($timestamp) != 10) 765 throw new RemoteException('The provided value is not a valid timestamp', 311); 766 767 $recents = getRecentsSince($timestamp, null, '', RECENTS_MEDIA_CHANGES); 768 769 $changes = array(); 770 771 foreach ($recents as $recent) { 772 $change = array(); 773 $change['name'] = $recent['id']; 774 $change['lastModified'] = $this->api->toDate($recent['date']); 775 $change['author'] = $recent['user']; 776 $change['version'] = $recent['date']; 777 $change['perms'] = $recent['perms']; 778 $change['size'] = @filesize(mediaFN($recent['id'])); 779 array_push($changes, $change); 780 } 781 782 if (!empty($changes)) { 783 return $changes; 784 } else { 785 // in case we still have nothing at this point 786 throw new RemoteException('There are no changes in the specified timeframe', 321); 787 } 788 } 789 790 /** 791 * Returns a list of available revisions of a given wiki page 792 * Number of returned pages is set by $conf['recent'] 793 * However not accessible pages are skipped, so less than $conf['recent'] could be returned 794 * 795 * @author Michael Klier <chi@chimeric.de> 796 * 797 * @param string $id page id 798 * @param int $first skip the first n changelog lines (0 = from current(if exists), 1 = from 1st old rev, 2 = from 2nd old rev, etc) 799 * @return array 800 * @throws RemoteAccessDeniedException no read access for page 801 * @throws RemoteException empty id 802 */ 803 public function pageVersions($id, $first) { 804 $id = $this->resolvePageId($id); 805 if(auth_quickaclcheck($id) < AUTH_READ) { 806 throw new RemoteAccessDeniedException('You are not allowed to read this page', 111); 807 } 808 global $conf; 809 810 $versions = array(); 811 812 if(empty($id)) { 813 throw new RemoteException('Empty page ID', 131); 814 } 815 816 $first = (int) $first; 817 $first_rev = $first - 1; 818 $first_rev = $first_rev < 0 ? 0 : $first_rev; 819 $pagelog = new PageChangeLog($id); 820 $revisions = $pagelog->getRevisions($first_rev, $conf['recent']); 821 822 if($first == 0) { 823 array_unshift($revisions, ''); // include current revision 824 if ( count($revisions) > $conf['recent'] ){ 825 array_pop($revisions); // remove extra log entry 826 } 827 } 828 829 if(!empty($revisions)) { 830 foreach($revisions as $rev) { 831 $file = wikiFN($id,$rev); 832 $time = @filemtime($file); 833 // we check if the page actually exists, if this is not the 834 // case this can lead to less pages being returned than 835 // specified via $conf['recent'] 836 if($time){ 837 $pagelog->setChunkSize(1024); 838 $info = $pagelog->getRevisionInfo($rev ? $rev : $time); 839 if(!empty($info)) { 840 $data = array(); 841 $data['user'] = $info['user']; 842 $data['ip'] = $info['ip']; 843 $data['type'] = $info['type']; 844 $data['sum'] = $info['sum']; 845 $data['modified'] = $this->api->toDate($info['date']); 846 $data['version'] = $info['date']; 847 array_push($versions, $data); 848 } 849 } 850 } 851 return $versions; 852 } else { 853 return array(); 854 } 855 } 856 857 /** 858 * The version of Wiki RPC API supported 859 */ 860 public function wiki_RPCVersion(){ 861 return 2; 862 } 863 864 865 /** 866 * Locks or unlocks a given batch of pages 867 * 868 * Give an associative array with two keys: lock and unlock. Both should contain a 869 * list of pages to lock or unlock 870 * 871 * Returns an associative array with the keys locked, lockfail, unlocked and 872 * unlockfail, each containing lists of pages. 873 * 874 * @param array[] $set list pages with array('lock' => array, 'unlock' => array) 875 * @return array 876 */ 877 public function setLocks($set){ 878 $locked = array(); 879 $lockfail = array(); 880 $unlocked = array(); 881 $unlockfail = array(); 882 883 foreach((array) $set['lock'] as $id){ 884 $id = $this->resolvePageId($id); 885 if(auth_quickaclcheck($id) < AUTH_EDIT || checklock($id)){ 886 $lockfail[] = $id; 887 }else{ 888 lock($id); 889 $locked[] = $id; 890 } 891 } 892 893 foreach((array) $set['unlock'] as $id){ 894 $id = $this->resolvePageId($id); 895 if(auth_quickaclcheck($id) < AUTH_EDIT || !unlock($id)){ 896 $unlockfail[] = $id; 897 }else{ 898 $unlocked[] = $id; 899 } 900 } 901 902 return array( 903 'locked' => $locked, 904 'lockfail' => $lockfail, 905 'unlocked' => $unlocked, 906 'unlockfail' => $unlockfail, 907 ); 908 } 909 910 /** 911 * Return API version 912 * 913 * @return int 914 */ 915 public function getAPIVersion(){ 916 return DOKU_API_VERSION; 917 } 918 919 /** 920 * Login 921 * 922 * @param string $user 923 * @param string $pass 924 * @return int 925 */ 926 public function login($user,$pass){ 927 global $conf; 928 /** @var DokuWiki_Auth_Plugin $auth */ 929 global $auth; 930 931 if(!$conf['useacl']) return 0; 932 if(!$auth) return 0; 933 934 @session_start(); // reopen session for login 935 if($auth->canDo('external')){ 936 $ok = $auth->trustExternal($user,$pass,false); 937 }else{ 938 $evdata = array( 939 'user' => $user, 940 'password' => $pass, 941 'sticky' => false, 942 'silent' => true, 943 ); 944 $ok = trigger_event('AUTH_LOGIN_CHECK', $evdata, 'auth_login_wrapper'); 945 } 946 session_write_close(); // we're done with the session 947 948 return $ok; 949 } 950 951 /** 952 * Log off 953 * 954 * @return int 955 */ 956 public function logoff(){ 957 global $conf; 958 global $auth; 959 if(!$conf['useacl']) return 0; 960 if(!$auth) return 0; 961 962 auth_logoff(); 963 964 return 1; 965 } 966 967 /** 968 * Resolve page id 969 * 970 * @param string $id page id 971 * @return string 972 */ 973 private function resolvePageId($id) { 974 $id = cleanID($id); 975 if(empty($id)) { 976 global $conf; 977 $id = cleanID($conf['start']); 978 } 979 return $id; 980 } 981 982 } 983
title
Description
Body
title
Description
Body
title
Description
Body
title
Body