Completed
Pull Request — master (#2413)
by Michael
17:27 queued 12:53
created

Ajax::call_lock()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 27
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 17
nc 6
nop 0
dl 0
loc 27
rs 8.439
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 (saveDraft()) {
144
            echo $lang['draftdate'] . ' ' . dformat();
145
        }
146
147
    }
148
149
    /**
150
     * Delete a draft
151
     *
152
     * @author Andreas Gohr <[email protected]>
153
     */
154
    protected function call_draftdel() {
155
        global $INPUT;
156
        $id = cleanID($INPUT->str('id'));
157
        if(empty($id)) return;
158
159
        $client = $_SERVER['REMOTE_USER'];
160
        if(!$client) $client = clientIP(true);
161
162
        $cname = getCacheName($client . $id, '.draft');
163
        @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...
164
    }
165
166
    /**
167
     * Return subnamespaces for the Mediamanager
168
     *
169
     * @author Andreas Gohr <[email protected]>
170
     */
171
    protected function call_medians() {
172
        global $conf;
173
        global $INPUT;
174
175
        // wanted namespace
176
        $ns = cleanID($INPUT->post->str('ns'));
177
        $dir = utf8_encodeFN(str_replace(':', '/', $ns));
178
179
        $lvl = count(explode(':', $ns));
180
181
        $data = array();
182
        search($data, $conf['mediadir'], 'search_index', array('nofiles' => true), $dir);
183
        foreach(array_keys($data) as $item) {
184
            $data[$item]['level'] = $lvl + 1;
185
        }
186
        echo html_buildlist($data, 'idx', 'media_nstree_item', 'media_nstree_li');
187
    }
188
189
    /**
190
     * Return list of files for the Mediamanager
191
     *
192
     * @author Andreas Gohr <[email protected]>
193
     */
194
    protected function call_medialist() {
195
        global $NS;
196
        global $INPUT;
197
198
        $NS = cleanID($INPUT->post->str('ns'));
199
        $sort = $INPUT->post->bool('recent') ? 'date' : 'natural';
200
        if($INPUT->post->str('do') == 'media') {
201
            tpl_mediaFileList();
202
        } else {
203
            tpl_mediaContent(true, $sort);
204
        }
205
    }
206
207
    /**
208
     * Return the content of the right column
209
     * (image details) for the Mediamanager
210
     *
211
     * @author Kate Arzamastseva <[email protected]>
212
     */
213
    protected function call_mediadetails() {
214
        global $IMG, $JUMPTO, $REV, $fullscreen, $INPUT;
215
        $fullscreen = true;
216
        require_once(DOKU_INC . 'lib/exe/mediamanager.php');
217
218
        $image = '';
219
        if($INPUT->has('image')) $image = cleanID($INPUT->str('image'));
220
        if(isset($IMG)) $image = $IMG;
221
        if(isset($JUMPTO)) $image = $JUMPTO;
222
        $rev = false;
223
        if(isset($REV) && !$JUMPTO) $rev = $REV;
224
225
        html_msgarea();
226
        tpl_mediaFileDetails($image, $rev);
227
    }
228
229
    /**
230
     * Returns image diff representation for mediamanager
231
     *
232
     * @author Kate Arzamastseva <[email protected]>
233
     */
234
    protected function call_mediadiff() {
235
        global $NS;
236
        global $INPUT;
237
238
        $image = '';
239
        if($INPUT->has('image')) $image = cleanID($INPUT->str('image'));
240
        $NS = getNS($image);
241
        $auth = auth_quickaclcheck("$NS:*");
242
        media_diff($image, $NS, $auth, true);
0 ignored issues
show
Security Bug introduced by
It seems like $NS defined by getNS($image) on line 240 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...
243
    }
244
245
    /**
246
     * Manages file uploads
247
     *
248
     * @author Kate Arzamastseva <[email protected]>
249
     */
250
    protected function call_mediaupload() {
251
        global $NS, $MSG, $INPUT;
252
253
        $id = '';
254
        if($_FILES['qqfile']['tmp_name']) {
255
            $id = $INPUT->post->str('mediaid', $_FILES['qqfile']['name']);
256
        } elseif($INPUT->get->has('qqfile')) {
257
            $id = $INPUT->get->str('qqfile');
258
        }
259
260
        $id = cleanID($id);
261
262
        $NS = $INPUT->str('ns');
263
        $ns = $NS . ':' . getNS($id);
264
265
        $AUTH = auth_quickaclcheck("$ns:*");
266
        if($AUTH >= AUTH_UPLOAD) {
267
            io_createNamespace("$ns:xxx", 'media');
268
        }
269
270
        if($_FILES['qqfile']['error']) unset($_FILES['qqfile']);
271
272
        $res = false;
273
        if($_FILES['qqfile']['tmp_name']) $res = media_upload($NS, $AUTH, $_FILES['qqfile']);
274
        if($INPUT->get->has('qqfile')) $res = media_upload_xhr($NS, $AUTH);
275
276
        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...
277
            $result = array(
278
                'success' => true,
279
                'link' => media_managerURL(array('ns' => $ns, 'image' => $NS . ':' . $id), '&'),
280
                'id' => $NS . ':' . $id,
281
                'ns' => $NS
282
            );
283
        } else {
284
            $error = '';
285
            if(isset($MSG)) {
286
                foreach($MSG as $msg) {
287
                    $error .= $msg['msg'];
288
                }
289
            }
290
            $result = array(
291
                'error' => $error,
292
                'ns' => $NS
293
            );
294
        }
