1 <?php rcs_id('$Id: Request.php,v 1.20 2002-09-12 11:45:33 rurban Exp $');
3 // FIXME: write log entry.
8 $this->_fix_magic_quotes_gpc();
9 $this->_fix_multipart_form_data();
11 switch($this->get('REQUEST_METHOD')) {
14 // $this->sanify_input_array(&$GLOBALS['HTTP_GET_VARS']);
15 $this->args = &$GLOBALS['HTTP_GET_VARS'];
18 // $this->sanify_input_array(&$GLOBALS['HTTP_POST_VARS']);
19 $this->args = &$GLOBALS['HTTP_POST_VARS'];
22 $this->args = array();
26 // Defer session_start until we decided to load DB_Session (or not).
27 // $this->session = new Request_SessionVars;
28 $this->cookies = new Request_CookieVars;
31 $this->_log_entry = & new Request_AccessLogEntry($this,
34 $GLOBALS['request'] = $this;
38 $vars = &$GLOBALS['HTTP_SERVER_VARS'];
40 if (isset($vars[$key]))
45 $addr = $vars['REMOTE_ADDR'];
46 if (defined('ENABLE_REVERSE_DNS') && ENABLE_REVERSE_DNS)
47 return $vars[$key] = gethostbyaddr($addr);
55 function getArg($key) {
56 if (isset($this->args[$key]))
57 return $this->args[$key];
65 function setArg($key, $val) {
67 unset($this->args[$key]);
69 $this->args[$key] = $val;
72 function debugVars() {
74 foreach (array('start_debug','debug_port','debug_no_cache') as $key) {
75 if (isset($GLOBALS['HTTP_GET_VARS'][$key]))
76 $array[$key] = $GLOBALS['HTTP_GET_VARS'][$key];
82 // Well oh well. Do we really want to pass POST params back as GET?
83 function getURLtoSelf($args = false, $exclude = array()) {
84 $get_args = $this->args;
86 $get_args = array_merge($get_args, $args);
88 $get_args = array_merge($get_args, $this->debugVars());
90 foreach ($exclude as $ex) {
91 if (!empty($get_args[$ex])) unset($get_args[$ex]);
94 $pagename = $get_args['pagename'];
95 unset ($get_args['pagename']);
96 if ($get_args['action'] == 'browse')
97 unset($get_args['action']);
99 return WikiURL($pagename, $get_args);
103 return $this->get("REQUEST_METHOD") == "POST";
106 function redirect($url) {
107 header("Location: $url");
108 if (isset($this->_log_entry))
109 $this->_log_entry->setStatus(302);
112 function setStatus($status) {
113 if (preg_match('|^HTTP/.*?\s(\d+)|i', $status, $m)) {
118 $status = (integer) $status;
119 $reasons = array('200' => 'OK',
121 '400' => 'Bad Request',
122 '401' => 'Unauthorized',
123 '403' => 'Forbidden',
124 '404' => 'Not Found');
125 header(sprintf("HTTP/1.0 %d %s", $status, $reason[$status]));
128 if (isset($this->_log_entry))
129 $this->_log_entry->setStatus($status);
132 function compress_output() {
133 if (function_exists('ob_gzhandler')) {
134 ob_start('ob_gzhandler');
135 $this->_is_compressing_output = true;
140 if (!empty($this->_is_compressing_output))
144 function getSessionVar($key) {
145 return $this->session->get($key);
147 function setSessionVar($key, $val) {
148 return $this->session->set($key, $val);
150 function deleteSessionVar($key) {
151 return $this->session->delete($key);
154 function getCookieVar($key) {
155 return $this->cookies->get($key);
157 function setCookieVar($key, $val, $lifetime_in_days = false) {
158 return $this->cookies->set($key, $val, $lifetime_in_days);
160 function deleteCookieVar($key) {
161 return $this->cookies->delete($key);
164 function getUploadedFile($key) {
165 return Request_UploadedFile::getUploadedFile($key);
169 function _fix_magic_quotes_gpc() {
170 $needs_fix = array('HTTP_POST_VARS',
177 if (get_magic_quotes_gpc()) {
178 foreach ($needs_fix as $vars)
179 $this->_stripslashes($GLOBALS[$vars]);
183 function _stripslashes(&$var) {
184 if (is_array($var)) {
185 foreach ($var as $key => $val)
186 $this->_stripslashes($var[$key]);
188 elseif (is_string($var))
189 $var = stripslashes($var);
192 function _fix_multipart_form_data () {
193 if (preg_match('|^multipart/form-data|', $this->get('CONTENT_TYPE')))
194 $this->_strip_leading_nl($GLOBALS['HTTP_POST_VARS']);
197 function _strip_leading_nl(&$var) {
198 if (is_array($var)) {
199 foreach ($var as $key => $val)
200 $this->_strip_leading_nl($var[$key]);
202 elseif (is_string($var))
203 $var = preg_replace('|^\r?\n?|', '', $var);
206 // Fixme: Seperate into fields of type: displayed, db, internal, password, ...
207 // and define for each type the allowed characters.
208 function sanify_input_array (&$arr) {
210 foreach (array_keys($arr) as $key) {
211 if (!in_array($key,array('edit','password')))
212 $arr[$key] = $this->sanify_userinput($arr[$key]);
217 function sanify_userinput ($var) {
218 // Prevent possible XSS attacks (cross site scripting attacks)
219 // See http://www.cert.org/advisories/CA-2000-02.html, http://www.perl.com/pub/a/2002/02/20/css.html
220 // <script> tags, ...
221 // /wiki/?pagename=<script>alert(document.cookie)</script>
222 if (is_string($var)) {
223 return strip_tags($var);
224 } elseif (is_array($var)) {
225 $this->sanify_input_array($var);
233 class Request_SessionVars {
234 function Request_SessionVars() {
235 // Prevent cacheing problems with IE 5
236 session_cache_limiter('none');
242 $vars = &$GLOBALS['HTTP_SESSION_VARS'];
243 if (isset($vars[$key]))
248 function set($key, $val) {
249 $vars = &$GLOBALS['HTTP_SESSION_VARS'];
250 if (ini_get('register_globals')) {
251 // This is funky but necessary, at least in some PHP's
252 $GLOBALS[$key] = $val;
255 session_register($key);
258 function delete($key) {
259 $vars = &$GLOBALS['HTTP_SESSION_VARS'];
260 if (ini_get('register_globals'))
261 unset($GLOBALS[$key]);
263 session_unregister($key);
267 class Request_CookieVars {
270 $vars = &$GLOBALS['HTTP_COOKIE_VARS'];
271 if (isset($vars[$key])) {
272 @$val = unserialize($vars[$key]);
279 function set($key, $val, $persist_days = false) {
280 $vars = &$GLOBALS['HTTP_COOKIE_VARS'];
282 if (is_numeric($persist_days)) {
283 $expires = time() + (24 * 3600) * $persist_days;
289 $packedval = serialize($val);
290 $vars[$key] = $packedval;
291 setcookie($key, $packedval, $expires, '/');
294 function delete($key) {
295 $vars = &$GLOBALS['HTTP_COOKIE_VARS'];
301 class Request_UploadedFile {
302 function getUploadedFile($postname) {
303 global $HTTP_POST_FILES;
305 if (!isset($HTTP_POST_FILES[$postname]))
308 $fileinfo = &$HTTP_POST_FILES[$postname];
309 if (!is_uploaded_file($fileinfo['tmp_name']))
310 return false; // possible malicious attack.
312 return new Request_UploadedFile($fileinfo);
315 function Request_UploadedFile($fileinfo) {
316 $this->_info = $fileinfo;
320 return $this->_info['size'];
324 return $this->_info['name'];
328 return $this->_info['type'];
332 if ( ($fd = fopen($this->_info['tmp_name'], "rb")) ) {
333 if ($this->getSize() < filesize($this->_info['tmp_name'])) {
334 // FIXME: Some PHP's (or is it some browsers?) put
335 // HTTP/MIME headers in the file body, some don't.
337 // At least, I think that's the case. I know I used
338 // to need this code, now I don't.
340 // This code is more-or-less untested currently.
342 // Dump HTTP headers.
343 while ( ($header = fgets($fd, 4096)) ) {
344 if (trim($header) == '') {
347 else if (!preg_match('/^content-(length|type):/i', $header)) {
357 function getContents() {
359 $data = fread($fd, $this->getSize());
366 * Create NCSA "combined" log entry for current request.
368 class Request_AccessLogEntry
373 * The log entry will be automatically appended to the log file
374 * when the current request terminates.
376 * If you want to modify a Request_AccessLogEntry before it gets
377 * written (e.g. via the setStatus and setSize methods) you should
378 * use an '&' on the constructor, so that you're working with the
379 * original (rather than a copy) object.
382 * $log_entry = & new Request_AccessLogEntry($req, "/tmp/wiki_access_log");
383 * $log_entry->setStatus(401);
387 * @param $request object Request object for current request.
388 * @param $logfile string Log file name.
390 function Request_AccessLogEntry (&$request, $logfile) {
391 $this->logfile = $logfile;
393 $this->host = $request->get('REMOTE_HOST');
394 $this->ident = $request->get('REMOTE_IDENT');
397 $this->user = '-'; // FIXME: get logged-in user name
398 $this->time = time();
399 $this->request = join(' ', array($request->get('REQUEST_METHOD'),
400 $request->get('REQUEST_URI'),
401 $request->get('SERVER_PROTOCOL')));
404 $this->referer = (string) $request->get('HTTP_REFERER');
405 $this->user_agent = (string) $request->get('HTTP_USER_AGENT');
407 global $Request_AccessLogEntry_entries;
408 if (!isset($Request_AccessLogEntry_entries)) {
409 register_shutdown_function("Request_AccessLogEntry_shutdown_function");
411 $Request_AccessLogEntry_entries[] = &$this;
415 * Set result status code.
417 * @param $status integer HTTP status code.
419 function setStatus ($status) {
420 $this->status = $status;
426 * @param $size integer
428 function setSize ($size) {
433 * Get time zone offset.
435 * This is a static member function.
437 * @param $time integer Unix timestamp (defaults to current time).
438 * @return string Zone offset, e.g. "-0800" for PST.
440 function _zone_offset ($time = false) {
443 $offset = date("Z", $time);
448 $offhours = floor($offset / 3600);
449 $offmins = $offset / 60 - $offhours * 60;
450 return sprintf("%s%02d%02d", $negoffset, $offhours, $offmins);
454 * Format time in NCSA format.
456 * This is a static member function.
458 * @param $time integer Unix timestamp (defaults to current time).
459 * @return string Formatted date & time.
461 function _ncsa_time($time = false) {
465 return date("d/M/Y:H:i:s", $time) .
466 " " . $this->_zone_offset();
470 * Write entry to log file.
473 $entry = sprintf('%s %s %s [%s] "%s" %d %d "%s" "%s"',
474 $this->host, $this->ident, $this->user,
475 $this->_ncsa_time($this->time),
476 $this->request, $this->status, $this->size,
477 $this->referer, $this->user_agent);
479 //Error log doesn't provide locking.
480 //error_log("$entry\n", 3, $this->logfile);
483 if (($fp = fopen($this->logfile, "a"))) {
485 fputs($fp, "$entry\n");
495 * @see Request_AccessLogEntry
497 function Request_AccessLogEntry_shutdown_function ()
499 global $Request_AccessLogEntry_entries;
501 foreach ($Request_AccessLogEntry_entries as $entry) {
504 unset($Request_AccessLogEntry_entries);
511 // c-hanging-comment-ender-p: nil
512 // indent-tabs-mode: nil