Completed
Push — master ( 31110e...2f70e4 )
by Andreas
03:30
created

Ajax::call_lock()   C

Complexity

Conditions 8
Paths 12

Size

Total Lines 41
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 28
nc 12
nop 0
dl 0
loc 41
rs 5.3846
c 0
b 0
f 0
1
<?php
2
3
namespace dokuwiki;
4
5
/**
6
 * Manage all builtin AJAX calls
7
 *
8
 * @todo The calls should be refactored out to their own proper classes
9
 * @package dokuwiki
10
 */
11
class Ajax {
12
13
    /**
14
     * Execute the given call
15
     *
16
     * @param string $call name of the ajax call
17
     */
18
    public function __construct($call) {
19
        $callfn = 'call_' . $call;
20
        if(method_exists($this, $callfn)) {
21
            $this->$callfn();
22
        } else {
23
            $evt = new \Doku_Event('AJAX_CALL_UNKNOWN', $call);
24
            if($evt->advise_before()) {
25
                print "AJAX call '" . hsc($call) . "' unknown!\n";
26
            } else {
27
                $evt->advise_after();
28
                unset($evt);
29
            }
30
        }
31
    }
32
33
    /**
34
     * Searches for matching pagenames
35
     *
36
     * @author Andreas Gohr <[email protected]>
37
     */
38
    protected function call_qsearch() {
39
        global $lang;
40
        global $INPUT;
41
42
        $maxnumbersuggestions = 50;
43
44
        $query = $INPUT->post->str('q');
45
        if(empty($query)) $query = $INPUT->get->str('q');
46
        if(empty($query)) return;
47
48
        $query = urldecode($query);
49
50
        $data = ft_pageLookup($query, true, useHeading('navigation'));
51
52
        if(!count($data)) return;
53
54
        print '<strong>' . $lang['quickhits'] . '</strong>';
55
        print '<ul>';
56
        $counter = 0;
57
        foreach($data as $id => $title) {
58
            if(useHeading('navigation')) {
59
                $name = $title;
60
            } else {
61
                $ns = getNS($id);
62
                if($ns) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $ns of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
63
                    $name = noNS($id) . ' (' . $ns . ')';
64
                } else {
65
                    $name = $id;
66
                }
67
            }
68
            echo '<li>' . html_wikilink(':' . $id, $name) . '</li>';
69
70
            $counter++;
71
            if($counter > $maxnumbersuggestions) {
72
                echo '<li>...</li>';
73
                break;
74
            }
75
        }
76
        print '</ul>';
77
    }
78
79
    /**
80
     * Support OpenSearch suggestions
81
     *
82
     * @link   http://www.opensearch.org/Specifications/OpenSearch/Extensions/Suggestions/1.0
83
     * @author Mike Frysinger <[email protected]>
84
     */
85
    protected function call_suggestions() {
86
        global $INPUT;
87
88
        $query = cleanID($INPUT->post->str('q'));
89
        if(empty($query)) $query = cleanID($INPUT->get->str('q'));
90
        if(empty($query)) return;
91
92
        $data = ft_pageLookup($query);
93
        if(!count($data)) return;
94
        $data = array_keys($data);
95
96
        // limit results to 15 hits
97
        $data = array_slice($data, 0, 15);
98
        $data = array_map('trim', $data);
99
        $data = array_map('noNS', $data);
100
        $data = array_unique($data);
101
        sort($data);
102
103
        /* now construct a json */
104
        $suggestions = array(
105
            $query,  // the original query
106
            $data,   // some suggestions
107
            array(), // no description
108
            array()  // no urls
109
        );
110
        $json = new \JSON();
111
112
        header('Content-Type: application/x-suggestions+json');
113
        print $json->encode($suggestions);
114
    }
115
116
    /**
117
     * Refresh a page lock and save draft
118
     *
119
     * Andreas Gohr <[email protected]>
120
     */
121
    protected function call_lock() {
122
        global $conf;
123
        global $lang;
124
        global $ID;
125
        global $INFO;
126
        global $INPUT;
127
128
        $ID = cleanID($INPUT->post->str('id'));
129
        if(empty($ID)) return;
130
131
        $INFO = pageinfo();
132
133
        if(!$INFO['writable']) {
134
            echo 'Permission denied';
135
            return;
136
        }
137
138
        if(!checklock($ID)) {
139
            lock($ID);
140
            echo 1;
141
        }
142
143
        if($conf['usedraft'] && $INPUT->post->str('wikitext')) {
144
            $client = $_SERVER['REMOTE_USER'];
145
            if(!$client) $client = clientIP(true);
146
147
            $draft = array(
148
                'id' => $ID,
149
                'prefix' => substr($INPUT->post->str('prefix'), 0, -1),
150
                'text' => $INPUT->post->str('wikitext'),
151
                'suffix' => $INPUT->post->str('suffix'),
152
                'date' => $INPUT->post->int('date'),
153
                'client' => $client,
154
            );
155
            $cname = getCacheName($draft['client'] . $ID, '.draft');
156
            if(io_saveFile($cname, serialize($draft))) {
157
                echo $lang['draftdate'] . ' ' . dformat();
158
            }
159
        }
160
161
    }
