Completed
Push — master ( bf6f54...20dc95 )
by Andreas
03:16
created

ajax.php ➔ ajax_lock()   B

Complexity

Conditions 6
Paths 15

Size

Total Lines 30
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 21
nc 15
nop 0
dl 0
loc 30
rs 8.439
c 0
b 0
f 0
1
<?php
2
/**
3
 * DokuWiki AJAX call handler
4
 *
5
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6
 * @author     Andreas Gohr <[email protected]>
7
 */
8
9
if(!defined('DOKU_INC')) define('DOKU_INC',dirname(__FILE__).'/../../');
10
require_once(DOKU_INC.'inc/init.php');
11
//close session
12
session_write_close();
13
14
header('Content-Type: text/html; charset=utf-8');
15
16
//call the requested function
17
if($INPUT->has('call')) {
18
    $call = $INPUT->filter('utf8_stripspecials')->str('call');
19
} else {
20
    exit;
21
}
22
$callfn = 'ajax_'.$call;
23
24
if(function_exists($callfn)){
25
    $callfn();
26
}else{
27
    $evt = new Doku_Event('AJAX_CALL_UNKNOWN', $call);
28
    if ($evt->advise_before()) {
29
        print "AJAX call '".hsc($call)."' unknown!\n";
30
        exit;
31
    }
32
    $evt->advise_after();
33
    unset($evt);
34
}
35
36
/**
37
 * Searches for matching pagenames
38
 *
39
 * @author Andreas Gohr <[email protected]>
40
 */
41
function ajax_qsearch(){
42
    global $lang;
43
    global $INPUT;
44
45
    $maxnumbersuggestions = 50;
46
47
    $query = $INPUT->post->str('q');
48
    if(empty($query)) $query = $INPUT->get->str('q');
49
    if(empty($query)) return;
50
51
    $query = urldecode($query);
52
53
    $data = ft_pageLookup($query, true, useHeading('navigation'));
54
55
    if(!count($data)) return;
56
57
    print '<strong>'.$lang['quickhits'].'</strong>';
58
    print '<ul>';
59
    $counter = 0;
60
    foreach($data as $id => $title){
61
        if (useHeading('navigation')) {
62
            $name = $title;
63
        } else {
64
            $ns = getNS($id);
65
            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...
66
                $name = noNS($id).' ('.$ns.')';
67
            }else{
68
                $name = $id;
69
            }
70
        }
71
        echo '<li>' . html_wikilink(':'.$id,$name) . '</li>';
72
73
        $counter ++;
74
        if($counter > $maxnumbersuggestions) {
75
            echo '<li>...</li>';
76
            break;
77
        }
78
    }
79
    print '</ul>';
80
}
81
82
/**
83
 * Support OpenSearch suggestions
84
 *
85
 * @link   http://www.opensearch.org/Specifications/OpenSearch/Extensions/Suggestions/1.0
86
 * @author Mike Frysinger <[email protected]>
87
 */
88
function ajax_suggestions() {
89
    global $INPUT;
90
91
    $query = cleanID($INPUT->post->str('q'));
92
    if(empty($query)) $query = cleanID($INPUT->get->str('q'));
93
    if(empty($query)) return;
94
95
    $data = ft_pageLookup($query);
96
    if(!count($data)) return;
97
    $data = array_keys($data);
98
99
    // limit results to 15 hits
100
    $data = array_slice($data, 0, 15);
101
    $data = array_map('trim',$data);
102
    $data = array_map('noNS',$data);
103
    $data = array_unique($data);
104
    sort($data);
105
106
    /* now construct a json */
107
    $suggestions = array(
108
                        $query,  // the original query
109
                        $data,   // some suggestions
110
                        array(), // no description
111
                        array()  // no urls
112
                   );
113
    $json = new JSON();
114
115
    header('Content-Type: application/x-suggestions+json');
116
    print $json->encode($suggestions);
117
}
118
119
/**
120
 * Refresh a page lock and save draft
121
 *
122
 * Andreas Gohr <[email protected]>
123
 */