295
        $json = new \JSON;
296
        header('Content-Type: application/json');
297
        echo $json->encode($result);
298
    }
299
300
    /**
301
     * Return sub index for index view
302
     *
303
     * @author Andreas Gohr <[email protected]>
304
     */
305
    protected function call_index() {
306
        global $conf;
307
        global $INPUT;
308
309
        // wanted namespace
310
        $ns = cleanID($INPUT->post->str('idx'));
311
        $dir = utf8_encodeFN(str_replace(':', '/', $ns));
312
313
        $lvl = count(explode(':', $ns));
314
315
        $data = array();
316
        search($data, $conf['datadir'], 'search_index', array('ns' => $ns), $dir);
317
        foreach(array_keys($data) as $item) {
318
            $data[$item]['level'] = $lvl + 1;
319
        }
320
        echo html_buildlist($data, 'idx', 'html_list_index', 'html_li_index');
321
    }
322
323
    /**
324
     * List matching namespaces and pages for the link wizard
325
     *
326
     * @author Andreas Gohr <[email protected]>
327
     */
328
    protected function call_linkwiz() {
329
        global $conf;
330
        global $lang;
331
        global $INPUT;
332
333
        $q = ltrim(trim($INPUT->post->str('q')), ':');
334
        $id = noNS($q);
335
        $ns = getNS($q);
336
337
        $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...
338
        $id = cleanID($id);
339
340
        $nsd = utf8_encodeFN(str_replace(':', '/', $ns));
341
342
        $data = array();
343
        if($q && !$ns) {
344
345
            // use index to lookup matching pages
346
            $pages = ft_pageLookup($id, true);
347
348
            // result contains matches in pages and namespaces
349
            // we now extract the matching namespaces to show
350
            // them seperately
351
            $dirs = array();
352
353
            foreach($pages as $pid => $title) {
354
                if(strpos(noNS($pid), $id) === false) {
355
                    // match was in the namespace
356
                    $dirs[getNS($pid)] = 1; // assoc array avoids dupes
357
                } else {
358
                    // it is a matching page, add it to the result
359
                    $data[] = array(
360
                        'id' => $pid,
361
                        'title' => $title,
362
                        'type' => 'f',
363
                    );
364
                }
365
                unset($pages[$pid]);
366
            }
367
            foreach($dirs as $dir => $junk) {
368
                $data[] = array(
369
                    'id' => $dir,
370
                    'type' => 'd',
371
                );
372
            }
373
374
        } else {
375
376
            $opts = array(
377
                'depth' => 1,
378
                'listfiles' => true,
379
                'listdirs' => true,
380
                'pagesonly' => true,
381
                'firsthead' => true,
382
                'sneakyacl' => $conf['sneaky_index'],
383
            );
384
            if($id) $opts['filematch'] = '^.*\/' . $id;
385
            if($id) $opts['dirmatch'] = '^.*\/' . $id;
386
            search($data, $conf['datadir'], 'search_universal', $opts, $nsd);
387
388
            // add back to upper
389
            if($ns) {
390
                array_unshift(
391
                    $data, array(
392
                             'id' => getNS($ns),
393
                             'type' => 'u',
394
                         )
395
                );
396
            }
397
        }
398
399
        // fixme sort results in a useful way ?
400
401
        if(!count($data)) {
402
            echo $lang['nothingfound'];
403
            exit;
404
        }
405
406
        // output the found data
407
        $even = 1;
408
        foreach($data as $item) {
409
            $even *= -1; //zebra
410
411
            if(($item['type'] == 'd' || $item['type'] == 'u') && $item['id']) $item['id'] .= ':';
412
            $link = wl($item['id']);
413
414
            echo '<div class="' . (($even > 0) ? 'even' : 'odd') . ' type_' . $item['type'] . '">';
415
416
            if($item['type'] == 'u') {
417
                $name = $lang['upperns'];
418
            } else {
419
                $name = hsc($item['id']);
420
            }
421
422
            echo '<a href="' . $link . '" title="' . hsc($item['id']) . '" class="wikilink1">' . $name . '</a>';
423
424
            if(!blank($item['title'])) {
425
                echo '<span>' . hsc($item['title']) . '</span>';
426
            }
427
            echo '</div>';
428
        }
429
430
    }
431
432
}
433