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