124
function ajax_lock(){
125
    global $lang;
126
    global $ID;
127
    global $INFO;
128
    global $INPUT;
129
130
    $ID = cleanID($INPUT->post->str('id'));
131
    if($ID === '') return;
132
    $INFO = pageinfo();
133
    if(isset($INFO['draft'])) unset($INFO['draft']);
134
135
    // the preview action does locking and draft saving for us
136
    try {
137
        $preview = new \dokuwiki\Action\Preview();
138
        $preview->checkPermissions();
139
        $preview->preProcess();
140
    } catch(\dokuwiki\Action\Exception\ActionException $e) {
141
        echo $e->getMessage();
142
        return;
143
    }
144
145
    if(!checklock($ID)){
146
        lock($ID);
147
        echo 1;
148
    }
149
150
    if(isset($INFO['draft'])) {
151
        echo $lang['draftdate'].' '.dformat();
152
    }
153
}
154
155
/**
156
 * Delete a draft
157
 *
158
 * @author Andreas Gohr <[email protected]>
159
 */
160
function ajax_draftdel(){
161
    global $INPUT;
162
    $id = cleanID($INPUT->str('id'));
163
    if(empty($id)) return;
164
165
    $client = $_SERVER['REMOTE_USER'];
166
    if(!$client) $client = clientIP(true);
167
168
    $cname = getCacheName($client.$id,'.draft');
169
    @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...
170
}
171
172
/**
173
 * Return subnamespaces for the Mediamanager
174
 *
175
 * @author Andreas Gohr <[email protected]>
176
 */
177
function ajax_medians(){
178
    global $conf;
179
    global $INPUT;
180
181
    // wanted namespace
182
    $ns  = cleanID($INPUT->post->str('ns'));
183
    $dir  = utf8_encodeFN(str_replace(':','/',$ns));
184
185
    $lvl = count(explode(':',$ns));
186
187
    $data = array();
188
    search($data,$conf['mediadir'],'search_index',array('nofiles' => true),$dir);
189
    foreach(array_keys($data) as $item){
190
        $data[$item]['level'] = $lvl+1;
191
    }
192
    echo html_buildlist($data, 'idx', 'media_nstree_item', 'media_nstree_li');
193
}
194
195
/**
196
 * Return list of files for the Mediamanager
197
 *
198
 * @author Andreas Gohr <[email protected]>
199
 */
200
function ajax_medialist(){
201
    global $NS;
202
    global $INPUT;
203
204
    $NS = cleanID($INPUT->post->str('ns'));
205
    $sort = $INPUT->post->bool('recent') ? 'date' : 'natural';
206
    if ($INPUT->post->str('do') == 'media') {
207
        tpl_mediaFileList();
208
    } else {
209
        tpl_mediaContent(true, $sort);
210
    }
211
}
212
213
/**
214
 * Return the content of the right column
215
 * (image details) for the Mediamanager
216
 *
217
 * @author Kate Arzamastseva <[email protected]>
218
 */
219
function ajax_mediadetails(){
220
    global $IMG, $JUMPTO, $REV, $fullscreen, $INPUT;
221
    $fullscreen = true;
222
    require_once(DOKU_INC.'lib/exe/mediamanager.php');
223
224
    $image = '';
225
    if ($INPUT->has('image')) $image = cleanID($INPUT->str('image'));
226
    if (isset($IMG)) $image = $IMG;
227
    if (isset($JUMPTO)) $image = $JUMPTO;
228
    $rev = false;
229
    if (isset($REV) && !$JUMPTO) $rev = $REV;
230
231
    html_msgarea();
232
    tpl_mediaFileDetails($image, $rev);
233
}
234
235
/**
236
 * Returns image diff representation for mediamanager
237
 * @author Kate Arzamastseva <[email protected]>
238
 */
239
function ajax_mediadiff(){
240
    global $NS;
241
    global $INPUT;
242
243
    $image = '';
244
    if ($INPUT->has('image')) $image = cleanID($INPUT->str('image'));
245
    $NS = getNS($image);
246
    $auth = auth_quickaclcheck("$NS:*");
247
    media_diff($image, $NS, $auth, true);
0 ignored issues
show
Security Bug introduced by
It seems like $NS defined by getNS($image) on line 245 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...
248
}
249
250
function ajax_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) { io_createNamespace("$ns:xxx", 'media'); }
267
268
    if ($_FILES['qqfile']['error']) unset($_FILES['qqfile']);
269
270
    $res = false;
271
    if ($_FILES['qqfile']['tmp_name']) $res = media_upload($NS, $AUTH, $_FILES['qqfile']);
272
    if ($INPUT->get->has('qqfile')) $res = media_upload_xhr($NS, $AUTH);
273
274
    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...
275
        $result = array(
276
            'success' => true,
277
            'link' => media_managerURL(array('ns' => $ns, 'image' => $NS . ':' . $id), '&'),
278
            'id' => $NS . ':' . $id,
279
            'ns' => $NS
280
        );
