Completed
Push — syntaxtableclasses ( 0c4c02...2e0ebe )
by Andreas
05:40
created

RemoteAPICore::logoff()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 3
nop 0
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Increased whenever the API is changed
5
 */
6
define('DOKU_API_VERSION', 9);
7
8
class RemoteAPICore {
9
10
    private $api;
11
12
    public function __construct(RemoteAPI $api) {
13
        $this->api = $api;
14
    }
15
16
    /**
17
     * Returns details about the core methods
18
     *
19
     * @return array
20
     */
21
    function __getRemoteInfo() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
22
        return array(
23
            'dokuwiki.getVersion' => array(
24
                'args' => array(),
25
                'return' => 'string',
26
                'doc' => 'Returns the running DokuWiki version.'
27
            ), 'dokuwiki.login' => array(
28
                'args' => array('string', 'string'),
29
                'return' => 'int',
30
                'doc' => 'Tries to login with the given credentials and sets auth cookies.',
31
                'public' => '1'
32
            ), 'dokuwiki.logoff' => array(
33
                'args' => array(),
34
                'return' => 'int',
35
                'doc' => 'Tries to logoff by expiring auth cookies and the associated PHP session.'
36
            ), 'dokuwiki.getPagelist' => array(
37
                'args' => array('string', 'array'),
38
                'return' => 'array',
39
                'doc' => 'List all pages within the given namespace.',
40
                'name' => 'readNamespace'
41
            ), 'dokuwiki.search' => array(
42
                'args' => array('string'),
43
                'return' => 'array',
44
                'doc' => 'Perform a fulltext search and return a list of matching pages'
45
            ), 'dokuwiki.getTime' => array(
46
                'args' => array(),
47
                'return' => 'int',
48
                'doc' =>  'Returns the current time at the remote wiki server as Unix timestamp.',
49
            ), 'dokuwiki.setLocks' => array(
50
                'args' => array('array'),
51
                'return' => 'array',
52
                'doc' => 'Lock or unlock pages.'
53
            ), 'dokuwiki.getTitle' => array(
54
                'args' => array(),
55
                'return' => 'string',
56
                'doc' => 'Returns the wiki title.',
57
                'public' => '1'
58
            ), 'dokuwiki.appendPage' => array(
59
                'args' => array('string', 'string', 'array'),
60
                'return' => 'bool',
61
                'doc' => 'Append text to a wiki page.'
62
            ),  'wiki.getPage' => array(
63
                'args' => array('string'),
64
                'return' => 'string',
65
                'doc' => 'Get the raw Wiki text of page, latest version.',
66
                'name' => 'rawPage',
67
            ), 'wiki.getPageVersion' => array(
68
                'args' => array('string', 'int'),
69
                'name' => 'rawPage',
70
                'return' => 'string',
71
                'doc' => 'Return a raw wiki page'
72
            ), 'wiki.getPageHTML' => array(
73
                'args' => array('string'),
74
                'return' => 'string',
75
                'doc' => 'Return page in rendered HTML, latest version.',
76
                'name' => 'htmlPage'
77
            ), 'wiki.getPageHTMLVersion' => array(
78
                'args' => array('string', 'int'),
79
                'return' => 'string',
80
                'doc' => 'Return page in rendered HTML.',
81
                'name' => 'htmlPage'
82
            ), 'wiki.getAllPages' => array(
83
                'args' => array(),
84
                'return' => 'array',
85
                'doc' => 'Returns a list of all pages. The result is an array of utf8 pagenames.',
86
                'name' => 'listPages'
87
            ), 'wiki.getAttachments' => array(
88
                'args' => array('string', 'array'),
89
                'return' => 'array',
90
                'doc' => 'Returns a list of all media files.',
91
                'name' => 'listAttachments'
92
            ), 'wiki.getBackLinks' => array(
93
                'args' => array('string'),
94
                'return' => 'array',
95
                'doc' => 'Returns the pages that link to this page.',
96
                'name' => 'listBackLinks'
97
            ), 'wiki.getPageInfo' => array(
98
                'args' => array('string'),
99
                'return' => 'array',
100
                'doc' => 'Returns a struct with info about the page.',
101
                'name' => 'pageInfo'
102
            ), 'wiki.getPageInfoVersion' => array(
103
                'args' => array('string', 'int'),
104
                'return' => 'array',
105
                'doc' => 'Returns a struct with info about the page.',
106
                'name' => 'pageInfo'
107
            ), 'wiki.getPageVersions' => array(
108
                'args' => array('string', 'int'),
109
                'return' => 'array',
110
                'doc' => 'Returns the available revisions of the page.',
111
                'name' => 'pageVersions'
112
            ), 'wiki.putPage' => array(
113
                'args' => array('string', 'string', 'array'),
114
                'return' => 'bool',
115
                'doc' => 'Saves a wiki page.'
116
            ), 'wiki.listLinks' => array(
117
                'args' => array('string'),
118
                'return' => 'array',
119
                'doc' => 'Lists all links contained in a wiki page.'
120
            ), 'wiki.getRecentChanges' => array(
121
                'args' => array('int'),
122
                'return' => 'array',
123
                'Returns a struct about all recent changes since given timestamp.'
124
            ), 'wiki.getRecentMediaChanges' => array(
125
                'args' => array('int'),
126
                'return' => 'array',
127
                'Returns a struct about all recent media changes since given timestamp.'
128
            ), 'wiki.aclCheck' => array(
129
                'args' => array('string'),
130
                'return' => 'int',
131
                'doc' => 'Returns the permissions of a given wiki page.'
132
            ), 'wiki.putAttachment' => array(
133
                'args' => array('string', 'file', 'array'),
134
                'return' => 'array',
135
                'doc' => 'Upload a file to the wiki.'
136
            ), 'wiki.deleteAttachment' => array(
137
                'args' => array('string'),
138
                'return' => 'int',
139
                'doc' => 'Delete a file from the wiki.'
140
            ), 'wiki.getAttachment' => array(
141
                'args' => array('string'),
142
                'doc' => 'Return a media file',
143
                'return' => 'file',
144
                'name' => 'getAttachment',
145
            ), 'wiki.getAttachmentInfo' => array(
146
                'args' => array('string'),
147
                'return' => 'array',
148
                'doc' => 'Returns a struct with info about the attachment.'
149
            ), 'dokuwiki.getXMLRPCAPIVersion' => array(
150
                'args' => array(),
151
                'name' => 'getAPIVersion',
152
                'return' => 'int',
153
                'doc' => 'Returns the XMLRPC API version.',
154
                'public' => '1',
155
            ), 'wiki.getRPCVersionSupported' => array(
156
                'args' => array(),
157
                'name' => 'wiki_RPCVersion',
158
                'return' => 'int',
159
                'doc' => 'Returns 2 with the supported RPC API version.',
160
                'public' => '1'
161
            ),
162
163
        );
164
    }
