PSR-2 compatibility for the remote API libs

This commit is contained in:
Andreas Gohr 2018-05-07 22:21:39 +02:00
parent e1cdd96c58
commit dd87735d91
12 changed files with 357 additions and 260 deletions

View File

@ -1,5 +1,7 @@
<?php
use dokuwiki\Remote\Api;
class MockAuth extends DokuWiki_Auth_Plugin {
function isCaseSensitive() { return true; }
}
@ -131,7 +133,7 @@ class remote_test extends DokuWikiTest {
protected $userinfo;
/** @var RemoteAPI */
/** @var Api */
protected $remote;
function setUp() {
@ -162,7 +164,7 @@ class remote_test extends DokuWikiTest {
$conf['useacl'] = 0;
$this->userinfo = $USERINFO;
$this->remote = new RemoteAPI();
$this->remote = new Api();
$auth = new MockAuth();
}
@ -206,7 +208,7 @@ class remote_test extends DokuWikiTest {
}
/**
* @expectedException RemoteAccessDeniedException
* @expectedException dokuwiki\Remote\AccessDeniedException
*/
function test_hasAccessFail() {
global $conf;
@ -260,7 +262,7 @@ class remote_test extends DokuWikiTest {
}
/**
* @expectedException RemoteException
* @expectedException dokuwiki\Remote\RemoteException
*/
function test_forceAccessFail() {
global $conf;
@ -275,7 +277,7 @@ class remote_test extends DokuWikiTest {
$conf['remoteuser'] = '';
$conf['useacl'] = 1;
$USERINFO['grps'] = array('grp');
$remoteApi = new RemoteApi();
$remoteApi = new Api();
$remoteApi->getCoreMethods(new RemoteAPICoreTest());
$this->assertEquals($remoteApi->call('wiki.stringTestMethod'), 'success');
@ -287,12 +289,12 @@ class remote_test extends DokuWikiTest {
}
/**
* @expectedException RemoteException
* @expectedException dokuwiki\Remote\RemoteException
*/
function test_generalCoreFunctionOnArgumentMismatch() {
global $conf;
$conf['remote'] = 1;
$remoteApi = new RemoteApi();
$remoteApi = new Api();
$remoteApi->getCoreMethods(new RemoteAPICoreTest());
$remoteApi->call('wiki.voidTestMethod', array('something'));
@ -305,7 +307,7 @@ class remote_test extends DokuWikiTest {
$conf['remoteuser'] = '';
$conf['useacl'] = 1;
$remoteApi = new RemoteApi();
$remoteApi = new Api();
$remoteApi->getCoreMethods(new RemoteAPICoreTest());
$this->assertEquals($remoteApi->call('wiki.oneStringArgMethod', array('string')), 'string');
@ -321,7 +323,7 @@ class remote_test extends DokuWikiTest {
$conf['remoteuser'] = '';
$conf['useacl'] = 1;
$remoteApi = new RemoteApi();
$remoteApi = new Api();
$this->assertEquals($remoteApi->call('plugin.testplugin.method1'), null);
$this->assertEquals($remoteApi->call('plugin.testplugin.method2', array('string', 7)), array('string', 7, false));
$this->assertEquals($remoteApi->call('plugin.testplugin.method2ext', array('string', 7, true)), array('string', 7, true));
@ -329,20 +331,20 @@ class remote_test extends DokuWikiTest {
}
/**
* @expectedException RemoteException
* @expectedException dokuwiki\Remote\RemoteException
*/
function test_notExistingCall() {
global $conf;
$conf['remote'] = 1;
$remoteApi = new RemoteApi();
$remoteApi = new Api();
$remoteApi->call('dose not exist');
}
function test_publicCallCore() {
global $conf;
$conf['useacl'] = 1;
$remoteApi = new RemoteApi();
$remoteApi = new Api();
$remoteApi->getCoreMethods(new RemoteAPICoreTest());
$this->assertTrue($remoteApi->call('wiki.publicCall'));
}
@ -350,28 +352,28 @@ class remote_test extends DokuWikiTest {
function test_publicCallPlugin() {
global $conf;
$conf['useacl'] = 1;
$remoteApi = new RemoteApi();
$remoteApi = new Api();
$this->assertTrue($remoteApi->call('plugin.testplugin.publicCall'));
}
/**
* @expectedException RemoteAccessDeniedException
* @expectedException dokuwiki\Remote\AccessDeniedException
*/
function test_publicCallCoreDeny() {
global $conf;
$conf['useacl'] = 1;
$remoteApi = new RemoteApi();
$remoteApi = new Api();
$remoteApi->getCoreMethods(new RemoteAPICoreTest());
$remoteApi->call('wiki.stringTestMethod');
}
/**
* @expectedException RemoteAccessDeniedException
* @expectedException dokuwiki\Remote\AccessDeniedException
*/
function test_publicCallPluginDeny() {
global $conf;
$conf['useacl'] = 1;
$remoteApi = new RemoteApi();
$remoteApi = new Api();
$remoteApi->call('plugin.testplugin.methodString');
}
@ -384,7 +386,7 @@ class remote_test extends DokuWikiTest {
global $EVENT_HANDLER;
$EVENT_HANDLER->register_hook('RPC_CALL_ADD', 'BEFORE', $this, 'pluginCallCustomPathRegister');
$remoteApi = new RemoteAPI();
$remoteApi = new Api();
$result = $remoteApi->call('custom.path');
$this->assertEquals($result, 'success');
}

View File

@ -1,5 +1,7 @@
<?php
use dokuwiki\Remote\Api;
use dokuwiki\Remote\ApiCore;
use dokuwiki\test\mock\DokuWiki_Auth_Plugin;
/**
@ -9,7 +11,7 @@ class remoteapicore_test extends DokuWikiTest {
protected $userinfo;
protected $oldAuthAcl;
/** @var RemoteAPI */
/** @var Api */
protected $remote;
public function setUp() {
@ -29,7 +31,7 @@ class remoteapicore_test extends DokuWikiTest {
$conf['remoteuser'] = '@user';
$conf['useacl'] = 0;
$this->remote = new RemoteAPI();
$this->remote = new Api();
}
public function tearDown() {
@ -468,7 +470,7 @@ You can use up to five different levels of',
}
public function test_getXMLRPCAPIVersion() {
$this->assertEquals(DOKU_API_VERSION, $this->remote->call('dokuwiki.getXMLRPCAPIVersion'));
$this->assertEquals(ApiCore::API_VERSION, $this->remote->call('dokuwiki.getXMLRPCAPIVersion'));
}
public function test_getRPCVersionSupported() {

View File

@ -1,5 +1,7 @@
<?php
use dokuwiki\Remote\Api;
/**
* Class remoteapicore_test
*/
@ -7,7 +9,7 @@ class remoteapicore_aclcheck_test extends DokuWikiTest {
protected $userinfo;
protected $oldAuthAcl;
/** @var RemoteAPI */
/** @var Api */
protected $remote;
protected $pluginsEnabled = array('auth_plugin_authplain');
@ -38,7 +40,7 @@ class remoteapicore_aclcheck_test extends DokuWikiTest {
$conf['remoteuser'] = '@user';
$conf['useacl'] = 0;
$this->remote = new RemoteAPI();
$this->remote = new Api();
}

View File

@ -0,0 +1,10 @@
<?php
namespace dokuwiki\Remote;
/**
* Class AccessDeniedException
*/
class AccessDeniedException extends RemoteException
{
}

View File

@ -1,9 +1,9 @@
<?php
if (!defined('DOKU_INC')) die();
namespace dokuwiki\Remote;
class RemoteException extends Exception {}
class RemoteAccessDeniedException extends RemoteException {}
use DokuWiki_Remote_Plugin;
use Input;
/**
* This class provides information about remote access to the wiki.
@ -33,19 +33,18 @@ class RemoteAccessDeniedException extends RemoteException {}
*
* plugin methods are formed like 'plugin.<plugin name>.<method name>'.
* i.e.: plugin.clock.getTime or plugin.clock_gmt.getTime
*
* @throws RemoteException
*/
class RemoteAPI {
class Api
{
/**
* @var RemoteAPICore
* @var ApiCore
*/
private $coreMethods = null;
/**
* @var array remote methods provided by dokuwiki plugins - will be filled lazy via
* {@see RemoteAPI#getPluginMethods}
* {@see dokuwiki\Remote\RemoteAPI#getPluginMethods}
*/
private $pluginMethods = null;
@ -63,7 +62,8 @@ class RemoteAPI {
/**
* constructor
*/
public function __construct() {
public function __construct()
{
$this->dateTransformation = array($this, 'dummyTransformation');
$this->fileTransformation = array($this, 'dummyTransformation');
}
@ -72,8 +72,10 @@ class RemoteAPI {
* Get all available methods with remote access.
*
* @return array with information to all available methods
* @throws RemoteException
*/
public function getMethods() {
public function getMethods()
{
return array_merge($this->getCoreMethods(), $this->getPluginMethods());
}
@ -83,8 +85,10 @@ class RemoteAPI {
* @param string $method name of the method to call.
* @param array $args arguments to pass to the given method
* @return mixed result of method call, must be a primitive type.
* @throws RemoteException
*/
public function call($method, $args = array()) {
public function call($method, $args = array())
{
if ($args === null) {
$args = array();
}
@ -104,7 +108,8 @@ class RemoteAPI {
* @param string $name name of the method
* @return bool if method exists
*/
private function coreMethodExist($name) {
private function coreMethodExist($name)
{
$coreMethods = $this->getCoreMethods();
return array_key_exists($name, $coreMethods);
}
@ -113,14 +118,15 @@ class RemoteAPI {
* Try to call custom methods provided by plugins
*
* @param string $method name of method
* @param array $args
* @param array $args
* @return mixed
* @throws RemoteException if method not exists
* @throws \dokuwiki\Remote\RemoteException if method not exists
*/
private function callCustomCallPlugin($method, $args) {
private function callCustomCallPlugin($method, $args)
{
$customCalls = $this->getCustomCallPlugins();
if (!array_key_exists($method, $customCalls)) {
throw new RemoteException('Method does not exist', -32603);
throw new \dokuwiki\Remote\RemoteException('Method does not exist', -32603);
}
$customCall = $customCalls[$method];
return $this->callPlugin($customCall[0], $customCall[1], $args);
@ -132,7 +138,8 @@ class RemoteAPI {
* @return array with pairs of custom plugin calls
* @triggers RPC_CALL_ADD
*/
private function getCustomCallPlugins() {
private function getCustomCallPlugins()
{
if ($this->pluginCustomCalls === null) {
$data = array();
trigger_event('RPC_CALL_ADD', $data);
@ -146,15 +153,16 @@ class RemoteAPI {
*
* @param string $pluginName
* @param string $method method name
* @param array $args
* @param array $args
* @return mixed return of custom method
* @throws RemoteException
* @throws \dokuwiki\Remote\RemoteException
*/
private function callPlugin($pluginName, $method, $args) {
private function callPlugin($pluginName, $method, $args)
{
$plugin = plugin_load('remote', $pluginName);
$methods = $this->getPluginMethods();
if (!$plugin) {
throw new RemoteException('Method does not exist', -32603);
throw new \dokuwiki\Remote\RemoteException('Method does not exist', -32603);
}
$this->checkAccess($methods[$method]);
$name = $this->getMethodName($methods, $method);
@ -165,11 +173,12 @@ class RemoteAPI {
* Call a core method
*
* @param string $method name of method
* @param array $args
* @param array $args
* @return mixed
* @throws RemoteException if method not exist
* @throws \dokuwiki\Remote\RemoteException if method not exist
*/
private function callCoreMethod($method, $args) {
private function callCoreMethod($method, $args)
{
$coreMethods = $this->getCoreMethods();
$this->checkAccess($coreMethods[$method]);
if (!isset($coreMethods[$method])) {
@ -183,11 +192,13 @@ class RemoteAPI {
* Check if access should be checked
*
* @param array $methodMeta data about the method
* @throws AccessDeniedException
*/
private function checkAccess($methodMeta) {
private function checkAccess($methodMeta)
{
if (!isset($methodMeta['public'])) {
$this->forceAccess();
} else{
} else {
if ($methodMeta['public'] == '0') {
$this->forceAccess();
}
@ -201,7 +212,8 @@ class RemoteAPI {
* @param array $args
* @throws RemoteException if wrong parameter count
*/
private function checkArgumentLength($methodMeta, $args) {
private function checkArgumentLength($methodMeta, $args)
{
if (count($methodMeta['args']) < count($args)) {
throw new RemoteException('Method does not exist - wrong parameter count.', -32603);
}
@ -214,36 +226,38 @@ class RemoteAPI {
* @param string $method name of method
* @return string
*/
private function getMethodName($methodMeta, $method) {
private function getMethodName($methodMeta, $method)
{
if (isset($methodMeta[$method]['name'])) {
return $methodMeta[$method]['name'];
}
$method = explode('.', $method);
return $method[count($method)-1];
return $method[count($method) - 1];
}
/**
* Perform access check for current user
*
* @return bool true if the current user has access to remote api.
* @throws RemoteAccessDeniedException If remote access disabled
* @throws AccessDeniedException If remote access disabled
*/
public function hasAccess() {
public function hasAccess()
{
global $conf;
global $USERINFO;
/** @var Input $INPUT */
global $INPUT;
if (!$conf['remote']) {
throw new RemoteAccessDeniedException('server error. RPC server not enabled.',-32604);
throw new AccessDeniedException('server error. RPC server not enabled.', -32604);
}
if(trim($conf['remoteuser']) == '!!not set!!') {
if (trim($conf['remoteuser']) == '!!not set!!') {
return false;
}
if(!$conf['useacl']) {
if (!$conf['useacl']) {
return true;
}
if(trim($conf['remoteuser']) == '') {
if (trim($conf['remoteuser']) == '') {
return true;
}
@ -254,11 +268,12 @@ class RemoteAPI {
* Requests access
*
* @return void
* @throws RemoteException On denied access.
* @throws AccessDeniedException On denied access.
*/
public function forceAccess() {
public function forceAccess()
{
if (!$this->hasAccess()) {
throw new RemoteAccessDeniedException('server error. not authorized to call method', -32604);
throw new AccessDeniedException('server error. not authorized to call method', -32604);
}
}
@ -268,7 +283,8 @@ class RemoteAPI {
* @return array all plugin methods.
* @throws RemoteException if not implemented
*/
public function getPluginMethods() {
public function getPluginMethods()
{
if ($this->pluginMethods === null) {
$this->pluginMethods = array();
$plugins = plugin_list('remote');
@ -280,7 +296,12 @@ class RemoteAPI {
throw new RemoteException("Plugin $pluginName does not implement DokuWiki_Remote_Plugin");
}
$methods = $plugin->_getMethods();
try {
$methods = $plugin->_getMethods();
} catch (\ReflectionException $e) {
throw new RemoteException('Automatic aggregation of available remote methods failed', 0, $e);
}
foreach ($methods as $method => $meta) {
$this->pluginMethods["plugin.$pluginName.$method"] = $meta;
}
@ -292,14 +313,15 @@ class RemoteAPI {
/**
* Collects all the core methods
*
* @param RemoteAPICore $apiCore this parameter is used for testing. Here you can pass a non-default RemoteAPICore
* instance. (for mocking)
* @param ApiCore $apiCore this parameter is used for testing. Here you can pass a non-default RemoteAPICore
* instance. (for mocking)
* @return array all core methods.
*/
public function getCoreMethods($apiCore = null) {
public function getCoreMethods($apiCore = null)
{
if ($this->coreMethods === null) {
if ($apiCore === null) {
$this->coreMethods = new RemoteAPICore($this);
$this->coreMethods = new ApiCore($this);
} else {
$this->coreMethods = $apiCore;
}
@ -313,7 +335,8 @@ class RemoteAPI {
* @param mixed $data
* @return mixed
*/
public function toFile($data) {
public function toFile($data)
{
return call_user_func($this->fileTransformation, $data);
}
@ -323,7 +346,8 @@ class RemoteAPI {
* @param mixed $data
* @return mixed
*/
public function toDate($data) {
public function toDate($data)
{
return call_user_func($this->dateTransformation, $data);
}
@ -333,7 +357,8 @@ class RemoteAPI {
* @param mixed $data
* @return mixed
*/
public function dummyTransformation($data) {
public function dummyTransformation($data)
{
return $data;
}
@ -342,7 +367,8 @@ class RemoteAPI {
*
* @param callback $dateTransformation
*/
public function setDateTransformation($dateTransformation) {
public function setDateTransformation($dateTransformation)
{
$this->dateTransformation = $dateTransformation;
}
@ -351,7 +377,8 @@ class RemoteAPI {
*
* @param callback $fileTransformation
*/
public function setFileTransformation($fileTransformation) {
public function setFileTransformation($fileTransformation)
{
$this->fileTransformation = $fileTransformation;
}
}

View File

@ -1,22 +1,32 @@
<?php
/**
* Increased whenever the API is changed
*/
namespace dokuwiki\Remote;
use Doku_Renderer_xhtml;
use DokuWiki_Auth_Plugin;
use MediaChangeLog;
use PageChangeLog;
define('DOKU_API_VERSION', 10);
/**
* Provides the core methods for the remote API.
* The methods are ordered in 'wiki.<method>' and 'dokuwiki.<method>' namespaces
*/
class RemoteAPICore {
class ApiCore
{
/** @var int Increased whenever the API is changed */
const API_VERSION = 10;
/** @var Api */
private $api;
/**
* @param RemoteAPI $api
* @param Api $api
*/
public function __construct(RemoteAPI $api) {
public function __construct(Api $api)
{
$this->api = $api;
}
@ -25,7 +35,8 @@ class RemoteAPICore {
*
* @return array
*/
public function __getRemoteInfo() {
public function __getRemoteInfo()
{
return array(
'dokuwiki.getVersion' => array(
'args' => array(),
@ -52,7 +63,7 @@ class RemoteAPICore {
), 'dokuwiki.getTime' => array(
'args' => array(),
'return' => 'int',
'doc' => 'Returns the current time at the remote wiki server as Unix timestamp.',
'doc' => 'Returns the current time at the remote wiki server as Unix timestamp.',
), 'dokuwiki.setLocks' => array(
'args' => array('array'),
'return' => 'array',
@ -66,7 +77,7 @@ class RemoteAPICore {
'args' => array('string', 'string', 'array'),
'return' => 'bool',
'doc' => 'Append text to a wiki page.'
), 'wiki.getPage' => array(
), 'wiki.getPage' => array(
'args' => array('string'),
'return' => 'string',
'doc' => 'Get the raw Wiki text of page, latest version.',
@ -161,7 +172,7 @@ class RemoteAPICore {
'public' => '1',
), 'wiki.getRPCVersionSupported' => array(
'args' => array(),
'name' => 'wiki_RPCVersion',
'name' => 'wikiRpcVersion',
'return' => 'int',
'doc' => 'Returns 2 with the supported RPC API version.',
'public' => '1'
@ -173,14 +184,16 @@ class RemoteAPICore {
/**
* @return string
*/
public function getVersion() {
public function getVersion()
{
return getVersion();
}
/**
* @return int unix timestamp
*/
public function getTime() {
public function getTime()
{
return time();
}
@ -190,15 +203,16 @@ class RemoteAPICore {
* @param string $id wiki page id
* @param int|string $rev revision timestamp of the page or empty string
* @return string page text.
* @throws RemoteAccessDeniedException if no permission for page
* @throws AccessDeniedException if no permission for page
*/
public function rawPage($id,$rev=''){
public function rawPage($id, $rev = '')
{
$id = $this->resolvePageId($id);
if(auth_quickaclcheck($id) < AUTH_READ){
throw new RemoteAccessDeniedException('You are not allowed to read this file', 111);
if (auth_quickaclcheck($id) < AUTH_READ) {
throw new AccessDeniedException('You are not allowed to read this file', 111);
}
$text = rawWiki($id,$rev);
if(!$text) {
$text = rawWiki($id, $rev);
if (!$text) {
return pageTemplate($id);
} else {
return $text;
@ -212,13 +226,14 @@ class RemoteAPICore {
*
* @param string $id file id
* @return mixed media file
* @throws RemoteAccessDeniedException no permission for media
* @throws AccessDeniedException no permission for media
* @throws RemoteException not exist
*/
public function getAttachment($id){
public function getAttachment($id)
{
$id = cleanID($id);
if (auth_quickaclcheck(getNS($id).':*') < AUTH_READ) {
throw new RemoteAccessDeniedException('You are not allowed to read this file', 211);
if (auth_quickaclcheck(getNS($id) . ':*') < AUTH_READ) {
throw new AccessDeniedException('You are not allowed to read this file', 211);
}
$file = mediaFN($id);
@ -238,7 +253,8 @@ class RemoteAPICore {
* @param string $id page id
* @return array
*/
public function getAttachmentInfo($id){
public function getAttachmentInfo($id)
{
$id = cleanID($id);
$info = array(
'lastModified' => $this->api->toDate(0),
@ -246,15 +262,15 @@ class RemoteAPICore {
);
$file = mediaFN($id);
if(auth_quickaclcheck(getNS($id) . ':*') >= AUTH_READ) {
if(file_exists($file)) {
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)) {
if (!empty($revisions)) {
$info['lastModified'] = $this->api->toDate($revisions[0]);
}
}
@ -266,17 +282,18 @@ class RemoteAPICore {
/**
* Return a wiki page rendered to html
*
* @param string $id page id
* @param string $id page id
* @param string|int $rev revision timestamp or empty string
* @return null|string html
* @throws RemoteAccessDeniedException no access to page
* @throws AccessDeniedException no access to page
*/
public function htmlPage($id,$rev=''){
public function htmlPage($id, $rev = '')
{
$id = $this->resolvePageId($id);
if(auth_quickaclcheck($id) < AUTH_READ){
throw new RemoteAccessDeniedException('You are not allowed to read this page', 111);
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);
return p_wiki_xhtml($id, $rev, false);
}
/**
@ -284,14 +301,15 @@ class RemoteAPICore {
*
* @return array
*/
public function listPages(){
$list = array();
public function listPages()
{
$list = array();
$pages = idx_get_indexer()->getPages();
$pages = array_filter(array_filter($pages,'isVisiblePage'),'page_exists');
$pages = array_filter(array_filter($pages, 'isVisiblePage'), 'page_exists');
foreach(array_keys($pages) as $idx) {
foreach (array_keys($pages) as $idx) {
$perm = auth_quickaclcheck($pages[$idx]);
if($perm < AUTH_READ) {
if ($perm < AUTH_READ) {
continue;
}
$page = array();
@ -309,15 +327,16 @@ class RemoteAPICore {
* List all pages in the given namespace (and below)
*
* @param string $ns
* @param array $opts
* @param array $opts
* $opts['depth'] recursion level, 0 for all
* $opts['hash'] do md5 sum of content?
* @return array
*/
public function readNamespace($ns,$opts){
public function readNamespace($ns, $opts)
{
global $conf;
if(!is_array($opts)) $opts=array();
if (!is_array($opts)) $opts = array();
$ns = cleanID($ns);
$dir = utf8_encodeFN(str_replace(':', '/', $ns));
@ -333,29 +352,30 @@ class RemoteAPICore {
* @param string $query
* @return array
*/
public function search($query){
public function search($query)
{
$regex = array();
$data = ft_pageSearch($query,$regex);
$data = ft_pageSearch($query, $regex);
$pages = array();
// prepare additional data
$idx = 0;
foreach($data as $id => $score){
foreach ($data as $id => $score) {
$file = wikiFN($id);
if($idx < FT_SNIPPET_NUMBER){
$snippet = ft_snippet($id,$regex);
if ($idx < FT_SNIPPET_NUMBER) {
$snippet = ft_snippet($id, $regex);
$idx++;
}else{
} else {
$snippet = '';
}
$pages[] = array(
'id' => $id,
'score' => intval($score),
'rev' => filemtime($file),
'mtime' => filemtime($file),
'size' => filesize($file),
'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
);
@ -368,7 +388,8 @@ class RemoteAPICore {
*
* @return string
*/
public function getTitle(){
public function getTitle()
{
global $conf;
return $conf['title'];
}
@ -383,15 +404,16 @@ class RemoteAPICore {
* @author Gina Haeussge <osd@foosel.net>
*
* @param string $ns
* @param array $options
* @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 RemoteAccessDeniedException no access to the media files
* @throws AccessDeniedException no access to the media files
*/
public function listAttachments($ns, $options = array()) {
public function listAttachments($ns, $options = array())
{
global $conf;
$ns = cleanID($ns);
@ -399,15 +421,15 @@ class RemoteAPICore {
if (!is_array($options)) $options = array();
$options['skipacl'] = 0; // no ACL skipping for XMLRPC
if(auth_quickaclcheck($ns.':*') >= AUTH_READ) {
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();
if (!$len) return array();
for($i=0; $i<$len; $i++) {
for ($i = 0; $i < $len; $i++) {
unset($data[$i]['meta']);
$data[$i]['perms'] = $data[$i]['perm'];
unset($data[$i]['perm']);
@ -415,7 +437,7 @@ class RemoteAPICore {
}
return $data;
} else {
throw new RemoteAccessDeniedException('You are not allowed to list media files.', 215);
throw new AccessDeniedException('You are not allowed to list media files.', 215);
}
}
@ -425,33 +447,35 @@ class RemoteAPICore {
* @param string $id page id
* @return array
*/
public function listBackLinks($id){
public function listBackLinks($id)
{
return ft_backlinks($this->resolvePageId($id));
}
/**
* Return some basic data about a page
*
* @param string $id page id
* @param string $id page id
* @param string|int $rev revision timestamp or empty string
* @return array
* @throws RemoteAccessDeniedException no access for page
* @throws AccessDeniedException no access for page
* @throws RemoteException page not exist
*/
public function pageInfo($id,$rev=''){
public function pageInfo($id, $rev = '')
{
$id = $this->resolvePageId($id);
if(auth_quickaclcheck($id) < AUTH_READ){
throw new RemoteAccessDeniedException('You are not allowed to read this page', 111);
if (auth_quickaclcheck($id) < AUTH_READ) {
throw new AccessDeniedException('You are not allowed to read this page', 111);
}
$file = wikiFN($id,$rev);
$file = wikiFN($id, $rev);
$time = @filemtime($file);
if(!$time){
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 === '') {
if ($rev === '') {
$rev = $time;
}
@ -459,10 +483,10 @@ class RemoteAPICore {
$info = $pagelog->getRevisionInfo($rev);
$data = array(
'name' => $id,
'name' => $id,
'lastModified' => $this->api->toDate($rev),
'author' => (($info['user']) ? $info['user'] : $info['ip']),
'version' => $rev
'author' => (($info['user']) ? $info['user'] : $info['ip']),
'version' => $rev
);
return ($data);
@ -477,53 +501,54 @@ class RemoteAPICore {
* @param string $text wiki text
* @param array $params parameters: summary, minor edit
* @return bool
* @throws RemoteAccessDeniedException no write access for page
* @throws AccessDeniedException no write access for page
* @throws RemoteException no id, empty new page or locked
*/
public function putPage($id, $text, $params) {
public function putPage($id, $text, $params)
{
global $TEXT;
global $lang;
$id = $this->resolvePageId($id);
$TEXT = cleanText($text);
$sum = $params['sum'];
$id = $this->resolvePageId($id);
$TEXT = cleanText($text);
$sum = $params['sum'];
$minor = $params['minor'];
if(empty($id)) {
if (empty($id)) {
throw new RemoteException('Empty page ID', 131);
}
if(!page_exists($id) && trim($TEXT) == '' ) {
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 RemoteAccessDeniedException('You are not allowed to edit this page', 112);
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)) {
if (checklock($id)) {
throw new RemoteException('The page is currently locked', 133);
}
// SPAM check
if(checkwordblock()) {
if (checkwordblock()) {
throw new RemoteException('Positive wordblock check', 134);
}
// autoset summary on new pages
if(!page_exists($id) && empty($sum)) {
if (!page_exists($id) && empty($sum)) {
$sum = $lang['created'];
}
// autoset summary on deleted pages
if(page_exists($id) && empty($TEXT) && empty($sum)) {
if (page_exists($id) && empty($TEXT) && empty($sum)) {
$sum = $lang['deleted'];
}
lock($id);
saveWikiText($id,$TEXT,$sum,$minor);
saveWikiText($id, $TEXT, $sum, $minor);
unlock($id);
@ -540,13 +565,15 @@ class RemoteAPICore {
* @param string $text wiki text
* @param array $params such as summary,minor
* @return bool|string
* @throws RemoteException
*/
public function appendPage($id, $text, $params) {
public function appendPage($id, $text, $params)
{
$currentpage = $this->rawPage($id);
if (!is_string($currentpage)) {
return $currentpage;
}
return $this->putPage($id, $currentpage.$text, $params);
return $this->putPage($id, $currentpage . $text, $params);
}
/**
@ -560,17 +587,18 @@ class RemoteAPICore {
* @return false|string
* @throws RemoteException
*/
public function putAttachment($id, $file, $params) {
public function putAttachment($id, $file, $params)
{
$id = cleanID($id);
$auth = auth_quickaclcheck(getNS($id).':*');
$auth = auth_quickaclcheck(getNS($id) . ':*');
if(!isset($id)) {
if (!isset($id)) {
throw new RemoteException('Filename not given.', 231);
}
global $conf;
$ftmp = $conf['tmpdir'] . '/' . md5($id.clientIP());
$ftmp = $conf['tmpdir'] . '/' . md5($id . clientIP());
// save temporary file
@unlink($ftmp);
@ -591,17 +619,18 @@ class RemoteAPICore {
*
* @param string $id page id
* @return int
* @throws RemoteAccessDeniedException no permissions
* @throws AccessDeniedException no permissions
* @throws RemoteException file in use or not deleted
*/
public function deleteAttachment($id){
public function deleteAttachment($id)
{
$id = cleanID($id);
$auth = auth_quickaclcheck(getNS($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 RemoteAccessDeniedException('You don\'t have permissions to delete files.', 212);
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 {
@ -617,17 +646,18 @@ class RemoteAPICore {
* @param array|null $groups array of groups
* @return int permission level
*/
public function aclCheck($id, $user = null, $groups = null) {
public function aclCheck($id, $user = null, $groups = null)
{
/** @var DokuWiki_Auth_Plugin $auth */
global $auth;
$id = $this->resolvePageId($id);
if($user === null) {
if ($user === null) {
return auth_quickaclcheck($id);
} else {
if($groups === null) {
if ($groups === null) {
$userinfo = $auth->getUserData($user);
if($userinfo === false) {
if ($userinfo === false) {
$groups = array();
} else {
$groups = $userinfo['grps'];
@ -644,44 +674,45 @@ class RemoteAPICore {
*
* @param string $id page id
* @return array
* @throws RemoteAccessDeniedException no read access for page
* @throws AccessDeniedException no read access for page
*/
public function listLinks($id) {
public function listLinks($id)
{
$id = $this->resolvePageId($id);
if(auth_quickaclcheck($id) < AUTH_READ){
throw new RemoteAccessDeniedException('You are not allowed to read this page', 111);
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));
$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) {
foreach ($ins as $in) {
$link = array();
switch($in[0]) {
switch ($in[0]) {
case 'internallink':
$link['type'] = 'local';
$link['page'] = $in[1][0];
$link['href'] = wl($in[1][0]);
array_push($links,$link);
array_push($links, $link);
break;
case 'externallink':
$link['type'] = 'extern';
$link['page'] = $in[1][0];
$link['href'] = $in[1][0];
array_push($links,$link);
array_push($links, $link);
break;
case 'interwikilink':
$url = $Renderer->_resolveInterWiki($in[1][2],$in[1][3]);
$url = $Renderer->_resolveInterWiki($in[1][2], $in[1][3]);
$link['type'] = 'extern';
$link['page'] = $url;
$link['href'] = $url;
array_push($links,$link);
array_push($links, $link);
break;
}
}
@ -699,8 +730,9 @@ class RemoteAPICore {
* @return array
* @throws RemoteException no valid timestamp
*/
public function getRecentChanges($timestamp) {
if(strlen($timestamp) != 10) {
public function getRecentChanges($timestamp)
{
if (strlen($timestamp) != 10) {
throw new RemoteException('The provided value is not a valid timestamp', 311);
}
@ -710,12 +742,12 @@ class RemoteAPICore {
foreach ($recents as $recent) {
$change = array();
$change['name'] = $recent['id'];
$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']));
$change['author'] = $recent['user'];
$change['version'] = $recent['date'];
$change['perms'] = $recent['perms'];
$change['size'] = @filesize(wikiFN($recent['id']));
array_push($changes, $change);
}
@ -737,8 +769,9 @@ class RemoteAPICore {
* @return array
* @throws RemoteException no valid timestamp
*/
public function getRecentMediaChanges($timestamp) {
if(strlen($timestamp) != 10)
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);
@ -747,12 +780,12 @@ class RemoteAPICore {
foreach ($recents as $recent) {
$change = array();
$change['name'] = $recent['id'];
$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']));
$change['author'] = $recent['user'];
$change['version'] = $recent['date'];
$change['perms'] = $recent['perms'];
$change['size'] = @filesize(mediaFN($recent['id']));
array_push($changes, $change);
}
@ -771,25 +804,26 @@ class RemoteAPICore {
*
* @author Michael Klier <chi@chimeric.de>
*
* @param string $id page id
* @param int $first skip the first n changelog lines
* @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 RemoteAccessDeniedException no read access for page
* @throws AccessDeniedException no read access for page
* @throws RemoteException empty id
*/
public function pageVersions($id, $first) {
public function pageVersions($id, $first)
{
$id = $this->resolvePageId($id);
if(auth_quickaclcheck($id) < AUTH_READ) {
throw new RemoteAccessDeniedException('You are not allowed to read this page', 111);
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)) {
if (empty($id)) {
throw new RemoteException('Empty page ID', 131);
}
@ -799,29 +833,29 @@ class RemoteAPICore {
$pagelog = new PageChangeLog($id);
$revisions = $pagelog->getRevisions($first_rev, $conf['recent']);
if($first == 0) {
if ($first == 0) {
array_unshift($revisions, ''); // include current revision
if ( count($revisions) > $conf['recent'] ){
if (count($revisions) > $conf['recent']) {
array_pop($revisions); // remove extra log entry
}
}
if(!empty($revisions)) {
foreach($revisions as $rev) {
$file = wikiFN($id,$rev);
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){
if ($time) {
$pagelog->setChunkSize(1024);
$info = $pagelog->getRevisionInfo($rev ? $rev : $time);
if(!empty($info)) {
if (!empty($info)) {
$data = array();
$data['user'] = $info['user'];
$data['ip'] = $info['ip'];
$data['ip'] = $info['ip'];
$data['type'] = $info['type'];
$data['sum'] = $info['sum'];
$data['sum'] = $info['sum'];
$data['modified'] = $this->api->toDate($info['date']);
$data['version'] = $info['date'];
array_push($versions, $data);
@ -837,11 +871,11 @@ class RemoteAPICore {
/**
* The version of Wiki RPC API supported
*/
public function wiki_RPCVersion(){
public function wikiRpcVersion()
{
return 2;
}
/**
* Locks or unlocks a given batch of pages
*
@ -854,35 +888,36 @@ class RemoteAPICore {
* @param array[] $set list pages with array('lock' => array, 'unlock' => array)
* @return array
*/
public function setLocks($set){
$locked = array();
$lockfail = array();
$unlocked = array();
public function setLocks($set)
{
$locked = array();
$lockfail = array();
$unlocked = array();
$unlockfail = array();
foreach((array) $set['lock'] as $id){
foreach ((array) $set['lock'] as $id) {
$id = $this->resolvePageId($id);
if(auth_quickaclcheck($id) < AUTH_EDIT || checklock($id)){
if (auth_quickaclcheck($id) < AUTH_EDIT || checklock($id)) {
$lockfail[] = $id;
}else{
} else {
lock($id);
$locked[] = $id;
}
}
foreach((array) $set['unlock'] as $id){
foreach ((array) $set['unlock'] as $id) {
$id = $this->resolvePageId($id);
if(auth_quickaclcheck($id) < AUTH_EDIT || !unlock($id)){
if (auth_quickaclcheck($id) < AUTH_EDIT || !unlock($id)) {
$unlockfail[] = $id;
}else{
} else {
$unlocked[] = $id;
}
}
return array(
'locked' => $locked,
'lockfail' => $lockfail,
'unlocked' => $unlocked,
'locked' => $locked,
'lockfail' => $lockfail,
'unlocked' => $unlocked,
'unlockfail' => $unlockfail,
);
}
@ -892,8 +927,9 @@ class RemoteAPICore {
*
* @return int
*/
public function getAPIVersion(){
return DOKU_API_VERSION;
public function getAPIVersion()
{
return self::API_VERSION;
}
/**
@ -903,23 +939,24 @@ class RemoteAPICore {
* @param string $pass
* @return int
*/
public function login($user,$pass){
public function login($user, $pass)
{
global $conf;
/** @var DokuWiki_Auth_Plugin $auth */
global $auth;
if(!$conf['useacl']) return 0;
if(!$auth) return 0;
if (!$conf['useacl']) return 0;
if (!$auth) return 0;
@session_start(); // reopen session for login
if($auth->canDo('external')){
$ok = $auth->trustExternal($user,$pass,false);
}else{
if ($auth->canDo('external')) {
$ok = $auth->trustExternal($user, $pass, false);
} else {
$evdata = array(
'user' => $user,
'user' => $user,
'password' => $pass,
'sticky' => false,
'silent' => true,
'sticky' => false,
'silent' => true,
);
$ok = trigger_event('AUTH_LOGIN_CHECK', $evdata, 'auth_login_wrapper');
}
@ -933,11 +970,12 @@ class RemoteAPICore {
*
* @return int
*/
public function logoff(){
public function logoff()
{
global $conf;
global $auth;
if(!$conf['useacl']) return 0;
if(!$auth) return 0;
if (!$conf['useacl']) return 0;
if (!$auth) return 0;
auth_logoff();
@ -950,14 +988,13 @@ class RemoteAPICore {
* @param string $id page id
* @return string
*/
private function resolvePageId($id) {
private function resolvePageId($id)
{
$id = cleanID($id);
if(empty($id)) {
if (empty($id)) {
global $conf;
$id = cleanID($conf['start']);
}
return $id;
}
}

View File

@ -0,0 +1,10 @@
<?php
namespace dokuwiki\Remote;
/**
* Class RemoteException
*/
class RemoteException extends \Exception
{
}

0
inc/deprecated.php Normal file
View File

View File

@ -76,8 +76,6 @@ function load_autoload($name){
'Sitemapper' => DOKU_INC.'inc/Sitemapper.php',
'PassHash' => DOKU_INC.'inc/PassHash.class.php',
'Mailer' => DOKU_INC.'inc/Mailer.class.php',
'RemoteAPI' => DOKU_INC.'inc/remote.php',
'RemoteAPICore' => DOKU_INC.'inc/RemoteAPICore.php',
'Subscription' => DOKU_INC.'inc/subscription.php',
'DokuWiki_PluginInterface' => DOKU_INC.'inc/PluginInterface.php',

View File

@ -1,5 +1,10 @@
<?php
if(!defined('DOKU_INC')) define('DOKU_INC',dirname(__FILE__).'/../../');
use dokuwiki\Remote\AccessDeniedException;
use dokuwiki\Remote\Api;
use dokuwiki\Remote\RemoteException;
if(!defined('DOKU_INC')) define('DOKU_INC', dirname(__FILE__).'/../../');
require_once(DOKU_INC.'inc/init.php');
session_write_close(); //close session
@ -17,7 +22,7 @@ class dokuwiki_xmlrpc_server extends IXR_Server {
* Constructor. Register methods and run Server
*/
public function __construct(){
$this->remote = new RemoteAPI();
$this->remote = new Api();
$this->remote->setDateTransformation(array($this, 'toDate'));
$this->remote->setFileTransformation(array($this, 'toFile'));
parent::__construct();
@ -32,7 +37,7 @@ class dokuwiki_xmlrpc_server extends IXR_Server {
try {
$result = $this->remote->call($methodname, $args);
return $result;
} catch (RemoteAccessDeniedException $e) {
} catch (AccessDeniedException $e) {
if (!isset($_SERVER['REMOTE_USER'])) {
http_status(401);
return new IXR_Error(-32603, "server error. not authorized to call method $methodname");

View File

@ -1,5 +1,7 @@
<?php
use dokuwiki\Remote\AccessDeniedException;
/**
* Class remote_plugin_acl
*/
@ -8,7 +10,7 @@ class remote_plugin_acl extends DokuWiki_Remote_Plugin {
/**
* Returns details about the remote plugin methods
*
* @return array Information about all provided methods. {@see RemoteAPI}
* @return array Information about all provided methods. {@see dokuwiki\Remote\RemoteAPI}
*/
public function _getMethods() {
return array(
@ -34,12 +36,12 @@ class remote_plugin_acl extends DokuWiki_Remote_Plugin {
/**
* List all ACL config entries
*
* @throws RemoteAccessDeniedException
* @throws AccessDeniedException
* @return dictionary {Scope: ACL}, where ACL = dictionnary {user/group: permissions_int}
*/
public function listAcls(){
if(!auth_isadmin()) {
throw new RemoteAccessDeniedException(
throw new AccessDeniedException(
'You are not allowed to access ACLs, superuser permission is required',
114
);
@ -56,12 +58,12 @@ class remote_plugin_acl extends DokuWiki_Remote_Plugin {
* @param string $scope
* @param string $user
* @param int $level see also inc/auth.php
* @throws RemoteAccessDeniedException
* @throws AccessDeniedException
* @return bool
*/
public function addAcl($scope, $user, $level){
if(!auth_isadmin()) {
throw new RemoteAccessDeniedException(
throw new AccessDeniedException(
'You are not allowed to access ACLs, superuser permission is required',
114
);
@ -77,12 +79,12 @@ class remote_plugin_acl extends DokuWiki_Remote_Plugin {
*
* @param string $scope
* @param string $user
* @throws RemoteAccessDeniedException
* @throws AccessDeniedException
* @return bool
*/
public function delAcl($scope, $user){
if(!auth_isadmin()) {
throw new RemoteAccessDeniedException(
throw new AccessDeniedException(
'You are not allowed to access ACLs, superuser permission is required',
114
);

View File

@ -1,5 +1,7 @@
<?php
use dokuwiki\Remote\Api;
/**
* Class DokuWiki_Remote_Plugin
*/
@ -11,7 +13,7 @@ abstract class DokuWiki_Remote_Plugin extends DokuWiki_Plugin {
* Constructor
*/
public function __construct() {
$this->api = new RemoteAPI();
$this->api = new Api();
}
/**
@ -20,7 +22,7 @@ abstract class DokuWiki_Remote_Plugin extends DokuWiki_Plugin {
* By default it exports all public methods of a remote plugin. Methods beginning
* with an underscore are skipped.
*
* @return array Information about all provided methods. {@see RemoteAPI}.
* @return array Information about all provided methods. {@see dokuwiki\Remote\RemoteAPI}.
* @throws ReflectionException
*/
public function _getMethods() {
@ -96,7 +98,7 @@ abstract class DokuWiki_Remote_Plugin extends DokuWiki_Plugin {
}
/**
* @return RemoteAPI
* @return Api
*/
protected function getApi() {
return $this->api;