]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/Request.php
Minor reindenting and rewrapping in emacs.
[SourceForge/phpwiki.git] / lib / Request.php
1 <?php rcs_id('$Id: Request.php,v 1.7 2002-01-09 16:57:20 carstenklapp Exp $');
2
3 // FIXME: write log entry.
4
5 class Request {
6         
7     function Request() {
8         $this->_fix_magic_quotes_gpc();
9         $this->_fix_multipart_form_data();
10         
11         switch($this->get('REQUEST_METHOD')) {
12         case 'GET':
13         case 'HEAD':
14             $this->args = &$GLOBALS['HTTP_GET_VARS'];
15             break;
16         case 'POST':
17             $this->args = &$GLOBALS['HTTP_POST_VARS'];
18             break;
19         default:
20             $this->args = array();
21             break;
22         }
23         
24         $this->session = new Request_SessionVars;
25         $this->cookies = new Request_CookieVars;
26         
27         if (ACCESS_LOG)
28             $this->_log_entry = & new Request_AccessLogEntry($this,
29                                                              ACCESS_LOG);
30         
31         $TheRequest = $this;
32     }
33
34     function get($key) {
35         $vars = &$GLOBALS['HTTP_SERVER_VARS'];
36
37         if (isset($vars[$key]))
38             return $vars[$key];
39
40         switch ($key) {
41         case 'REMOTE_HOST':
42             $addr = $vars['REMOTE_ADDR'];
43             if (defined('ENABLE_REVERSE_DNS') && ENABLE_REVERSE_DNS)
44                 return $vars[$key] = gethostbyaddr($addr);
45             else
46                 return $addr;
47         default:
48             return false;
49         }
50     }
51
52     function getArg($key) {
53         if (isset($this->args[$key]))
54             return $this->args[$key];
55         return false;
56     }
57
58     function setArg($key, $val) {
59         $this->args[$key] = $val;
60     }
61
62     function getURLtoSelf($args = false) {
63         $get_args = $this->args;
64         if ($args)
65             $get_args = array_merge($get_args, $args);
66
67         unset ($get_args['pagename']);
68         if ($get_args['action'] == 'browse')
69             unset($get_args['action']);
70
71         return WikiURL($this->getArg('pagename'), $get_args);
72     }
73     
74     
75     function redirect($url) {
76         header("Location: $url");
77         if (isset($this->_log_entry))
78             $this->_log_entry->setStatus(302);
79     }
80
81     function setStatus($status) {
82         if (preg_match('|^HTTP/.*?\s(\d+)|i', $status, $m)) {
83             header($status);
84             $status = $m[1];
85         }
86         else {
87             $status = (integer) $status;
88             $reasons = array('200' => 'OK',
89                              '302' => 'Found',
90                              '400' => 'Bad Request',
91                              '401' => 'Unauthorized',
92                              '403' => 'Forbidden',
93                              '404' => 'Not Found');
94             header(sprintf("HTTP/1.0 %d %s", $status, $reason[$status]));
95         }
96
97         if (isset($this->_log_entry))
98             $this->_log_entry->setStatus($status);
99     }
100
101     function compress_output() {
102         if (function_exists('ob_gzhandler')) {
103             ob_start('ob_gzhandler');
104             $this->_is_compressing_output = true;
105         }
106     }
107
108     function finish() {
109         if (!empty($this->_is_compressing_output))
110             ob_end_flush();
111     }
112     
113
114     function getSessionVar($key) {
115         return $this->session->get($key);
116     }
117     function setSessionVar($key, $val) {
118         return $this->session->set($key, $val);
119     }
120     function deleteSessionVar($key) {
121         return $this->session->delete($key);
122     }
123
124     function getCookieVar($key) {
125         return $this->cookies->get($key);
126     }
127     function setCookieVar($key, $val, $lifetime_in_days = false) {
128         return $this->cookies->set($key, $val, $lifetime_in_days);
129     }
130     function deleteCookieVar($key) {
131         return $this->cookies->delete($key);
132     }
133     
134     function getUploadedFile($key) {
135         return Request_UploadedFile::getUploadedFile($key);
136     }
137     
138
139     function _fix_magic_quotes_gpc() {
140         $needs_fix = array('HTTP_POST_VARS',
141                            'HTTP_GET_VARS',
142                            'HTTP_COOKIE_VARS',
143                            'HTTP_SERVER_VARS',
144                            'HTTP_POST_FILES');
145         
146         // Fix magic quotes.
147         if (get_magic_quotes_gpc()) {
148             foreach ($needs_fix as $vars)
149                 $this->_stripslashes($GLOBALS[$vars]);
150         }
151     }
152
153
154     function _stripslashes(&$var) {
155         if (is_array($var)) {
156             foreach ($var as $key => $val)
157                 $this->_stripslashes($var[$key]);
158         }
159         elseif (is_string($var))
160             $var = stripslashes($var);
161     }
162     
163     function _fix_multipart_form_data () {
164         if (preg_match('|^multipart/form-data|', $this->get('CONTENT_TYPE')))
165             $this->_strip_leading_nl($GLOBALS['HTTP_POST_VARS']);
166     }
167     
168     function _strip_leading_nl(&$var) {
169         if (is_array($var)) {
170             foreach ($var as $key => $val)
171                 $this->_strip_leading_nl($var[$key]);
172         }
173         elseif (is_string($var))
174             $var = preg_replace('|^\r?\n?|', '', $var);
175     }
176 }
177
178 class Request_SessionVars {
179     function Request_SessionVars() {
180         session_start();
181     }
182     
183     function get($key) {
184         $vars = &$GLOBALS['HTTP_SESSION_VARS'];
185         if (isset($vars[$key]))
186             return $vars[$key];
187         return false;
188     }
189     
190     function set($key, $val) {
191         $vars = &$GLOBALS['HTTP_SESSION_VARS'];
192         if (ini_get('register_globals')) {
193             // This is funky but necessary, at least in some PHP's
194             $GLOBALS[$key] = $val;
195         }
196         $vars[$key] = $val;
197         session_register($key);
198     }
199     
200     function delete($key) {
201         $vars = &$GLOBALS['HTTP_SESSION_VARS'];
202         if (ini_get('register_globals'))
203             unset($GLOBALS[$key]);
204         unset($vars[$key]);
205         session_unregister($key);
206     }
207 }
208
209 class Request_CookieVars {
210     
211     function get($key) {
212         $vars = &$GLOBALS['HTTP_COOKIE_VARS'];
213         if (isset($vars[$key])) {
214             @$val = unserialize($vars[$key]);
215             if (!empty($val))
216                 return $val;
217         }
218         return false;
219     }
220         
221     function set($key, $val, $persist_days = false) {
222         $vars = &$GLOBALS['HTTP_COOKIE_VARS'];
223         
224         if (is_numeric($persist_days)) {
225             $expires = time() + (24 * 3600) * $persist_days;
226         }
227         else {
228             $expires = 0;
229         }
230         
231         $packedval = serialize($val);
232         $vars[$key] = $packedval;
233         setcookie($key, $packedval, $expires, '/');
234     }
235     
236     function delete($key) {
237         $vars = &$GLOBALS['HTTP_COOKIE_VARS'];
238         setcookie($key);
239         unset($vars[$key]);
240     }
241 }
242
243 class Request_UploadedFile {
244     function getUploadedFile($postname) {
245         global $HTTP_POST_FILES;
246         
247         if (!isset($HTTP_POST_FILES[$postname]))
248             return false;
249         
250         $fileinfo = &$HTTP_POST_FILES[$postname];
251         if (!is_uploaded_file($fileinfo['tmp_name']))
252             return false;       // possible malicious attack.
253
254         return new Request_UploadedFile($fileinfo);
255     }
256     
257     function Request_UploadedFile($fileinfo) {
258         $this->_info = $fileinfo;
259     }
260
261     function getSize() {
262         return $this->_info['size'];
263     }
264
265     function getName() {
266         return $this->_info['name'];
267     }
268
269     function getType() {
270         return $this->_info['type'];
271     }
272
273     function open() {
274         if ( ($fd = fopen($this->_info['tmp_name'], "rb")) ) {
275             if ($this->getSize() < filesize($this->_info['tmp_name'])) {
276                 // FIXME: Some PHP's (or is it some browsers?) put
277                 //    HTTP/MIME headers in the file body, some don't.
278                 //
279                 // At least, I think that's the case.  I know I used
280                 // to need this code, now I don't.
281                 //
282                 // This code is more-or-less untested currently.
283                 //
284                 // Dump HTTP headers.
285                 while ( ($header = fgets($fd, 4096)) ) {
286                     if (trim($header) == '') {
287                         break;
288                     }
289                     else if (!preg_match('/^content-(length|type):/i', $header)) {
290                         rewind($fd);
291                         break;
292                     }
293                 }
294             }
295         }
296         return $fd;
297     }
298
299     function getContents() {
300         $fd = $this->open();
301         $data = fread($fd, $this->getSize());
302         fclose($fd);
303         return $data;
304     }
305 }
306
307 /**
308  * Create NCSA "combined" log entry for current request.
309  */
310 class Request_AccessLogEntry
311 {
312     /**
313      * Constructor.
314      *
315      * The log entry will be automatically appended to the log file
316      * when the current request terminates.
317      *
318      * If you want to modify a Request_AccessLogEntry before it gets
319      * written (e.g. via the setStatus and setSize methods) you should
320      * use an '&' on the constructor, so that you're working with the
321      * original (rather than a copy) object.
322      *
323      * <pre>
324      *    $log_entry = & new Request_AccessLogEntry($req, "/tmp/wiki_access_log");
325      *    $log_entry->setStatus(401);
326      * </pre>
327      *
328      *
329      * @param $request object  Request object for current request.
330      * @param $logfile string  Log file name.
331      */
332     function Request_AccessLogEntry ($request, $logfile) {
333         $this->logfile = $logfile;
334         
335         $this->host  = $request->get('REMOTE_HOST');
336         $this->ident = $request->get('REMOTE_IDENT');
337         if (!$this->ident)
338             $this->ident = '-';
339         $this->user = '-';        // FIXME: get logged-in user name
340         $this->time = time();
341         $this->request = join(' ', array($request->get('REQUEST_METHOD'),
342                                          $request->get('REQUEST_URI'),
343                                          $request->get('SERVER_PROTOCOL')));
344         $this->status = 200;
345         $this->size = 0;
346         $this->referer = (string) $request->get('HTTP_REFERER');
347         $this->user_agent = (string) $request->get('HTTP_USER_AGENT');
348
349         global $Request_AccessLogEntry_entries;
350         if (!isset($Request_AccessLogEntry_entries)) {
351             register_shutdown_function("Request_AccessLogEntry_shutdown_function");
352         }
353         $Request_AccessLogEntry_entries[] = &$this;
354     }
355
356     /**
357      * Set result status code.
358      *
359      * @param $status integer  HTTP status code.
360      */
361     function setStatus ($status) {
362         $this->status = $status;
363     }
364     
365     /**
366      * Set response size.
367      *
368      * @param $size integer
369      */
370     function setSize ($size) {
371         $this->size = $size;
372     }
373     
374     /**
375      * Get time zone offset.
376      *
377      * This is a static member function.
378      *
379      * @param $time integer Unix timestamp (defaults to current time).
380      * @return string Zone offset, e.g. "-0800" for PST.
381      */
382     function _zone_offset ($time = false) {
383         if (!$time)
384             $time = time();
385         $offset = date("Z", $time);
386         if ($offset < 0) {
387             $negoffset = "-";
388             $offset = -$offset;
389         }
390         $offhours = floor($offset / 3600);
391         $offmins  = $offset / 60 - $offhours * 60;
392         return sprintf("%s%02d%02d", $negoffset, $offhours, $offmins);
393     }
394
395     /**
396      * Format time in NCSA format.
397      *
398      * This is a static member function.
399      *
400      * @param $time integer Unix timestamp (defaults to current time).
401      * @return string Formatted date & time.
402      */
403     function _ncsa_time($time = false) {
404         if (!$time)
405             $time = time();
406
407         return date("d/M/Y:H:i:s", $time) .
408             " " . $this->_zone_offset();
409     }
410
411     /**
412      * Write entry to log file.
413      */
414     function write() {
415         $entry = sprintf('%s %s %s [%s] "%s" %d %d "%s" "%s"',
416                          $this->host, $this->ident, $this->user,
417                          $this->_ncsa_time($this->time),
418                          $this->request, $this->status, $this->size,
419                          $this->referer, $this->user_agent);
420
421         //Error log doesn't provide locking.
422         //error_log("$entry\n", 3, $this->logfile);
423
424         // Alternate method 
425         if (($fp = fopen($this->logfile, "a"))) {
426             flock($fp, LOCK_EX);
427             fputs($fp, "$entry\n");
428             fclose($fp);
429         }
430     }
431 }
432
433 /**
434  * Shutdown callback.
435  *
436  * @access private
437  * @see Request_AccessLogEntry
438  */
439 function Request_AccessLogEntry_shutdown_function ()
440 {
441     global $Request_AccessLogEntry_entries;
442     
443     foreach ($Request_AccessLogEntry_entries as $entry) {
444         $entry->write();
445     }
446     unset($Request_AccessLogEntry_entries);
447 }
448
449 // Local Variables:
450 // mode: php
451 // tab-width: 8
452 // c-basic-offset: 4
453 // c-hanging-comment-ender-p: nil
454 // indent-tabs-mode: nil
455 // End:   
456 ?>