281
    } else {
282
        $error = '';
283
        if(isset($MSG)) {
284
            foreach($MSG as $msg) {
285
                $error .= $msg['msg'];
286
            }
287
        }
288
        $result = array(
289
            'error' => $error,
290
            'ns' => $NS
291
        );
292
    }
293
    $json = new JSON;
294
    header('Content-Type: application/json');
295
    echo $json->encode($result);
296
}
297
298
/**
299
 * Return sub index for index view
300
 *
301
 * @author Andreas Gohr <[email protected]>
302
 */
303
function ajax_index(){
304
    global $conf;
305
    global $INPUT;
306
307
    // wanted namespace
308
    $ns  = cleanID($INPUT->post->str('idx'));
309
    $dir  = utf8_encodeFN(str_replace(':','/',$ns));
310
311
    $lvl = count(explode(':',$ns));
312
313
    $data = array();
314
    search($data,$conf['datadir'],'search_index',array('ns' => $ns),$dir);
315
    foreach(array_keys($data) as $item){
316
        $data[$item]['level'] = $lvl+1;
317
    }
318
    echo html_buildlist($data, 'idx', 'html_list_index', 'html_li_index');
319
}
320
321
/**
322
 * List matching namespaces and pages for the link wizard
323
 *
324
 * @author Andreas Gohr <[email protected]>
325
 */
326
function ajax_linkwiz(){
327
    global $conf;
328
    global $lang;
329
    global $INPUT;
330
331
    $q  = ltrim(trim($INPUT->post->str('q')),':');
332
    $id = noNS($q);
333
    $ns = getNS($q);
334
335
    $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...
336
    $id = cleanID($id);
337
338
    $nsd  = utf8_encodeFN(str_replace(':','/',$ns));
339
340
    $data = array();
341
    if($q && !$ns){
342
343
        // use index to lookup matching pages
344
        $pages = ft_pageLookup($id,true);
345
346
        // result contains matches in pages and namespaces
347
        // we now extract the matching namespaces to show
348
        // them seperately
349
        $dirs  = array();
350
351
        foreach($pages as $pid => $title){
352
            if(strpos(noNS($pid),$id) === false){
353
                // match was in the namespace
354
                $dirs[getNS($pid)] = 1; // assoc array avoids dupes
355
            }else{
356
                // it is a matching page, add it to the result
357
                $data[] = array(
358
                        'id'    => $pid,
359
                        'title' => $title,
360
                        'type'  => 'f',
361
                        );
362
            }
363
            unset($pages[$pid]);
364
        }
365
        foreach($dirs as $dir => $junk){
366
            $data[] = array(
367
                    'id'   => $dir,
368
                    'type' => 'd',
369
                    );
370
        }
371
372
    }else{
373
374
        $opts = array(
375
                'depth' => 1,
376
                'listfiles' => true,
377
                'listdirs'  => true,
378
                'pagesonly' => true,
379
                'firsthead' => true,
380
                'sneakyacl' => $conf['sneaky_index'],
381
                );
382
        if($id) $opts['filematch'] = '^.*\/'.$id;
383
        if($id) $opts['dirmatch']  = '^.*\/'.$id;
384
        search($data,$conf['datadir'],'search_universal',$opts,$nsd);
385
386
        // add back to upper
387
        if($ns){
388
            array_unshift($data,array(
389
                        'id'   => getNS($ns),
390
                        'type' => 'u',
391
                        ));
392
        }
393
    }
394
395
    // fixme sort results in a useful way ?
396
397
    if(!count($data)){
398
        echo $lang['nothingfound'];
399
        exit;
400
    }
401
402
    // output the found data
403
    $even = 1;
404
    foreach($data as $item){
405
        $even *= -1; //zebra
406
407
        if(($item['type'] == 'd' || $item['type'] == 'u') && $item['id']) $item['id'] .= ':';
408
        $link = wl($item['id']);
409
410
        echo '<div class="'.(($even > 0)?'even':'odd').' type_'.$item['type'].'">';
411
412
        if($item['type'] == 'u'){
413
            $name = $lang['upperns'];
414
        }else{
415
            $name = hsc($item['id']);
416
        }
417
418
        echo '<a href="'.$link.'" title="'.hsc($item['id']).'" class="wikilink1">'.$name.'</a>';
419
420
        if(!blank($item['title'])){
421
            echo '<span>'.hsc($item['title']).'</span>';
422
        }
423
        echo '</div>';
424
    }
425
426
}
427
428
//Setup VIM: ex: et ts=2 :
429