xref: /dokuwiki/inc/Remote/JsonRpcServer.php (revision cf927d07914d82d58a7663afc5d95be13e10f1a3)
1<?php
2
3namespace dokuwiki\Remote;
4
5/**
6 * Provide the Remote XMLRPC API as a JSON based API
7 */
8class JsonRpcServer
9{
10    protected $remote;
11
12    /**
13     * JsonRpcServer constructor.
14     */
15    public function __construct()
16    {
17        $this->remote = new Api();
18        $this->remote->setFileTransformation([$this, 'toFile']);
19    }
20
21    /**
22     * Serve the request
23     *
24     * @return mixed
25     * @throws RemoteException
26     */
27    public function serve()
28    {
29        global $conf;
30        global $INPUT;
31
32        if (!$conf['remote']) {
33            http_status(404);
34            throw new RemoteException("JSON-RPC server not enabled.", -32605);
35        }
36        if (!empty($conf['remotecors'])) {
37            header('Access-Control-Allow-Origin: ' . $conf['remotecors']);
38        }
39        if ($INPUT->server->str('REQUEST_METHOD') !== 'POST') {
40            http_status(405);
41            header('Allow: POST');
42            throw new RemoteException("JSON-RPC server only accepts POST requests.", -32606);
43        }
44        if ($INPUT->server->str('CONTENT_TYPE') !== 'application/json') {
45            http_status(415);
46            throw new RemoteException("JSON-RPC server only accepts application/json requests.", -32606);
47        }
48
49        $call = $INPUT->server->str('PATH_INFO');
50        $call = trim($call, '/');
51        try {
52            $args = json_decode(file_get_contents('php://input'), true, 512, JSON_THROW_ON_ERROR);
53        } catch (\Exception $e) {
54            $args = [];
55        }
56        if (!is_array($args)) $args = [];
57
58        return $this->call($call, $args);
59    }
60
61    /**
62     * Call an API method
63     *
64     * @param string $methodname
65     * @param array $args
66     * @return mixed
67     * @throws RemoteException
68     */
69    public function call($methodname, $args)
70    {
71        try {
72            $result = $this->remote->call($methodname, $args);
73            return $result;
74        } catch (AccessDeniedException $e) {
75            if (!isset($_SERVER['REMOTE_USER'])) {
76                http_status(401);
77                throw new RemoteException("server error. not authorized to call method $methodname", -32603);
78            } else {
79                http_status(403);
80                throw new RemoteException("server error. forbidden to call the method $methodname", -32604);
81            }
82        } catch (RemoteException $e) {
83            http_status(400);
84            throw $e;
85        }
86    }
87
88    /**
89     * @param string $data
90     * @return string
91     */
92    public function toFile($data)
93    {
94        return base64_encode($data);
95    }
96}
97