162
163
    /**
164
     * Delete a draft
165
     *
166
     * @author Andreas Gohr <[email protected]>
167
     */
168
    protected function call_draftdel() {
169
        global $INPUT;
170
        $id = cleanID($INPUT->str('id'));
171
        if(empty($id)) return;
172
173
        $client = $_SERVER['REMOTE_USER'];
174
        if(!$client) $client = clientIP(true);
175
176
        $cname = getCacheName($client . $id, '.draft');
177
        @unlink($cname);
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...
178
    }
179
180
    /**
181
     * Return subnamespaces for the Mediamanager
182
     *
183
     * @author Andreas Gohr <[email protected]>
184
     */
185
    protected function call_medians() {
186
        global $conf;
187
        global $INPUT;
188
189
        // wanted namespace
190
        $ns = cleanID($INPUT->post->str('ns'));
191
        $dir = utf8_encodeFN(str_replace(':', '/', $ns));
192
193
        $lvl = count(explode(':', $ns));
194
195
        $data = array();
196
        search($data, $conf['mediadir'], 'search_index', array('nofiles' => true), $dir);
197
        foreach(array_keys($data) as $item) {
198
            $data[$item]['level'] = $lvl + 1;
199
        }
200
        echo html_buildlist($data, 'idx', 'media_nstree_item', 'media_nstree_li');
201
    }
202
203
    /**
204
     * Return list of files for the Mediamanager
205
     *
206
     * @author Andreas Gohr <[email protected]>
207
     */
208
    protected function call_medialist() {
209
        global $NS;
210
        global $INPUT;
211
212
        $NS = cleanID($INPUT->post->str('ns'));
213
        $sort = $INPUT->post->bool('recent') ? 'date' : 'natural';
214
        if($INPUT->post->str('do') == 'media') {
215
            tpl_mediaFileList();
216
        } else {
217
            tpl_mediaContent(true, $sort);
218
        }
219
    }
220
221
    /**
222
     * Return the content of the right column
223
     * (image details) for the Mediamanager
224
     *
225
     * @author Kate Arzamastseva <[email protected]>
226
     */
227
    protected function call_mediadetails() {
228
        global $IMG, $JUMPTO, $REV, $fullscreen, $INPUT;
229
        $fullscreen = true;
230
        require_once(DOKU_INC . 'lib/exe/mediamanager.php');
231
232
        $image = '';
233
        if($INPUT->has('image')) $image = cleanID($INPUT->str('image'));
234
        if(isset($IMG)) $image = $IMG;
235
        if(isset($JUMPTO)) $image = $JUMPTO;
236
        $rev = false;
237
        if(isset($REV) && !$JUMPTO) $rev = $REV;
238
239
        html_msgarea();
240
        tpl_mediaFileDetails($image, $rev);
241
    }
242
243
    /**
244
     * Returns image diff representation for mediamanager
245
     *
246
     * @author Kate Arzamastseva <[email protected]>
247
     */
248
    protected function call_mediadiff() {
249
        global $NS;
250
        global $INPUT;
251
252
        $image = '';
253
        if($INPUT->has('image')) $image = cleanID($INPUT->str('image'));
254
        $NS = getNS($image);
255
        $auth = auth_quickaclcheck("$NS:*");
256
        media_diff($image, $NS, $auth, true);
0 ignored issues
show
Security Bug introduced by
It seems like $NS defined by getNS($image) on line 254 can also be of type false; however, media_diff() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
257
    }
258
259
    /**
260
     * Manages file uploads
261
     *
262
     * @author Kate Arzamastseva <[email protected]>
263
     */
264
    protected function call_mediaupload() {
265
        global $NS, $MSG, $INPUT;
266
267
        $id = '';
268
        if($_FILES['qqfile']['tmp_name']) {
269
            $id = $INPUT->post->str('mediaid', $_FILES['qqfile']['name']);
270
        } elseif($INPUT->get->has('qqfile')) {
271
            $id = $INPUT->get->str('qqfile');
272
        }
273
274
        $id = cleanID($id);
275
276
        $NS = $INPUT->str('ns');
277
        $ns = $NS . ':' . getNS($id);
278
279
        $AUTH = auth_quickaclcheck("$ns:*");
280
        if($AUTH >= AUTH_UPLOAD) {
281
            io_createNamespace("$ns:xxx", 'media');
282
        }
283
284
        if($_FILES['qqfile']['error']) unset($_FILES['qqfile']);
285
286
        $res = false;
287
        if($_FILES['qqfile']['tmp_name']) $res = media_upload($NS, $AUTH, $_FILES['qqfile']);
288
        if($INPUT->get->has('qqfile')) $res = media_upload_xhr($NS, $AUTH);
289
290
        if($res) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $res of type false|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
291
            $result = array(
292
                'success' => true,
293
                'link' => media_managerURL(array('ns' => $ns, 'image' => $NS . ':' . $id), '&'),
294
                'id' => $NS . ':' . $id,
295
                'ns' => $NS
296
            );
297
        } else {
298
            $error = '';
299
            if(isset($MSG)) {
300
                foreach($MSG as $msg) {
301
                    $error .= $msg['msg'];
302
                }
303
            }
304
            $result = array(
305
                'error' => $error,
306
                'ns' => $NS
307
            );
308
        }