165
166
    /**
167
     * @return string
168
     */
169
    function getVersion() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
170
        return getVersion();
171
    }
172
173
    /**
174
     * @return int unix timestamp
175
     */
176
    function getTime() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
177
        return time();
178
    }
179
180
    /**
181
     * Return a raw wiki page
182
     *
183
     * @param string $id wiki page id
184
     * @param int|string $rev revision timestamp of the page or empty string
185
     * @return string page text.
186
     * @throws RemoteAccessDeniedException if no permission for page
187
     */
188
    function rawPage($id,$rev=''){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
189
        $id = $this->resolvePageId($id);
190
        if(auth_quickaclcheck($id) < AUTH_READ){
191
            throw new RemoteAccessDeniedException('You are not allowed to read this file', 111);
192
        }
193
        $text = rawWiki($id,$rev);
194
        if(!$text) {
195
            return pageTemplate($id);
196
        } else {
197
            return $text;
198
        }
199
    }
200
201
    /**
202
     * Return a media file
203
     *
204
     * @author Gina Haeussge <[email protected]>
205
     *
206
     * @param string $id file id
207
     * @return mixed media file
208
     * @throws RemoteAccessDeniedException no permission for media
209
     * @throws RemoteException not exist
210
     */
211
    function getAttachment($id){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
212
        $id = cleanID($id);
213
        if (auth_quickaclcheck(getNS($id).':*') < AUTH_READ) {
214
            throw new RemoteAccessDeniedException('You are not allowed to read this file', 211);
215
        }
216
217
        $file = mediaFN($id);
218
        if (!@ file_exists($file)) {
219
            throw new RemoteException('The requested file does not exist', 221);
220
        }
221
222
        $data = io_readFile($file, false);
223
        return $this->api->toFile($data);
224
    }
