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