2 rcs_id('$Id: main.php,v 1.68 2002-08-23 18:29:30 rurban Exp $');
5 define ('USE_PREFS_IN_PAGE', true);
7 include "lib/config.php";
8 include "lib/stdlib.php";
9 require_once('lib/Request.php');
10 require_once("lib/WikiUser.php");
11 require_once('lib/WikiDB.php');
13 class WikiRequest extends Request {
15 function WikiRequest () {
19 $this->setArg('pagename', $this->_deducePagename());
20 $this->setArg('action', $this->_deduceAction());
23 $this->_user = new WikiUser($this->getSessionVar('wiki_user'));
25 // $this->_user = new WikiDB_User($this->getSessionVar('wiki_user'), $this->getAuthDbh());
26 $this->_prefs = $this->_user->getPreferences();
29 // This really maybe should be part of the constructor, but since it
30 // may involve HTML/template output, the global $request really needs
31 // to be initialized before we do this stuff.
32 function updateAuthAndPrefs () {
34 // Handle preference updates, an authentication requests, if any.
35 if ($new_prefs = $this->getArg('pref')) {
36 $this->setArg('pref', false);
37 if ($this->isPost() and !empty($new_prefs['passwd']) and
38 ($new_prefs['passwd2'] != $new_prefs['passwd'])) {
39 $this->_prefs->set('passwd','');
40 // $this->_prefs->set('passwd2',''); // This is not stored anyway
41 include_once("themes/" . THEME . "/themeinfo.php");
44 foreach ($new_prefs as $key => $val) {
45 if ($key == 'passwd') {
46 $val = crypt('passwd');
48 $this->_prefs->set($key, $val);
52 // Handle authentication request, if any.
53 if ($auth_args = $this->getArg('auth')) {
54 $this->setArg('auth', false);
55 include_once("themes/" . THEME . "/themeinfo.php");
56 $this->_handleAuthRequest($auth_args); // possible NORETURN
58 elseif ( ! $this->_user->isSignedIn() ) {
59 // If not auth request, try to sign in as saved user.
60 if (($saved_user = $this->getPref('userid')) != false) {
61 include_once("themes/" . THEME . "/themeinfo.php");
62 $this->_signIn($saved_user);
66 // Save preferences in session and cookie
68 $this->_user->setPreferences($this->_prefs, $id_only);
70 if ($theme = $this->getPref('theme') ) {
71 // Load user-defined theme
72 include_once("themes/$theme/themeinfo.php");
75 include_once("themes/" . THEME . "/themeinfo.php");
79 include_once("themes/" . THEME . "/themeinfo.php");
82 include_once("themes/default/themeinfo.php");
84 assert(!empty($Theme));
86 // Ensure user has permissions for action
87 $require_level = $this->requiredAuthority($this->getArg('action'));
88 if (! $this->_user->hasAuthority($require_level))
89 $this->_notAuthorized($require_level); // NORETURN
96 function getPrefs () {
100 // Convenience function:
101 function getPref ($key) {
102 return $this->_prefs->get($key);
106 if (!isset($this->_dbi)) {
107 // needs PHP 4.1. better use $this->_user->...
108 $this->_dbi = WikiDB::open($GLOBALS['DBParams']);
113 function getAuthDbh () {
114 global $DBParams, $DBAuthParams;
115 if (!isset($this->_auth_dbi)) {
116 if ($DBParams['dbtype'] == 'dba' or empty($DBAuthParams['auth_dsn']))
117 $this->_auth_dbi = $this->getDbh(); // use phpwiki database
118 elseif ($DBAuthParams['auth_dsn'] == $DBParams['dsn'])
119 $this->_auth_dbi = $this->getDbh(); // same phpwiki database
120 else // use external database
121 // needs PHP 4.1. better use $this->_user->...
122 $this->_auth_dbi = WikiDB_User::open($DBAuthParams);
124 return $this->_auth_dbi;
128 * Get requested page from the page database.
130 * This is a convenience function.
132 function getPage () {
133 if (!isset($this->_dbi))
135 return $this->_dbi->getPage($this->getArg('pagename'));
138 function _handleAuthRequest ($auth_args) {
139 if (!is_array($auth_args))
142 // Ignore password unless POST'ed.
143 if (!$this->isPost())
144 unset($auth_args['passwd']);
146 $user = $this->_user->AuthCheck($auth_args);
148 if (isa($user, 'WikiUser')) {
149 // Successful login (or logout.)
150 $this->_setUser($user);
153 // Login attempt failed.
154 $fail_message = $user;
155 $auth_args['pass_required'] = true;
156 // If no password was submitted, it's not really
157 // a failure --- just need to prompt for password...
158 if (!isset($auth_args['passwd'])) {
159 //$auth_args['pass_required'] = false;
160 $fail_message = false;
162 $this->_user->PrintLoginForm($this, $auth_args, $fail_message);
163 $this->finish(); //NORETURN
166 // Login request cancelled.
171 * Attempt to sign in (bogo-login).
175 * @param $userid string Userid to attempt to sign in as.
178 function _signIn ($userid) {
179 $user = $this->_user->AuthCheck(array('userid' => $userid));
180 if (isa($user, 'WikiUser')) {
181 $this->_setUser($user); // success!
185 function _setUser ($user) {
186 $this->_user = $user;
187 $this->setCookieVar('WIKI_ID', $user->_userid, 365);
188 $this->setSessionVar('wiki_user', $user);
190 // Save userid to prefs..
191 $this->_prefs->set('userid',
192 $user->isSignedIn() ? $user->getId() : '');
195 function _notAuthorized ($require_level) {
196 // User does not have required authority. Prompt for login.
197 $what = $this->getActionDescription($this->getArg('action'));
199 if ($require_level >= WIKIAUTH_FORBIDDEN) {
200 $this->finish(fmt("%s is disallowed on this wiki.",
201 $this->getDisallowedActionDescription($this->getArg('action'))));
203 elseif ($require_level == WIKIAUTH_BOGO)
204 $msg = fmt("You must sign in to %s.", $what);
205 elseif ($require_level == WIKIAUTH_USER)
206 $msg = fmt("You must log in to %s.", $what);
208 $msg = fmt("You must be an administrator to %s.", $what);
209 $pass_required = ($require_level >= WIKIAUTH_USER);
211 $this->_user->PrintLoginForm($this, compact('require_level','pass_required'), $msg);
212 $this->finish(); // NORETURN
215 function getActionDescription($action) {
216 static $actionDescriptions;
217 if (! $actionDescriptions) {
219 = array('browse' => _("browse pages in this wiki"),
220 'diff' => _("diff pages in this wiki"),
221 'dumphtml' => _("dump html pages from this wiki"),
222 'dumpserial' => _("dump serial pages from this wiki"),
223 'edit' => _("edit pages in this wiki"),
224 'loadfile' => _("load files into this wiki"),
225 'lock' => _("lock pages in this wiki"),
226 'remove' => _("remove pages from this wiki"),
227 'unlock' => _("unlock pages in this wiki"),
228 'upload' => _("upload a zip dump to this wiki"),
229 'viewsource' => _("view the source of pages in this wiki"),
230 'zip' => _("download a zip dump from this wiki"),
231 'ziphtml' => _("download an html zip dump from this wiki")
234 if (in_array($action, array_keys($actionDescriptions)))
235 return $actionDescriptions[$action];
239 function getDisallowedActionDescription($action) {
240 static $disallowedActionDescriptions;
241 if (! $disallowedActionDescriptions) {
242 $disallowedActionDescriptions
243 = array('browse' => _("Browsing pages"),
244 'diff' => _("Diffing pages"),
245 'dumphtml' => _("Dumping html pages"),
246 'dumpserial' => _("Dumping serial pages"),
247 'edit' => _("Editing pages"),
248 'loadfile' => _("Loading files"),
249 'lock' => _("Locking pages"),
250 'remove' => _("Removing pages"),
251 'unlock' => _("Unlocking pages"),
252 'upload' => _("Uploading zip dumps"),
253 'viewsource' => _("Viewing the source of pages"),
254 'zip' => _("Downloading zip dumps"),
255 'ziphtml' => _("Downloading html zip dumps")
258 if (in_array($action, array_keys($disallowedActionDescriptions)))
259 return $disallowedActionDescriptions[$action];
264 function requiredAuthority ($action) {
266 // Todo: Check individual page permissions.
271 return WIKIAUTH_ANON;
274 if (defined('ZIPDUMP_AUTH') && ZIPDUMP_AUTH)
275 return WIKIAUTH_ADMIN;
276 return WIKIAUTH_ANON;
279 if (defined('ZIPDUMP_AUTH') && ZIPDUMP_AUTH)
280 return WIKIAUTH_ADMIN;
281 return WIKIAUTH_ANON;
284 if (defined('REQUIRE_SIGNIN_BEFORE_EDIT') && REQUIRE_SIGNIN_BEFORE_EDIT)
285 return WIKIAUTH_BOGO;
286 return WIKIAUTH_ANON;
287 // return WIKIAUTH_BOGO;
296 return WIKIAUTH_ADMIN;
298 // Temp workaround for french single-word action pages 'Historique'
299 // Some of this make sense as SubPage actions or buttons.
300 $singleWordActionPages =
301 array("Historique", "Info",
302 _("Preferences"), _("Administration"),
303 _("Today"), _("Help"));
304 if (in_array($action, $singleWordActionPages))
305 return WIKIAUTH_ANON; // ActionPage.
306 global $WikiNameRegexp;
307 if (preg_match("/$WikiNameRegexp\Z/A", $action))
308 return WIKIAUTH_ANON; // ActionPage.
310 return WIKIAUTH_ADMIN;
314 function possiblyDeflowerVirginWiki () {
315 if ($this->getArg('action') != 'browse')
317 if ($this->getArg('pagename') != HOME_PAGE)
320 $page = $this->getPage();
321 $current = $page->getCurrentRevision();
322 if ($current->getVersion() > 0)
323 return; // Homepage exists.
325 include('lib/loadsave.php');
327 $this->finish(); // NORETURN
330 function handleAction () {
331 $action = $this->getArg('action');
332 $method = "action_$action";
333 if (method_exists($this, $method)) {
336 elseif ($this->isActionPage($action)) {
337 $this->actionpage($action);
340 $this->finish(fmt("%s: Bad action", $action));
345 function finish ($errormsg = false) {
349 exit(); // just in case CloseDataBase calls us
352 if (!empty($this->_dbi))
353 $this->_dbi->close();
357 global $ErrorManager;
358 $ErrorManager->flushPostponedErrors();
360 if (!empty($errormsg)) {
363 HTML::h2(_("Fatal PhpWiki Error")),
366 echo "\n</body></html>";
373 function _deducePagename () {
374 if ($this->getArg('pagename'))
375 return $this->getArg('pagename');
378 $pathinfo = $this->get('PATH_INFO');
379 $tail = substr($pathinfo, strlen(PATH_INFO_PREFIX));
381 if ($tail && $pathinfo == PATH_INFO_PREFIX . $tail) {
386 $query_string = $this->get('QUERY_STRING');
387 if (preg_match('/^[^&=]+$/', $query_string)) {
388 return urldecode($query_string);
394 function _deduceAction () {
395 if (!($action = $this->getArg('action')))
398 if (method_exists($this, "action_$action"))
401 // Allow for, e.g. action=LikePages
402 if ($this->isActionPage($action))
405 // Check for _('PhpWikiAdministration').'/'._('Remove') actions
406 $pagename = $this->getArg('pagename');
407 if (strstr($pagename,_('PhpWikiAdministration')))
410 trigger_error("$action: Unknown action", E_USER_NOTICE);
414 function _deduceUsername () {
415 if ($userid = $this->getSessionVar('wiki_user'))
417 if ($userid = $this->getCookieVar('WIKI_ID'))
422 function isActionPage ($pagename) {
423 if (isSubPage($pagename))
424 $subpagename = subPageSlice($pagename,-1); // last element
426 $subpagename = $pagename;
427 // Temp workaround for french single-word action page 'Historique'
428 $singleWordActionPages = array("Historique", "Info", _('Preferences'));
429 if (! in_array($subpagename, $singleWordActionPages)) {
430 // Allow for, e.g. action=LikePages
431 global $WikiNameRegexp;
432 if (!preg_match("/$WikiNameRegexp\\Z/A", $subpagename))
435 $dbi = $this->getDbh();
436 $page = $dbi->getPage($pagename);
437 $rev = $page->getCurrentRevision();
438 // FIXME: more restrictive check for sane plugin?
439 if (strstr($rev->getPackedContent(), '<?plugin'))
441 trigger_error("$pagename: Does not appear to be an 'action page'", E_USER_NOTICE);
445 function action_browse () {
446 $this->compress_output();
447 include_once("lib/display.php");
451 function action_verify () {
452 $this->action_browse();
455 function actionpage ($action) {
456 $this->compress_output();
457 include_once("lib/display.php");
458 actionPage($this, $action);
461 function action_diff () {
462 $this->compress_output();
463 include_once "lib/diff.php";
467 function action_search () {
468 // This is obsolete: reformulate URL and redirect.
469 // FIXME: this whole section should probably be deleted.
470 if ($this->getArg('searchtype') == 'full') {
471 $search_page = _("FullTextSearch");
474 $search_page = _("TitleSearch");
476 $this->redirect(WikiURL($search_page,
477 array('s' => $this->getArg('searchterm')),
481 function action_edit () {
482 $this->compress_output();
483 include "lib/editpage.php";
484 $e = new PageEditor ($this);
488 function action_viewsource () {
489 $this->compress_output();
490 include "lib/editpage.php";
491 $e = new PageEditor ($this);
495 function action_lock () {
496 $page = $this->getPage();
497 $page->set('locked', true);
498 $this->action_browse();
501 function action_unlock () {
502 // FIXME: This check is redundant.
503 //$user->requireAuth(WIKIAUTH_ADMIN);
504 $page = $this->getPage();
505 $page->set('locked', false);
506 $this->action_browse();
509 function action_remove () {
510 // FIXME: This check is redundant.
511 //$user->requireAuth(WIKIAUTH_ADMIN);
512 $pagename = $this->getArg('pagename');
513 if (strstr($pagename,_('PhpWikiAdministration'))) {
514 $this->action_browse();
516 include('lib/removepage.php');
522 function action_upload () {
523 include_once("lib/loadsave.php");
527 function action_zip () {
528 include_once("lib/loadsave.php");
530 // I don't think it hurts to add cruft at the end of the zip file.
531 echo "\n========================================================\n";
532 echo "PhpWiki " . PHPWIKI_VERSION . " source:\n$GLOBALS[RCS_IDS]\n";
535 function action_ziphtml () {
536 include_once("lib/loadsave.php");
537 MakeWikiZipHtml($this);
538 // I don't think it hurts to add cruft at the end of the zip file.
539 echo "\n========================================================\n";
540 echo "PhpWiki " . PHPWIKI_VERSION . " source:\n$GLOBALS[RCS_IDS]\n";
543 function action_dumpserial () {
544 include_once("lib/loadsave.php");
548 function action_dumphtml () {
549 include_once("lib/loadsave.php");
550 DumpHtmlToDir($this);
553 function action_loadfile () {
554 include_once("lib/loadsave.php");
555 LoadFileOrDir($this);
560 function is_safe_action ($action) {
561 return WikiRequest::requiredAuthority($action) < WIKIAUTH_ADMIN;
568 $request = new WikiRequest();
569 $request->updateAuthAndPrefs();
571 /* FIXME: is this needed anymore?
572 if (USE_PATH_INFO && ! $request->get('PATH_INFO')
573 && ! preg_match(',/$,', $request->get('REDIRECT_URL'))) {
574 $request->redirect(SERVER_URL
575 . preg_replace('/(\?|$)/', '/\1',
576 $request->get('REQUEST_URI'),
582 // Enable the output of most of the warning messages.
583 // The warnings will screw up zip files though.
584 global $ErrorManager;
585 if (substr($request->getArg('action'), 0, 3) != 'zip') {
586 $ErrorManager->setPostponedErrorMask(E_NOTICE|E_USER_NOTICE);
587 //$ErrorManager->setPostponedErrorMask(0);
591 //if ($user->is_authenticated())
592 // $LogEntry->user = $user->getId();
594 $request->possiblyDeflowerVirginWiki();
596 $request->handleAction();
597 if (defined('DEBUG') and DEBUG>1) phpinfo(INFO_VARIABLES);
601 // Used for debugging purposes
602 function getmicrotime(){
603 list($usec, $sec) = explode(" ", microtime());
604 return ((float)$usec + (float)$sec);
606 if (defined('DEBUG')) $GLOBALS['debugclock'] = getmicrotime();
615 // c-hanging-comment-ender-p: nil
616 // indent-tabs-mode: nil