Completed
Push — actionrefactor ( 549a9e...0f9e19 )
by Andreas
04:26
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->post->has('call')){
18
    $call = $INPUT->post->str('call');
19
}else if($INPUT->get->has('call')){
20
    $call = $INPUT->get->str('call');
21
}else{
22
    exit;
23
}
24
$callfn = 'ajax_'.$call;
25
26
if(function_exists($callfn)){
27
    $callfn();
28
}else{
29
    $evt = new Doku_Event('AJAX_CALL_UNKNOWN', $call);
30
    if ($evt->advise_before()) {
31
        print "AJAX call '".htmlspecialchars($call)."' unknown!\n";
32
        exit;
33
    }
34
    $evt->advise_after();
35
    unset($evt);
36
}
37
38
/**
39
 * Searches for matching pagenames
40
 *
41
 * @author Andreas Gohr <[email protected]>
42
 */
43
function ajax_qsearch(){
44
    global $lang;
45
    global $INPUT;
46
47
    $maxnumbersuggestions = 50;
48
49
    $query = $INPUT->post->str('q');
50
    if(empty($query)) $query = $INPUT->get->str('q');
51
    if(empty($query)) return;
52
53
    $query = urldecode($query);
54
55
    $data = ft_pageLookup($query, true, useHeading('navigation'));
56
57
    if(!count($data)) return;
58
59
    print '<strong>'.$lang['quickhits'].'</strong>';
60
    print '<ul>';
61
    $counter = 0;
62
    foreach($data as $id => $title){
63
        if (useHeading('navigation')) {
64
            $name = $title;
65
        } else {
66
            $ns = getNS($id);
67
            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...
68
                $name = noNS($id).' ('.$ns.')';
69
            }else{
70
                $name = $id;
71
            }
72
        }
73
        echo '<li>' . html_wikilink(':'.$id,$name) . '</li>';
74
75
        $counter ++;
76
        if($counter > $maxnumbersuggestions) {
77
            echo '<li>...</li>';
78
            break;
79
        }
80
    }
81
    print '</ul>';
82
}
83
84
/**
85
 * Support OpenSearch suggestions
86
 *
87
 * @link   http://www.opensearch.org/Specifications/OpenSearch/Extensions/Suggestions/1.0
88
 * @author Mike Frysinger <[email protected]>
89
 */
90
function ajax_suggestions() {
91
    global $INPUT;
92
93
    $query = cleanID($INPUT->post->str('q'));
94
    if(empty($query)) $query = cleanID($INPUT->get->str('q'));
95
    if(empty($query)) return;
96
97
    $data = ft_pageLookup($query);
98
    if(!count($data)) return;
99
    $data = array_keys($data);
100
101
    // limit results to 15 hits
102
    $data = array_slice($data, 0, 15);
103
    $data = array_map('trim',$data);
104
    $data = array_map('noNS',$data);
105
    $data = array_unique($data);
106
    sort($data);
107
108
    /* now construct a json */
109
    $suggestions = array(
110
                        $query,  // the original query
111
                        $data,   // some suggestions
112
                        array(), // no description
113
                        array()  // no urls
114
                   );
115
    $json = new JSON();
116
117
    header('Content-Type: application/x-suggestions+json');
118
    print $json->encode($suggestions);
119
}
120
121
/**
122
 * Refresh a page lock and save draft
123
 *
124
 * Andreas Gohr <[email protected]>
125
 */
126
function ajax_lock(){
127
    global $lang;
128
    global $ID;
129
    global $INFO;
130
    global $INPUT;
131
132
    $ID = cleanID($INPUT->post->str('id'));
133
    if($ID === '') return;
134
    $INFO = pageinfo();
135
    if(isset($INFO['draft'])) unset($INFO['draft']);
136
137
    // the preview action does locking and draft saving for us
138
    try {
139
        $preview = new \dokuwiki\Action\Preview();
140
        $preview->checkPermissions();
141
        $preview->preProcess();
142
    } catch(\dokuwiki\Action\Exception\ActionException $e) {
143
        echo $e->getMessage();
144
        return;
145
    }
146
147
    if(!checklock($ID)){
148
        lock($ID);
149
        echo 1;
150
    }
151
152
    if(isset($INFO['draft'])) {
153
        echo $lang['draftdate'].' '.dformat();
154
    }
155
}
156
157
/**
158
 * Delete a draft
159
 *
160
 * @author Andreas Gohr <[email protected]>
161
 */
162
function ajax_draftdel(){
163
    global $INPUT;
164
    $id = cleanID($INPUT->str('id'));
165
    if(empty($id)) return;
166
167
    $client = $_SERVER['REMOTE_USER'];
168
    if(!$client) $client = clientIP(true);
169
170
    $cname = getCacheName($client.$id,'.draft');
171
    @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...
172
}
173
174
/**
175
 * Return subnamespaces for the Mediamanager
176
 *
177
 * @author Andreas Gohr <[email protected]>
178
 */
