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