Go to the documentation of this file.
30 use Wikimedia\AtEase\AtEase;
117 $this->requestTime = $_SERVER[
'REQUEST_TIME_FLOAT'];
121 $this->data = $_POST + $_GET;
123 $this->queryAndPathParams = $this->queryParams = $_GET;
145 if ( isset( $_SERVER[
'REQUEST_URI'] ) ) {
147 $url = $_SERVER[
'REQUEST_URI'];
148 if ( !preg_match(
'!^https?://!', $url ) ) {
149 $url =
'http://unused' . $url;
151 AtEase::suppressWarnings();
152 $a = parse_url( $url );
153 AtEase::restoreWarnings();
157 $path = $a[
'path'] ??
'';
169 $router->
add(
"$wgScript/$1" );
171 if ( isset( $_SERVER[
'SCRIPT_NAME'] )
172 && strpos( $_SERVER[
'SCRIPT_NAME'],
'.php' ) !==
false
177 $router->add( $_SERVER[
'SCRIPT_NAME'] .
"/$1" );
187 if ( $articlePaths ) {
188 $router->add( $articlePaths, [
'action' =>
'$key' ] );
194 [
'variant' =>
'$2' ],
195 [
'$2' => MediaWikiServices::getInstance()->getContentLanguage()->
200 Hooks::run(
'WebRequestPathInfoRouter', [ $router ] );
207 if ( !empty( $_SERVER[
'ORIG_PATH_INFO'] ) ) {
211 $matches[
'title'] = substr( $_SERVER[
'ORIG_PATH_INFO'], 1 );
212 } elseif ( !empty( $_SERVER[
'PATH_INFO'] ) ) {
214 $matches[
'title'] = substr( $_SERVER[
'PATH_INFO'], 1 );
232 $stdPort = $proto ===
'https' ? 443 : 80;
234 $varNames = [
'HTTP_HOST',
'SERVER_NAME',
'HOSTNAME',
'SERVER_ADDR' ];
237 foreach ( $varNames as $varName ) {
238 if ( !isset( $_SERVER[$varName] ) ) {
254 } elseif ( $parts[1] ===
false ) {
255 if ( isset( $_SERVER[
'SERVER_PORT'] ) ) {
256 $port = $_SERVER[
'SERVER_PORT'];
275 if ( ( !empty( $_SERVER[
'HTTPS'] ) && $_SERVER[
'HTTPS'] !==
'off' ) ||
276 ( isset( $_SERVER[
'HTTP_X_FORWARDED_PROTO'] ) &&
277 $_SERVER[
'HTTP_X_FORWARDED_PROTO'] ===
'https' ) ) {
306 if ( self::$reqId ) {
339 if ( $this->protocol ===
null ) {
354 if ( defined(
'MW_API' ) ) {
359 foreach (
$matches as $key => $val ) {
360 $this->data[$key] = $this->queryAndPathParams[$key] = $val;
375 foreach ( (array)$bases as $keyValue =>
$base ) {
378 $baseLen = strlen(
$base );
379 if ( substr(
$path, 0, $baseLen ) ==
$base ) {
380 $raw = substr(
$path, $baseLen );
382 $matches = [
'title' => rawurldecode( $raw ) ];
401 if ( is_array(
$data ) ) {
402 foreach (
$data as $key => $val ) {
406 $contLang = MediaWikiServices::getInstance()->getContentLanguage();
407 $data = $contLang ? $contLang->normalize(
$data ) :
408 UtfNormal\Validator::cleanUp(
$data );
422 # PHP is so nice to not touch input data, except sometimes:
423 # https://www.php.net/variables.external#language.variables.external.dot-in-names
424 # Work around PHP *feature* to avoid *bugs* elsewhere.
425 $name = strtr( $name,
'.',
'_' );
427 if ( !isset( $arr[$name] ) ) {
432 # Optimisation: Skip UTF-8 normalization and legacy transcoding for simple ASCII strings.
433 $isAsciiStr = ( is_string(
$data ) && preg_match(
'/[^\x20-\x7E]/',
$data ) === 0 );
434 if ( !$isAsciiStr ) {
435 if ( isset( $_GET[$name] ) && is_string(
$data ) ) {
436 # Check for alternate/legacy character encoding.
437 $data = MediaWikiServices::getInstance()
438 ->getContentLanguage()
439 ->checkTitleEncoding(
$data );
460 $name = strtr( $name,
'.',
'_' );
461 if ( isset( $this->data[$name] ) && !is_array( $this->data[$name] ) ) {
462 $val = $this->data[$name];
466 if ( is_null( $val ) ) {
483 public function getVal( $name, $default =
null ) {
484 $val = $this->
getGPCVal( $this->data, $name, $default );
485 if ( is_array( $val ) ) {
488 if ( is_null( $val ) ) {
503 $ret = $this->data[$key] ??
null;
504 $this->data[$key] = $value;
515 if ( !isset( $this->data[$key] ) ) {
518 $ret = $this->data[$key];
519 unset( $this->data[$key] );
533 public function getArray( $name, $default =
null ) {
534 $val = $this->
getGPCVal( $this->data, $name, $default );
535 if ( is_null( $val ) ) {
553 $val = $this->
getArray( $name, $default );
554 if ( is_array( $val ) ) {
555 $val = array_map(
'intval', $val );
569 public function getInt( $name, $default = 0 ) {
570 return intval( $this->
getRawVal( $name, $default ) );
583 return is_numeric( $val )
598 public function getFloat( $name, $default = 0.0 ) {
599 return floatval( $this->
getRawVal( $name, $default ) );
611 public function getBool( $name, $default =
false ) {
612 return (
bool)$this->
getRawVal( $name, $default );
625 return $this->
getBool( $name, $default )
626 && strcasecmp( $this->
getRawVal( $name ),
'false' ) !== 0;
638 # Checkboxes and buttons are only present when clicked
639 # Presence connotes truth, absence false
640 return $this->
getRawVal( $name,
null ) !==
null;
653 public function getText( $name, $default =
'' ) {
654 $val = $this->
getVal( $name, $default );
655 return str_replace(
"\r\n",
"\n", $val );
666 $names = func_get_args();
667 if ( count( $names ) == 0 ) {
668 $names = array_keys( $this->data );
672 foreach ( $names as $name ) {
673 $value = $this->
getGPCVal( $this->data, $name,
null );
674 if ( !is_null( $value ) ) {
675 $retVal[$name] = $value;
688 return array_diff( array_keys( $this->
getValues() ), $exclude );
735 return $_SERVER[
'QUERY_STRING'];
759 static $input =
null;
760 if ( $input ===
null ) {
761 $input = file_get_contents(
'php://input' );
772 return $_SERVER[
'REQUEST_METHOD'] ??
'GET';
799 if ( $this->sessionId !==
null ) {
800 $session = SessionManager::singleton()->getSessionById( (
string)$this->sessionId,
true, $this );
806 $session = SessionManager::singleton()->getSessionForRequest( $this );
807 $this->sessionId = $session->getSessionId();
839 public function getCookie( $key, $prefix =
null, $default =
null ) {
840 if ( $prefix ===
null ) {
844 return $this->
getGPCVal( $_COOKIE, $prefix . $key, $default );
857 if ( isset( $_SERVER[
'REQUEST_URI'] ) && strlen( $_SERVER[
'REQUEST_URI'] ) ) {
858 $base = $_SERVER[
'REQUEST_URI'];
859 } elseif ( isset( $_SERVER[
'HTTP_X_ORIGINAL_URL'] )
860 && strlen( $_SERVER[
'HTTP_X_ORIGINAL_URL'] )
863 $base = $_SERVER[
'HTTP_X_ORIGINAL_URL'];
864 } elseif ( isset( $_SERVER[
'SCRIPT_NAME'] ) ) {
865 $base = $_SERVER[
'SCRIPT_NAME'];
866 if ( isset( $_SERVER[
'QUERY_STRING'] ) && $_SERVER[
'QUERY_STRING'] !=
'' ) {
867 $base .=
'?' . $_SERVER[
'QUERY_STRING'];
871 throw new MWException(
"Web server doesn't provide either " .
872 "REQUEST_URI, HTTP_X_ORIGINAL_URL or SCRIPT_NAME. Report details " .
873 "of your web server configuration to https://phabricator.wikimedia.org/" );
879 $hash = strpos(
$base,
'#' );
880 if ( $hash !==
false ) {
884 if (
$base[0] ==
'/' ) {
886 return preg_replace(
'!^/+!',
'/',
$base );
889 return preg_replace(
'!^[^:]+://[^/]+/+!',
'/',
$base );
942 unset( $newquery[
'title'] );
943 $newquery = array_merge( $newquery, $array );
960 $limit = $this->
getInt(
'limit', 0 );
964 if ( ( $limit == 0 ) && ( $optionname !=
'' ) ) {
965 $limit = $wgUser->getIntOption( $optionname );
970 if ( $limit > 5000 ) {
971 $limit = 5000; # We have *some* limits...
974 $offset = $this->
getInt(
'offset', 0 );
979 return [ $limit, $offset ];
990 return $file->getTempName();
1001 return $file->getError();
1017 return $file->getName();
1038 if ( !is_object( $this->
response ) ) {
1039 $class = ( $this instanceof
FauxRequest ) ? FauxResponse::class : WebResponse::class;
1049 if ( count( $this->headers ) ) {
1053 $apacheHeaders = function_exists(
'apache_request_headers' ) ? apache_request_headers() :
false;
1054 if ( $apacheHeaders ) {
1055 foreach ( $apacheHeaders as $tempName => $tempValue ) {
1056 $this->headers[strtoupper( $tempName )] = $tempValue;
1059 foreach ( $_SERVER as $name => $value ) {
1060 if ( substr( $name, 0, 5 ) ===
'HTTP_' ) {
1061 $name = str_replace(
'_',
'-', substr( $name, 5 ) );
1062 $this->headers[$name] = $value;
1063 } elseif ( $name ===
'CONTENT_LENGTH' ) {
1064 $this->headers[
'CONTENT-LENGTH'] = $value;
1094 $name = strtoupper( $name );
1095 if ( !isset( $this->headers[$name] ) ) {
1098 $value = $this->headers[$name];
1099 if ( $flags & self::GETHEADER_LIST ) {
1100 $value = array_map(
'trim', explode(
',', $value ) );
1138 $extWhitelist[] =
'php';
1143 if ( $newUrl !==
false ) {
1149 'Invalid file extension found in the path info or query string.' );
1162 header(
'Location: ' . $url );
1163 header(
'Content-Type: text/html' );
1164 $encUrl = htmlspecialchars( $url );
1169 <title>Security redirect</title>
1172 <h1>Security redirect</h1>
1174 We can
't serve non-HTML content from the URL you have requested, because
1175 Internet Explorer would interpret it as an incorrect and potentially dangerous
1177 <p>Instead, please use <a href="$encUrl">this URL</a>, which is the same as the
1178 URL you have requested, except that "&*" is appended. This prevents Internet
1179 Explorer from seeing a bogus file extension.
1197 public function getAcceptLang() {
1198 // Modified version of code found at
1199 // http://www.thefutureoftheweb.com/blog/use-accept-language-header
1200 $acceptLang = $this->getHeader( 'Accept-
Language' );
1201 if ( !$acceptLang ) {
1205 // Return the language codes in lower case
1206 $acceptLang = strtolower( $acceptLang );
1208 // Break up string into pieces (languages and q factors)
1211 '/([a-z]{1,8}(-[a-z]{1,8})*|\*)\s*(;\s*q\s*=\s*(1(\.0{0,3})?|0(\.[0-9]{0,3})?)?)?/
',
1216 if ( !count( $lang_parse[1] ) ) {
1220 $langcodes = $lang_parse[1];
1221 $qvalues = $lang_parse[4];
1222 $indices = range( 0, count( $lang_parse[1] ) - 1 );
1224 // Set default q factor to 1
1225 foreach ( $indices as $index ) {
1226 if ( $qvalues[$index] === '' ) {
1227 $qvalues[$index] = 1;
1228 } elseif ( $qvalues[$index] == 0 ) {
1229 unset( $langcodes[$index], $qvalues[$index], $indices[$index] );
1233 // Sort list. First by $qvalues, then by order. Reorder $langcodes the same way
1234 array_multisort( $qvalues, SORT_DESC, SORT_NUMERIC, $indices, $langcodes );
1236 // Create a list like "en" => 0.8
1237 $langs = array_combine( $langcodes, $qvalues );
1250 protected function getRawIP() {
1251 if ( !isset( $_SERVER['REMOTE_ADDR
'] ) ) {
1255 if ( is_array( $_SERVER['REMOTE_ADDR
'] ) || strpos( $_SERVER['REMOTE_ADDR
'], ',
' ) !== false ) {
1256 throw new MWException( __METHOD__
1257 . " : Could not determine the remote IP address due to multiple values." );
1259 $ipchain = $_SERVER['REMOTE_ADDR
'];
1262 return IP::canonicalize( $ipchain );
1274 public function getIP() {
1275 global $wgUsePrivateIPs;
1277 # Return cached result
1278 if ( $this->ip !== null ) {
1282 # collect the originating ips
1283 $ip = $this->getRawIP();
1285 throw new MWException( 'Unable to determine
IP.
' );
1289 $forwardedFor = $this->getHeader( 'X-Forwarded-For
' );
1290 if ( $forwardedFor !== false ) {
1291 $proxyLookup = MediaWikiServices::getInstance()->getProxyLookup();
1292 $isConfigured = $proxyLookup->isConfiguredProxy( $ip );
1293 $ipchain = array_map( 'trim
', explode( ',
', $forwardedFor ) );
1294 $ipchain = array_reverse( $ipchain );
1295 array_unshift( $ipchain, $ip );
1297 # Step through XFF list and find the last address in the list which is a
1298 # trusted server. Set $ip to the IP address given by that trusted server,
1299 # unless the address is not sensible (e.g. private). However, prefer private
1300 # IP addresses over proxy servers controlled by this site (more sensible).
1301 # Note that some XFF values might be "unknown" with Squid/Varnish.
1302 foreach ( $ipchain as $i => $curIP ) {
1303 $curIP = IP::sanitizeIP( IP::canonicalize( $curIP ) );
1304 if ( !$curIP || !isset( $ipchain[$i + 1] ) || $ipchain[$i + 1] === 'unknown
'
1305 || !$proxyLookup->isTrustedProxy( $curIP )
1307 break; // IP is not valid/trusted or does not point to anything
1310 IP::isPublic( $ipchain[$i + 1] ) ||
1312 $proxyLookup->isConfiguredProxy( $curIP ) // T50919; treat IP as sane
1314 // Follow the next IP according to the proxy
1315 $nextIP = IP::canonicalize( $ipchain[$i + 1] );
1316 if ( !$nextIP && $isConfigured ) {
1317 // We have not yet made it past CDN/proxy servers of this site,
1318 // so either they are misconfigured or there is some IP spoofing.
1319 throw new MWException( "Invalid IP given in XFF '$forwardedFor
'." );
1322 // keep traversing the chain
1329 # Allow extensions to improve our guess
1330 Hooks::run( 'GetIP
', [ &$ip ] );
1333 throw new MWException( "Unable to determine IP." );
1336 wfDebug( "IP: $ip\n" );
1346 public function setIP( $ip ) {
1362 public function hasSafeMethod() {
1363 if ( !isset( $_SERVER['REQUEST_METHOD
'] ) ) {
1364 return false; // CLI mode
1367 return in_array( $_SERVER['REQUEST_METHOD
'], [ 'GET
', 'HEAD
', 'OPTIONS
', 'TRACE
' ] );
1388 public function isSafeRequest() {
1389 if ( $this->markedAsSafe && $this->wasPosted() ) {
1390 return true; // marked as a "safe" POST
1393 return $this->hasSafeMethod();
1406 public function markAsSafeRequest() {
1407 $this->markedAsSafe = true;
add( $path, $params=[], $options=[])
Add a new path pattern to the path router.
initHeaders()
Initialise the header list.
SessionId null $sessionId
Session ID to use for this request.
WebRequest clone which takes values from a provided array.
getSessionData( $key)
Get data from the session.
array $headers
Lazy-initialized request headers indexed by upper-case header name.
getValueNames( $exclude=[])
Returns the names of all input values excluding those in $exclude.
static combineHostAndPort( $host, $port, $defaultPort=false)
Given a host name and a port, combine them into host/port string like you might find in a URL.
array $data
The parameters from $_GET, $_POST and the path router.
getSessionId()
Get the session id for this request, if any.
$wgScript
The URL path to index.php.
$queryParams
The parameters from $_GET only.
appendQueryValue( $key, $value)
interpolateTitle()
Check for title, action, and/or variant data in the URL and interpolate it into the GET variables.
setSessionId(SessionId $sessionId)
Set the session for this request.
getElapsedTime()
Get the number of seconds to have elapsed since request start, in fractional seconds,...
getIntOrNull( $name)
Fetch an integer value from the input or return null if empty.
A collection of public static functions to play with IP address and IP ranges.
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
getRawPostString()
Return the contents of the POST with no decoding.
static detectProtocol()
Detect the protocol from $_SERVER.
getGPCVal( $arr, $name, $default)
Fetch a value from the given array or return $default if it's not set.
Show an error that looks like an HTTP server error.
getRawQueryString()
Return the contents of the Query with no decoding.
appendQueryArray( $array)
Appends or replaces value of query variables.
$wgAllowExternalReqID
Whether to respect/honour the request ID provided by the incoming request via the X-Request-Id header...
static getActionPaths(array $actionPaths, $articlePath)
getFileTempname( $key)
Return the path to the temporary file where PHP has stored the upload.
bool $wgAssumeProxiesUseDefaultProtocolPorts
When the wiki is running behind a proxy and this is set to true, assumes that the proxy exposes the w...
getText( $name, $default='')
Fetch a text string from the given array or return $default if it's not set.
string $protocol
Cached URL protocol.
getMethod()
Get the HTTP method used for this request.
getFileName( $key)
Return the original filename of the uploaded file, as reported by the submitting user agent.
getQueryValuesOnly()
Get the values passed in the query string only, not including the path router parameters.
setVal( $key, $value)
Set an arbitrary value into our get/post data.
static string $reqId
The unique request ID.
getRawInput()
Return the raw request body, with no processing.
getUpload( $key)
Return a WebRequestUpload object corresponding to the key.
getValues()
Extracts the given named values into an array.
static getPathInfo( $want='all')
Extract relevant query arguments from the http request uri's path to be merged with the normal php pr...
getFullRequestURL()
Return the request URI with the canonical service and hostname, path, and query string.
getArray( $name, $default=null)
Fetch an array from the input or return $default if it's not set.
WebResponse $response
Lazy-init response object.
getAllHeaders()
Get an array containing all request headers.
Object to access the $_FILES array.
normalizeUnicode( $data)
Recursively normalizes UTF-8 strings in the given array.
getRawVal( $name, $default=null)
Fetch a scalar from the input without normalization, or return $default if it's not set.
static areServerVarsBad( $vars, $extWhitelist=[])
Check a subset of $_SERVER (or the whole of $_SERVER if you like) to see if it indicates that the req...
getCheck( $name)
Return true if the named value is set in the input, whatever that value is (even "0").
getProtocol()
Get the current URL protocol (http or https)
getSession()
Return the session for this request.
response()
Return a handle to WebResponse style object, for setting cookies, headers and other stuff,...
static splitHostAndPort( $both)
Given a host/port string, like one might find in the host part of a URL per RFC 2732,...
getLimitOffset( $deflimit=50, $optionname='rclimit')
Check for limit and offset parameters on the input, and return sensible defaults if not given.
checkUrlExtension( $extWhitelist=[])
Check if Internet Explorer will detect an incorrect cache extension in PATH_INFO or QUERY_STRING.
getIntArray( $name, $default=null)
Fetch an array of integers, or return $default if it's not set.
float $requestTime
The timestamp of the start of the request, with microsecond precision.
static fixUrlForIE6( $url, $extWhitelist=[])
Returns a variant of $url which will pass isUrlExtensionBad() but has the same GET parameters,...
static getMain()
Get the RequestContext object associated with the main request.
bool $markedAsSafe
Whether this HTTP request is "safe" (even if it is an HTTP post)
getCookie( $key, $prefix=null, $default=null)
Get a cookie from the $_COOKIE jar.
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form stripping il...
getUploadError( $key)
Return the upload error or 0.
array $queryAndPathParams
The parameters from $_GET.
setSessionData( $key, $data)
Set session data.
doSecurityRedirect( $url)
Attempt to redirect to a URL with a QUERY_STRING that's not dangerous in IE 6.
const GETHEADER_LIST
Flag to make WebRequest::getHeader return an array of values.
getVal( $name, $default=null)
Fetch a scalar from the input or return $default if it's not set.
getInt( $name, $default=0)
Fetch an integer value from the input or return $default if not set.
static getRequestId()
Get the unique request ID.
getFloat( $name, $default=0.0)
Fetch a floating point value from the input or return $default if not set.
static detectServer()
Work out an appropriate URL prefix containing scheme and host, based on information detected from $_S...
getHeader( $name, $flags=0)
Get a request header, or false if it isn't set.
static getGlobalRequestURL()
Return the path and query string portion of the main request URI.
string $ip
Cached client IP address.
getPostValues()
Get the values passed via POST.
wasPosted()
Returns true if the present request was reached by a POST operation, false otherwise (GET,...
unsetVal( $key)
Unset an arbitrary value from our get/post data.
wfGetServerUrl( $proto)
Get the wiki's "server", i.e.
getRequestURL()
Return the path and query string portion of the request URI.
static overrideRequestId( $id)
Override the unique request ID.
static extractTitle( $path, $bases, $key=false)
URL rewriting function; tries to extract page title and, optionally, one other fixed parameter value ...
Allow programs to request this object from WebRequest::response() and handle all outputting (or lack ...
getQueryValues()
Get the values passed in the query string and the path router parameters.
getFuzzyBool( $name, $default=false)
Fetch a boolean value from the input or return $default if not set.
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
$wgVariantArticlePath
Like $wgArticlePath, but on multi-variant wikis, this provides a path format that describes which par...
$wgCookiePrefix
Cookies generated by MediaWiki have names starting with this prefix.
Internationalisation code.
getBool( $name, $default=false)
Fetch a boolean value from the input or return $default if not set.
$wgUsePathInfo
Whether to support URLs like index.php/Page_title These often break when PHP is set up in CGI mode.
wfArrayToCgi( $array1, $array2=null, $prefix='')
This function takes one or two arrays as input, and returns a CGI-style string, e....
wfRandomString( $length=32)
Get a random string containing a number of pseudo-random hex characters.