225
226
    /**
227
     * Return info about a media file
228
     *
229
     * @author Gina Haeussge <[email protected]>
230
     *
231
     * @param string $id page id
232
     * @return array
233
     */
234
    function getAttachmentInfo($id){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
235
        $id = cleanID($id);
236
        $info = array(
237
            'lastModified' => $this->api->toDate(0),
238
            'size' => 0,
239
        );
240
241
        $file = mediaFN($id);
242
        if ((auth_quickaclcheck(getNS($id).':*') >= AUTH_READ) && file_exists($file)){
243
            $info['lastModified'] = $this->api->toDate(filemtime($file));
244
            $info['size'] = filesize($file);
245
        }
246
247
        return $info;
248
    }
249
250
    /**
251
     * Return a wiki page rendered to html
252
     *
253
     * @param string     $id  page id
254
     * @param string|int $rev revision timestamp or empty string
255
     * @return null|string html
256
     * @throws RemoteAccessDeniedException no access to page
257
     */
258
    function htmlPage($id,$rev=''){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
259
        $id = $this->resolvePageId($id);
260
        if(auth_quickaclcheck($id) < AUTH_READ){
261
            throw new RemoteAccessDeniedException('You are not allowed to read this page', 111);
262
        }
263
        return p_wiki_xhtml($id,$rev,false);
264
    }
265
266
    /**
267
     * List all pages - we use the indexer list here
268
     *
269
     * @return array
270
     */
271
    function listPages(){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
272
        $list  = array();
273
        $pages = idx_get_indexer()->getPages();
274
        $pages = array_filter(array_filter($pages,'isVisiblePage'),'page_exists');
275
276
        foreach(array_keys($pages) as $idx) {
277
            $perm = auth_quickaclcheck($pages[$idx]);
278
            if($perm < AUTH_READ) {
279
                continue;
280
            }
281
            $page = array();
282
            $page['id'] = trim($pages[$idx]);
283
            $page['perms'] = $perm;
284
            $page['size'] = @filesize(wikiFN($pages[$idx]));
285
            $page['lastModified'] = $this->api->toDate(@filemtime(wikiFN($pages[$idx])));
286
            $list[] = $page;
287
        }
288
289
        return $list;
290
    }
291
292
    /**
293
     * List all pages in the given namespace (and below)
294
     *
295
     * @param string $ns
296
     * @param array  $opts
297
     *    $opts['depth']   recursion level, 0 for all
298
     *    $opts['hash']    do md5 sum of content?
299
     * @return array
300
     */
301
    function readNamespace($ns,$opts){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
302
        global $conf;
303
304
        if(!is_array($opts)) $opts=array();
305
306
        $ns = cleanID($ns);
307
        $dir = utf8_encodeFN(str_replace(':', '/', $ns));
308
        $data = array();
309
        $opts['skipacl'] = 0; // no ACL skipping for XMLRPC
310
        search($data, $conf['datadir'], 'search_allpages', $opts, $dir);
311
        return $data;
312
    }
