85 protected $markedAsSafe =
false;
91 $this->requestTime = $_SERVER[
'REQUEST_TIME_FLOAT'];
95 $this->data = $_POST + $_GET;
119 if ( !empty( $_SERVER[
'REQUEST_URI'] ) ) {
121 $url = $_SERVER[
'REQUEST_URI'];
122 if ( !preg_match(
'!^https?://!', $url ) ) {
123 $url =
'http://unused' . $url;
125 Wikimedia\suppressWarnings();
126 $a = parse_url( $url );
127 Wikimedia\restoreWarnings();
129 $path = isset( $a[
'path'] ) ? $a[
'path'] :
'';
132 if ( $path ==
$wgScript && $want !==
'all' ) {
141 $router->
add(
"$wgScript/$1" );
143 if ( isset( $_SERVER[
'SCRIPT_NAME'] )
144 && preg_match(
'/\.php/', $_SERVER[
'SCRIPT_NAME'] )
146 # Check for SCRIPT_NAME, we handle index.php explicitly
147 # But we do have some other .php files such as img_auth.php
148 # Don't let root article paths clober the parsing for them
149 $router->add( $_SERVER[
'SCRIPT_NAME'] .
"/$1" );
165 [
'variant' =>
'$2' ],
170 Hooks::run(
'WebRequestPathInfoRouter', [ $router ] );
175 if ( isset( $_SERVER[
'ORIG_PATH_INFO'] ) && $_SERVER[
'ORIG_PATH_INFO'] !=
'' ) {
179 $matches[
'title'] = substr( $_SERVER[
'ORIG_PATH_INFO'], 1 );
181 } elseif ( isset( $_SERVER[
'PATH_INFO'] ) && $_SERVER[
'PATH_INFO'] !=
'' ) {
183 $matches[
'title'] = substr( $_SERVER[
'PATH_INFO'], 1 );
199 $proto = self::detectProtocol();
200 $stdPort = $proto ===
'https' ? 443 : 80;
202 $varNames = [
'HTTP_HOST',
'SERVER_NAME',
'HOSTNAME',
'SERVER_ADDR' ];
205 foreach ( $varNames as $varName ) {
206 if ( !isset( $_SERVER[$varName] ) ) {
210 $parts = IP::splitHostAndPort( $_SERVER[$varName] );
222 } elseif ( $parts[1] ===
false ) {
223 if ( isset( $_SERVER[
'SERVER_PORT'] ) ) {
224 $port = $_SERVER[
'SERVER_PORT'];
232 return $proto .
'://' . IP::combineHostAndPort( $host, $port, $stdPort );
243 if ( ( !empty( $_SERVER[
'HTTPS'] ) && $_SERVER[
'HTTPS'] !==
'off' ) ||
244 ( isset( $_SERVER[
'HTTP_X_FORWARDED_PROTO'] ) &&
245 $_SERVER[
'HTTP_X_FORWARDED_PROTO'] ===
'https' ) ) {
260 return microtime(
true ) - $this->requestTime;
274 if ( !self::$reqId ) {
275 self::$reqId = isset( $_SERVER[
'UNIQUE_ID'] )
298 if ( $this->protocol ===
null ) {
299 $this->protocol = self::detectProtocol();
301 return $this->protocol;
313 if ( defined(
'MW_API' ) ) {
317 $matches = self::getPathInfo(
'title' );
318 foreach (
$matches as $key => $val ) {
319 $this->data[$key] = $_GET[$key] = $_REQUEST[$key] = $val;
334 foreach ( (array)$bases as $keyValue =>
$base ) {
337 $baseLen = strlen(
$base );
338 if ( substr( $path, 0, $baseLen ) ==
$base ) {
339 $raw = substr( $path, $baseLen );
341 $matches = [
'title' => rawurldecode( $raw ) ];
360 if ( is_array(
$data ) ) {
361 foreach (
$data as $key => $val ) {
368 UtfNormal\Validator::cleanUp(
$data );
382 # PHP is so nice to not touch input data, except sometimes:
384 # Work around PHP *feature* to avoid *bugs* elsewhere.
385 $name = strtr( $name,
'.',
'_' );
386 if ( isset( $arr[$name] ) ) {
389 if ( isset( $_GET[$name] ) && !is_array(
$data ) ) {
390 # Check for alternate/legacy character encoding.
415 $name = strtr( $name,
'.',
'_' );
416 if ( isset( $this->data[$name] ) && !is_array( $this->data[$name] ) ) {
417 $val = $this->data[
$name];
421 if ( is_null( $val ) ) {
438 public function getVal( $name, $default =
null ) {
439 $val = $this->
getGPCVal( $this->data, $name, $default );
440 if ( is_array( $val ) ) {
443 if ( is_null( $val ) ) {
458 $ret = isset( $this->data[$key] ) ? $this->data[$key] :
null;
459 $this->data[$key] =
$value;
470 if ( !isset( $this->data[$key] ) ) {
473 $ret = $this->data[$key];
474 unset( $this->data[$key] );
488 public function getArray( $name, $default =
null ) {
489 $val = $this->
getGPCVal( $this->data, $name, $default );
490 if ( is_null( $val ) ) {
508 $val = $this->
getArray( $name, $default );
509 if ( is_array( $val ) ) {
510 $val = array_map(
'intval', $val );
524 public function getInt( $name, $default = 0 ) {
525 return intval( $this->
getRawVal( $name, $default ) );
538 return is_numeric( $val )
553 public function getFloat( $name, $default = 0.0 ) {
554 return floatval( $this->
getRawVal( $name, $default ) );
566 public function getBool( $name, $default =
false ) {
567 return (
bool)$this->
getRawVal( $name, $default );
580 return $this->
getBool( $name, $default )
581 && strcasecmp( $this->
getRawVal( $name ),
'false' ) !== 0;
593 # Checkboxes and buttons are only present when clicked
594 # Presence connotes truth, absence false
595 return $this->
getRawVal( $name,
null ) !==
null;
608 public function getText( $name, $default =
'' ) {
609 $val = $this->
getVal( $name, $default );
610 return str_replace(
"\r\n",
"\n", $val );
621 $names = func_get_args();
622 if ( count( $names ) == 0 ) {
623 $names = array_keys( $this->data );
627 foreach ( $names as $name ) {
629 if ( !is_null(
$value ) ) {
643 return array_diff( array_keys( $this->
getValues() ), $exclude );
665 return $_SERVER[
'QUERY_STRING'];
691 $input = file_get_contents(
'php://input' );
702 return isset( $_SERVER[
'REQUEST_METHOD'] ) ? $_SERVER[
'REQUEST_METHOD'] :
'GET';
729 if ( $this->sessionId !==
null ) {
730 $session = SessionManager::singleton()->getSessionById( (
string)$this->sessionId,
true, $this );
736 $session = SessionManager::singleton()->getSessionForRequest( $this );
737 $this->sessionId = $session->getSessionId();
748 $this->sessionId = $sessionId;
758 return $this->sessionId;
769 public function getCookie( $key, $prefix =
null, $default =
null ) {
770 if ( $prefix ===
null ) {
774 $name = $prefix . $key;
776 $name = strtr( $name,
'.',
'_' );
777 if ( isset( $_COOKIE[$name] ) ) {
778 return $_COOKIE[
$name];
794 $name = $prefix . $key;
796 $name = strtr( $name,
'.',
'_' );
797 if ( isset( $_COOKIE[$name] ) ) {
798 return $_COOKIE[
$name];
801 $legacyName = $prefix .
"ss0-" . $key;
802 $legacyName = strtr( $legacyName,
'.',
'_' );
803 if ( isset( $_COOKIE[$legacyName] ) ) {
804 return $_COOKIE[$legacyName];
820 if ( isset( $_SERVER[
'REQUEST_URI'] ) && strlen( $_SERVER[
'REQUEST_URI'] ) ) {
821 $base = $_SERVER[
'REQUEST_URI'];
822 } elseif ( isset( $_SERVER[
'HTTP_X_ORIGINAL_URL'] )
823 && strlen( $_SERVER[
'HTTP_X_ORIGINAL_URL'] )
826 $base = $_SERVER[
'HTTP_X_ORIGINAL_URL'];
827 } elseif ( isset( $_SERVER[
'SCRIPT_NAME'] ) ) {
828 $base = $_SERVER[
'SCRIPT_NAME'];
829 if ( isset( $_SERVER[
'QUERY_STRING'] ) && $_SERVER[
'QUERY_STRING'] !=
'' ) {
830 $base .=
'?' . $_SERVER[
'QUERY_STRING'];
834 throw new MWException(
"Web server doesn't provide either " .
835 "REQUEST_URI, HTTP_X_ORIGINAL_URL or SCRIPT_NAME. Report details " .
836 "of your web server configuration to https://phabricator.wikimedia.org/" );
842 $hash = strpos(
$base,
'#' );
843 if ( $hash !==
false ) {
847 if (
$base[0] ==
'/' ) {
849 return preg_replace(
'!^/+!',
'/',
$base );
852 return preg_replace(
'!^[^:]+://[^/]+/+!',
'/',
$base );
864 return self::getGlobalRequestURL();
898 unset( $newquery[
'title'] );
899 $newquery = array_merge( $newquery, $array );
916 $limit = $this->
getInt(
'limit', 0 );
920 if ( ( $limit == 0 ) && ( $optionname !=
'' ) ) {
921 $limit =
$wgUser->getIntOption( $optionname );
926 if ( $limit > 5000 ) {
927 $limit = 5000; # We have *
some* limits...
930 $offset = $this->
getInt(
'offset', 0 );
935 return [ $limit, $offset ];
946 return $file->getTempName();
957 return $file->getError();
973 return $file->getName();
994 if ( !is_object( $this->
response ) ) {
995 $class = ( $this instanceof
FauxRequest ) ? FauxResponse::class : WebResponse::class;
1005 if ( count( $this->headers ) ) {
1009 $apacheHeaders = function_exists(
'apache_request_headers' ) ? apache_request_headers() :
false;
1010 if ( $apacheHeaders ) {
1011 foreach ( $apacheHeaders as $tempName => $tempValue ) {
1012 $this->headers[strtoupper( $tempName )] = $tempValue;
1015 foreach ( $_SERVER as $name =>
$value ) {
1016 if ( substr( $name, 0, 5 ) ===
'HTTP_' ) {
1017 $name = str_replace(
'_',
'-', substr( $name, 5 ) );
1019 } elseif ( $name ===
'CONTENT_LENGTH' ) {
1020 $this->headers[
'CONTENT-LENGTH'] =
$value;
1033 return $this->headers;
1050 $name = strtoupper( $name );
1051 if ( !isset( $this->headers[$name] ) ) {
1055 if ( $flags & self::GETHEADER_LIST ) {
1094 $extWhitelist[] =
'php';
1099 if ( $newUrl !==
false ) {
1105 'Invalid file extension found in the path info or query string.' );
1118 header(
'Location: ' . $url );
1119 header(
'Content-Type: text/html' );
1120 $encUrl = htmlspecialchars( $url );
1130We can
't serve non-HTML content from the URL you have requested, because
1131Internet Explorer would interpret it as an incorrect and potentially dangerous
1133<p>Instead, please use <a href="$encUrl">this URL</a>, which is the same as the
1134URL you have requested, except that "&*" is appended. This prevents Internet
1135Explorer from seeing a bogus file extension.
1153 public function getAcceptLang() {
1154 // Modified version of code found at
1155 // http://www.thefutureoftheweb.com/blog/use-accept-language-header
1156 $acceptLang = $this->getHeader( 'Accept-
Language' );
1157 if ( !$acceptLang ) {
1161 // Return the language codes in lower case
1162 $acceptLang = strtolower( $acceptLang );
1164 // Break up string into pieces (languages and q factors)
1167 '/([a-z]{1,8}(-[a-z]{1,8})*|\*)\s*(;\s*q\s*=\s*(1(\.0{0,3})?|0(\.[0-9]{0,3})?)?)?/
',
1172 if ( !count( $lang_parse[1] ) ) {
1176 $langcodes = $lang_parse[1];
1177 $qvalues = $lang_parse[4];
1178 $indices = range( 0, count( $lang_parse[1] ) - 1 );
1180 // Set default q factor to 1
1181 foreach ( $indices as $index ) {
1182 if ( $qvalues[$index] === '' ) {
1183 $qvalues[$index] = 1;
1184 } elseif ( $qvalues[$index] == 0 ) {
1185 unset( $langcodes[$index], $qvalues[$index], $indices[$index] );
1189 // Sort list. First by $qvalues, then by order. Reorder $langcodes the same way
1190 array_multisort( $qvalues, SORT_DESC, SORT_NUMERIC, $indices, $langcodes );
1192 // Create a list like "en" => 0.8
1193 $langs = array_combine( $langcodes, $qvalues );
1206 protected function getRawIP() {
1207 if ( !isset( $_SERVER['REMOTE_ADDR
'] ) ) {
1211 if ( is_array( $_SERVER['REMOTE_ADDR
'] ) || strpos( $_SERVER['REMOTE_ADDR
'], ',
' ) !== false ) {
1212 throw new MWException( __METHOD__
1213 . " : Could not determine the remote IP address due to multiple values." );
1215 $ipchain = $_SERVER['REMOTE_ADDR
'];
1218 return IP::canonicalize( $ipchain );
1230 public function getIP() {
1231 global $wgUsePrivateIPs;
1233 # Return cached result
1234 if ( $this->ip !== null ) {
1238 # collect the originating ips
1239 $ip = $this->getRawIP();
1241 throw new MWException( 'Unable to determine
IP.
' );
1245 $forwardedFor = $this->getHeader( 'X-Forwarded-For
' );
1246 if ( $forwardedFor !== false ) {
1247 $proxyLookup = MediaWikiServices::getInstance()->getProxyLookup();
1248 $isConfigured = $proxyLookup->isConfiguredProxy( $ip );
1249 $ipchain = array_map( 'trim
', explode( ',
', $forwardedFor ) );
1250 $ipchain = array_reverse( $ipchain );
1251 array_unshift( $ipchain, $ip );
1253 # Step through XFF list and find the last address in the list which is a
1254 # trusted server. Set $ip to the IP address given by that trusted server,
1255 # unless the address is not sensible (e.g. private). However, prefer private
1256 # IP addresses over proxy servers controlled by this site (more sensible).
1257 # Note that some XFF values might be "unknown" with Squid/Varnish.
1258 foreach ( $ipchain as $i => $curIP ) {
1259 $curIP = IP::sanitizeIP( IP::canonicalize( $curIP ) );
1260 if ( !$curIP || !isset( $ipchain[$i + 1] ) || $ipchain[$i + 1] === 'unknown
'
1261 || !$proxyLookup->isTrustedProxy( $curIP )
1263 break; // IP is not valid/trusted or does not point to anything
1266 IP::isPublic( $ipchain[$i + 1] ) ||
1268 $proxyLookup->isConfiguredProxy( $curIP ) // T50919; treat IP as sane
1270 // Follow the next IP according to the proxy
1271 $nextIP = IP::canonicalize( $ipchain[$i + 1] );
1272 if ( !$nextIP && $isConfigured ) {
1273 // We have not yet made it past CDN/proxy servers of this site,
1274 // so either they are misconfigured or there is some IP spoofing.
1275 throw new MWException( "Invalid IP given in XFF '$forwardedFor
'." );
1278 // keep traversing the chain
1285 # Allow extensions to improve our guess
1286 Hooks::run( 'GetIP
', [ &$ip ] );
1289 throw new MWException( "Unable to determine IP." );
1292 wfDebug( "IP: $ip\n" );
1302 public function setIP( $ip ) {
1318 public function hasSafeMethod() {
1319 if ( !isset( $_SERVER['REQUEST_METHOD
'] ) ) {
1320 return false; // CLI mode
1323 return in_array( $_SERVER['REQUEST_METHOD
'], [ 'GET
', 'HEAD
', 'OPTIONS
', 'TRACE
' ] );
1344 public function isSafeRequest() {
1345 if ( $this->markedAsSafe && $this->wasPosted() ) {
1346 return true; // marked as a "safe" POST
1349 return $this->hasSafeMethod();
1362 public function markAsSafeRequest() {
1363 $this->markedAsSafe = true;
This list may contain false positives That usually means there is additional text with links below the first Each row contains links to the first and second redirect
$wgUsePathInfo
Whether to support URLs like index.php/Page_title These often break when PHP is set up in CGI mode.
$wgScript
The URL path to index.php.
bool $wgUseSameSiteLegacyCookies
If true, when a cross-site cookie with SameSite=None is sent, a legacy cookie with an "ss0" prefix wi...
bool $wgAssumeProxiesUseDefaultProtocolPorts
When the wiki is running behind a proxy and this is set to true, assumes that the proxy exposes the w...
$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.
wfRandomString( $length=32)
Get a random string containing a number of pseudo-random hex characters.
wfExpandUrl( $url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL.
wfArrayToCgi( $array1, $array2=null, $prefix='')
This function takes one or two arrays as input, and returns a CGI-style string, e....
WebRequest clone which takes values from a provided array.
Show an error that looks like an HTTP server error.
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...
static fixUrlForIE6( $url, $extWhitelist=[])
Returns a variant of $url which will pass isUrlExtensionBad() but has the same GET parameters,...
A collection of public static functions to play with IP address and IP ranges.
Internationalisation code.
add( $path, $params=[], $options=[])
Add a new path pattern to the path router.
Object to access the $_FILES array.
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form stripping il...
getIntOrNull( $name)
Fetch an integer value from the input or return null if empty.
getValueNames( $exclude=[])
Returns the names of all input values excluding those in $exclude.
bool $markedAsSafe
Whether this HTTP request is "safe" (even if it is an HTTP post)
getUpload( $key)
Return a WebRequestUpload object corresponding to the key.
string $protocol
Cached URL protocol.
getArray( $name, $default=null)
Fetch an array from the input or return $default if it's not set.
interpolateTitle()
Check for title, action, and/or variant data in the URL and interpolate it into the GET variables.
static detectProtocol()
Detect the protocol from $_SERVER.
getSession()
Return the session for this request.
getRawInput()
Return the raw request body, with no processing.
getRawQueryString()
Return the contents of the Query with no decoding.
getFileTempname( $key)
Return the path to the temporary file where PHP has stored the upload.
getVal( $name, $default=null)
Fetch a scalar from the input or return $default if it's not set.
getFloat( $name, $default=0.0)
Fetch a floating point value from the input or return $default if not set.
WebResponse $response
Lazy-init response object.
getUploadError( $key)
Return the upload error or 0.
getAllHeaders()
Get an array containing all request headers.
getFuzzyBool( $name, $default=false)
Fetch a boolean value from the input or return $default if not set.
getGPCVal( $arr, $name, $default)
Fetch a value from the given array or return $default if it's not set.
static getRequestId()
Get the unique request ID.
getProtocol()
Get the current URL protocol (http or https)
getMethod()
Get the HTTP method used for this request.
initHeaders()
Initialise the header list.
getBool( $name, $default=false)
Fetch a boolean value from the input or return $default if not set.
string $ip
Cached client IP address.
static getGlobalRequestURL()
Return the path and query string portion of the main request URI.
setVal( $key, $value)
Set an arbitrary value into our get/post data.
static string $reqId
The unique request ID.
getFullRequestURL()
Return the request URI with the canonical service and hostname, path, and query string.
checkUrlExtension( $extWhitelist=[])
Check if Internet Explorer will detect an incorrect cache extension in PATH_INFO or QUERY_STRING.
getElapsedTime()
Get the number of seconds to have elapsed since request start, in fractional seconds,...
float $requestTime
The timestamp of the start of the request, with microsecond precision.
getCrossSiteCookie( $key, $prefix='', $default=null)
Get a cookie set with SameSite=None possibly with a legacy fallback cookie.
getCheck( $name)
Return true if the named value is set in the input, whatever that value is (even "0").
appendQueryArray( $array)
Appends or replaces value of query variables.
static detectServer()
Work out an appropriate URL prefix containing scheme and host, based on information detected from $_S...
getSessionId()
Get the session id for this request, if any.
getRawPostString()
Return the contents of the POST with no decoding.
getQueryValues()
Get the values passed in the query string.
response()
Return a handle to WebResponse style object, for setting cookies, headers and other stuff,...
getInt( $name, $default=0)
Fetch an integer value from the input or return $default if not set.
wasPosted()
Returns true if the present request was reached by a POST operation, false otherwise (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.
getFileName( $key)
Return the original filename of the uploaded file, as reported by the submitting user agent.
const GETHEADER_LIST
Flag to make WebRequest::getHeader return an array of values.
getRawVal( $name, $default=null)
Fetch a scalar from the input without normalization, or return $default if it's not set.
getIntArray( $name, $default=null)
Fetch an array of integers, or return $default if it's not set.
appendQueryValue( $key, $value)
normalizeUnicode( $data)
Recursively normalizes UTF-8 strings in the given array.
static overrideRequestId( $id)
Override the unique request ID.
unsetVal( $key)
Unset an arbitrary value from our get/post data.
static getPathInfo( $want='all')
Extract relevant query arguments from the http request uri's path to be merged with the normal php pr...
SessionId null $sessionId
Session ID to use for this request.
setSessionId(SessionId $sessionId)
Set the session for this request.
getCookie( $key, $prefix=null, $default=null)
Get a cookie from the $_COOKIE jar.
getLimitOffset( $deflimit=50, $optionname='rclimit')
Check for limit and offset parameters on the input, and return sensible defaults if not given.
static extractTitle( $path, $bases, $key=false)
URL rewriting function; tries to extract page title and, optionally, one other fixed parameter value ...
getText( $name, $default='')
Fetch a text string from the given array or return $default if it's not set.
getRequestURL()
Return the path and query string portion of the request URI.
getHeader( $name, $flags=0)
Get a request header, or false if it isn't set.
getSessionData( $key)
Get data from the session.
getValues()
Extracts the given named values into an array.
Allow programs to request this object from WebRequest::response() and handle all outputting (or lack ...
this class mediates it Skin Encapsulates a look and feel for the wiki All of the functions that render HTML and make choices about how to render it are here and are called from various other places when and is meant to be subclassed with other skins that may override some of its functions The User object contains a reference to a and so rather than having a global skin object we just rely on the global User and get the skin with $wgUser and also has some character encoding functions and other locale stuff The current user interface language is instantiated as and the local content language as $wgContLang
I won t presume to tell you how to I m just describing the methods I chose to use for myself If you do choose to follow these it will probably be easier for you to collaborate with others on the but if you want to contribute without by all means do which work well I also use K &R brace matching style I know that s a religious issue for some
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
Allows to change the fields on the form that will be generated $name
this hook is for auditing only $response
if(is_array($mode)) switch( $mode) $input