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