313
314
    /**
315
     * List all pages in the given namespace (and below)
316
     *
317
     * @param string $query
318
     * @return array
319
     */
320
    function search($query){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
321
        $regex = array();
322
        $data  = ft_pageSearch($query,$regex);
323
        $pages = array();
324
325
        // prepare additional data
326
        $idx = 0;
327
        foreach($data as $id => $score){
328
            $file = wikiFN($id);
329
330
            if($idx < FT_SNIPPET_NUMBER){
331
                $snippet = ft_snippet($id,$regex);
332
                $idx++;
333
            }else{
334
                $snippet = '';
335
            }
336
337
            $pages[] = array(
338
                'id'      => $id,
339
                'score'   => intval($score),
340
                'rev'     => filemtime($file),
341
                'mtime'   => filemtime($file),
342
                'size'    => filesize($file),
343
                'snippet' => $snippet,
344
                'title' => useHeading('navigation') ? p_get_first_heading($id) : $id
345
            );
346
        }
347
        return $pages;
348
    }
349
350
    /**
351
     * Returns the wiki title.
352
     *
353
     * @return string
354
     */
355
    function getTitle(){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
356
        global $conf;
357
        return $conf['title'];
358
    }
359
360
    /**
361
     * List all media files.
362
     *
363
     * Available options are 'recursive' for also including the subnamespaces
364
     * in the listing, and 'pattern' for filtering the returned files against
365
     * a regular expression matching their name.
366
     *
367
     * @author Gina Haeussge <[email protected]>
368
     *
369
     * @param string $ns
370
     * @param array  $options
371
     *   $options['depth']     recursion level, 0 for all
372
     *   $options['showmsg']   shows message if invalid media id is used
373
     *   $options['pattern']   check given pattern
374
     *   $options['hash']      add hashes to result list
375
     * @return array
376
     * @throws RemoteAccessDeniedException no access to the media files
377
     */
378
    function listAttachments($ns, $options = array()) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
379
        global $conf;
380
381
        $ns = cleanID($ns);
382
383
        if (!is_array($options)) $options = array();
384
        $options['skipacl'] = 0; // no ACL skipping for XMLRPC
385
386
        if(auth_quickaclcheck($ns.':*') >= AUTH_READ) {
387
            $dir = utf8_encodeFN(str_replace(':', '/', $ns));
388
389
            $data = array();
390
            search($data, $conf['mediadir'], 'search_media', $options, $dir);
391
            $len = count($data);
392
            if(!$len) return array();
393
394
            for($i=0; $i<$len; $i++) {
395
                unset($data[$i]['meta']);
396
                $data[$i]['perms'] = $data[$i]['perm'];
397
                unset($data[$i]['perm']);
398
                $data[$i]['lastModified'] = $this->api->toDate($data[$i]['mtime']);
399
            }
400
            return $data;
401
        } else {
402
            throw new RemoteAccessDeniedException('You are not allowed to list media files.', 215);
403
        }
404
    }
405
406
    /**
407
     * Return a list of backlinks
408
     *
409
     * @param string $id page id
410
     * @return array
411
     */
412
    function listBackLinks($id){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
413
        return ft_backlinks($this->resolvePageId($id));
414
    }
415
416
    /**
417
     * Return some basic data about a page
418
     *
419
     * @param string     $id page id
420
     * @param string|int $rev revision timestamp or empty string
421
     * @return array
422
     * @throws RemoteAccessDeniedException no access for page
423
     * @throws RemoteException page not exist
424
     */
425
    function pageInfo($id,$rev=''){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
426
        $id = $this->resolvePageId($id);
427
        if(auth_quickaclcheck($id) < AUTH_READ){
428
            throw new RemoteAccessDeniedException('You are not allowed to read this page', 111);
429
        }
430
        $file = wikiFN($id,$rev);
431
        $time = @filemtime($file);
432
        if(!$time){
433
            throw new RemoteException('The requested page does not exist', 121);
434
        }
435
436
        $pagelog = new PageChangeLog($id, 1024);
437
        $info = $pagelog->getRevisionInfo($time);
438
439
        $data = array(
440
            'name'         => $id,
441
            'lastModified' => $this->api->toDate($time),
442
            'author'       => (($info['user']) ? $info['user'] : $info['ip']),
443
            'version'      => $time
444
        );
445
446
        return ($data);
447
    }