179
function ajax_medians(){
180
    global $conf;
181
    global $INPUT;
182
183
    // wanted namespace
184
    $ns  = cleanID($INPUT->post->str('ns'));
185
    $dir  = utf8_encodeFN(str_replace(':','/',$ns));
186
187
    $lvl = count(explode(':',$ns));
188
189
    $data = array();
190
    search($data,$conf['mediadir'],'search_index',array('nofiles' => true),$dir);
191
    foreach(array_keys($data) as $item){
192
        $data[$item]['level'] = $lvl+1;
193
    }
194
    echo html_buildlist($data, 'idx', 'media_nstree_item', 'media_nstree_li');
195
}
196
197
/**
198
 * Return list of files for the Mediamanager
199
 *
200
 * @author Andreas Gohr <[email protected]>
201
 */
202
function ajax_medialist(){
203
    global $NS;
204
    global $INPUT;
205
206
    $NS = cleanID($INPUT->post->str('ns'));
207
    $sort = $INPUT->post->bool('recent') ? 'date' : 'natural';
208
    if ($INPUT->post->str('do') == 'media') {
209
        tpl_mediaFileList();
210
    } else {
211
        tpl_mediaContent(true, $sort);
212
    }
213
}
214
215
/**
216
 * Return the content of the right column
217
 * (image details) for the Mediamanager
218
 *
219
 * @author Kate Arzamastseva <[email protected]>
220
 */
221
function ajax_mediadetails(){
222
    global $IMG, $JUMPTO, $REV, $fullscreen, $INPUT;
223
    $fullscreen = true;
224
    require_once(DOKU_INC.'lib/exe/mediamanager.php');
225
226
    $image = '';
227
    if ($INPUT->has('image')) $image = cleanID($INPUT->str('image'));
228
    if (isset($IMG)) $image = $IMG;
229
    if (isset($JUMPTO)) $image = $JUMPTO;
230
    $rev = false;
231
    if (isset($REV) && !$JUMPTO) $rev = $REV;
232
233
    html_msgarea();
234
    tpl_mediaFileDetails($image, $rev);
235
}
236
237
/**
238
 * Returns image diff representation for mediamanager
239
 * @author Kate Arzamastseva <[email protected]>
240
 */
241
function ajax_mediadiff(){
242
    global $NS;
243
    global $INPUT;
244
245
    $image = '';
246
    if ($INPUT->has('image')) $image = cleanID($INPUT->str('image'));
247
    $NS = getNS($image);
248
    $auth = auth_quickaclcheck("$NS:*");
249
    media_diff($image, $NS, $auth, true);
0 ignored issues
show
Security Bug introduced by
It seems like $NS defined by getNS($image) on line 247 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...
250
}
251
252
function ajax_mediaupload(){
253
    global $NS, $MSG, $INPUT;
254
255
    $id = '';
256
    if ($_FILES['qqfile']['tmp_name']) {
257
        $id = $INPUT->post->str('mediaid', $_FILES['qqfile']['name']);
258
    } elseif ($INPUT->get->has('qqfile')) {
259
        $id = $INPUT->get->str('qqfile');
260
    }
261
262
    $id = cleanID($id);
263
264
    $NS = $INPUT->str('ns');
265
    $ns = $NS.':'.getNS($id);
266
267
    $AUTH = auth_quickaclcheck("$ns:*");
268
    if($AUTH >= AUTH_UPLOAD) { io_createNamespace("$ns:xxx", 'media'); }
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
function ajax_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
function ajax_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($data,array(
391
                        'id'   => getNS($ns),
392
                        'type' => 'u',
393
                        ));
394
        }
395
    }
396
397
    // fixme sort results in a useful way ?
398
399
    if(!count($data)){
400
        echo $lang['nothingfound'];
401
        exit;
402
    }
403
404
    // output the found data
405
    $even = 1;
406
    foreach($data as $item){
407
        $even *= -1; //zebra
408
409
        if(($item['type'] == 'd' || $item['type'] == 'u') && $item['id']) $item['id'] .= ':';
410
        $link = wl($item['id']);
411
412
        echo '<div class="'.(($even > 0)?'even':'odd').' type_'.$item['type'].'">';
413
414
        if($item['type'] == 'u'){
415
            $name = $lang['upperns'];
416
        }else{
417
            $name = htmlspecialchars($item['id']);
418
        }
419
420
        echo '<a href="'.$link.'" title="'.htmlspecialchars($item['id']).'" class="wikilink1">'.$name.'</a>';
421
422
        if(!blank($item['title'])){
423
            echo '<span>'.htmlspecialchars($item['title']).'</span>';
424
        }
425
        echo '</div>';
426
    }
427
428
}
429
430
//Setup VIM: ex: et ts=2 :
431