MediaWiki REL1_33
WebRequest.php
Go to the documentation of this file.
1<?php
30
31// The point of this class is to be a wrapper around super globals
32// phpcs:disable MediaWiki.Usage.SuperGlobalsUsage.SuperGlobals
33
42 protected $data, $headers = [];
43
48 const GETHEADER_LIST = 1;
49
54 private static $reqId;
55
60 private $response;
61
66 private $ip;
67
72 protected $requestTime;
73
78 protected $protocol;
79
85 protected $sessionId = null;
86
88 protected $markedAsSafe = false;
89
93 public function __construct() {
94 $this->requestTime = $_SERVER['REQUEST_TIME_FLOAT'];
95
96 // POST overrides GET data
97 // We don't use $_REQUEST here to avoid interference from cookies...
98 $this->data = $_POST + $_GET;
99 }
100
116 public static function getPathInfo( $want = 'all' ) {
117 global $wgUsePathInfo;
118 // PATH_INFO is mangled due to https://bugs.php.net/bug.php?id=31892
119 // And also by Apache 2.x, double slashes are converted to single slashes.
120 // So we will use REQUEST_URI if possible.
121 $matches = [];
122 if ( !empty( $_SERVER['REQUEST_URI'] ) ) {
123 // Slurp out the path portion to examine...
124 $url = $_SERVER['REQUEST_URI'];
125 if ( !preg_match( '!^https?://!', $url ) ) {
126 $url = 'http://unused' . $url;
127 }
129 $a = parse_url( $url );
131 if ( $a ) {
132 $path = $a['path'] ?? '';
133
134 global $wgScript;
135 if ( $path == $wgScript && $want !== 'all' ) {
136 // Script inside a rewrite path?
137 // Abort to keep from breaking...
138 return $matches;
139 }
140
141 $router = new PathRouter;
142
143 // Raw PATH_INFO style
144 $router->add( "$wgScript/$1" );
145
146 if ( isset( $_SERVER['SCRIPT_NAME'] )
147 && preg_match( '/\.php/', $_SERVER['SCRIPT_NAME'] )
148 ) {
149 # Check for SCRIPT_NAME, we handle index.php explicitly
150 # But we do have some other .php files such as img_auth.php
151 # Don't let root article paths clober the parsing for them
152 $router->add( $_SERVER['SCRIPT_NAME'] . "/$1" );
153 }
154
155 global $wgArticlePath;
156 if ( $wgArticlePath ) {
157 $router->add( $wgArticlePath );
158 }
159
160 global $wgActionPaths;
161 if ( $wgActionPaths ) {
162 $router->add( $wgActionPaths, [ 'action' => '$key' ] );
163 }
164
166 if ( $wgVariantArticlePath ) {
167 $router->add( $wgVariantArticlePath,
168 [ 'variant' => '$2' ],
169 [ '$2' => MediaWikiServices::getInstance()->getContentLanguage()->
170 getVariants() ]
171 );
172 }
173
174 Hooks::run( 'WebRequestPathInfoRouter', [ $router ] );
175
176 $matches = $router->parse( $path );
177 }
178 } elseif ( $wgUsePathInfo ) {
179 if ( isset( $_SERVER['ORIG_PATH_INFO'] ) && $_SERVER['ORIG_PATH_INFO'] != '' ) {
180 // Mangled PATH_INFO
181 // https://bugs.php.net/bug.php?id=31892
182 // Also reported when ini_get('cgi.fix_pathinfo')==false
183 $matches['title'] = substr( $_SERVER['ORIG_PATH_INFO'], 1 );
184
185 } elseif ( isset( $_SERVER['PATH_INFO'] ) && $_SERVER['PATH_INFO'] != '' ) {
186 // Regular old PATH_INFO yay
187 $matches['title'] = substr( $_SERVER['PATH_INFO'], 1 );
188 }
189 }
190
191 return $matches;
192 }
193
200 public static function detectServer() {
202
203 $proto = self::detectProtocol();
204 $stdPort = $proto === 'https' ? 443 : 80;
205
206 $varNames = [ 'HTTP_HOST', 'SERVER_NAME', 'HOSTNAME', 'SERVER_ADDR' ];
207 $host = 'localhost';
208 $port = $stdPort;
209 foreach ( $varNames as $varName ) {
210 if ( !isset( $_SERVER[$varName] ) ) {
211 continue;
212 }
213
214 $parts = IP::splitHostAndPort( $_SERVER[$varName] );
215 if ( !$parts ) {
216 // Invalid, do not use
217 continue;
218 }
219
220 $host = $parts[0];
221 if ( $wgAssumeProxiesUseDefaultProtocolPorts && isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) ) {
222 // T72021: Assume that upstream proxy is running on the default
223 // port based on the protocol. We have no reliable way to determine
224 // the actual port in use upstream.
225 $port = $stdPort;
226 } elseif ( $parts[1] === false ) {
227 if ( isset( $_SERVER['SERVER_PORT'] ) ) {
228 $port = $_SERVER['SERVER_PORT'];
229 } // else leave it as $stdPort
230 } else {
231 $port = $parts[1];
232 }
233 break;
234 }
235
236 return $proto . '://' . IP::combineHostAndPort( $host, $port, $stdPort );
237 }
238
246 public static function detectProtocol() {
247 if ( ( !empty( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] !== 'off' ) ||
248 ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) &&
249 $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https' ) ) {
250 return 'https';
251 } else {
252 return 'http';
253 }
254 }
255
263 public function getElapsedTime() {
264 return microtime( true ) - $this->requestTime;
265 }
266
275 public static function getRequestId() {
276 // This method is called from various error handlers and should be kept simple.
277
278 if ( !self::$reqId ) {
279 self::$reqId = $_SERVER['UNIQUE_ID'] ?? wfRandomString( 24 );
280 }
281
282 return self::$reqId;
283 }
284
292 public static function overrideRequestId( $id ) {
293 self::$reqId = $id;
294 }
295
300 public function getProtocol() {
301 if ( $this->protocol === null ) {
302 $this->protocol = self::detectProtocol();
303 }
304 return $this->protocol;
305 }
306
314 public function interpolateTitle() {
315 // T18019: title interpolation on API queries is useless and sometimes harmful
316 if ( defined( 'MW_API' ) ) {
317 return;
318 }
319
320 $matches = self::getPathInfo( 'title' );
321 foreach ( $matches as $key => $val ) {
322 $this->data[$key] = $_GET[$key] = $_REQUEST[$key] = $val;
323 }
324 }
325
336 static function extractTitle( $path, $bases, $key = false ) {
337 foreach ( (array)$bases as $keyValue => $base ) {
338 // Find the part after $wgArticlePath
339 $base = str_replace( '$1', '', $base );
340 $baseLen = strlen( $base );
341 if ( substr( $path, 0, $baseLen ) == $base ) {
342 $raw = substr( $path, $baseLen );
343 if ( $raw !== '' ) {
344 $matches = [ 'title' => rawurldecode( $raw ) ];
345 if ( $key ) {
346 $matches[$key] = $keyValue;
347 }
348 return $matches;
349 }
350 }
351 }
352 return [];
353 }
354
362 public function normalizeUnicode( $data ) {
363 if ( is_array( $data ) ) {
364 foreach ( $data as $key => $val ) {
365 $data[$key] = $this->normalizeUnicode( $val );
366 }
367 } else {
368 $contLang = MediaWikiServices::getInstance()->getContentLanguage();
369 $data = $contLang ? $contLang->normalize( $data ) :
370 UtfNormal\Validator::cleanUp( $data );
371 }
372 return $data;
373 }
374
383 private function getGPCVal( $arr, $name, $default ) {
384 # PHP is so nice to not touch input data, except sometimes:
385 # https://secure.php.net/variables.external#language.variables.external.dot-in-names
386 # Work around PHP *feature* to avoid *bugs* elsewhere.
387 $name = strtr( $name, '.', '_' );
388 if ( isset( $arr[$name] ) ) {
389 $data = $arr[$name];
390 if ( isset( $_GET[$name] ) && is_string( $data ) ) {
391 # Check for alternate/legacy character encoding.
392 $contLang = MediaWikiServices::getInstance()->getContentLanguage();
393 $data = $contLang->checkTitleEncoding( $data );
394 }
395 $data = $this->normalizeUnicode( $data );
396 return $data;
397 } else {
398 return $default;
399 }
400 }
401
414 public function getRawVal( $name, $default = null ) {
415 $name = strtr( $name, '.', '_' ); // See comment in self::getGPCVal()
416 if ( isset( $this->data[$name] ) && !is_array( $this->data[$name] ) ) {
417 $val = $this->data[$name];
418 } else {
419 $val = $default;
420 }
421 if ( is_null( $val ) ) {
422 return $val;
423 } else {
424 return (string)$val;
425 }
426 }
427
438 public function getVal( $name, $default = null ) {
439 $val = $this->getGPCVal( $this->data, $name, $default );
440 if ( is_array( $val ) ) {
441 $val = $default;
442 }
443 if ( is_null( $val ) ) {
444 return $val;
445 } else {
446 return (string)$val;
447 }
448 }
449
457 public function setVal( $key, $value ) {
458 $ret = $this->data[$key] ?? null;
459 $this->data[$key] = $value;
460 return $ret;
461 }
462
469 public function unsetVal( $key ) {
470 if ( !isset( $this->data[$key] ) ) {
471 $ret = null;
472 } else {
473 $ret = $this->data[$key];
474 unset( $this->data[$key] );
475 }
476 return $ret;
477 }
478
488 public function getArray( $name, $default = null ) {
489 $val = $this->getGPCVal( $this->data, $name, $default );
490 if ( is_null( $val ) ) {
491 return null;
492 } else {
493 return (array)$val;
494 }
495 }
496
507 public function getIntArray( $name, $default = null ) {
508 $val = $this->getArray( $name, $default );
509 if ( is_array( $val ) ) {
510 $val = array_map( 'intval', $val );
511 }
512 return $val;
513 }
514
524 public function getInt( $name, $default = 0 ) {
525 return intval( $this->getRawVal( $name, $default ) );
526 }
527
536 public function getIntOrNull( $name ) {
537 $val = $this->getRawVal( $name );
538 return is_numeric( $val )
539 ? intval( $val )
540 : null;
541 }
542
553 public function getFloat( $name, $default = 0.0 ) {
554 return floatval( $this->getRawVal( $name, $default ) );
555 }
556
566 public function getBool( $name, $default = false ) {
567 return (bool)$this->getRawVal( $name, $default );
568 }
569
579 public function getFuzzyBool( $name, $default = false ) {
580 return $this->getBool( $name, $default )
581 && strcasecmp( $this->getRawVal( $name ), 'false' ) !== 0;
582 }
583
592 public function getCheck( $name ) {
593 # Checkboxes and buttons are only present when clicked
594 # Presence connotes truth, absence false
595 return $this->getRawVal( $name, null ) !== null;
596 }
597
608 public function getText( $name, $default = '' ) {
609 $val = $this->getVal( $name, $default );
610 return str_replace( "\r\n", "\n", $val );
611 }
612
620 public function getValues() {
621 $names = func_get_args();
622 if ( count( $names ) == 0 ) {
623 $names = array_keys( $this->data );
624 }
625
626 $retVal = [];
627 foreach ( $names as $name ) {
628 $value = $this->getGPCVal( $this->data, $name, null );
629 if ( !is_null( $value ) ) {
630 $retVal[$name] = $value;
631 }
632 }
633 return $retVal;
634 }
635
642 public function getValueNames( $exclude = [] ) {
643 return array_diff( array_keys( $this->getValues() ), $exclude );
644 }
645
653 public function getQueryValues() {
654 return $_GET;
655 }
656
665 public function getPostValues() {
666 return $_POST;
667 }
668
676 public function getRawQueryString() {
677 return $_SERVER['QUERY_STRING'];
678 }
679
686 public function getRawPostString() {
687 if ( !$this->wasPosted() ) {
688 return '';
689 }
690 return $this->getRawInput();
691 }
692
700 public function getRawInput() {
701 static $input = null;
702 if ( $input === null ) {
703 $input = file_get_contents( 'php://input' );
704 }
705 return $input;
706 }
707
713 public function getMethod() {
714 return $_SERVER['REQUEST_METHOD'] ?? 'GET';
715 }
716
726 public function wasPosted() {
727 return $this->getMethod() == 'POST';
728 }
729
740 public function getSession() {
741 if ( $this->sessionId !== null ) {
742 $session = SessionManager::singleton()->getSessionById( (string)$this->sessionId, true, $this );
743 if ( $session ) {
744 return $session;
745 }
746 }
747
748 $session = SessionManager::singleton()->getSessionForRequest( $this );
749 $this->sessionId = $session->getSessionId();
750 return $session;
751 }
752
759 public function setSessionId( SessionId $sessionId ) {
760 $this->sessionId = $sessionId;
761 }
762
769 public function getSessionId() {
770 return $this->sessionId;
771 }
772
781 public function getCookie( $key, $prefix = null, $default = null ) {
782 if ( $prefix === null ) {
783 global $wgCookiePrefix;
784 $prefix = $wgCookiePrefix;
785 }
786 return $this->getGPCVal( $_COOKIE, $prefix . $key, $default );
787 }
788
796 public static function getGlobalRequestURL() {
797 // This method is called on fatal errors; it should not depend on anything complex.
798
799 if ( isset( $_SERVER['REQUEST_URI'] ) && strlen( $_SERVER['REQUEST_URI'] ) ) {
800 $base = $_SERVER['REQUEST_URI'];
801 } elseif ( isset( $_SERVER['HTTP_X_ORIGINAL_URL'] )
802 && strlen( $_SERVER['HTTP_X_ORIGINAL_URL'] )
803 ) {
804 // Probably IIS; doesn't set REQUEST_URI
805 $base = $_SERVER['HTTP_X_ORIGINAL_URL'];
806 } elseif ( isset( $_SERVER['SCRIPT_NAME'] ) ) {
807 $base = $_SERVER['SCRIPT_NAME'];
808 if ( isset( $_SERVER['QUERY_STRING'] ) && $_SERVER['QUERY_STRING'] != '' ) {
809 $base .= '?' . $_SERVER['QUERY_STRING'];
810 }
811 } else {
812 // This shouldn't happen!
813 throw new MWException( "Web server doesn't provide either " .
814 "REQUEST_URI, HTTP_X_ORIGINAL_URL or SCRIPT_NAME. Report details " .
815 "of your web server configuration to https://phabricator.wikimedia.org/" );
816 }
817 // User-agents should not send a fragment with the URI, but
818 // if they do, and the web server passes it on to us, we
819 // need to strip it or we get false-positive redirect loops
820 // or weird output URLs
821 $hash = strpos( $base, '#' );
822 if ( $hash !== false ) {
823 $base = substr( $base, 0, $hash );
824 }
825
826 if ( $base[0] == '/' ) {
827 // More than one slash will look like it is protocol relative
828 return preg_replace( '!^/+!', '/', $base );
829 } else {
830 // We may get paths with a host prepended; strip it.
831 return preg_replace( '!^[^:]+://[^/]+/+!', '/', $base );
832 }
833 }
834
842 public function getRequestURL() {
843 return self::getGlobalRequestURL();
844 }
845
856 public function getFullRequestURL() {
857 return wfGetServerUrl( PROTO_CURRENT ) . $this->getRequestURL();
858 }
859
865 public function appendQueryValue( $key, $value ) {
866 return $this->appendQueryArray( [ $key => $value ] );
867 }
868
875 public function appendQueryArray( $array ) {
876 $newquery = $this->getQueryValues();
877 unset( $newquery['title'] );
878 $newquery = array_merge( $newquery, $array );
879
880 return wfArrayToCgi( $newquery );
881 }
882
892 public function getLimitOffset( $deflimit = 50, $optionname = 'rclimit' ) {
893 global $wgUser;
894
895 $limit = $this->getInt( 'limit', 0 );
896 if ( $limit < 0 ) {
897 $limit = 0;
898 }
899 if ( ( $limit == 0 ) && ( $optionname != '' ) ) {
900 $limit = $wgUser->getIntOption( $optionname );
901 }
902 if ( $limit <= 0 ) {
903 $limit = $deflimit;
904 }
905 if ( $limit > 5000 ) {
906 $limit = 5000; # We have *some* limits...
907 }
908
909 $offset = $this->getInt( 'offset', 0 );
910 if ( $offset < 0 ) {
911 $offset = 0;
912 }
913
914 return [ $limit, $offset ];
915 }
916
923 public function getFileTempname( $key ) {
924 $file = new WebRequestUpload( $this, $key );
925 return $file->getTempName();
926 }
927
934 public function getUploadError( $key ) {
935 $file = new WebRequestUpload( $this, $key );
936 return $file->getError();
937 }
938
950 public function getFileName( $key ) {
951 $file = new WebRequestUpload( $this, $key );
952 return $file->getName();
953 }
954
961 public function getUpload( $key ) {
962 return new WebRequestUpload( $this, $key );
963 }
964
971 public function response() {
972 /* Lazy initialization of response object for this request */
973 if ( !is_object( $this->response ) ) {
974 $class = ( $this instanceof FauxRequest ) ? FauxResponse::class : WebResponse::class;
975 $this->response = new $class();
976 }
977 return $this->response;
978 }
979
983 protected function initHeaders() {
984 if ( count( $this->headers ) ) {
985 return;
986 }
987
988 $apacheHeaders = function_exists( 'apache_request_headers' ) ? apache_request_headers() : false;
989 if ( $apacheHeaders ) {
990 foreach ( $apacheHeaders as $tempName => $tempValue ) {
991 $this->headers[strtoupper( $tempName )] = $tempValue;
992 }
993 } else {
994 foreach ( $_SERVER as $name => $value ) {
995 if ( substr( $name, 0, 5 ) === 'HTTP_' ) {
996 $name = str_replace( '_', '-', substr( $name, 5 ) );
997 $this->headers[$name] = $value;
998 } elseif ( $name === 'CONTENT_LENGTH' ) {
999 $this->headers['CONTENT-LENGTH'] = $value;
1000 }
1001 }
1002 }
1003 }
1004
1010 public function getAllHeaders() {
1011 $this->initHeaders();
1012 return $this->headers;
1013 }
1014
1027 public function getHeader( $name, $flags = 0 ) {
1028 $this->initHeaders();
1029 $name = strtoupper( $name );
1030 if ( !isset( $this->headers[$name] ) ) {
1031 return false;
1032 }
1033 $value = $this->headers[$name];
1034 if ( $flags & self::GETHEADER_LIST ) {
1035 $value = array_map( 'trim', explode( ',', $value ) );
1036 }
1037 return $value;
1038 }
1039
1047 public function getSessionData( $key ) {
1048 return $this->getSession()->get( $key );
1049 }
1050
1058 public function setSessionData( $key, $data ) {
1059 $this->getSession()->set( $key, $data );
1060 }
1061
1072 public function checkUrlExtension( $extWhitelist = [] ) {
1073 $extWhitelist[] = 'php';
1074 if ( IEUrlExtension::areServerVarsBad( $_SERVER, $extWhitelist ) ) {
1075 if ( !$this->wasPosted() ) {
1077 $this->getFullRequestURL(), $extWhitelist );
1078 if ( $newUrl !== false ) {
1079 $this->doSecurityRedirect( $newUrl );
1080 return false;
1081 }
1082 }
1083 throw new HttpError( 403,
1084 'Invalid file extension found in the path info or query string.' );
1085 }
1086 return true;
1087 }
1088
1096 protected function doSecurityRedirect( $url ) {
1097 header( 'Location: ' . $url );
1098 header( 'Content-Type: text/html' );
1099 $encUrl = htmlspecialchars( $url );
1100 echo <<<HTML
1101<!DOCTYPE html>
1102<html>
1103<head>
1104<title>Security redirect</title>
1105</head>
1106<body>
1107<h1>Security redirect</h1>
1108<p>
1109We can't serve non-HTML content from the URL you have requested, because
1110Internet Explorer would interpret it as an incorrect and potentially dangerous
1111content type.</p>
1112<p>Instead, please use <a href="$encUrl">this URL</a>, which is the same as the
1113URL you have requested, except that "&amp;*" is appended. This prevents Internet
1114Explorer from seeing a bogus file extension.
1115</p>
1116</body>
1117</html>
1118HTML;
1119 echo "\n";
1120 return true;
1121 }
1122
1132 public function getAcceptLang() {
1133 // Modified version of code found at
1134 // http://www.thefutureoftheweb.com/blog/use-accept-language-header
1135 $acceptLang = $this->getHeader( 'Accept-Language' );
1136 if ( !$acceptLang ) {
1137 return [];
1138 }
1139
1140 // Return the language codes in lower case
1141 $acceptLang = strtolower( $acceptLang );
1142
1143 // Break up string into pieces (languages and q factors)
1144 $lang_parse = null;
1145 preg_match_all(
1146 '/([a-z]{1,8}(-[a-z]{1,8})*|\*)\s*(;\s*q\s*=\s*(1(\.0{0,3})?|0(\.[0-9]{0,3})?)?)?/',
1147 $acceptLang,
1148 $lang_parse
1149 );
1150
1151 if ( !count( $lang_parse[1] ) ) {
1152 return [];
1153 }
1154
1155 $langcodes = $lang_parse[1];
1156 $qvalues = $lang_parse[4];
1157 $indices = range( 0, count( $lang_parse[1] ) - 1 );
1158
1159 // Set default q factor to 1
1160 foreach ( $indices as $index ) {
1161 if ( $qvalues[$index] === '' ) {
1162 $qvalues[$index] = 1;
1163 } elseif ( $qvalues[$index] == 0 ) {
1164 unset( $langcodes[$index], $qvalues[$index], $indices[$index] );
1165 }
1166 }
1167
1168 // Sort list. First by $qvalues, then by order. Reorder $langcodes the same way
1169 array_multisort( $qvalues, SORT_DESC, SORT_NUMERIC, $indices, $langcodes );
1170
1171 // Create a list like "en" => 0.8
1172 $langs = array_combine( $langcodes, $qvalues );
1173
1174 return $langs;
1175 }
1176
1185 protected function getRawIP() {
1186 if ( !isset( $_SERVER['REMOTE_ADDR'] ) ) {
1187 return null;
1188 }
1189
1190 if ( is_array( $_SERVER['REMOTE_ADDR'] ) || strpos( $_SERVER['REMOTE_ADDR'], ',' ) !== false ) {
1191 throw new MWException( __METHOD__
1192 . " : Could not determine the remote IP address due to multiple values." );
1193 } else {
1194 $ipchain = $_SERVER['REMOTE_ADDR'];
1195 }
1196
1197 return IP::canonicalize( $ipchain );
1198 }
1199
1209 public function getIP() {
1210 global $wgUsePrivateIPs;
1211
1212 # Return cached result
1213 if ( $this->ip !== null ) {
1214 return $this->ip;
1215 }
1216
1217 # collect the originating ips
1218 $ip = $this->getRawIP();
1219 if ( !$ip ) {
1220 throw new MWException( 'Unable to determine IP.' );
1221 }
1222
1223 # Append XFF
1224 $forwardedFor = $this->getHeader( 'X-Forwarded-For' );
1225 if ( $forwardedFor !== false ) {
1226 $proxyLookup = MediaWikiServices::getInstance()->getProxyLookup();
1227 $isConfigured = $proxyLookup->isConfiguredProxy( $ip );
1228 $ipchain = array_map( 'trim', explode( ',', $forwardedFor ) );
1229 $ipchain = array_reverse( $ipchain );
1230 array_unshift( $ipchain, $ip );
1231
1232 # Step through XFF list and find the last address in the list which is a
1233 # trusted server. Set $ip to the IP address given by that trusted server,
1234 # unless the address is not sensible (e.g. private). However, prefer private
1235 # IP addresses over proxy servers controlled by this site (more sensible).
1236 # Note that some XFF values might be "unknown" with Squid/Varnish.
1237 foreach ( $ipchain as $i => $curIP ) {
1238 $curIP = IP::sanitizeIP( IP::canonicalize( $curIP ) );
1239 if ( !$curIP || !isset( $ipchain[$i + 1] ) || $ipchain[$i + 1] === 'unknown'
1240 || !$proxyLookup->isTrustedProxy( $curIP )
1241 ) {
1242 break; // IP is not valid/trusted or does not point to anything
1243 }
1244 if (
1245 IP::isPublic( $ipchain[$i + 1] ) ||
1246 $wgUsePrivateIPs ||
1247 $proxyLookup->isConfiguredProxy( $curIP ) // T50919; treat IP as sane
1248 ) {
1249 // Follow the next IP according to the proxy
1250 $nextIP = IP::canonicalize( $ipchain[$i + 1] );
1251 if ( !$nextIP && $isConfigured ) {
1252 // We have not yet made it past CDN/proxy servers of this site,
1253 // so either they are misconfigured or there is some IP spoofing.
1254 throw new MWException( "Invalid IP given in XFF '$forwardedFor'." );
1255 }
1256 $ip = $nextIP;
1257 // keep traversing the chain
1258 continue;
1259 }
1260 break;
1261 }
1262 }
1263
1264 # Allow extensions to improve our guess
1265 Hooks::run( 'GetIP', [ &$ip ] );
1266
1267 if ( !$ip ) {
1268 throw new MWException( "Unable to determine IP." );
1269 }
1270
1271 wfDebug( "IP: $ip\n" );
1272 $this->ip = $ip;
1273 return $ip;
1274 }
1275
1281 public function setIP( $ip ) {
1282 $this->ip = $ip;
1283 }
1284
1297 public function hasSafeMethod() {
1298 if ( !isset( $_SERVER['REQUEST_METHOD'] ) ) {
1299 return false; // CLI mode
1300 }
1301
1302 return in_array( $_SERVER['REQUEST_METHOD'], [ 'GET', 'HEAD', 'OPTIONS', 'TRACE' ] );
1303 }
1304
1323 public function isSafeRequest() {
1324 if ( $this->markedAsSafe && $this->wasPosted() ) {
1325 return true; // marked as a "safe" POST
1326 }
1327
1328 return $this->hasSafeMethod();
1329 }
1330
1341 public function markAsSafeRequest() {
1342 $this->markedAsSafe = true;
1343 }
1344}
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
and that you know you can do these things To protect your we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights These restrictions translate to certain responsibilities for you if you distribute copies of the or if you modify it For if you distribute copies of such a whether gratis or for a you must give the recipients all the rights that you have You must make sure that receive or can get the source code And you must show them these terms so they know their rights We protect your rights with two and(2) offer you this license which gives you legal permission to copy
$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 $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.
wfGetServerUrl( $proto)
Get the wiki's "server", i.e.
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.
Definition HttpError.php:30
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.
Definition IP.php:67
Internationalisation code.
Definition Language.php:36
MediaWiki exception.
MediaWikiServices is the service locator for the application scope of MediaWiki.
Value object holding the session ID in a manner that can be globally updated.
Definition SessionId.php:38
This serves as the entry point to the MediaWiki session handling system.
Manages data for an an authenticated session.
Definition Session.php:48
PathRouter class.
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.
getPostValues()
Get the values passed via POST.
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.
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 ...
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
Definition hooks.txt:2003
Allows to change the fields on the form that will be generated $name
Definition hooks.txt:271
this hook is for auditing only $response
Definition hooks.txt:780
$data
Utility to generate mapping file used in mw.Title (phpCharToUpper.json)
const PROTO_CURRENT
Definition Defines.php:231
$wgActionPaths
Definition img_auth.php:47
$wgArticlePath
Definition img_auth.php:46
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
if(is_array($mode)) switch( $mode) $input
title