PageRenderTime 43ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/exe/ajax.php

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