translation update
[dokuwiki.git] / inc / remote.php
blob2ef28afd2765e018f56c51e9e98fcb7efe990063
1 <?php
3 if (!defined('DOKU_INC')) die();
5 class RemoteException extends Exception {}
6 class RemoteAccessDeniedException extends RemoteException {}
8 /**
9 * This class provides information about remote access to the wiki.
11 * == Types of methods ==
12 * There are two types of remote methods. The first is the core methods.
13 * These are always available and provided by dokuwiki.
14 * The other is plugin methods. These are provided by remote plugins.
16 * == Information structure ==
17 * The information about methods will be given in an array with the following structure:
18 * array(
19 * 'method.remoteName' => array(
20 * 'args' => array(
21 * 'type eg. string|int|...|date|file',
22 * )
23 * 'name' => 'method name in class',
24 * 'return' => 'type',
25 * 'public' => 1/0 - method bypass default group check (used by login)
26 * ['doc' = 'method documentation'],
27 * )
28 * )
30 * plugin names are formed the following:
31 * core methods begin by a 'dokuwiki' or 'wiki' followed by a . and the method name itself.
32 * i.e.: dokuwiki.version or wiki.getPage
34 * plugin methods are formed like 'plugin.<plugin name>.<method name>'.
35 * i.e.: plugin.clock.getTime or plugin.clock_gmt.getTime
37 * @throws RemoteException
39 class RemoteAPI {
41 /**
42 * @var RemoteAPICore
44 private $coreMethods = null;
46 /**
47 * @var array remote methods provided by dokuwiki plugins - will be filled lazy via
48 * {@see RemoteAPI#getPluginMethods}
50 private $pluginMethods = null;
52 /**
53 * @var array contains custom calls to the api. Plugins can use the XML_CALL_REGISTER event.
54 * The data inside is 'custom.call.something' => array('plugin name', 'remote method name')
56 * The remote method name is the same as in the remote name returned by _getMethods().
58 private $pluginCustomCalls = null;
60 private $dateTransformation;
61 private $fileTransformation;
63 public function __construct() {
64 $this->dateTransformation = array($this, 'dummyTransformation');
65 $this->fileTransformation = array($this, 'dummyTransformation');
68 /**
69 * Get all available methods with remote access.
71 * @return array with information to all available methods
73 public function getMethods() {
74 return array_merge($this->getCoreMethods(), $this->getPluginMethods());
77 /**
78 * call a method via remote api.
80 * @param string $method name of the method to call.
81 * @param array $args arguments to pass to the given method
82 * @return mixed result of method call, must be a primitive type.
84 public function call($method, $args = array()) {
85 if ($args === null) {
86 $args = array();
88 list($type, $pluginName, $call) = explode('.', $method, 3);
89 if ($type === 'plugin') {
90 return $this->callPlugin($pluginName, $method, $args);
92 if ($this->coreMethodExist($method)) {
93 return $this->callCoreMethod($method, $args);
95 return $this->callCustomCallPlugin($method, $args);
98 private function coreMethodExist($name) {
99 $coreMethods = $this->getCoreMethods();
100 return array_key_exists($name, $coreMethods);
103 private function callCustomCallPlugin($method, $args) {
104 $customCalls = $this->getCustomCallPlugins();
105 if (!array_key_exists($method, $customCalls)) {
106 throw new RemoteException('Method does not exist', -32603);
108 $customCall = $customCalls[$method];
109 return $this->callPlugin($customCall[0], $customCall[1], $args);
112 private function getCustomCallPlugins() {
113 if ($this->pluginCustomCalls === null) {
114 $data = array();
115 trigger_event('RPC_CALL_ADD', $data);
116 $this->pluginCustomCalls = $data;
118 return $this->pluginCustomCalls;
121 private function callPlugin($pluginName, $method, $args) {
122 $plugin = plugin_load('remote', $pluginName);
123 $methods = $this->getPluginMethods();
124 if (!$plugin) {
125 throw new RemoteException('Method does not exist', -32603);
127 $this->checkAccess($methods[$method]);
128 $name = $this->getMethodName($methods, $method);
129 return call_user_func_array(array($plugin, $name), $args);
132 private function callCoreMethod($method, $args) {
133 $coreMethods = $this->getCoreMethods();
134 $this->checkAccess($coreMethods[$method]);
135 if (!isset($coreMethods[$method])) {
136 throw new RemoteException('Method does not exist', -32603);
138 $this->checkArgumentLength($coreMethods[$method], $args);
139 return call_user_func_array(array($this->coreMethods, $this->getMethodName($coreMethods, $method)), $args);
142 private function checkAccess($methodMeta) {
143 if (!isset($methodMeta['public'])) {
144 $this->forceAccess();
145 } else{
146 if ($methodMeta['public'] == '0') {
147 $this->forceAccess();
152 private function checkArgumentLength($method, $args) {
153 if (count($method['args']) < count($args)) {
154 throw new RemoteException('Method does not exist - wrong parameter count.', -32603);
158 private function getMethodName($methodMeta, $method) {
159 if (isset($methodMeta[$method]['name'])) {
160 return $methodMeta[$method]['name'];
162 $method = explode('.', $method);
163 return $method[count($method)-1];
167 * @return bool true if the current user has access to remote api.
169 public function hasAccess() {
170 global $conf;
171 global $USERINFO;
172 if (!$conf['remote']) {
173 return false;
175 if(!$conf['useacl']) {
176 return true;
178 if(trim($conf['remoteuser']) == '') {
179 return true;
182 return auth_isMember($conf['remoteuser'], $_SERVER['REMOTE_USER'], (array) $USERINFO['grps']);
186 * @throws RemoteException On denied access.
187 * @return void
189 public function forceAccess() {
190 if (!$this->hasAccess()) {
191 throw new RemoteAccessDeniedException('server error. not authorized to call method', -32604);
196 * @return array all plugin methods.
198 public function getPluginMethods() {
199 if ($this->pluginMethods === null) {
200 $this->pluginMethods = array();
201 $plugins = plugin_list('remote');
203 foreach ($plugins as $pluginName) {
204 $plugin = plugin_load('remote', $pluginName);
205 if (!is_subclass_of($plugin, 'DokuWiki_Remote_Plugin')) {
206 throw new RemoteException("Plugin $pluginName does not implement DokuWiki_Remote_Plugin");
209 $methods = $plugin->_getMethods();
210 foreach ($methods as $method => $meta) {
211 $this->pluginMethods["plugin.$pluginName.$method"] = $meta;
215 return $this->pluginMethods;
219 * @param RemoteAPICore $apiCore this parameter is used for testing. Here you can pass a non-default RemoteAPICore
220 * instance. (for mocking)
221 * @return array all core methods.
223 public function getCoreMethods($apiCore = null) {
224 if ($this->coreMethods === null) {
225 if ($apiCore === null) {
226 $this->coreMethods = new RemoteAPICore($this);
227 } else {
228 $this->coreMethods = $apiCore;
231 return $this->coreMethods->__getRemoteInfo();
234 public function toFile($data) {
235 return call_user_func($this->fileTransformation, $data);
238 public function toDate($data) {
239 return call_user_func($this->dateTransformation, $data);
242 public function dummyTransformation($data) {
243 return $data;
246 public function setDateTransformation($dateTransformation) {
247 $this->dateTransformation = $dateTransformation;
250 public function setFileTransformation($fileTransformation) {
251 $this->fileTransformation = $fileTransformation;