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