448
449
    /**
450
     * Save a wiki page
451
     *
452
     * @author Michael Klier <[email protected]>
453
     *
454
     * @param string $id page id
455
     * @param string $text wiki text
456
     * @param array $params parameters: summary, minor edit
457
     * @return bool
458
     * @throws RemoteAccessDeniedException no write access for page
459
     * @throws RemoteException no id, empty new page or locked
460
     */
461
    function putPage($id, $text, $params) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
462
        global $TEXT;
463
        global $lang;
464
465
        $id    = $this->resolvePageId($id);
466
        $TEXT  = cleanText($text);
467
        $sum   = $params['sum'];
468
        $minor = $params['minor'];
469
470
        if(empty($id)) {
471
            throw new RemoteException('Empty page ID', 131);
472
        }
473
474
        if(!page_exists($id) && trim($TEXT) == '' ) {
475
            throw new RemoteException('Refusing to write an empty new wiki page', 132);
476
        }
477
478
        if(auth_quickaclcheck($id) < AUTH_EDIT) {
479
            throw new RemoteAccessDeniedException('You are not allowed to edit this page', 112);
480
        }
481
482
        // Check, if page is locked
483
        if(checklock($id)) {
484
            throw new RemoteException('The page is currently locked', 133);
485
        }
486
487
        // SPAM check
488
        if(checkwordblock()) {
489
            throw new RemoteException('Positive wordblock check', 134);
490
        }
491
492
        // autoset summary on new pages
493
        if(!page_exists($id) && empty($sum)) {
494
            $sum = $lang['created'];
495
        }
496
497
        // autoset summary on deleted pages
498
        if(page_exists($id) && empty($TEXT) && empty($sum)) {
499
            $sum = $lang['deleted'];
500
        }
501
502
        lock($id);
503
504
        saveWikiText($id,$TEXT,$sum,$minor);
505
506
        unlock($id);
507
508
        // run the indexer if page wasn't indexed yet
509
        idx_addPage($id);
510
511
        return true;
512
    }
513
514
    /**
515
     * Appends text to a wiki page.
516
     *
517
     * @param string $id page id
518
     * @param string $text wiki text
519
     * @param array $params such as summary,minor
520
     * @return bool|string
521
     */
522
    function appendPage($id, $text, $params) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
523
        $currentpage = $this->rawPage($id);
524
        if (!is_string($currentpage)) {
525
            return $currentpage;
526
        }
527
        return $this->putPage($id, $currentpage.$text, $params);
528
    }
529
530
    /**
531
     * Uploads a file to the wiki.
532
     *
533
     * Michael Klier <[email protected]>
534
     *
535
     * @param string $id page id
536
     * @param string $file
537
     * @param array $params such as overwrite
538
     * @return false|string
539
     * @throws RemoteException
540
     */
541
    function putAttachment($id, $file, $params) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
542
        $id = cleanID($id);
543
        $auth = auth_quickaclcheck(getNS($id).':*');
544
545
        if(!isset($id)) {
546
            throw new RemoteException('Filename not given.', 231);
547
        }
548
549
        global $conf;
550
551
        $ftmp = $conf['tmpdir'] . '/' . md5($id.clientIP());
552
553
        // save temporary file
554
        @unlink($ftmp);
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
555
        io_saveFile($ftmp, $file);
556
557
        $res = media_save(array('name' => $ftmp), $id, $params['ow'], $auth, 'rename');
558
        if (is_array($res)) {
559
            throw new RemoteException($res[0], -$res[1]);
560
        } else {
561
            return $res;
562
        }
