Failed Conditions
Push — betterDraftHandling ( 0aabe6 )
by Michael
09:36 queued 05:50
created

Ajax::call_lock()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 26
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

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