]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/main.php
Added a page load timer temporarily, to help in
[SourceForge/phpwiki.git] / lib / main.php
1 <?php
2 rcs_id('$Id: main.php,v 1.49 2002-02-05 22:04:04 lakka Exp $');
3
4
5 include "lib/config.php";
6 include "lib/stdlib.php";
7 require_once('lib/Request.php');
8 require_once("lib/WikiUser.php");
9 require_once('lib/WikiDB.php');
10
11 // FIXME: move to config?
12 if (defined('THEME')) {
13     include("themes/" . THEME . "/themeinfo.php");
14 }
15 if (empty($Theme)) {
16     include("themes/default/themeinfo.php");
17 }
18 assert(!empty($Theme));
19
20 class _UserPreference
21 {
22     function _UserPreference ($default_value) {
23         $this->default_value = $default_value;
24     }
25
26     function sanify ($value) {
27         return (string) $value;
28     }
29 }
30
31 class _UserPreference_int extends _UserPreference 
32 {
33     function _UserPreference_int ($default, $minval = false, $maxval = false) {
34         $this->_UserPreference((int) $default);
35         $this->_minval = (int) $minval;
36         $this->_maxval = (int) $maxval;
37     }
38     
39     function sanify ($value) {
40         $value = (int) $value;
41         if ($this->_minval !== false && $value < $this->_minval)
42             $value = $this->_minval;
43         if ($this->_maxval !== false && $value > $this->_maxval)
44             $value = $this->_maxval;
45         return $value;
46     }
47 }
48
49 $UserPreferences = array('editWidth' => new _UserPreference_int(80, 30, 150),
50                          'editHeight' => new _UserPreference_int(22, 5, 80),
51                          'timeOffset' => new _UserPreference(TimezoneOffset(false, true)),
52                          'userid' => new _UserPreference(''));
53
54 class UserPreferences {
55     function UserPreferences ($saved_prefs = false) {
56         $this->_prefs = array();
57
58         if (isa($saved_prefs, 'UserPreferences')) {
59             foreach ($saved_prefs->_prefs as $name => $value)
60                 $this->set($name, $value);
61         }
62     }
63
64     function _getPref ($name) {
65         global $UserPreferences;
66         if (!isset($UserPreferences[$name])) {
67             trigger_error("$name: unknown preference", E_USER_NOTICE);
68             return false;
69         }
70         return $UserPreferences[$name];
71     }
72     
73     function get ($name) {
74         if (isset($this->_prefs[$name]))
75             return $this->_prefs[$name];
76         if (!($pref = $this->_getPref($name)))
77             return false;
78         return $pref->default_value;
79     }
80
81     function set ($name, $value) {
82         if (!($pref = $this->_getPref($name)))
83             return false;
84         $this->_prefs[$name] = $pref->sanify($value);
85     }
86 }
87
88
89 class WikiRequest extends Request {
90
91     function WikiRequest () {
92         $this->Request();
93         
94         // Normalize args...
95         $this->setArg('pagename', $this->_deducePagename());
96         $this->setArg('action', $this->_deduceAction());
97
98         // Restore auth state
99         $this->_user = new WikiUser($this->getSessionVar('wiki_user'));
100
101         // Restore saved preferences
102         if (!($prefs = $this->getCookieVar('WIKI_PREFS2')))
103             $prefs = $this->getSessionVar('wiki_prefs');
104         $this->_prefs = new UserPreferences($prefs);
105     }
106
107     // This really maybe should be part of the constructor, but since it
108     // may involve HTML/template output, the global $request really needs
109     // to be initialized before we do this stuff.
110     function updateAuthAndPrefs () {
111         // Handle preference updates, an authentication requests, if any.
112         if ($new_prefs = $this->getArg('pref')) {
113             $this->setArg('pref', false);
114             foreach ($new_prefs as $key => $val)
115                 $this->_prefs->set($key, $val);
116         }
117
118         // Handle authentication request, if any.
119         if ($auth_args = $this->getArg('auth')) {
120             $this->setArg('auth', false);
121             $this->_handleAuthRequest($auth_args); // possible NORETURN
122         }
123         elseif ( ! $this->_user->isSignedIn() ) {
124             // If not auth request, try to sign in as saved user.
125             if (($saved_user = $this->getPref('userid')) != false)
126                 $this->_signIn($saved_user);
127         }
128
129         // Save preferences
130         $this->setSessionVar('wiki_prefs', $this->_prefs);
131         $this->setCookieVar('WIKI_PREFS2', $this->_prefs, 365);
132
133         // Ensure user has permissions for action
134         $require_level = $this->requiredAuthority($this->getArg('action'));
135         if (! $this->_user->hasAuthority($require_level))
136             $this->_notAuthorized($require_level); // NORETURN
137     }
138
139     function getUser () {
140         return $this->_user;
141     }
142
143     function getPrefs () {
144         return $this->_prefs;
145     }
146
147     // Convenience function:
148     function getPref ($key) {
149         return $this->_prefs->get($key);
150     }
151
152     function getDbh () {
153         if (!isset($this->_dbi)) {
154             $this->_dbi = WikiDB::open($GLOBALS['DBParams']);
155         }
156         return $this->_dbi;
157     }
158
159     /**
160      * Get requested page from the page database.
161      *
162      * This is a convenience function.
163      */
164     function getPage () {
165         if (!isset($this->_dbi))
166             $this->getDbh();
167         return $this->_dbi->getPage($this->getArg('pagename'));
168     }
169
170     function _handleAuthRequest ($auth_args) {
171         if (!is_array($auth_args))
172             return;
173
174         // Ignore password unless POSTed.
175         if (!$this->isPost())
176             unset($auth_args['password']);
177
178         $user = WikiUser::AuthCheck($auth_args);
179
180         if (isa($user, 'WikiUser')) {
181             // Successful login (or logout.)
182             $this->_setUser($user);
183         }
184         elseif ($user) {
185             // Login attempt failed.
186             $fail_message = $user;
187             // If no password was submitted, it's not really
188             // a failure --- just need to prompt for password...
189             if (!isset($auth_args['password']))
190                 $fail_message = false;
191             WikiUser::PrintLoginForm($this, $auth_args, $fail_message);
192             $this->finish();    //NORETURN
193         }
194         else {
195             // Login request cancelled.
196         }
197     }
198
199     /**
200      * Attempt to sign in (bogo-login).
201      *
202      * Fails silently.
203      *
204      * @param $userid string Userid to attempt to sign in as.
205      * @access private
206      */
207     function _signIn ($userid) {
208         $user = WikiUser::AuthCheck(array('userid' => $userid));
209         if (isa($user, 'WikiUser'))
210             $this->_setUser($user); // success!
211     }
212
213     function _setUser ($user) {
214         $this->_user = $user;
215         $this->setSessionVar('wiki_user', $user);
216
217         // Save userid to prefs..
218         $this->_prefs->set('userid',
219                            $user->isSignedIn() ? $user->getId() : '');
220     }
221
222     function _notAuthorized ($require_level) {
223         // User does not have required authority.  Prompt for login.
224         $what = HTML::em($this->getArg('action'));
225
226         if ($require_level >= WIKIAUTH_FORBIDDEN) {
227             $this->finish(fmt("Action %s is disallowed on this wiki", $what));
228         }
229         elseif ($require_level == WIKIAUTH_BOGO)
230             $msg = fmt("You must sign in to %s this wiki", $what);
231         elseif ($require_level == WIKIAUTH_USER)
232             $msg = fmt("You must log in to %s this wiki", $what);
233         else
234             $msg = fmt("You must be an administrator to %s this wiki", $what);
235         
236         WikiUser::PrintLoginForm($this, compact('require_level'), $msg);
237         $this->finish();    // NORETURN
238     }
239     
240     function requiredAuthority ($action) {
241         // FIXME: clean up.
242         switch ($action) {
243         case 'browse':
244         case 'viewsource':
245         case 'diff':
246             return WIKIAUTH_ANON;
247
248         case 'zip':
249             if (defined('ZIPDUMP_AUTH') && ZIPDUMP_AUTH)
250                 return WIKIAUTH_ADMIN;
251             return WIKIAUTH_ANON;
252             
253         case 'edit':
254             if (defined('REQUIRE_SIGNIN_BEFORE_EDIT') && REQUIRE_SIGNIN_BEFORE_EDIT)
255                 return WIKIAUTH_BOGO;
256             return WIKIAUTH_ANON;
257             // return WIKIAUTH_BOGO;
258
259         case 'upload':
260         case 'dumpserial':
261         case 'loadfile':
262         case 'remove':
263         case 'lock':
264         case 'unlock':
265             return WIKIAUTH_ADMIN;
266         default:
267             global $WikiNameRegexp;
268             if (preg_match("/$WikiNameRegexp\Z/A", $action))
269                 return WIKIAUTH_ANON; // ActionPage.
270             else
271                 return WIKIAUTH_ADMIN;
272         }
273     }
274         
275     function possiblyDeflowerVirginWiki () {
276         if ($this->getArg('action') != 'browse')
277             return;
278         if ($this->getArg('pagename') != HomePage)
279             return;
280
281         $page = $this->getPage();
282         $current = $page->getCurrentRevision();
283         if ($current->getVersion() > 0)
284             return;             // Homepage exists.
285
286         include('lib/loadsave.php');
287         SetupWiki($this);
288         $this->finish();        // NORETURN
289     }
290
291     function handleAction () {
292         $action = $this->getArg('action');
293         $method = "action_$action";
294         if (method_exists($this, $method)) {
295             $this->{$method}();
296         }
297         elseif ($this->isActionPage($action)) {
298             $this->actionpage($action);
299         }
300         else {
301             $this->finish(fmt("%s: Bad action", $action));
302         }
303     }
304         
305         
306     function finish ($errormsg = false) {
307         static $in_exit = 0;
308
309         if ($in_exit)
310             exit();             // just in case CloseDataBase calls us
311         $in_exit = true;
312
313         if (!empty($this->_dbi))
314             $this->_dbi->close();
315         unset($this->_dbi);
316         
317
318         global $ErrorManager;
319         $ErrorManager->flushPostponedErrors();
320    
321         if (!empty($errormsg)) {
322             PrintXML(HTML::br(),
323                      HTML::hr(),
324                      HTML::h2(_("Fatal PhpWiki Error")),
325                      $errormsg);
326             // HACK:
327             echo "\n</body></html>";
328         }
329
330         Request::finish();
331         exit;
332     }
333         
334     function _deducePagename () {
335         if ($this->getArg('pagename'))
336             return $this->getArg('pagename');
337
338         if (USE_PATH_INFO) {
339             $pathinfo = $this->get('PATH_INFO');
340             $tail = substr($pathinfo, strlen(PATH_INFO_PREFIX));
341             
342             if ($tail && $pathinfo == PATH_INFO_PREFIX . $tail) {
343                 return $tail;
344             }
345         }
346
347         $query_string = $this->get('QUERY_STRING');
348         if (preg_match('/^[^&=]+$/', $query_string)) {
349             return urldecode($query_string);
350         }
351     
352         return HomePage;
353     }
354
355     function _deduceAction () {
356         if (!($action = $this->getArg('action')))
357             return 'browse';
358
359         if (method_exists($this, "action_$action"))
360             return $action;
361
362         // Allow for, e.g. action=LikePages
363         if ($this->isActionPage($action))
364             return $action;
365         
366         trigger_error("$action: Unknown action", E_USER_NOTICE);
367         return 'browse';
368     }
369
370     function isActionPage ($pagename) {
371         // Allow for, e.g. action=LikePages
372         global $WikiNameRegexp;
373         if (!preg_match("/$WikiNameRegexp\\Z/A", $pagename))
374             return false;
375         $dbi = $this->getDbh();
376         $page = $dbi->getPage($pagename);
377         $rev = $page->getCurrentRevision();
378         // FIXME: more restrictive check for sane plugin?
379         if (strstr($rev->getPackedContent(), '<?plugin'))
380             return true;
381         trigger_error("$pagename: Does not appear to be an 'action page'", E_USER_NOTICE);
382         return false;
383     }
384     
385     function action_browse () {
386         $this->compress_output();
387         include_once("lib/display.php");
388         displayPage($this);
389     }
390
391     function actionpage ($action) {
392         $this->compress_output();
393         include_once("lib/display.php");
394         actionPage($this, $action);
395     }
396     
397     function action_diff () {
398         $this->compress_output();
399         include_once "lib/diff.php";
400         showDiff($this);
401     }
402
403     function action_search () {
404         // This is obsolete: reformulate URL and redirect.
405         // FIXME: this whole section should probably be deleted.
406         if ($this->getArg('searchtype') == 'full') {
407             $search_page = _("FullTextSearch");
408         }
409         else {
410             $search_page = _("TitleSearch");
411         }
412         $this->redirect(WikiURL($search_page,
413                                 array('s' => $this->getArg('searchterm')),
414                                 'absolute_url'));
415     }
416
417     function action_edit () {
418         $this->compress_output();
419         include "lib/editpage.php";
420         $e = new PageEditor ($this);
421         $e->editPage();
422     }
423
424     function action_viewsource () {
425         $this->compress_output();
426         include "lib/editpage.php";
427         $e = new PageEditor ($this);
428         $e->viewSource();
429     }
430
431     function action_lock () {
432         $page = $this->getPage();
433         $page->set('locked', true);
434         $this->action_browse();
435     }
436
437     function action_unlock () {
438         // FIXME: This check is redundant.
439         //$user->requireAuth(WIKIAUTH_ADMIN);
440         $page = $this->getPage();
441         $page->set('locked', false);
442         $this->action_browse();
443     }
444
445     function action_remove () {
446         // FIXME: This check is redundant.
447         //$user->requireAuth(WIKIAUTH_ADMIN);
448         include('lib/removepage.php');
449         RemovePage($this);
450     }
451
452     
453     function action_upload () {
454         include_once("lib/loadsave.php");
455         LoadPostFile($this);
456     }
457     
458     function action_zip () {
459         include_once("lib/loadsave.php");
460         MakeWikiZip($this);
461         // I don't think it hurts to add cruft at the end of the zip file.
462         echo "\n========================================================\n";
463         echo "PhpWiki " . PHPWIKI_VERSION . " source:\n$GLOBALS[RCS_IDS]\n";
464     }
465         
466     function action_dumpserial () {
467         include_once("lib/loadsave.php");
468         DumpToDir($this);
469     }
470
471     function action_loadfile () {
472         include_once("lib/loadsave.php");
473         LoadFileOrDir($this);
474     }
475 }
476
477 //FIXME: deprecated
478 function is_safe_action ($action) {
479     return WikiRequest::requiredAuthority($action) < WIKIAUTH_ADMIN;
480 }
481
482
483 function main () {
484     global $request;
485
486     $request = new WikiRequest();
487     $request->updateAuthAndPrefs();
488     
489     /* FIXME: is this needed anymore?
490     if (USE_PATH_INFO && ! $request->get('PATH_INFO')
491         && ! preg_match(',/$,', $request->get('REDIRECT_URL'))) {
492         $request->redirect(SERVER_URL
493                            . preg_replace('/(\?|$)/', '/\1',
494                                           $request->get('REQUEST_URI'),
495                                           1));
496         exit;
497     }
498     */
499
500     // Enable the output of most of the warning messages.
501     // The warnings will screw up zip files though.
502     global $ErrorManager;
503     if ($request->getArg('action') != 'zip') {
504         $ErrorManager->setPostponedErrorMask(E_NOTICE|E_USER_NOTICE);
505         //$ErrorManager->setPostponedErrorMask(0);
506     }
507     
508     //FIXME:
509     //if ($user->is_authenticated())
510     //  $LogEntry->user = $user->getId();
511
512     $request->possiblyDeflowerVirginWiki();
513
514     $request->handleAction();
515     $request->finish();
516 }
517
518 // Used for debugging purposes
519 function getmicrotime(){ 
520         list($usec, $sec) = explode(" ",microtime()); 
521     return ((float)$usec + (float)$sec); 
522 }
523 define ('DEBUG', 1);
524 if (defined ('DEBUG')) $GLOBALS['debugclock'] = getmicrotime();
525
526 main();
527
528
529 // Local Variables:
530 // mode: php
531 // tab-width: 8
532 // c-basic-offset: 4
533 // c-hanging-comment-ender-p: nil
534 // indent-tabs-mode: nil
535 // End:   
536 ?>