563
    }
564
565
    /**
566
     * Deletes a file from the wiki.
567
     *
568
     * @author Gina Haeussge <[email protected]>
569
     *
570
     * @param string $id page id
571
     * @return int
572
     * @throws RemoteAccessDeniedException no permissions
573
     * @throws RemoteException file in use or not deleted
574
     */
575
    function deleteAttachment($id){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
576
        $id = cleanID($id);
577
        $auth = auth_quickaclcheck(getNS($id).':*');
578
        $res = media_delete($id, $auth);
579
        if ($res & DOKU_MEDIA_DELETED) {
580
            return 0;
581
        } elseif ($res & DOKU_MEDIA_NOT_AUTH) {
582
            throw new RemoteAccessDeniedException('You don\'t have permissions to delete files.', 212);
583
        } elseif ($res & DOKU_MEDIA_INUSE) {
584
            throw new RemoteException('File is still referenced', 232);
585
        } else {
586
            throw new RemoteException('Could not delete file', 233);
587
        }
588
    }
589
590
    /**
591
     * Returns the permissions of a given wiki page
592
     *
593
     * @param string $id page id
594
     * @return int permission level
595
     */
596
    function aclCheck($id) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
597
        $id = $this->resolvePageId($id);
598
        return auth_quickaclcheck($id);
599
    }
600
601
    /**
602
     * Lists all links contained in a wiki page
603
     *
604
     * @author Michael Klier <[email protected]>
605
     *
606
     * @param string $id page id
607
     * @return array
608
     * @throws RemoteAccessDeniedException  no read access for page
609
     */
610
    function listLinks($id) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
611
        $id = $this->resolvePageId($id);
612
        if(auth_quickaclcheck($id) < AUTH_READ){
613
            throw new RemoteAccessDeniedException('You are not allowed to read this page', 111);
614
        }
615
        $links = array();
616
617
        // resolve page instructions
618
        $ins   = p_cached_instructions(wikiFN($id));
619
620
        // instantiate new Renderer - needed for interwiki links
621
        include(DOKU_INC.'inc/parser/xhtml.php');
622
        $Renderer = new Doku_Renderer_xhtml();
623
        $Renderer->interwiki = getInterwiki();
624
625
        // parse parse instructions
626
        foreach($ins as $in) {
0 ignored issues
show
Bug introduced by
The expression $ins of type array|false|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
627
            $link = array();
628
            switch($in[0]) {
629
                case 'internallink':
630
                    $link['type'] = 'local';
631
                    $link['page'] = $in[1][0];
632
                    $link['href'] = wl($in[1][0]);
633
                    array_push($links,$link);
634
                    break;
635
                case 'externallink':
636
                    $link['type'] = 'extern';
637
                    $link['page'] = $in[1][0];
638
                    $link['href'] = $in[1][0];
639
                    array_push($links,$link);
640
                    break;
641
                case 'interwikilink':
642
                    $url = $Renderer->_resolveInterWiki($in[1][2],$in[1][3]);
643
                    $link['type'] = 'extern';
644
                    $link['page'] = $url;
645
                    $link['href'] = $url;
646
                    array_push($links,$link);
647
                    break;
648
            }
649
        }
650
651
        return ($links);
652
    }
653
654
    /**
655
     * Returns a list of recent changes since give timestamp
656
     *
657
     * @author Michael Hamann <[email protected]>
658
     * @author Michael Klier <[email protected]>
659
     *
660
     * @param int $timestamp unix timestamp
661
     * @return array
662
     * @throws RemoteException no valid timestamp
663
     */
664
    function getRecentChanges($timestamp) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
665
        if(strlen($timestamp) != 10) {
666
            throw new RemoteException('The provided value is not a valid timestamp', 311);
667
        }
668
669
        $recents = getRecentsSince($timestamp);
670
671
        $changes = array();
