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