]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/Request.php
only WikiDB method missing
[SourceForge/phpwiki.git] / lib / Request.php
1 <?php //-*-php-*-
2 rcs_id('$Id: Request.php,v 1.38 2004-01-25 10:26:02 rurban Exp $');
3
4
5 // backward compatibility for PHP < 4.2.0
6 if (!function_exists('ob_clean')) {
7     function ob_clean() {
8         ob_end_clean();
9         ob_start();
10     }
11 }
12
13         
14 class Request {
15         
16     function Request() {
17         $this->_fix_magic_quotes_gpc();
18         $this->_fix_multipart_form_data();
19         
20         switch($this->get('REQUEST_METHOD')) {
21         case 'GET':
22         case 'HEAD':
23             $this->args = &$GLOBALS['HTTP_GET_VARS'];
24             break;
25         case 'POST':
26             $this->args = &$GLOBALS['HTTP_POST_VARS'];
27             break;
28         default:
29             $this->args = array();
30             break;
31         }
32         
33         $this->session = new Request_SessionVars; 
34         $this->cookies = new Request_CookieVars;
35         
36         if (ACCESS_LOG) {
37             if (! is_writeable(ACCESS_LOG)) {
38                 trigger_error
39                     (sprintf(_("%s is not writable."), _("The PhpWiki access log file"))
40                     . "\n"
41                     . sprintf(_("Please ensure that %s is writable, or redefine %s in index.php."),
42                             sprintf(_("the file '%s'"), ACCESS_LOG),
43                             'ACCESS_LOG')
44                     , E_USER_NOTICE);
45             }
46             else
47                 $this->_log_entry = & new Request_AccessLogEntry($this,
48                                                                 ACCESS_LOG);
49         }
50         
51         $GLOBALS['request'] = $this;
52     }
53
54     function get($key) {
55         if (!empty($GLOBALS['HTTP_SERVER_VARS']))
56             $vars = &$GLOBALS['HTTP_SERVER_VARS'];
57         else // cgi or other servers than Apache
58             $vars = &$GLOBALS['_ENV'];
59
60         if (isset($vars[$key]))
61             return $vars[$key];
62
63         switch ($key) {
64         case 'REMOTE_HOST':
65             $addr = $vars['REMOTE_ADDR'];
66             if (defined('ENABLE_REVERSE_DNS') && ENABLE_REVERSE_DNS)
67                 return $vars[$key] = gethostbyaddr($addr);
68             else
69                 return $addr;
70         default:
71             return false;
72         }
73     }
74
75     function getArg($key) {
76         if (isset($this->args[$key]))
77             return $this->args[$key];
78         return false;
79     }
80
81     function getArgs () {
82         return $this->args;
83     }
84     
85     function setArg($key, $val) {
86         if ($val === false)
87             unset($this->args[$key]);
88         else
89             $this->args[$key] = $val;
90     }
91     
92     // Well oh well. Do we really want to pass POST params back as GET?
93     function getURLtoSelf($args = false, $exclude = array()) {
94
95         // Err... good point...
96         if ($this->isPost())
97             trigger_error("Request::getURLtoSelf() should probably not be from POST",
98                           E_USER_NOTICE);
99         
100         $get_args = $this->args;
101         if ($args)
102             $get_args = array_merge($get_args, $args);
103
104         foreach ($exclude as $ex) {
105             if (!empty($get_args[$ex])) unset($get_args[$ex]);
106         }
107
108         $pagename = $get_args['pagename'];
109         unset ($get_args['pagename']);
110         if ($get_args['action'] == 'browse')
111             unset($get_args['action']);
112
113         return WikiURL($pagename, $get_args);
114     }
115
116     function isPost () {
117         return $this->get("REQUEST_METHOD") == "POST";
118     }
119
120     function isGetOrHead () {
121         return in_array($this->get('REQUEST_METHOD'),
122                         array('GET', 'HEAD'));
123     }
124
125     function httpVersion() {
126         if (!preg_match('@HTTP\s*/\s*(\d+.\d+)@', $this->get('SERVER_PROTOCOL'), $m))
127             return false;
128         return (float) $m[1];
129     }
130     
131     function redirect($url, $noreturn=true) {
132         $bogus = defined('DISABLE_HTTP_REDIRECT') and DISABLE_HTTP_REDIRECT;
133         
134         if (!$bogus) {
135             header("Location: $url");
136             /*
137              * "302 Found" is not really meant to be sent in response
138              * to a POST.  Worse still, according to (both HTTP 1.0
139              * and 1.1) spec, the user, if it is sent, the user agent
140              * is supposed to use the same method to fetch the
141              * redirected URI as the original.
142              *
143              * That means if we redirect from a POST, the user-agent
144              * supposed to generate another POST.  Not what we want.
145              * (We do this after a page save after all.)
146              *
147              * Fortunately, most/all browsers don't do that.
148              *
149              * "303 See Other" is what we really want.  But it only
150              * exists in HTTP/1.1
151              *
152              * FIXME: this is still not spec compliant for HTTP
153              * version < 1.1.
154              */
155             $status = $this->httpVersion() >= 1.1 ? 303 : 302;
156
157             $this->setStatus($status);
158         }
159
160         if ($noreturn) {
161             include_once('lib/Template.php');
162             $this->discardOutput();
163             $tmpl = new Template('redirect', $this, array('REDIRECT_URL' => $url));
164             $tmpl->printXML();
165             $this->finish();
166         }
167         else if ($bogus) {
168             return JavaScript("
169               function redirect(url) {
170                 if (typeof location.replace == 'function')
171                   location.replace(url);
172                 else if (typeof location.assign == 'function')
173                   location.assign(url);
174                 else
175                   window.location = url;
176               }
177               redirect('" . addslashes($url) . "')");
178         }
179     }
180
181     /** Set validators for this response.
182      *
183      * This sets a (possibly incomplete) set of validators
184      * for this response.
185      *
186      * The validator set can be extended using appendValidators().
187      *
188      * When you're all done setting and appending validators, you
189      * must call checkValidators() to check them and set the
190      * appropriate headers in the HTTP response.
191      *
192      * Example Usage:
193      *  ...
194      *  $request->setValidators(array('pagename' => $pagename,
195      *                                '%mtime' => $rev->get('mtime')));
196      *  ...
197      *  // Wups... response content depends on $otherpage, too...
198      *  $request->appendValidators(array('otherpage' => $otherpagerev->getPageName(),
199      *                                   '%mtime' => $otherpagerev->get('mtime')));
200      *  ...
201      *  // After all validators have been set:
202      *  $request->checkValidators();
203      */
204     function setValidators($validator_set) {
205         if (is_array($validator_set))
206             $validator_set = new HTTP_ValidatorSet($validator_set);
207         $this->_validators = $validator_set;
208     }
209     
210     /** Append validators for this response.
211      *
212      * This appends additional validators to this response.
213      * You must call setValidators() before calling this method.
214      */ 
215     function appendValidators($validator_set) {
216         $this->_validators->append($validator_set);
217     }
218     
219     /** Check validators and set headers in HTTP response
220      *
221      * This sets the appropriate "Last-Modified" and "ETag"
222      * headers in the HTTP response.
223      *
224      * Additionally, if the validators match any(all) conditional
225      * headers in the HTTP request, this method will not return, but
226      * instead will send "304 Not Modified" or "412 Precondition
227      * Failed" (as appropriate) back to the client.
228      */
229     function checkValidators() {
230         $validators = &$this->_validators;
231         
232         // Set validator headers
233         if (($etag = $validators->getETag()) !== false)
234             header("ETag: " . $etag->asString());
235         if (($mtime = $validators->getModificationTime()) !== false)
236             header("Last-Modified: " . Rfc1123DateTime($mtime));
237
238         // Set cache control headers
239         $this->cacheControl();
240
241         if (CACHE_CONTROL == 'NONE')
242             return;             // don't check conditionals...
243         
244         // Check conditional headers in request
245         $status = $validators->checkConditionalRequest($this);
246         if ($status) {
247             // Return short response due to failed conditionals
248             $this->setStatus($status);
249             print "\n\n";
250             $this->discardOutput();
251             $this->finish();
252             exit();
253         }
254     }
255
256     /** Set the cache control headers in the HTTP response.
257      */
258     function cacheControl($strategy=CACHE_CONTROL, $max_age=CACHE_CONTROL_MAX_AGE) {
259         if ($strategy == 'NONE') {
260             $cache_control = "no-cache";
261             $max_age = -20;
262         }
263         elseif ($strategy == 'ALLOW_STALE' && $max_age > 0) {
264             $cache_control = sprintf("max-age=%d", $max_age);
265         }
266         else {
267             $cache_control = "must-revalidate";
268             $max_age = -20;
269         }
270         header("Cache-Control: $cache_control");
271         header("Expires: " . Rfc1123DateTime(time() + $max_age));
272         header("Vary: Cookie"); // FIXME: add more here?
273     }
274     
275     function setStatus($status) {
276         if (preg_match('|^HTTP/.*?\s(\d+)|i', $status, $m)) {
277             header($status);
278             $status = $m[1];
279         }
280         else {
281             $status = (integer) $status;
282             $reason = array('200' => 'OK',
283                             '302' => 'Found',
284                             '303' => 'See Other',
285                             '304' => 'Not Modified',
286                             '400' => 'Bad Request',
287                             '401' => 'Unauthorized',
288                             '403' => 'Forbidden',
289                             '404' => 'Not Found',
290                             '412' => 'Precondition Failed');
291             // FIXME: is it always okay to send HTTP/1.1 here, even for older clients?
292             header(sprintf("HTTP/1.1 %d %s", $status, $reason[$status]));
293         }
294
295         if (isset($this->_log_entry))
296             $this->_log_entry->setStatus($status);
297     }
298
299     function buffer_output($compress = true) {
300         if (defined('COMPRESS_OUTPUT')) {
301             if (!COMPRESS_OUTPUT)
302                 $compress = false;
303         }
304         elseif (!function_exists('version_compare')
305                 || version_compare(phpversion(), '4.2.3', "<")) {
306             $compress = false;
307         }
308
309         if (!function_exists('ob_gzhandler'))
310             $compress = false;
311         
312         if ($compress) {
313             ob_start('ob_gzhandler');
314             /*
315              * Attempt to prevent Apache from doing the dreaded double-gzip.
316              *
317              * It would be better if we could detect when apache was going
318              * to zip for us, and then let it ... but I have yet to figure
319              * out how to do that.
320              */
321             @apache_note('no-gzip', 1);
322         }
323         else {
324             // Now we alway buffer output.
325             // This is so we can set HTTP headers (e.g. for redirect)
326             // at any point.
327             // FIXME: change the name of this method.
328             ob_start();
329         }
330         $this->_is_buffering_output = true;
331     }
332
333     function discardOutput() {
334         if (!empty($this->_is_buffering_output))
335             ob_clean();
336         else
337             trigger_error("Not buffering output", E_USER_NOTICE);
338     }
339     
340     function finish() {
341         if (!empty($this->_is_buffering_output)) {
342             //header(sprintf("Content-Length: %d", ob_get_length()));
343             ob_end_flush();
344         }
345         exit;
346     }
347
348     function getSessionVar($key) {
349         return $this->session->get($key);
350     }
351     function setSessionVar($key, $val) {
352         return $this->session->set($key, $val);
353     }
354     function deleteSessionVar($key) {
355         return $this->session->delete($key);
356     }
357
358     function getCookieVar($key) {
359         return $this->cookies->get($key);
360     }
361     function setCookieVar($key, $val, $lifetime_in_days = false) {
362         return $this->cookies->set($key, $val, $lifetime_in_days);
363     }
364     function deleteCookieVar($key) {
365         return $this->cookies->delete($key);
366     }
367     
368     function getUploadedFile($key) {
369         return Request_UploadedFile::getUploadedFile($key);
370     }
371     
372
373     function _fix_magic_quotes_gpc() {
374         $needs_fix = array('HTTP_POST_VARS',
375                            'HTTP_GET_VARS',
376                            'HTTP_COOKIE_VARS',
377                            'HTTP_SERVER_VARS',
378                            'HTTP_POST_FILES');
379         
380         // Fix magic quotes.
381         if (get_magic_quotes_gpc()) {
382             foreach ($needs_fix as $vars)
383                 $this->_stripslashes($GLOBALS[$vars]);
384         }
385     }
386
387     function _stripslashes(&$var) {
388         if (is_array($var)) {
389             foreach ($var as $key => $val)
390                 $this->_stripslashes($var[$key]);
391         }
392         elseif (is_string($var))
393             $var = stripslashes($var);
394     }
395     
396     function _fix_multipart_form_data () {
397         if (preg_match('|^multipart/form-data|', $this->get('CONTENT_TYPE')))
398             $this->_strip_leading_nl($GLOBALS['HTTP_POST_VARS']);
399     }
400     
401     function _strip_leading_nl(&$var) {
402         if (is_array($var)) {
403             foreach ($var as $key => $val)
404                 $this->_strip_leading_nl($var[$key]);
405         }
406         elseif (is_string($var))
407             $var = preg_replace('|^\r?\n?|', '', $var);
408     }
409 }
410
411 class Request_SessionVars {
412     function Request_SessionVars() {
413         // Prevent cacheing problems with IE 5
414         session_cache_limiter('none');
415                                         
416         session_start();
417     }
418     
419     function get($key) {
420         $vars = &$GLOBALS['HTTP_SESSION_VARS'];
421         if (isset($vars[$key]))
422             return $vars[$key];
423         return false;
424     }
425     
426     function set($key, $val) {
427         $vars = &$GLOBALS['HTTP_SESSION_VARS'];
428         if (!function_usable('ini_get') or ini_get('register_globals')) {
429             // This is funky but necessary, at least in some PHP's
430             $GLOBALS[$key] = $val;
431         }
432         $vars[$key] = $val;
433         session_register($key);
434     }
435     
436     function delete($key) {
437         $vars = &$GLOBALS['HTTP_SESSION_VARS'];
438         if (!function_usable('ini_get') or ini_get('register_globals'))
439             unset($GLOBALS[$key]);
440         unset($vars[$key]);
441         session_unregister($key);
442     }
443 }
444
445 class Request_CookieVars {
446     
447     function get($key) {
448         $vars = &$GLOBALS['HTTP_COOKIE_VARS'];
449         if (isset($vars[$key])) {
450             @$val = unserialize($vars[$key]);
451             if (!empty($val))
452                 return $val;
453         }
454         return false;
455     }
456         
457     function set($key, $val, $persist_days = false) {
458         $vars = &$GLOBALS['HTTP_COOKIE_VARS'];
459         
460         if (is_numeric($persist_days)) {
461             $expires = time() + (24 * 3600) * $persist_days;
462         }
463         else {
464             $expires = 0;
465         }
466         
467         $packedval = serialize($val);
468         $vars[$key] = $packedval;
469         setcookie($key, $packedval, $expires, '/');
470     }
471     
472     function delete($key) {
473         $vars = &$GLOBALS['HTTP_COOKIE_VARS'];
474         setcookie($key);
475         unset($vars[$key]);
476     }
477 }
478
479 class Request_UploadedFile {
480     function getUploadedFile($postname) {
481         global $HTTP_POST_FILES;
482         
483         if (!isset($HTTP_POST_FILES[$postname]))
484             return false;
485         
486         $fileinfo = &$HTTP_POST_FILES[$postname];
487         if (!is_uploaded_file($fileinfo['tmp_name']))
488             return false;       // possible malicious attack.
489
490         return new Request_UploadedFile($fileinfo);
491     }
492     
493     function Request_UploadedFile($fileinfo) {
494         $this->_info = $fileinfo;
495     }
496
497     function getSize() {
498         return $this->_info['size'];
499     }
500
501     function getName() {
502         return $this->_info['name'];
503     }
504
505     function getType() {
506         return $this->_info['type'];
507     }
508
509     function getTmpName() {
510         return $this->_info['tmp_name'];
511     }
512
513     function open() {
514         if ( ($fd = fopen($this->_info['tmp_name'], "rb")) ) {
515             if ($this->getSize() < filesize($this->_info['tmp_name'])) {
516                 // FIXME: Some PHP's (or is it some browsers?) put
517                 //    HTTP/MIME headers in the file body, some don't.
518                 //
519                 // At least, I think that's the case.  I know I used
520                 // to need this code, now I don't.
521                 //
522                 // This code is more-or-less untested currently.
523                 //
524                 // Dump HTTP headers.
525                 while ( ($header = fgets($fd, 4096)) ) {
526                     if (trim($header) == '') {
527                         break;
528                     }
529                     else if (!preg_match('/^content-(length|type):/i', $header)) {
530                         rewind($fd);
531                         break;
532                     }
533                 }
534             }
535         }
536         return $fd;
537     }
538
539     function getContents() {
540         $fd = $this->open();
541         $data = fread($fd, $this->getSize());
542         fclose($fd);
543         return $data;
544     }
545 }
546
547 /**
548  * Create NCSA "combined" log entry for current request.
549  */
550 class Request_AccessLogEntry
551 {
552     /**
553      * Constructor.
554      *
555      * The log entry will be automatically appended to the log file
556      * when the current request terminates.
557      *
558      * If you want to modify a Request_AccessLogEntry before it gets
559      * written (e.g. via the setStatus and setSize methods) you should
560      * use an '&' on the constructor, so that you're working with the
561      * original (rather than a copy) object.
562      *
563      * <pre>
564      *    $log_entry = & new Request_AccessLogEntry($req, "/tmp/wiki_access_log");
565      *    $log_entry->setStatus(401);
566      * </pre>
567      *
568      *
569      * @param $request object  Request object for current request.
570      * @param $logfile string  Log file name.
571      */
572     function Request_AccessLogEntry (&$request, $logfile) {
573         $this->logfile = $logfile;
574         
575         $this->host  = $request->get('REMOTE_HOST');
576         $this->ident = $request->get('REMOTE_IDENT');
577         if (!$this->ident)
578             $this->ident = '-';
579         $this->user = '-';        // FIXME: get logged-in user name
580         $this->time = time();
581         $this->request = join(' ', array($request->get('REQUEST_METHOD'),
582                                          $request->get('REQUEST_URI'),
583                                          $request->get('SERVER_PROTOCOL')));
584         $this->status = 200;
585         $this->size = 0;
586         $this->referer = (string) $request->get('HTTP_REFERER');
587         $this->user_agent = (string) $request->get('HTTP_USER_AGENT');
588
589         global $Request_AccessLogEntry_entries;
590         if (!isset($Request_AccessLogEntry_entries)) {
591             register_shutdown_function("Request_AccessLogEntry_shutdown_function");
592         }
593         $Request_AccessLogEntry_entries[] = &$this;
594     }
595
596     /**
597      * Set result status code.
598      *
599      * @param $status integer  HTTP status code.
600      */
601     function setStatus ($status) {
602         $this->status = $status;
603     }
604     
605     /**
606      * Set response size.
607      *
608      * @param $size integer
609      */
610     function setSize ($size) {
611         $this->size = $size;
612     }
613     
614     /**
615      * Get time zone offset.
616      *
617      * This is a static member function.
618      *
619      * @param $time integer Unix timestamp (defaults to current time).
620      * @return string Zone offset, e.g. "-0800" for PST.
621      */
622     function _zone_offset ($time = false) {
623         if (!$time)
624             $time = time();
625         $offset = date("Z", $time);
626         $negoffset = "";
627         if ($offset < 0) {
628             $negoffset = "-";
629             $offset = -$offset;
630         }
631         $offhours = floor($offset / 3600);
632         $offmins  = $offset / 60 - $offhours * 60;
633         return sprintf("%s%02d%02d", $negoffset, $offhours, $offmins);
634     }
635
636     /**
637      * Format time in NCSA format.
638      *
639      * This is a static member function.
640      *
641      * @param $time integer Unix timestamp (defaults to current time).
642      * @return string Formatted date & time.
643      */
644     function _ncsa_time($time = false) {
645         if (!$time)
646             $time = time();
647
648         return date("d/M/Y:H:i:s", $time) .
649             " " . $this->_zone_offset();
650     }
651
652     /**
653      * Write entry to log file.
654      */
655     function write() {
656         $entry = sprintf('%s %s %s [%s] "%s" %d %d "%s" "%s"',
657                          $this->host, $this->ident, $this->user,
658                          $this->_ncsa_time($this->time),
659                          $this->request, $this->status, $this->size,
660                          $this->referer, $this->user_agent);
661
662         //Error log doesn't provide locking.
663         //error_log("$entry\n", 3, $this->logfile);
664
665         // Alternate method
666         if (($fp = fopen($this->logfile, "a"))) {
667             flock($fp, LOCK_EX);
668             fputs($fp, "$entry\n");
669             fclose($fp);
670         }
671     }
672 }
673
674 /**
675  * Shutdown callback.
676  *
677  * @access private
678  * @see Request_AccessLogEntry
679  */
680 function Request_AccessLogEntry_shutdown_function ()
681 {
682     global $Request_AccessLogEntry_entries;
683     
684     foreach ($Request_AccessLogEntry_entries as $entry) {
685         $entry->write();
686     }
687     unset($Request_AccessLogEntry_entries);
688 }
689
690
691 class HTTP_ETag {
692     function HTTP_ETag($val, $is_weak=false) {
693         $this->_val = hash($val);
694         $this->_weak = $is_weak;
695     }
696
697     /** Comparison
698      *
699      * Strong comparison: If either (or both) tag is weak, they
700      *  are not equal.
701      */
702     function equals($that, $strong_match=false) {
703         if ($this->_val != $that->_val)
704             return false;
705         if ($strong_match and ($this->_weak or $that->_weak))
706             return false;
707         return true;
708     }
709
710
711     function asString() {
712         $quoted = '"' . addslashes($this->_val) . '"';
713         return $this->_weak ? "W/$quoted" : $quoted;
714     }
715
716     /** Parse tag from header.
717      *
718      * This is a static member function.
719      */
720     function parse($strval) {
721         if (!preg_match(':^(W/)?"(.+)"$:i', trim($strval), $m))
722             return false;       // parse failed
723         list(,$weak,$str) = $m;
724         return new HTTP_ETag(stripslashes($str), $weak);
725     }
726
727     function matches($taglist, $strong_match=false) {
728         $taglist = trim($taglist);
729
730         if ($taglist == '*') {
731             if ($strong_match)
732                 return ! $this->_weak;
733             else
734                 return true;
735         }
736
737         while (preg_match('@^(W/)?"((?:\\\\.|[^"])*)"\s*,?\s*@i',
738                           $taglist, $m)) {
739             list($match, $weak, $str) = $m;
740             $taglist = substr($taglist, strlen($match));
741             $tag = new HTTP_ETag(stripslashes($str), $weak);
742             if ($this->equals($tag, $strong_match)) {
743                 return true;
744             }
745         }
746         return false;
747     }
748 }
749
750 // Possible results from the HTTP_ValidatorSet::_check*() methods.
751 // (Higher numerical values take precedence.)
752 define ('_HTTP_VAL_PASS', 0);   // Test is irrelevant
753 define ('_HTTP_VAL_NOT_MODIFIED', 1); // Test passed, content not changed
754 define ('_HTTP_VAL_MODIFIED', 2); // Test failed, content changed
755 define ('_HTTP_VAL_FAILED', 3); // Precondition failed.
756
757 class HTTP_ValidatorSet {
758     function HTTP_ValidatorSet($validators) {
759         $this->_mtime = $this->_weak = false;
760         $this->_tag = array();
761         
762         foreach ($validators as $key => $val) {
763             if ($key == '%mtime') {
764                 $this->_mtime = $val;
765             }
766             elseif ($key == '%weak') {
767                 if ($val)
768                     $this->_weak = true;
769             }
770             else {
771                 $this->_tag[$key] = $val;
772             }
773         }
774     }
775
776     function append($that) {
777         if (is_array($that))
778             $that = new HTTP_ValidatorSet($that);
779
780         // Pick the most recent mtime
781         if (isset($that->_mtime))
782             if (!isset($this->_mtime) || $that->_mtime > $this->_mtime)
783                 $this->_mtime = $that->_mtime;
784
785         // If either is weak, we're weak
786         if (!empty($that->_weak))
787             $this->_weak = true;
788
789         $this->_tag = array_merge($this->_tag, $that->_tag);
790     }
791
792     function getETag() {
793         if (! $this->_tag)
794             return false;
795         return new HTTP_ETag($this->_tag, $this->_weak);
796     }
797
798     function getModificationTime() {
799         return $this->_mtime;
800     }
801     
802     function checkConditionalRequest (&$request) {
803         $result = max($this->_checkIfUnmodifiedSince($request),
804                       $this->_checkIfModifiedSince($request),
805                       $this->_checkIfMatch($request),
806                       $this->_checkIfNoneMatch($request));
807
808         if ($result == _HTTP_VAL_PASS || $result == _HTTP_VAL_MODIFIED)
809             return false;       // "please proceed with normal processing"
810         elseif ($result == _HTTP_VAL_FAILED)
811             return 412;         // "412 Precondition Failed"
812         elseif ($result == _HTTP_VAL_NOT_MODIFIED)
813             return 304;         // "304 Not Modified"
814
815         trigger_error("Ack, shouldn't get here", E_USER_ERROR);
816         return false;
817     }
818
819     function _checkIfUnmodifiedSince(&$request) {
820         if ($this->_mtime !== false) {
821             $since = ParseRfc1123DateTime($request->get("HTTP_IF_UNMODIFIED_SINCE"));
822             if ($since !== false && $this->_mtime > $since)
823                 return _HTTP_VAL_FAILED;
824         }
825         return _HTTP_VAL_PASS;
826     }
827
828     function _checkIfModifiedSince(&$request) {
829         if ($this->_mtime !== false and $request->isGetOrHead()) {
830             $since = ParseRfc1123DateTime($request->get("HTTP_IF_MODIFIED_SINCE"));
831             if ($since !== false) {
832                 if ($this->_mtime <= $since)
833                     return _HTTP_VAL_NOT_MODIFIED;
834                 return _HTTP_VAL_MODIFIED;
835             }
836         }
837         return _HTTP_VAL_PASS;
838     }
839
840     function _checkIfMatch(&$request) {
841         if ($this->_tag && ($taglist = $request->get("HTTP_IF_MATCH"))) {
842             $tag = $this->getETag();
843             if (!$tag->matches($taglist, 'strong'))
844                 return _HTTP_VAL_FAILED;
845         }
846         return _HTTP_VAL_PASS;
847     }
848
849     function _checkIfNoneMatch(&$request) {
850         if ($this->_tag && ($taglist = $request->get("HTTP_IF_NONE_MATCH"))) {
851             $tag = $this->getETag();
852             $strong_compare = ! $request->isGetOrHead();
853             if ($taglist) {
854                 if ($tag->matches($taglist, $strong_compare)) {
855                     if ($request->isGetOrHead())
856                         return _HTTP_VAL_NOT_MODIFIED;
857                     else
858                         return _HTTP_VAL_FAILED;
859                 }
860                 return _HTTP_VAL_MODIFIED;
861             }
862         }
863         return _HTTP_VAL_PASS;
864     }
865 }
866
867
868 // $Log: not supported by cvs2svn $
869 // Revision 1.37  2003/12/26 06:41:16  carstenklapp
870 // Bugfix: Try to defer OS errors about session.save_path and ACCESS_LOG,
871 // so they don't prevent IE from partially (or not at all) rendering the
872 // page. This should help a little for the IE user who encounters trouble
873 // when setting up a new PhpWiki for the first time.
874 //
875
876 // Local Variables:
877 // mode: php
878 // tab-width: 8
879 // c-basic-offset: 4
880 // c-hanging-comment-ender-p: nil
881 // indent-tabs-mode: nil
882 // End:   
883 ?>