672
673
        foreach ($recents as $recent) {
674
            $change = array();
675
            $change['name']         = $recent['id'];
676
            $change['lastModified'] = $this->api->toDate($recent['date']);
677
            $change['author']       = $recent['user'];
678
            $change['version']      = $recent['date'];
679
            $change['perms']        = $recent['perms'];
680
            $change['size']         = @filesize(wikiFN($recent['id']));
681
            array_push($changes, $change);
682
        }
683
684
        if (!empty($changes)) {
685
            return $changes;
686
        } else {
687
            // in case we still have nothing at this point
688
            throw new RemoteException('There are no changes in the specified timeframe', 321);
689
        }
690
    }
691
692
    /**
693
     * Returns a list of recent media changes since give timestamp
694
     *
695
     * @author Michael Hamann <[email protected]>
696
     * @author Michael Klier <[email protected]>
697
     *
698
     * @param int $timestamp unix timestamp
699
     * @return array
700
     * @throws RemoteException no valid timestamp
701
     */
702
    function getRecentMediaChanges($timestamp) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
703
        if(strlen($timestamp) != 10)
704
            throw new RemoteException('The provided value is not a valid timestamp', 311);
705
706
        $recents = getRecentsSince($timestamp, null, '', RECENTS_MEDIA_CHANGES);
707
708
        $changes = array();
709
710
        foreach ($recents as $recent) {
711
            $change = array();
712
            $change['name']         = $recent['id'];
713
            $change['lastModified'] = $this->api->toDate($recent['date']);
714
            $change['author']       = $recent['user'];
715
            $change['version']      = $recent['date'];
716
            $change['perms']        = $recent['perms'];
717
            $change['size']         = @filesize(mediaFN($recent['id']));
718
            array_push($changes, $change);
719
        }
720
721
        if (!empty($changes)) {
722
            return $changes;
723
        } else {
724
            // in case we still have nothing at this point
725
            throw new RemoteException('There are no changes in the specified timeframe', 321);
726
        }
727
    }
728
729
    /**
730
     * Returns a list of available revisions of a given wiki page
731
     *
732
     * @author Michael Klier <[email protected]>
733
     *
734
     * @param string $id    page id
735
     * @param int    $first skip the first n changelog lines
736
     * @return array
737
     * @throws RemoteAccessDeniedException no read access for page
738
     * @throws RemoteException empty id
739
     */
740
    function pageVersions($id, $first) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
741
        $id = $this->resolvePageId($id);
742
        if(auth_quickaclcheck($id) < AUTH_READ) {
743
            throw new RemoteAccessDeniedException('You are not allowed to read this page', 111);
744
        }
745
        global $conf;
746
747
        $versions = array();
748
749
        if(empty($id)) {
750
            throw new RemoteException('Empty page ID', 131);
751
        }
752
753
        $pagelog = new PageChangeLog($id);
754
        $revisions = $pagelog->getRevisions($first, $conf['recent']+1);
755
756
        if(count($revisions)==0 && $first!=0) {
757
            $first=0;
758
            $revisions = $pagelog->getRevisions($first, $conf['recent']+1);
759
        }
760
761
        if(count($revisions)>0 && $first==0) {
762
            array_unshift($revisions, '');  // include current revision
763
            if ( count($revisions) > $conf['recent'] ){
764
                array_pop($revisions);          // remove extra log entry
765
            }
766
        }
767
768
        if(count($revisions) > $conf['recent']) {
769
            array_pop($revisions); // remove extra log entry
770
        }
771
772
        if(!empty($revisions)) {
773
            foreach($revisions as $rev) {
774
                $file = wikiFN($id,$rev);
775
                $time = @filemtime($file);
776
                // we check if the page actually exists, if this is not the
777
                // case this can lead to less pages being returned than
778
                // specified via $conf['recent']
779
                if($time){
780
                    $pagelog->setChunkSize(1024);
781
                    $info = $pagelog->getRevisionInfo($time);
782
                    if(!empty($info)) {
783
                        $data = array();
784
                        $data['user'] = $info['user'];
785
                        $data['ip']   = $info['ip'];
786
                        $data['type'] = $info['type'];
787
                        $data['sum']  = $info['sum'];
788
                        $data['modified'] = $this->api->toDate($info['date']);
789
                        $data['version'] = $info['date'];
790
                        array_push($versions, $data);
791
                    }
792
                }
793
            }
794
            return $versions;
795
        } else {
796
            return array();
797
        }