309
        $json = new \JSON;
310
        header('Content-Type: application/json');
311
        echo $json->encode($result);
312
    }
313
314
    /**
315
     * Return sub index for index view
316
     *
317
     * @author Andreas Gohr <[email protected]>
318
     */
319
    protected function call_index() {
320
        global $conf;
321
        global $INPUT;
322
323
        // wanted namespace
324
        $ns = cleanID($INPUT->post->str('idx'));
325
        $dir = utf8_encodeFN(str_replace(':', '/', $ns));
326
327
        $lvl = count(explode(':', $ns));
328
329
        $data = array();
330
        search($data, $conf['datadir'], 'search_index', array('ns' => $ns), $dir);
331
        foreach(array_keys($data) as $item) {
332
            $data[$item]['level'] = $lvl + 1;
333
        }
334
        echo html_buildlist($data, 'idx', 'html_list_index', 'html_li_index');
335
    }
336
337
    /**
338
     * List matching namespaces and pages for the link wizard
339
     *
340
     * @author Andreas Gohr <[email protected]>
341
     */
342
    protected function call_linkwiz() {
343
        global $conf;
344
        global $lang;
345
        global $INPUT;
346
347
        $q = ltrim(trim($INPUT->post->str('q')), ':');
348
        $id = noNS($q);
349
        $ns = getNS($q);
350
351
        $ns = cleanID($ns);
0 ignored issues
show
Security Bug introduced by
It seems like $ns can also be of type false; however, cleanID() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
352
        $id = cleanID($id);
353
354
        $nsd = utf8_encodeFN(str_replace(':', '/', $ns));
355
356
        $data = array();
357
        if($q && !$ns) {
358
359
            // use index to lookup matching pages
360
            $pages = ft_pageLookup($id, true);
361
362
            // result contains matches in pages and namespaces
363
            // we now extract the matching namespaces to show
364
            // them seperately
365
            $dirs = array();
366
367
            foreach($pages as $pid => $title) {
368
                if(strpos(noNS($pid), $id) === false) {
369
                    // match was in the namespace
370
                    $dirs[getNS($pid)] = 1; // assoc array avoids dupes
371
                } else {
372
                    // it is a matching page, add it to the result
373
                    $data[] = array(
374
                        'id' => $pid,
375
                        'title' => $title,
376
                        'type' => 'f',
377
                    );
378
                }
379
                unset($pages[$pid]);
380
            }
381
            foreach($dirs as $dir => $junk) {
382
                $data[] = array(
383
                    'id' => $dir,
384
                    'type' => 'd',
385
                );
386
            }
387
388
        } else {
389
390
            $opts = array(
391
                'depth' => 1,
392
                'listfiles' => true,
393
                'listdirs' => true,
394
                'pagesonly' => true,
395
                'firsthead' => true,
396
                'sneakyacl' => $conf['sneaky_index'],
397
            );
398
            if($id) $opts['filematch'] = '^.*\/' . $id;
399
            if($id) $opts['dirmatch'] = '^.*\/' . $id;
400
            search($data, $conf['datadir'], 'search_universal', $opts, $nsd);
401
402
            // add back to upper
403
            if($ns) {
404
                array_unshift(
405
                    $data, array(
406
                             'id' => getNS($ns),
407
                             'type' => 'u',
408
                         )
409
                );
410
            }
411
        }
412
413
        // fixme sort results in a useful way ?
414
415
        if(!count($data)) {
416
            echo $lang['nothingfound'];
417
            exit;
418
        }
419
420
        // output the found data
421
        $even = 1;
422
        foreach($data as $item) {
423
            $even *= -1; //zebra
424
425
            if(($item['type'] == 'd' || $item['type'] == 'u') && $item['id']) $item['id'] .= ':';
426
            $link = wl($item['id']);
427
428
            echo '<div class="' . (($even > 0) ? 'even' : 'odd') . ' type_' . $item['type'] . '">';
429
430
            if($item['type'] == 'u') {
431
                $name = $lang['upperns'];
432
            } else {
433
                $name = hsc($item['id']);
434
            }
435
436
            echo '<a href="' . $link . '" title="' . hsc($item['id']) . '" class="wikilink1">' . $name . '</a>';
437
438
            if(!blank($item['title'])) {
439
                echo '<span>' . hsc($item['title']) . '</span>';
440
            }
441
            echo '</div>';
442
        }
443
444
    }
445
446
}
447