diff options
Diffstat (limited to 'includes/WebRequest.php')
-rw-r--r-- | includes/WebRequest.php | 190 |
1 files changed, 120 insertions, 70 deletions
diff --git a/includes/WebRequest.php b/includes/WebRequest.php index 0928e4d5..b6d6d27a 100644 --- a/includes/WebRequest.php +++ b/includes/WebRequest.php @@ -39,16 +39,15 @@ if ( !function_exists( '__autoload' ) ) { * not create a second WebRequest object; make a FauxRequest object if * you want to pass arbitrary data to some function in place of the web * input. - * + * * @ingroup HTTP */ class WebRequest { - var $data = array(); - var $headers; + protected $data, $headers = array(); private $_response; - function __construct() { - /// @fixme This preemptive de-quoting can interfere with other web libraries + public function __construct() { + /// @todo Fixme: this preemptive de-quoting can interfere with other web libraries /// and increases our memory footprint. It would be cleaner to do on /// demand; but currently we have no wrapper for $_SERVER etc. $this->checkMagicQuotes(); @@ -65,13 +64,15 @@ class WebRequest { * as we may need the list of language variants to determine * available variant URLs. */ - function interpolateTitle() { + public function interpolateTitle() { global $wgUsePathInfo; + if ( $wgUsePathInfo ) { // PATH_INFO is mangled due to http://bugs.php.net/bug.php?id=31892 // And also by Apache 2.x, double slashes are converted to single slashes. // So we will use REQUEST_URI if possible. $matches = array(); + if ( !empty( $_SERVER['REQUEST_URI'] ) ) { // Slurp out the path portion to examine... $url = $_SERVER['REQUEST_URI']; @@ -161,9 +162,8 @@ class WebRequest { * used for undoing the evil that is magic_quotes_gpc. * @param $arr array: will be modified * @return array the original array - * @private */ - function &fix_magic_quotes( &$arr ) { + private function &fix_magic_quotes( &$arr ) { foreach( $arr as $key => $val ) { if( is_array( $val ) ) { $this->fix_magic_quotes( $arr[$key] ); @@ -179,10 +179,11 @@ class WebRequest { * through fix_magic_quotes to strip out the stupid slashes. * WARNING: This should only be done once! Running a second * time could damage the values. - * @private */ - function checkMagicQuotes() { - if ( function_exists( 'get_magic_quotes_gpc' ) && get_magic_quotes_gpc() ) { + private function checkMagicQuotes() { + $mustFixQuotes = function_exists( 'get_magic_quotes_gpc' ) + && get_magic_quotes_gpc(); + if( $mustFixQuotes ) { $this->fix_magic_quotes( $_COOKIE ); $this->fix_magic_quotes( $_ENV ); $this->fix_magic_quotes( $_GET ); @@ -204,7 +205,8 @@ class WebRequest { $data[$key] = $this->normalizeUnicode( $val ); } } else { - $data = UtfNormal::cleanUp( $data ); + global $wgContLang; + $data = $wgContLang->normalize( $data ); } return $data; } @@ -216,9 +218,12 @@ class WebRequest { * @param $name string * @param $default mixed * @return mixed - * @private */ - function getGPCVal( $arr, $name, $default ) { + private function getGPCVal( $arr, $name, $default ) { + # PHP is so nice to not touch input data, except sometimes: + # http://us2.php.net/variables.external#language.variables.external.dot-in-names + # Work around PHP *feature* to avoid *bugs* elsewhere. + $name = strtr( $name, '.', '_' ); if( isset( $arr[$name] ) ) { global $wgContLang; $data = $arr[$name]; @@ -246,7 +251,7 @@ class WebRequest { * @param $default string: optional default (or NULL) * @return string */ - function getVal( $name, $default = NULL ) { + public function getVal( $name, $default = null ) { $val = $this->getGPCVal( $this->data, $name, $default ); if( is_array( $val ) ) { $val = $default; @@ -257,14 +262,14 @@ class WebRequest { return (string)$val; } } - + /** * Set an aribtrary value into our get/post data. * @param $key string Key name to use * @param $value mixed Value to set * @return mixed old value if one was present, null otherwise */ - function setVal( $key, $value ) { + public function setVal( $key, $value ) { $ret = isset( $this->data[$key] ) ? $this->data[$key] : null; $this->data[$key] = $value; return $ret; @@ -279,7 +284,7 @@ class WebRequest { * @param $default array: optional default (or NULL) * @return array */ - function getArray( $name, $default = NULL ) { + public function getArray( $name, $default = null ) { $val = $this->getGPCVal( $this->data, $name, $default ); if( is_null( $val ) ) { return null; @@ -298,7 +303,7 @@ class WebRequest { * @param $default array: option default (or NULL) * @return array of ints */ - function getIntArray( $name, $default = NULL ) { + public function getIntArray( $name, $default = null ) { $val = $this->getArray( $name, $default ); if( is_array( $val ) ) { $val = array_map( 'intval', $val ); @@ -314,7 +319,7 @@ class WebRequest { * @param $default int * @return int */ - function getInt( $name, $default = 0 ) { + public function getInt( $name, $default = 0 ) { return intval( $this->getVal( $name, $default ) ); } @@ -325,7 +330,7 @@ class WebRequest { * @param $name string * @return int */ - function getIntOrNull( $name ) { + public function getIntOrNull( $name ) { $val = $this->getVal( $name ); return is_numeric( $val ) ? intval( $val ) @@ -340,7 +345,7 @@ class WebRequest { * @param $default bool * @return bool */ - function getBool( $name, $default = false ) { + public function getBool( $name, $default = false ) { return $this->getVal( $name, $default ) ? true : false; } @@ -351,10 +356,10 @@ class WebRequest { * @param $name string * @return bool */ - function getCheck( $name ) { + public function getCheck( $name ) { # Checkboxes and buttons are only present when clicked # Presence connotes truth, abscense false - $val = $this->getVal( $name, NULL ); + $val = $this->getVal( $name, null ); return isset( $val ); } @@ -370,7 +375,7 @@ class WebRequest { * @param $default string: optional * @return string */ - function getText( $name, $default = '' ) { + public function getText( $name, $default = '' ) { global $wgContLang; $val = $this->getVal( $name, $default ); return str_replace( "\r\n", "\n", @@ -382,7 +387,7 @@ class WebRequest { * If no arguments are given, returns all input values. * No transformation is performed on the values. */ - function getValues() { + public function getValues() { $names = func_get_args(); if ( count( $names ) == 0 ) { $names = array_keys( $this->data ); @@ -407,7 +412,7 @@ class WebRequest { * * @return bool */ - function wasPosted() { + public function wasPosted() { return $_SERVER['REQUEST_METHOD'] == 'POST'; } @@ -422,7 +427,7 @@ class WebRequest { * * @return bool */ - function checkSessionCookie() { + public function checkSessionCookie() { return isset( $_COOKIE[session_name()] ); } @@ -430,8 +435,8 @@ class WebRequest { * Return the path portion of the request URI. * @return string */ - function getRequestURL() { - if( isset( $_SERVER['REQUEST_URI'] ) ) { + public function getRequestURL() { + if( isset( $_SERVER['REQUEST_URI']) && strlen($_SERVER['REQUEST_URI']) ) { $base = $_SERVER['REQUEST_URI']; } elseif( isset( $_SERVER['SCRIPT_NAME'] ) ) { // Probably IIS; doesn't set REQUEST_URI @@ -465,7 +470,7 @@ class WebRequest { * Return the request URI with the canonical service and hostname. * @return string */ - function getFullRequestURL() { + public function getFullRequestURL() { global $wgServer; return $wgServer . $this->getRequestURL(); } @@ -475,7 +480,7 @@ class WebRequest { * @param $query String: query string fragment; do not include initial '?' * @return string */ - function appendQuery( $query ) { + public function appendQuery( $query ) { global $wgTitle; $basequery = ''; foreach( $_GET as $var => $val ) { @@ -500,11 +505,11 @@ class WebRequest { * @param $query String: query string fragment; do not include initial '?' * @return string */ - function escapeAppendQuery( $query ) { + public function escapeAppendQuery( $query ) { return htmlspecialchars( $this->appendQuery( $query ) ); } - function appendQueryValue( $key, $value, $onlyquery = false ) { + public function appendQueryValue( $key, $value, $onlyquery = false ) { return $this->appendQueryArray( array( $key => $value ), $onlyquery ); } @@ -515,7 +520,7 @@ class WebRequest { * the complete URL * @return string */ - function appendQueryArray( $array, $onlyquery = false ) { + public function appendQueryArray( $array, $onlyquery = false ) { global $wgTitle; $newquery = $_GET; unset( $newquery['title'] ); @@ -533,7 +538,7 @@ class WebRequest { * @param $optionname String: to specify an option other than rclimit to pull from. * @return array first element is limit, second is offset */ - function getLimitOffset( $deflimit = 50, $optionname = 'rclimit' ) { + public function getLimitOffset( $deflimit = 50, $optionname = 'rclimit' ) { global $wgUser; $limit = $this->getInt( 'limit', 0 ); @@ -555,9 +560,9 @@ class WebRequest { * @param $key String: * @return string or NULL if no such file. */ - function getFileTempname( $key ) { + public function getFileTempname( $key ) { if( !isset( $_FILES[$key] ) ) { - return NULL; + return null; } return $_FILES[$key]['tmp_name']; } @@ -567,7 +572,7 @@ class WebRequest { * @param $key String: * @return integer */ - function getFileSize( $key ) { + public function getFileSize( $key ) { if( !isset( $_FILES[$key] ) ) { return 0; } @@ -579,7 +584,7 @@ class WebRequest { * @param $key String: * @return integer */ - function getUploadError( $key ) { + public function getUploadError( $key ) { if( !isset( $_FILES[$key] ) || !isset( $_FILES[$key]['error'] ) ) { return 0/*UPLOAD_ERR_OK*/; } @@ -597,16 +602,17 @@ class WebRequest { * @param $key String: * @return string or NULL if no such file. */ - function getFileName( $key ) { + public function getFileName( $key ) { + global $wgContLang; if( !isset( $_FILES[$key] ) ) { - return NULL; + return null; } $name = $_FILES[$key]['name']; # Safari sends filenames in HTML-encoded Unicode form D... # Horrid and evil! Let's try to make some kind of sense of it. $name = Sanitizer::decodeCharReferences( $name ); - $name = UtfNormal::cleanUp( $name ); + $name = $wgContLang->normalize( $name ); wfDebug( "WebRequest::getFileName() '" . $_FILES[$key]['name'] . "' normalized to '$name'\n" ); return $name; } @@ -615,10 +621,11 @@ class WebRequest { * Return a handle to WebResponse style object, for setting cookies, * headers and other stuff, for Request being worked on. */ - function response() { + public function response() { /* Lazy initialization of response object for this request */ - if (!is_object($this->_response)) { - $this->_response = new WebResponse; + if ( !is_object( $this->_response ) ) { + $class = ( $this instanceof FauxRequest ) ? 'FauxResponse' : 'WebResponse'; + $this->_response = new $class(); } return $this->_response; } @@ -627,11 +634,10 @@ class WebRequest { * Get a request header, or false if it isn't set * @param $name String: case-insensitive header name */ - function getHeader( $name ) { + public function getHeader( $name ) { $name = strtoupper( $name ); if ( function_exists( 'apache_request_headers' ) ) { - if ( !isset( $this->headers ) ) { - $this->headers = array(); + if ( !$this->headers ) { foreach ( apache_request_headers() as $tempName => $tempValue ) { $this->headers[ strtoupper( $tempName ) ] = $tempValue; } @@ -650,18 +656,53 @@ class WebRequest { } } } - + /* * Get data from $_SESSION + * @param $key String Name of key in $_SESSION + * @return mixed */ - function getSessionData( $key ) { + public function getSessionData( $key ) { if( !isset( $_SESSION[$key] ) ) return null; return $_SESSION[$key]; } - function setSessionData( $key, $data ) { + + /** + * Set session data + * @param $key String Name of key in $_SESSION + * @param $data mixed + */ + public function setSessionData( $key, $data ) { $_SESSION[$key] = $data; } + + /** + * Returns true if the PATH_INFO ends with an extension other than a script + * extension. This could confuse IE for scripts that send arbitrary data which + * is not HTML but may be detected as such. + * + * Various past attempts to use the URL to make this check have generally + * run up against the fact that CGI does not provide a standard method to + * determine the URL. PATH_INFO may be mangled (e.g. if cgi.fix_pathinfo=0), + * but only by prefixing it with the script name and maybe some other stuff, + * the extension is not mangled. So this should be a reasonably portable + * way to perform this security check. + */ + public function isPathInfoBad() { + global $wgScriptExtension; + + if ( !isset( $_SERVER['PATH_INFO'] ) ) { + return false; + } + $pi = $_SERVER['PATH_INFO']; + $dotPos = strrpos( $pi, '.' ); + if ( $dotPos === false ) { + return false; + } + $ext = substr( $pi, $dotPos ); + return !in_array( $ext, array( $wgScriptExtension, '.php', '.php5' ) ); + } } /** @@ -670,64 +711,73 @@ class WebRequest { * @ingroup HTTP */ class FauxRequest extends WebRequest { - var $wasPosted = false; + private $wasPosted = false; + private $session = array(); + private $response; /** * @param $data Array of *non*-urlencoded key => value pairs, the * fake GET/POST values * @param $wasPosted Bool: whether to treat the data as POST */ - function FauxRequest( $data, $wasPosted = false, $session = null ) { + public function __construct( $data, $wasPosted = false, $session = null ) { if( is_array( $data ) ) { $this->data = $data; } else { throw new MWException( "FauxRequest() got bogus data" ); } $this->wasPosted = $wasPosted; - $this->headers = array(); - $this->session = $session ? $session : array(); + if( $session ) + $this->session = $session; } - - function notImplemented( $method ) { + + private function notImplemented( $method ) { throw new MWException( "{$method}() not implemented" ); } - function getText( $name, $default = '' ) { + public function getText( $name, $default = '' ) { # Override; don't recode since we're using internal data return (string)$this->getVal( $name, $default ); } - function getValues() { + public function getValues() { return $this->data; } - function wasPosted() { + public function wasPosted() { return $this->wasPosted; } - function checkSessionCookie() { + public function checkSessionCookie() { return false; } - function getRequestURL() { + public function getRequestURL() { $this->notImplemented( __METHOD__ ); } - function appendQuery( $query ) { + public function appendQuery( $query ) { $this->notImplemented( __METHOD__ ); } - function getHeader( $name ) { + public function getHeader( $name ) { return isset( $this->headers[$name] ) ? $this->headers[$name] : false; } - function getSessionData( $key ) { - if( !isset( $this->session[$key] ) ) - return null; - return $this->session[$key]; + public function setHeader( $name, $val ) { + $this->headers[$name] = $val; + } + + public function getSessionData( $key ) { + if( isset( $this->session[$key] ) ) + return $this->session[$key]; } - function setSessionData( $key, $data ) { + + public function setSessionData( $key, $data ) { $this->notImplemented( __METHOD__ ); } + public function isPathInfoBad() { + return false; + } } |