xref: /dokuwiki/inc/actions.php (revision 10bd69fc459dde7a3022736e9a9c39bdb52e81ef)
1<?php
2/**
3 * DokuWiki Actions
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Andreas Gohr <andi@splitbrain.org>
7 */
8
9  if(!defined('DOKU_INC')) define('DOKU_INC',fullpath(dirname(__FILE__).'/../').'/');
10  require_once(DOKU_INC.'inc/template.php');
11
12
13/**
14 * Call the needed action handlers
15 *
16 * @author Andreas Gohr <andi@splitbrain.org>
17 * @triggers ACTION_ACT_PREPROCESS
18 * @triggers ACTION_HEADERS_SEND
19 */
20function act_dispatch(){
21  global $INFO;
22  global $ACT;
23  global $ID;
24  global $QUERY;
25  global $lang;
26  global $conf;
27
28  // give plugins an opportunity to process the action
29  $evt = new Doku_Event('ACTION_ACT_PREPROCESS',$ACT);
30  if ($evt->advise_before()) {
31
32    //sanitize $ACT
33    $ACT = act_clean($ACT);
34
35    //check if searchword was given - else just show
36    $s = cleanID($QUERY);
37    if($ACT == 'search' && empty($s)){
38      $ACT = 'show';
39    }
40
41    //login stuff
42    if(in_array($ACT,array('login','logout'))){
43        $ACT = act_auth($ACT);
44    }
45
46    //check if user is asking to (un)subscribe a page
47    if($ACT == 'subscribe' || $ACT == 'unsubscribe')
48      $ACT = act_subscription($ACT);
49
50    //check permissions
51    $ACT = act_permcheck($ACT);
52
53    //register
54    $nil = array();
55    if($ACT == 'register' && $_POST['save'] && register()){
56      $ACT = 'login';
57    }
58
59    if ($ACT == 'resendpwd' && act_resendpwd()) {
60      $ACT = 'login';
61    }
62
63    //update user profile
64    if (($ACT == 'profile') && updateprofile()) {
65      msg($lang['profchanged'],1);
66      $ACT = 'show';
67    }
68
69    //save
70    if($ACT == 'save'){
71      if(checkSecurityToken()){
72        $ACT = act_save($ACT);
73      }else{
74        $ACT = 'show';
75      }
76    }
77
78    //cancel conflicting edit
79    if($ACT == 'cancel')
80      $ACT = 'show';
81
82    //draft deletion
83    if($ACT == 'draftdel')
84      $ACT = act_draftdel($ACT);
85
86    //draft saving on preview
87    if($ACT == 'preview')
88      $ACT = act_draftsave($ACT);
89
90    //edit
91    if(($ACT == 'edit' || $ACT == 'preview') && $INFO['editable']){
92      $ACT = act_edit($ACT);
93    }else{
94      unlock($ID); //try to unlock
95    }
96
97    //handle export
98    if(substr($ACT,0,7) == 'export_')
99      $ACT = act_export($ACT);
100
101    //display some infos
102    if($ACT == 'check'){
103      check();
104      $ACT = 'show';
105    }
106
107    //handle admin tasks
108    if($ACT == 'admin'){
109      // retrieve admin plugin name from $_REQUEST['page']
110      if (!empty($_REQUEST['page'])) {
111          $pluginlist = plugin_list('admin');
112          if (in_array($_REQUEST['page'], $pluginlist)) {
113            // attempt to load the plugin
114            if ($plugin =& plugin_load('admin',$_REQUEST['page']) !== NULL)
115                $plugin->handle();
116          }
117      }
118    }
119
120    // check permissions again - the action may have changed
121    $ACT = act_permcheck($ACT);
122  }  // end event ACTION_ACT_PREPROCESS default action
123  $evt->advise_after();
124  unset($evt);
125
126
127  //call template FIXME: all needed vars available?
128  $headers[] = 'Content-Type: text/html; charset=utf-8';
129  trigger_event('ACTION_HEADERS_SEND',$headers,'act_sendheaders');
130
131  include(template('main.php'));
132  // output for the commands is now handled in inc/templates.php
133  // in function tpl_content()
134}
135
136function act_sendheaders($headers) {
137  foreach ($headers as $hdr) header($hdr);
138}
139
140/**
141 * Sanitize the action command
142 *
143 * Add all allowed commands here.
144 *
145 * @author Andreas Gohr <andi@splitbrain.org>
146 */
147function act_clean($act){
148  global $lang;
149  global $conf;
150
151  // check if the action was given as array key
152  if(is_array($act)){
153    list($act) = array_keys($act);
154  }
155
156  //remove all bad chars
157  $act = strtolower($act);
158  $act = preg_replace('/[^1-9a-z_]+/','',$act);
159
160  if($act == 'export_html') $act = 'export_xhtml';
161  if($act == 'export_htmlbody') $act = 'export_xhtmlbody';
162
163  // check if action is disabled
164  if(!actionOK($act)){
165    msg('Command disabled: '.htmlspecialchars($act),-1);
166    return 'show';
167  }
168
169  //disable all acl related commands if ACL is disabled
170  if(!$conf['useacl'] && in_array($act,array('login','logout','register','admin',
171                                             'subscribe','unsubscribe','profile',
172                                             'resendpwd',))){
173    msg('Command unavailable: '.htmlspecialchars($act),-1);
174    return 'show';
175  }
176
177  if(!in_array($act,array('login','logout','register','save','cancel','edit','draft',
178                          'preview','search','show','check','index','revisions',
179                          'diff','recent','backlink','admin','subscribe',
180                          'unsubscribe','profile','resendpwd','recover','wordblock',
181                          'draftdel',)) && substr($act,0,7) != 'export_' ) {
182    msg('Command unknown: '.htmlspecialchars($act),-1);
183    return 'show';
184  }
185  return $act;
186}
187
188/**
189 * Run permissionchecks
190 *
191 * @author Andreas Gohr <andi@splitbrain.org>
192 */
193function act_permcheck($act){
194  global $INFO;
195  global $conf;
196
197  if(in_array($act,array('save','preview','edit','recover'))){
198    if($INFO['exists']){
199      if($act == 'edit'){
200        //the edit function will check again and do a source show
201        //when no AUTH_EDIT available
202        $permneed = AUTH_READ;
203      }else{
204        $permneed = AUTH_EDIT;
205      }
206    }else{
207      $permneed = AUTH_CREATE;
208    }
209  }elseif(in_array($act,array('login','search','recent','profile'))){
210    $permneed = AUTH_NONE;
211  }elseif($act == 'register'){
212    $permneed = AUTH_NONE;
213  }elseif($act == 'resendpwd'){
214    $permneed = AUTH_NONE;
215  }elseif($act == 'admin'){
216    if($INFO['ismanager']){
217      // if the manager has the needed permissions for a certain admin
218      // action is checked later
219      $permneed = AUTH_READ;
220    }else{
221      $permneed = AUTH_ADMIN;
222    }
223  }else{
224    $permneed = AUTH_READ;
225  }
226  if($INFO['perm'] >= $permneed) return $act;
227
228  return 'denied';
229}
230
231/**
232 * Handle 'draftdel'
233 *
234 * Deletes the draft for the current page and user
235 */
236function act_draftdel($act){
237  global $INFO;
238  @unlink($INFO['draft']);
239  $INFO['draft'] = null;
240  return 'show';
241}
242
243/**
244 * Saves a draft on preview
245 *
246 * @todo this currently duplicates code from ajax.php :-/
247 */
248function act_draftsave($act){
249  global $INFO;
250  global $ID;
251  global $conf;
252  if($conf['usedraft'] && $_POST['wikitext']){
253    $draft = array('id'     => $ID,
254                   'prefix' => $_POST['prefix'],
255                   'text'   => $_POST['wikitext'],
256                   'suffix' => $_POST['suffix'],
257                   'date'   => $_POST['date'],
258                   'client' => $INFO['client'],
259                  );
260    $cname = getCacheName($draft['client'].$ID,'.draft');
261    if(io_saveFile($cname,serialize($draft))){
262      $INFO['draft'] = $cname;
263    }
264  }
265  return $act;
266}
267
268/**
269 * Handle 'save'
270 *
271 * Checks for spam and conflicts and saves the page.
272 * Does a redirect to show the page afterwards or
273 * returns a new action.
274 *
275 * @author Andreas Gohr <andi@splitbrain.org>
276 */
277function act_save($act){
278  global $ID;
279  global $DATE;
280  global $PRE;
281  global $TEXT;
282  global $SUF;
283  global $SUM;
284
285  //spam check
286  if(checkwordblock())
287    return 'wordblock';
288  //conflict check //FIXME use INFO
289  if($DATE != 0 && @filemtime(wikiFN($ID)) > $DATE )
290    return 'conflict';
291
292  //save it
293  saveWikiText($ID,con($PRE,$TEXT,$SUF,1),$SUM,$_REQUEST['minor']); //use pretty mode for con
294  //unlock it
295  unlock($ID);
296
297  //delete draft
298  act_draftdel($act);
299
300  //show it
301  session_write_close();
302  header("Location: ".wl($ID,'',true));
303  exit();
304}
305
306/**
307 * Handle 'login', 'logout'
308 *
309 * @author Andreas Gohr <andi@splitbrain.org>
310 */
311function act_auth($act){
312  global $ID;
313  global $INFO;
314
315  //already logged in?
316  if($_SERVER['REMOTE_USER'] && $act=='login'){
317    header("Location: ".wl($ID,'',true));
318    exit;
319  }
320
321  //handle logout
322  if($act=='logout'){
323    $lockedby = checklock($ID); //page still locked?
324    if($lockedby == $_SERVER['REMOTE_USER'])
325      unlock($ID); //try to unlock
326
327    // do the logout stuff
328    auth_logoff();
329
330    // rebuild info array
331    $INFO = pageinfo();
332
333    return 'login';
334  }
335
336  return $act;
337}
338
339/**
340 * Handle 'edit', 'preview'
341 *
342 * @author Andreas Gohr <andi@splitbrain.org>
343 */
344function act_edit($act){
345  global $ID;
346  global $INFO;
347
348  //check if locked by anyone - if not lock for my self
349  $lockedby = checklock($ID);
350  if($lockedby) return 'locked';
351
352  lock($ID);
353  return $act;
354}
355
356/**
357 * Handle 'edit', 'preview'
358 *
359 * @author Andreas Gohr <andi@splitbrain.org>
360 */
361function act_export($act){
362  global $ID;
363  global $REV;
364
365  // search engines: never cache exported docs! (Google only currently)
366  header('X-Robots-Tag: noindex');
367
368  // no renderer for this
369  if($act == 'export_raw'){
370    header('Content-Type: text/plain; charset=utf-8');
371    print rawWiki($ID,$REV);
372    exit;
373  }
374
375  // html export #FIXME what about the template's style?
376  if($act == 'export_xhtml'){
377    global $conf;
378    global $lang;
379    header('Content-Type: text/html; charset=utf-8');
380    ptln('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"');
381    ptln(' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">');
382    ptln('<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="'.$conf['lang'].'"');
383    ptln(' lang="'.$conf['lang'].'" dir="'.$lang['direction'].'">');
384    ptln('<head>');
385    ptln('  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />');
386    ptln('  <title>'.$ID.'</title>');
387    tpl_metaheaders();
388    ptln('</head>');
389    ptln('<body>');
390    ptln('<div class="dokuwiki export">');
391    print p_wiki_xhtml($ID,$REV,false);
392    ptln('</div>');
393    ptln('</body>');
394    ptln('</html>');
395    exit;
396  }
397
398  // html body only
399  if($act == 'export_xhtmlbody'){
400    print p_wiki_xhtml($ID,$REV,false);
401    exit;
402  }
403
404  // try to run renderer
405  $mode = substr($act,7);
406  $text = p_cached_output(wikiFN($ID,$REV), $mode);
407  $headers = p_get_metadata($ID,"format $mode");
408  if(!is_null($text)){
409    if(is_array($headers)) foreach($headers as $key => $val){
410        header("$key: $val");
411    }
412    print $text;
413    exit;
414  }
415
416  return 'show';
417}
418
419/**
420 * Handle 'subscribe', 'unsubscribe'
421 *
422 * @author Steven Danz <steven-danz@kc.rr.com>
423 * @todo   localize
424 */
425function act_subscription($act){
426  global $ID;
427  global $INFO;
428  global $lang;
429
430  $file=metaFN($ID,'.mlist');
431  if ($act=='subscribe' && !$INFO['subscribed']){
432    if ($INFO['userinfo']['mail']){
433      if (io_saveFile($file,$_SERVER['REMOTE_USER']."\n",true)) {
434        $INFO['subscribed'] = true;
435        msg(sprintf($lang[$act.'_success'], $INFO['userinfo']['name'], $ID),1);
436      } else {
437        msg(sprintf($lang[$act.'_error'], $INFO['userinfo']['name'], $ID),1);
438      }
439    } else {
440      msg($lang['subscribe_noaddress']);
441    }
442  } elseif ($act=='unsubscribe' && $INFO['subscribed']){
443    if (io_deleteFromFile($file,$_SERVER['REMOTE_USER']."\n")) {
444      $INFO['subscribed'] = false;
445      msg(sprintf($lang[$act.'_success'], $INFO['userinfo']['name'], $ID),1);
446    } else {
447      msg(sprintf($lang[$act.'_error'], $INFO['userinfo']['name'], $ID),1);
448    }
449  }
450
451  return 'show';
452}
453
454//Setup VIM: ex: et ts=2 enc=utf-8 :
455