798
    }
799
800
    /**
801
     * The version of Wiki RPC API supported
802
     */
803
    function wiki_RPCVersion(){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
804
        return 2;
805
    }
806
807
808
    /**
809
     * Locks or unlocks a given batch of pages
810
     *
811
     * Give an associative array with two keys: lock and unlock. Both should contain a
812
     * list of pages to lock or unlock
813
     *
814
     * Returns an associative array with the keys locked, lockfail, unlocked and
815
     * unlockfail, each containing lists of pages.
816
     *
817
     * @param array[] $set list pages with array('lock' => array, 'unlock' => array)
818
     * @return array
819
     */
820
    function setLocks($set){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
821
        $locked     = array();
822
        $lockfail   = array();
823
        $unlocked   = array();
824
        $unlockfail = array();
825
826
        foreach((array) $set['lock'] as $id){
827
            $id = $this->resolvePageId($id);
828
            if(auth_quickaclcheck($id) < AUTH_EDIT || checklock($id)){
829
                $lockfail[] = $id;
830
            }else{
831
                lock($id);
832
                $locked[] = $id;
833
            }
834
        }
835
836
        foreach((array) $set['unlock'] as $id){
837
            $id = $this->resolvePageId($id);
838
            if(auth_quickaclcheck($id) < AUTH_EDIT || !unlock($id)){
839
                $unlockfail[] = $id;
840
            }else{
841
                $unlocked[] = $id;
842
            }
843
        }
844
845
        return array(
846
            'locked'     => $locked,
847
            'lockfail'   => $lockfail,
848
            'unlocked'   => $unlocked,
849
            'unlockfail' => $unlockfail,
850
        );
851
    }
852
853
    /**
854
     * Return API version
855
     *
856
     * @return int
857
     */
858
    function getAPIVersion(){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
859
        return DOKU_API_VERSION;
860
    }
861
862
    /**
863
     * Login
864
     *
865
     * @param string $user
866
     * @param string $pass
867
     * @return int
868
     */
869
    function login($user,$pass){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
870
        global $conf;
871
        /** @var DokuWiki_Auth_Plugin $auth */
872
        global $auth;
873
874
        if(!$conf['useacl']) return 0;
875
        if(!$auth) return 0;
876
877
        @session_start(); // reopen session for login
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
878
        if($auth->canDo('external')){
879
            $ok = $auth->trustExternal($user,$pass,false);
880
        }else{
881
            $evdata = array(
882
                'user'     => $user,
883
                'password' => $pass,
884
                'sticky'   => false,
885
                'silent'   => true,
886
            );
887
            $ok = trigger_event('AUTH_LOGIN_CHECK', $evdata, 'auth_login_wrapper');
888
        }
889
        session_write_close(); // we're done with the session
890
891
        return $ok;
892
    }
893
894
    /**
895
     * Log off
896
     *
897
     * @return int
898
     */
899
    function logoff(){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
900
        global $conf;
901
        global $auth;
902
        if(!$conf['useacl']) return 0;
903
        if(!$auth) return 0;
904
        
905
        auth_logoff();
906
907
        return 1;
908
    }
909
910
    /**
911
     * Resolve page id
912
     *
913
     * @param string $id page id
914
     * @return string
915
     */
916
    private function resolvePageId($id) {
917
        $id = cleanID($id);
918
        if(empty($id)) {
919
            global $conf;
920
            $id = cleanID($conf['start']);
921
        }
922
        return $id;
923
    }
924
925
}
926
927