1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093 |
- <?php
- namespace dokuwiki\Remote;
- use Doku_Renderer_xhtml;
- use dokuwiki\ChangeLog\MediaChangeLog;
- use dokuwiki\ChangeLog\PageChangeLog;
- use dokuwiki\Extension\Event;
- use dokuwiki\Utf8\Sort;
- define('DOKU_API_VERSION', 11);
- /**
- * Provides the core methods for the remote API.
- * The methods are ordered in 'wiki.<method>' and 'dokuwiki.<method>' namespaces
- */
- class ApiCore
- {
- /** @var int Increased whenever the API is changed */
- const API_VERSION = 11;
- /** @var Api */
- private $api;
- /**
- * @param Api $api
- */
- public function __construct(Api $api)
- {
- $this->api = $api;
- }
- /**
- * Returns details about the core methods
- *
- * @return array
- */
- public function getRemoteInfo()
- {
- return array(
- 'dokuwiki.getVersion' => array(
- 'args' => array(),
- 'return' => 'string',
- 'doc' => 'Returns the running DokuWiki version.'
- ), 'dokuwiki.login' => array(
- 'args' => array('string', 'string'),
- 'return' => 'int',
- 'doc' => 'Tries to login with the given credentials and sets auth cookies.',
- 'public' => '1'
- ), 'dokuwiki.logoff' => array(
- 'args' => array(),
- 'return' => 'int',
- 'doc' => 'Tries to logoff by expiring auth cookies and the associated PHP session.'
- ), 'dokuwiki.getPagelist' => array(
- 'args' => array('string', 'array'),
- 'return' => 'array',
- 'doc' => 'List all pages within the given namespace.',
- 'name' => 'readNamespace'
- ), 'dokuwiki.search' => array(
- 'args' => array('string'),
- 'return' => 'array',
- 'doc' => 'Perform a fulltext search and return a list of matching pages'
- ), 'dokuwiki.getTime' => array(
- 'args' => array(),
- 'return' => 'int',
- 'doc' => 'Returns the current time at the remote wiki server as Unix timestamp.',
- ), 'dokuwiki.setLocks' => array(
- 'args' => array('array'),
- 'return' => 'array',
- 'doc' => 'Lock or unlock pages.'
- ), 'dokuwiki.getTitle' => array(
- 'args' => array(),
- 'return' => 'string',
- 'doc' => 'Returns the wiki title.',
- 'public' => '1'
- ), 'dokuwiki.appendPage' => array(
- 'args' => array('string', 'string', 'array'),
- 'return' => 'bool',
- 'doc' => 'Append text to a wiki page.'
- ), 'dokuwiki.createUser' => array(
- 'args' => array('struct'),
- 'return' => 'bool',
- 'doc' => 'Create a user. The result is boolean'
- ),'dokuwiki.deleteUsers' => array(
- 'args' => array('array'),
- 'return' => 'bool',
- 'doc' => 'Remove one or more users from the list of registered users.'
- ), 'wiki.getPage' => array(
- 'args' => array('string'),
- 'return' => 'string',
- 'doc' => 'Get the raw Wiki text of page, latest version.',
- 'name' => 'rawPage',
- ), 'wiki.getPageVersion' => array(
- 'args' => array('string', 'int'),
- 'name' => 'rawPage',
- 'return' => 'string',
- 'doc' => 'Return a raw wiki page'
- ), 'wiki.getPageHTML' => array(
- 'args' => array('string'),
- 'return' => 'string',
- 'doc' => 'Return page in rendered HTML, latest version.',
- 'name' => 'htmlPage'
- ), 'wiki.getPageHTMLVersion' => array(
- 'args' => array('string', 'int'),
- 'return' => 'string',
- 'doc' => 'Return page in rendered HTML.',
- 'name' => 'htmlPage'
- ), 'wiki.getAllPages' => array(
- 'args' => array(),
- 'return' => 'array',
- 'doc' => 'Returns a list of all pages. The result is an array of utf8 pagenames.',
- 'name' => 'listPages'
- ), 'wiki.getAttachments' => array(
- 'args' => array('string', 'array'),
- 'return' => 'array',
- 'doc' => 'Returns a list of all media files.',
- 'name' => 'listAttachments'
- ), 'wiki.getBackLinks' => array(
- 'args' => array('string'),
- 'return' => 'array',
- 'doc' => 'Returns the pages that link to this page.',
- 'name' => 'listBackLinks'
- ), 'wiki.getPageInfo' => array(
- 'args' => array('string'),
- 'return' => 'array',
- 'doc' => 'Returns a struct with info about the page, latest version.',
- 'name' => 'pageInfo'
- ), 'wiki.getPageInfoVersion' => array(
- 'args' => array('string', 'int'),
- 'return' => 'array',
- 'doc' => 'Returns a struct with info about the page.',
- 'name' => 'pageInfo'
- ), 'wiki.getPageVersions' => array(
- 'args' => array('string', 'int'),
- 'return' => 'array',
- 'doc' => 'Returns the available revisions of the page.',
- 'name' => 'pageVersions'
- ), 'wiki.putPage' => array(
- 'args' => array('string', 'string', 'array'),
- 'return' => 'bool',
- 'doc' => 'Saves a wiki page.'
- ), 'wiki.listLinks' => array(
- 'args' => array('string'),
- 'return' => 'array',
- 'doc' => 'Lists all links contained in a wiki page.'
- ), 'wiki.getRecentChanges' => array(
- 'args' => array('int'),
- 'return' => 'array',
- 'doc' => 'Returns a struct about all recent changes since given timestamp.'
- ), 'wiki.getRecentMediaChanges' => array(
- 'args' => array('int'),
- 'return' => 'array',
- 'doc' => 'Returns a struct about all recent media changes since given timestamp.'
- ), 'wiki.aclCheck' => array(
- 'args' => array('string', 'string', 'array'),
- 'return' => 'int',
- 'doc' => 'Returns the permissions of a given wiki page. By default, for current user/groups'
- ), 'wiki.putAttachment' => array(
- 'args' => array('string', 'file', 'array'),
- 'return' => 'array',
- 'doc' => 'Upload a file to the wiki.'
- ), 'wiki.deleteAttachment' => array(
- 'args' => array('string'),
- 'return' => 'int',
- 'doc' => 'Delete a file from the wiki.'
- ), 'wiki.getAttachment' => array(
- 'args' => array('string'),
- 'doc' => 'Return a media file',
- 'return' => 'file',
- 'name' => 'getAttachment',
- ), 'wiki.getAttachmentInfo' => array(
- 'args' => array('string'),
- 'return' => 'array',
- 'doc' => 'Returns a struct with info about the attachment.'
- ), 'dokuwiki.getXMLRPCAPIVersion' => array(
- 'args' => array(),
- 'name' => 'getAPIVersion',
- 'return' => 'int',
- 'doc' => 'Returns the XMLRPC API version.',
- 'public' => '1',
- ), 'wiki.getRPCVersionSupported' => array(
- 'args' => array(),
- 'name' => 'wikiRpcVersion',
- 'return' => 'int',
- 'doc' => 'Returns 2 with the supported RPC API version.',
- 'public' => '1'
- ),
- );
- }
- /**
- * @return string
- */
- public function getVersion()
- {
- return getVersion();
- }
- /**
- * @return int unix timestamp
- */
- public function getTime()
- {
- return time();
- }
- /**
- * Return a raw wiki page
- *
- * @param string $id wiki page id
- * @param int|string $rev revision timestamp of the page or empty string
- * @return string page text.
- * @throws AccessDeniedException if no permission for page
- */
- public function rawPage($id, $rev = '')
- {
- $id = $this->resolvePageId($id);
- if (auth_quickaclcheck($id) < AUTH_READ) {
- throw new AccessDeniedException('You are not allowed to read this file', 111);
- }
- $text = rawWiki($id, $rev);
- if (!$text) {
- return pageTemplate($id);
- } else {
- return $text;
- }
- }
- /**
- * Return a media file
- *
- * @author Gina Haeussge <osd@foosel.net>
- *
- * @param string $id file id
- * @return mixed media file
- * @throws AccessDeniedException no permission for media
- * @throws RemoteException not exist
- */
- public function getAttachment($id)
- {
- $id = cleanID($id);
- if (auth_quickaclcheck(getNS($id) . ':*') < AUTH_READ) {
- throw new AccessDeniedException('You are not allowed to read this file', 211);
- }
- $file = mediaFN($id);
- if (!@ file_exists($file)) {
- throw new RemoteException('The requested file does not exist', 221);
- }
- $data = io_readFile($file, false);
- return $this->api->toFile($data);
- }
- /**
- * Return info about a media file
- *
- * @author Gina Haeussge <osd@foosel.net>
- *
- * @param string $id page id
- * @return array
- */
- public function getAttachmentInfo($id)
- {
- $id = cleanID($id);
- $info = array(
- 'lastModified' => $this->api->toDate(0),
- 'size' => 0,
- );
- $file = mediaFN($id);
- if (auth_quickaclcheck(getNS($id) . ':*') >= AUTH_READ) {
- if (file_exists($file)) {
- $info['lastModified'] = $this->api->toDate(filemtime($file));
- $info['size'] = filesize($file);
- } else {
- //Is it deleted media with changelog?
- $medialog = new MediaChangeLog($id);
- $revisions = $medialog->getRevisions(0, 1);
- if (!empty($revisions)) {
- $info['lastModified'] = $this->api->toDate($revisions[0]);
- }
- }
- }
- return $info;
- }
- /**
- * Return a wiki page rendered to html
- *
- * @param string $id page id
- * @param string|int $rev revision timestamp or empty string
- * @return null|string html
- * @throws AccessDeniedException no access to page
- */
- public function htmlPage($id, $rev = '')
- {
- $id = $this->resolvePageId($id);
- if (auth_quickaclcheck($id) < AUTH_READ) {
- throw new AccessDeniedException('You are not allowed to read this page', 111);
- }
- return p_wiki_xhtml($id, $rev, false);
- }
- /**
- * List all pages - we use the indexer list here
- *
- * @return array
- */
- public function listPages()
- {
- $list = array();
- $pages = idx_get_indexer()->getPages();
- $pages = array_filter(array_filter($pages, 'isVisiblePage'), 'page_exists');
- Sort::ksort($pages);
- foreach (array_keys($pages) as $idx) {
- $perm = auth_quickaclcheck($pages[$idx]);
- if ($perm < AUTH_READ) {
- continue;
- }
- $page = array();
- $page['id'] = trim($pages[$idx]);
- $page['perms'] = $perm;
- $page['size'] = @filesize(wikiFN($pages[$idx]));
- $page['lastModified'] = $this->api->toDate(@filemtime(wikiFN($pages[$idx])));
- $list[] = $page;
- }
- return $list;
- }
- /**
- * List all pages in the given namespace (and below)
- *
- * @param string $ns
- * @param array $opts
- * $opts['depth'] recursion level, 0 for all
- * $opts['hash'] do md5 sum of content?
- * @return array
- */
- public function readNamespace($ns, $opts = array())
- {
- global $conf;
- if (!is_array($opts)) $opts = array();
- $ns = cleanID($ns);
- $dir = utf8_encodeFN(str_replace(':', '/', $ns));
- $data = array();
- $opts['skipacl'] = 0; // no ACL skipping for XMLRPC
- search($data, $conf['datadir'], 'search_allpages', $opts, $dir);
- return $data;
- }
- /**
- * List all pages in the given namespace (and below)
- *
- * @param string $query
- * @return array
- */
- public function search($query)
- {
- $regex = array();
- $data = ft_pageSearch($query, $regex);
- $pages = array();
- // prepare additional data
- $idx = 0;
- foreach ($data as $id => $score) {
- $file = wikiFN($id);
- if ($idx < FT_SNIPPET_NUMBER) {
- $snippet = ft_snippet($id, $regex);
- $idx++;
- } else {
- $snippet = '';
- }
- $pages[] = array(
- 'id' => $id,
- 'score' => intval($score),
- 'rev' => filemtime($file),
- 'mtime' => filemtime($file),
- 'size' => filesize($file),
- 'snippet' => $snippet,
- 'title' => useHeading('navigation') ? p_get_first_heading($id) : $id
- );
- }
- return $pages;
- }
- /**
- * Returns the wiki title.
- *
- * @return string
- */
- public function getTitle()
- {
- global $conf;
- return $conf['title'];
- }
- /**
- * List all media files.
- *
- * Available options are 'recursive' for also including the subnamespaces
- * in the listing, and 'pattern' for filtering the returned files against
- * a regular expression matching their name.
- *
- * @author Gina Haeussge <osd@foosel.net>
- *
- * @param string $ns
- * @param array $options
- * $options['depth'] recursion level, 0 for all
- * $options['showmsg'] shows message if invalid media id is used
- * $options['pattern'] check given pattern
- * $options['hash'] add hashes to result list
- * @return array
- * @throws AccessDeniedException no access to the media files
- */
- public function listAttachments($ns, $options = array())
- {
- global $conf;
- $ns = cleanID($ns);
- if (!is_array($options)) $options = array();
- $options['skipacl'] = 0; // no ACL skipping for XMLRPC
- if (auth_quickaclcheck($ns . ':*') >= AUTH_READ) {
- $dir = utf8_encodeFN(str_replace(':', '/', $ns));
- $data = array();
- search($data, $conf['mediadir'], 'search_media', $options, $dir);
- $len = count($data);
- if (!$len) return array();
- for ($i = 0; $i < $len; $i++) {
- unset($data[$i]['meta']);
- $data[$i]['perms'] = $data[$i]['perm'];
- unset($data[$i]['perm']);
- $data[$i]['lastModified'] = $this->api->toDate($data[$i]['mtime']);
- }
- return $data;
- } else {
- throw new AccessDeniedException('You are not allowed to list media files.', 215);
- }
- }
- /**
- * Return a list of backlinks
- *
- * @param string $id page id
- * @return array
- */
- public function listBackLinks($id)
- {
- return ft_backlinks($this->resolvePageId($id));
- }
- /**
- * Return some basic data about a page
- *
- * @param string $id page id
- * @param string|int $rev revision timestamp or empty string
- * @return array
- * @throws AccessDeniedException no access for page
- * @throws RemoteException page not exist
- */
- public function pageInfo($id, $rev = '')
- {
- $id = $this->resolvePageId($id);
- if (auth_quickaclcheck($id) < AUTH_READ) {
- throw new AccessDeniedException('You are not allowed to read this page', 111);
- }
- $file = wikiFN($id, $rev);
- $time = @filemtime($file);
- if (!$time) {
- throw new RemoteException('The requested page does not exist', 121);
- }
- // set revision to current version if empty, use revision otherwise
- // as the timestamps of old files are not necessarily correct
- if ($rev === '') {
- $rev = $time;
- }
- $pagelog = new PageChangeLog($id, 1024);
- $info = $pagelog->getRevisionInfo($rev);
- $data = array(
- 'name' => $id,
- 'lastModified' => $this->api->toDate($rev),
- 'author' => is_array($info) ? (($info['user']) ? $info['user'] : $info['ip']) : null,
- 'version' => $rev
- );
- return ($data);
- }
- /**
- * Save a wiki page
- *
- * @author Michael Klier <chi@chimeric.de>
- *
- * @param string $id page id
- * @param string $text wiki text
- * @param array $params parameters: summary, minor edit
- * @return bool
- * @throws AccessDeniedException no write access for page
- * @throws RemoteException no id, empty new page or locked
- */
- public function putPage($id, $text, $params = array())
- {
- global $TEXT;
- global $lang;
- $id = $this->resolvePageId($id);
- $TEXT = cleanText($text);
- $sum = $params['sum'];
- $minor = $params['minor'];
- if (empty($id)) {
- throw new RemoteException('Empty page ID', 131);
- }
- if (!page_exists($id) && trim($TEXT) == '') {
- throw new RemoteException('Refusing to write an empty new wiki page', 132);
- }
- if (auth_quickaclcheck($id) < AUTH_EDIT) {
- throw new AccessDeniedException('You are not allowed to edit this page', 112);
- }
- // Check, if page is locked
- if (checklock($id)) {
- throw new RemoteException('The page is currently locked', 133);
- }
- // SPAM check
- if (checkwordblock()) {
- throw new RemoteException('Positive wordblock check', 134);
- }
- // autoset summary on new pages
- if (!page_exists($id) && empty($sum)) {
- $sum = $lang['created'];
- }
- // autoset summary on deleted pages
- if (page_exists($id) && empty($TEXT) && empty($sum)) {
- $sum = $lang['deleted'];
- }
- lock($id);
- saveWikiText($id, $TEXT, $sum, $minor);
- unlock($id);
- // run the indexer if page wasn't indexed yet
- idx_addPage($id);
- return true;
- }
- /**
- * Appends text to a wiki page.
- *
- * @param string $id page id
- * @param string $text wiki text
- * @param array $params such as summary,minor
- * @return bool|string
- * @throws RemoteException
- */
- public function appendPage($id, $text, $params = array())
- {
- $currentpage = $this->rawPage($id);
- if (!is_string($currentpage)) {
- return $currentpage;
- }
- return $this->putPage($id, $currentpage . $text, $params);
- }
- /**
- * Create one or more users
- *
- * @param array[] $userStruct User struct
- *
- * @return boolean Create state
- *
- * @throws AccessDeniedException
- * @throws RemoteException
- */
- public function createUser($userStruct)
- {
- if (!auth_isadmin()) {
- throw new AccessDeniedException('Only admins are allowed to create users', 114);
- }
- /** @var \dokuwiki\Extension\AuthPlugin $auth */
- global $auth;
- if(!$auth->canDo('addUser')) {
- throw new AccessDeniedException(
- sprintf('Authentication backend %s can\'t do addUser', $auth->getPluginName()),
- 114
- );
- }
- $user = trim($auth->cleanUser($userStruct['user'] ?? ''));
- $password = $userStruct['password'] ?? '';
- $name = trim(preg_replace('/[\x00-\x1f:<>&%,;]+/', '', $userStruct['name'] ?? ''));
- $mail = trim(preg_replace('/[\x00-\x1f:<>&%,;]+/', '', $userStruct['mail'] ?? ''));
- $groups = $userStruct['groups'] ?? [];
- $notify = (bool)$userStruct['notify'] ?? false;
- if ($user === '') throw new RemoteException('empty or invalid user', 401);
- if ($name === '') throw new RemoteException('empty or invalid user name', 402);
- if (!mail_isvalid($mail)) throw new RemoteException('empty or invalid mail address', 403);
- if(strlen($password) === 0) {
- $password = auth_pwgen($user);
- }
- if (!is_array($groups) || count($groups) === 0) {
- $groups = null;
- }
- $ok = $auth->triggerUserMod('create', array($user, $password, $name, $mail, $groups));
- if ($ok !== false && $ok !== null) {
- $ok = true;
- }
- if($ok) {
- if($notify) {
- auth_sendPassword($user, $password);
- }
- }
- return $ok;
- }
- /**
- * Remove one or more users from the list of registered users
- *
- * @param string[] $usernames List of usernames to remove
- *
- * @return bool
- *
- * @throws AccessDeniedException
- */
- public function deleteUsers($usernames)
- {
- if (!auth_isadmin()) {
- throw new AccessDeniedException('Only admins are allowed to delete users', 114);
- }
- /** @var \dokuwiki\Extension\AuthPlugin $auth */
- global $auth;
- return (bool)$auth->triggerUserMod('delete', array($usernames));
- }
- /**
- * Uploads a file to the wiki.
- *
- * Michael Klier <chi@chimeric.de>
- *
- * @param string $id page id
- * @param string $file
- * @param array $params such as overwrite
- * @return false|string
- * @throws RemoteException
- */
- public function putAttachment($id, $file, $params = array())
- {
- $id = cleanID($id);
- $auth = auth_quickaclcheck(getNS($id) . ':*');
- if (!isset($id)) {
- throw new RemoteException('Filename not given.', 231);
- }
- global $conf;
- $ftmp = $conf['tmpdir'] . '/' . md5($id . clientIP());
- // save temporary file
- @unlink($ftmp);
- io_saveFile($ftmp, $file);
- $res = media_save(array('name' => $ftmp), $id, $params['ow'], $auth, 'rename');
- if (is_array($res)) {
- throw new RemoteException($res[0], -$res[1]);
- } else {
- return $res;
- }
- }
- /**
- * Deletes a file from the wiki.
- *
- * @author Gina Haeussge <osd@foosel.net>
- *
- * @param string $id page id
- * @return int
- * @throws AccessDeniedException no permissions
- * @throws RemoteException file in use or not deleted
- */
- public function deleteAttachment($id)
- {
- $id = cleanID($id);
- $auth = auth_quickaclcheck(getNS($id) . ':*');
- $res = media_delete($id, $auth);
- if ($res & DOKU_MEDIA_DELETED) {
- return 0;
- } elseif ($res & DOKU_MEDIA_NOT_AUTH) {
- throw new AccessDeniedException('You don\'t have permissions to delete files.', 212);
- } elseif ($res & DOKU_MEDIA_INUSE) {
- throw new RemoteException('File is still referenced', 232);
- } else {
- throw new RemoteException('Could not delete file', 233);
- }
- }
- /**
- * Returns the permissions of a given wiki page for the current user or another user
- *
- * @param string $id page id
- * @param string|null $user username
- * @param array|null $groups array of groups
- * @return int permission level
- */
- public function aclCheck($id, $user = null, $groups = null)
- {
- /** @var \dokuwiki\Extension\AuthPlugin $auth */
- global $auth;
- $id = $this->resolvePageId($id);
- if ($user === null) {
- return auth_quickaclcheck($id);
- } else {
- if ($groups === null) {
- $userinfo = $auth->getUserData($user);
- if ($userinfo === false) {
- $groups = array();
- } else {
- $groups = $userinfo['grps'];
- }
- }
- return auth_aclcheck($id, $user, $groups);
- }
- }
- /**
- * Lists all links contained in a wiki page
- *
- * @author Michael Klier <chi@chimeric.de>
- *
- * @param string $id page id
- * @return array
- * @throws AccessDeniedException no read access for page
- */
- public function listLinks($id)
- {
- $id = $this->resolvePageId($id);
- if (auth_quickaclcheck($id) < AUTH_READ) {
- throw new AccessDeniedException('You are not allowed to read this page', 111);
- }
- $links = array();
- // resolve page instructions
- $ins = p_cached_instructions(wikiFN($id));
- // instantiate new Renderer - needed for interwiki links
- $Renderer = new Doku_Renderer_xhtml();
- $Renderer->interwiki = getInterwiki();
- // parse parse instructions
- foreach ($ins as $in) {
- $link = array();
- switch ($in[0]) {
- case 'internallink':
- $link['type'] = 'local';
- $link['page'] = $in[1][0];
- $link['href'] = wl($in[1][0]);
- array_push($links, $link);
- break;
- case 'externallink':
- $link['type'] = 'extern';
- $link['page'] = $in[1][0];
- $link['href'] = $in[1][0];
- array_push($links, $link);
- break;
- case 'interwikilink':
- $url = $Renderer->_resolveInterWiki($in[1][2], $in[1][3]);
- $link['type'] = 'extern';
- $link['page'] = $url;
- $link['href'] = $url;
- array_push($links, $link);
- break;
- }
- }
- return ($links);
- }
- /**
- * Returns a list of recent changes since give timestamp
- *
- * @author Michael Hamann <michael@content-space.de>
- * @author Michael Klier <chi@chimeric.de>
- *
- * @param int $timestamp unix timestamp
- * @return array
- * @throws RemoteException no valid timestamp
- */
- public function getRecentChanges($timestamp)
- {
- if (strlen($timestamp) != 10) {
- throw new RemoteException('The provided value is not a valid timestamp', 311);
- }
- $recents = getRecentsSince($timestamp);
- $changes = array();
- foreach ($recents as $recent) {
- $change = array();
- $change['name'] = $recent['id'];
- $change['lastModified'] = $this->api->toDate($recent['date']);
- $change['author'] = $recent['user'];
- $change['version'] = $recent['date'];
- $change['perms'] = $recent['perms'];
- $change['size'] = @filesize(wikiFN($recent['id']));
- array_push($changes, $change);
- }
- if (!empty($changes)) {
- return $changes;
- } else {
- // in case we still have nothing at this point
- throw new RemoteException('There are no changes in the specified timeframe', 321);
- }
- }
- /**
- * Returns a list of recent media changes since give timestamp
- *
- * @author Michael Hamann <michael@content-space.de>
- * @author Michael Klier <chi@chimeric.de>
- *
- * @param int $timestamp unix timestamp
- * @return array
- * @throws RemoteException no valid timestamp
- */
- public function getRecentMediaChanges($timestamp)
- {
- if (strlen($timestamp) != 10)
- throw new RemoteException('The provided value is not a valid timestamp', 311);
- $recents = getRecentsSince($timestamp, null, '', RECENTS_MEDIA_CHANGES);
- $changes = array();
- foreach ($recents as $recent) {
- $change = array();
- $change['name'] = $recent['id'];
- $change['lastModified'] = $this->api->toDate($recent['date']);
- $change['author'] = $recent['user'];
- $change['version'] = $recent['date'];
- $change['perms'] = $recent['perms'];
- $change['size'] = @filesize(mediaFN($recent['id']));
- array_push($changes, $change);
- }
- if (!empty($changes)) {
- return $changes;
- } else {
- // in case we still have nothing at this point
- throw new RemoteException('There are no changes in the specified timeframe', 321);
- }
- }
- /**
- * Returns a list of available revisions of a given wiki page
- * Number of returned pages is set by $conf['recent']
- * However not accessible pages are skipped, so less than $conf['recent'] could be returned
- *
- * @author Michael Klier <chi@chimeric.de>
- *
- * @param string $id page id
- * @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
- * @return array
- * @throws AccessDeniedException no read access for page
- * @throws RemoteException empty id
- */
- public function pageVersions($id, $first = 0)
- {
- $id = $this->resolvePageId($id);
- if (auth_quickaclcheck($id) < AUTH_READ) {
- throw new AccessDeniedException('You are not allowed to read this page', 111);
- }
- global $conf;
- $versions = array();
- if (empty($id)) {
- throw new RemoteException('Empty page ID', 131);
- }
- $first = (int) $first;
- $first_rev = $first - 1;
- $first_rev = $first_rev < 0 ? 0 : $first_rev;
- $pagelog = new PageChangeLog($id);
- $revisions = $pagelog->getRevisions($first_rev, $conf['recent']);
- if ($first == 0) {
- array_unshift($revisions, ''); // include current revision
- if (count($revisions) > $conf['recent']) {
- array_pop($revisions); // remove extra log entry
- }
- }
- if (!empty($revisions)) {
- foreach ($revisions as $rev) {
- $file = wikiFN($id, $rev);
- $time = @filemtime($file);
- // we check if the page actually exists, if this is not the
- // case this can lead to less pages being returned than
- // specified via $conf['recent']
- if ($time) {
- $pagelog->setChunkSize(1024);
- $info = $pagelog->getRevisionInfo($rev ? $rev : $time);
- if (!empty($info)) {
- $data = array();
- $data['user'] = $info['user'];
- $data['ip'] = $info['ip'];
- $data['type'] = $info['type'];
- $data['sum'] = $info['sum'];
- $data['modified'] = $this->api->toDate($info['date']);
- $data['version'] = $info['date'];
- array_push($versions, $data);
- }
- }
- }
- return $versions;
- } else {
- return array();
- }
- }
- /**
- * The version of Wiki RPC API supported
- */
- public function wikiRpcVersion()
- {
- return 2;
- }
- /**
- * Locks or unlocks a given batch of pages
- *
- * Give an associative array with two keys: lock and unlock. Both should contain a
- * list of pages to lock or unlock
- *
- * Returns an associative array with the keys locked, lockfail, unlocked and
- * unlockfail, each containing lists of pages.
- *
- * @param array[] $set list pages with array('lock' => array, 'unlock' => array)
- * @return array
- */
- public function setLocks($set)
- {
- $locked = array();
- $lockfail = array();
- $unlocked = array();
- $unlockfail = array();
- foreach ((array) $set['lock'] as $id) {
- $id = $this->resolvePageId($id);
- if (auth_quickaclcheck($id) < AUTH_EDIT || checklock($id)) {
- $lockfail[] = $id;
- } else {
- lock($id);
- $locked[] = $id;
- }
- }
- foreach ((array) $set['unlock'] as $id) {
- $id = $this->resolvePageId($id);
- if (auth_quickaclcheck($id) < AUTH_EDIT || !unlock($id)) {
- $unlockfail[] = $id;
- } else {
- $unlocked[] = $id;
- }
- }
- return array(
- 'locked' => $locked,
- 'lockfail' => $lockfail,
- 'unlocked' => $unlocked,
- 'unlockfail' => $unlockfail,
- );
- }
- /**
- * Return API version
- *
- * @return int
- */
- public function getAPIVersion()
- {
- return self::API_VERSION;
- }
- /**
- * Login
- *
- * @param string $user
- * @param string $pass
- * @return int
- */
- public function login($user, $pass)
- {
- global $conf;
- /** @var \dokuwiki\Extension\AuthPlugin $auth */
- global $auth;
- if (!$conf['useacl']) return 0;
- if (!$auth) return 0;
- @session_start(); // reopen session for login
- $ok = null;
- if ($auth->canDo('external')) {
- $ok = $auth->trustExternal($user, $pass, false);
- }
- if ($ok === null){
- $evdata = array(
- 'user' => $user,
- 'password' => $pass,
- 'sticky' => false,
- 'silent' => true,
- );
- $ok = Event::createAndTrigger('AUTH_LOGIN_CHECK', $evdata, 'auth_login_wrapper');
- }
- session_write_close(); // we're done with the session
- return $ok;
- }
- /**
- * Log off
- *
- * @return int
- */
- public function logoff()
- {
- global $conf;
- global $auth;
- if (!$conf['useacl']) return 0;
- if (!$auth) return 0;
- auth_logoff();
- return 1;
- }
- /**
- * Resolve page id
- *
- * @param string $id page id
- * @return string
- */
- private function resolvePageId($id)
- {
- $id = cleanID($id);
- if (empty($id)) {
- global $conf;
- $id = cleanID($conf['start']);
- }
- return $id;
- }
- }
|