MediaWiki REL1_30
WebRequest.php
Go to the documentation of this file.
1<?php
30
39 protected $data, $headers = [];
40
45 const GETHEADER_LIST = 1;
46
51 private static $reqId;
52
57 private $response;
58
63 private $ip;
64
69 protected $requestTime;
70
75 protected $protocol;
76
82 protected $sessionId = null;
83
85 protected $markedAsSafe = false;
86
90 public function __construct() {
91 $this->requestTime = isset( $_SERVER['REQUEST_TIME_FLOAT'] )
92 ? $_SERVER['REQUEST_TIME_FLOAT'] : microtime( true );
93
94 // POST overrides GET data
95 // We don't use $_REQUEST here to avoid interference from cookies...
96 $this->data = $_POST + $_GET;
97 }
98
114 public static function getPathInfo( $want = 'all' ) {
115 global $wgUsePathInfo;
116 // PATH_INFO is mangled due to https://bugs.php.net/bug.php?id=31892
117 // And also by Apache 2.x, double slashes are converted to single slashes.
118 // So we will use REQUEST_URI if possible.
119 $matches = [];
120 if ( !empty( $_SERVER['REQUEST_URI'] ) ) {
121 // Slurp out the path portion to examine...
122 $url = $_SERVER['REQUEST_URI'];
123 if ( !preg_match( '!^https?://!', $url ) ) {
124 $url = 'http://unused' . $url;
125 }
126 MediaWiki\suppressWarnings();
127 $a = parse_url( $url );
128 MediaWiki\restoreWarnings();
129 if ( $a ) {
130 $path = isset( $a['path'] ) ? $a['path'] : '';
131
132 global $wgScript;
133 if ( $path == $wgScript && $want !== 'all' ) {
134 // Script inside a rewrite path?
135 // Abort to keep from breaking...
136 return $matches;
137 }
138
139 $router = new PathRouter;
140
141 // Raw PATH_INFO style
142 $router->add( "$wgScript/$1" );
143
144 if ( isset( $_SERVER['SCRIPT_NAME'] )
145 && preg_match( '/\.php5?/', $_SERVER['SCRIPT_NAME'] )
146 ) {
147 # Check for SCRIPT_NAME, we handle index.php explicitly
148 # But we do have some other .php files such as img_auth.php
149 # Don't let root article paths clober the parsing for them
150 $router->add( $_SERVER['SCRIPT_NAME'] . "/$1" );
151 }
152
153 global $wgArticlePath;
154 if ( $wgArticlePath ) {
155 $router->add( $wgArticlePath );
156 }
157
158 global $wgActionPaths;
159 if ( $wgActionPaths ) {
160 $router->add( $wgActionPaths, [ 'action' => '$key' ] );
161 }
162
164 if ( $wgVariantArticlePath ) {
165 $router->add( $wgVariantArticlePath,
166 [ 'variant' => '$2' ],
167 [ '$2' => $wgContLang->getVariants() ]
168 );
169 }
170
171 Hooks::run( 'WebRequestPathInfoRouter', [ $router ] );
172
173 $matches = $router->parse( $path );
174 }
175 } elseif ( $wgUsePathInfo ) {
176 if ( isset( $_SERVER['ORIG_PATH_INFO'] ) && $_SERVER['ORIG_PATH_INFO'] != '' ) {
177 // Mangled PATH_INFO
178 // https://bugs.php.net/bug.php?id=31892
179 // Also reported when ini_get('cgi.fix_pathinfo')==false
180 $matches['title'] = substr( $_SERVER['ORIG_PATH_INFO'], 1 );
181
182 } elseif ( isset( $_SERVER['PATH_INFO'] ) && $_SERVER['PATH_INFO'] != '' ) {
183 // Regular old PATH_INFO yay
184 $matches['title'] = substr( $_SERVER['PATH_INFO'], 1 );
185 }
186 }
187
188 return $matches;
189 }
190
197 public static function detectServer() {
199
200 $proto = self::detectProtocol();
201 $stdPort = $proto === 'https' ? 443 : 80;
202
203 $varNames = [ 'HTTP_HOST', 'SERVER_NAME', 'HOSTNAME', 'SERVER_ADDR' ];
204 $host = 'localhost';
205 $port = $stdPort;
206 foreach ( $varNames as $varName ) {
207 if ( !isset( $_SERVER[$varName] ) ) {
208 continue;
209 }
210
211 $parts = IP::splitHostAndPort( $_SERVER[$varName] );
212 if ( !$parts ) {
213 // Invalid, do not use
214 continue;
215 }
216
217 $host = $parts[0];
218 if ( $wgAssumeProxiesUseDefaultProtocolPorts && isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) ) {
219 // T72021: Assume that upstream proxy is running on the default
220 // port based on the protocol. We have no reliable way to determine
221 // the actual port in use upstream.
222 $port = $stdPort;
223 } elseif ( $parts[1] === false ) {
224 if ( isset( $_SERVER['SERVER_PORT'] ) ) {
225 $port = $_SERVER['SERVER_PORT'];
226 } // else leave it as $stdPort
227 } else {
228 $port = $parts[1];
229 }
230 break;
231 }
232
233 return $proto . '://' . IP::combineHostAndPort( $host, $port, $stdPort );
234 }
235
243 public static function detectProtocol() {
244 if ( ( !empty( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] !== 'off' ) ||
245 ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) &&
246 $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https' ) ) {
247 return 'https';
248 } else {
249 return 'http';
250 }
251 }
252
260 public function getElapsedTime() {
261 return microtime( true ) - $this->requestTime;
262 }
263
272 public static function getRequestId() {
273 if ( !self::$reqId ) {
274 self::$reqId = isset( $_SERVER['UNIQUE_ID'] )
275 ? $_SERVER['UNIQUE_ID'] : wfRandomString( 24 );
276 }
277
278 return self::$reqId;
279 }
280
288 public static function overrideRequestId( $id ) {
289 self::$reqId = $id;
290 }
291
296 public function getProtocol() {
297 if ( $this->protocol === null ) {
298 $this->protocol = self::detectProtocol();
299 }
300 return $this->protocol;
301 }
302
310 public function interpolateTitle() {
311 // T18019: title interpolation on API queries is useless and sometimes harmful
312 if ( defined( 'MW_API' ) ) {
313 return;
314 }
315
316 $matches = self::getPathInfo( 'title' );
317 foreach ( $matches as $key => $val ) {
318 $this->data[$key] = $_GET[$key] = $_REQUEST[$key] = $val;
319 }
320 }
321
332 static function extractTitle( $path, $bases, $key = false ) {
333 foreach ( (array)$bases as $keyValue => $base ) {
334 // Find the part after $wgArticlePath
335 $base = str_replace( '$1', '', $base );
336 $baseLen = strlen( $base );
337 if ( substr( $path, 0, $baseLen ) == $base ) {
338 $raw = substr( $path, $baseLen );
339 if ( $raw !== '' ) {
340 $matches = [ 'title' => rawurldecode( $raw ) ];
341 if ( $key ) {
342 $matches[$key] = $keyValue;
343 }
344 return $matches;
345 }
346 }
347 }
348 return [];
349 }
350
358 public function normalizeUnicode( $data ) {
359 if ( is_array( $data ) ) {
360 foreach ( $data as $key => $val ) {
361 $data[$key] = $this->normalizeUnicode( $val );
362 }
363 } else {
364 global $wgContLang;
365 $data = isset( $wgContLang ) ?
366 $wgContLang->normalize( $data ) :
367 UtfNormal\Validator::cleanUp( $data );
368 }
369 return $data;
370 }
371
380 private function getGPCVal( $arr, $name, $default ) {
381 # PHP is so nice to not touch input data, except sometimes:
382 # https://secure.php.net/variables.external#language.variables.external.dot-in-names
383 # Work around PHP *feature* to avoid *bugs* elsewhere.
384 $name = strtr( $name, '.', '_' );
385 if ( isset( $arr[$name] ) ) {
386 global $wgContLang;
387 $data = $arr[$name];
388 if ( isset( $_GET[$name] ) && !is_array( $data ) ) {
389 # Check for alternate/legacy character encoding.
390 if ( isset( $wgContLang ) ) {
391 $data = $wgContLang->checkTitleEncoding( $data );
392 }
393 }
394 $data = $this->normalizeUnicode( $data );
395 return $data;
396 } else {
397 return $default;
398 }
399 }
400
413 public function getRawVal( $name, $default = null ) {
414 $name = strtr( $name, '.', '_' ); // See comment in self::getGPCVal()
415 if ( isset( $this->data[$name] ) && !is_array( $this->data[$name] ) ) {
416 $val = $this->data[$name];
417 } else {
418 $val = $default;
419 }
420 if ( is_null( $val ) ) {
421 return $val;
422 } else {
423 return (string)$val;
424 }
425 }
426
437 public function getVal( $name, $default = null ) {
438 $val = $this->getGPCVal( $this->data, $name, $default );
439 if ( is_array( $val ) ) {
440 $val = $default;
441 }
442 if ( is_null( $val ) ) {
443 return $val;
444 } else {
445 return (string)$val;
446 }
447 }
448
456 public function setVal( $key, $value ) {
457 $ret = isset( $this->data[$key] ) ? $this->data[$key] : null;
458 $this->data[$key] = $value;
459 return $ret;
460 }
461
468 public function unsetVal( $key ) {
469 if ( !isset( $this->data[$key] ) ) {
470 $ret = null;
471 } else {
472 $ret = $this->data[$key];
473 unset( $this->data[$key] );
474 }
475 return $ret;
476 }
477
487 public function getArray( $name, $default = null ) {
488 $val = $this->getGPCVal( $this->data, $name, $default );
489 if ( is_null( $val ) ) {
490 return null;
491 } else {
492 return (array)$val;
493 }
494 }
495
506 public function getIntArray( $name, $default = null ) {
507 $val = $this->getArray( $name, $default );
508 if ( is_array( $val ) ) {
509 $val = array_map( 'intval', $val );
510 }
511 return $val;
512 }
513
523 public function getInt( $name, $default = 0 ) {
524 return intval( $this->getRawVal( $name, $default ) );
525 }
526
535 public function getIntOrNull( $name ) {
536 $val = $this->getRawVal( $name );
537 return is_numeric( $val )
538 ? intval( $val )
539 : null;
540 }
541
552 public function getFloat( $name, $default = 0.0 ) {
553 return floatval( $this->getRawVal( $name, $default ) );
554 }
555
565 public function getBool( $name, $default = false ) {
566 return (bool)$this->getRawVal( $name, $default );
567 }
568
578 public function getFuzzyBool( $name, $default = false ) {
579 return $this->getBool( $name, $default )
580 && strcasecmp( $this->getRawVal( $name ), 'false' ) !== 0;
581 }
582
591 public function getCheck( $name ) {
592 # Checkboxes and buttons are only present when clicked
593 # Presence connotes truth, absence false
594 return $this->getRawVal( $name, null ) !== null;
595 }
596
607 public function getText( $name, $default = '' ) {
608 $val = $this->getVal( $name, $default );
609 return str_replace( "\r\n", "\n", $val );
610 }
611
619 public function getValues() {
620 $names = func_get_args();
621 if ( count( $names ) == 0 ) {
622 $names = array_keys( $this->data );
623 }
624
625 $retVal = [];
626 foreach ( $names as $name ) {
627 $value = $this->getGPCVal( $this->data, $name, null );
628 if ( !is_null( $value ) ) {
629 $retVal[$name] = $value;
630 }
631 }
632 return $retVal;
633 }
634
641 public function getValueNames( $exclude = [] ) {
642 return array_diff( array_keys( $this->getValues() ), $exclude );
643 }
644
652 public function getQueryValues() {
653 return $_GET;
654 }
655
663 public function getRawQueryString() {
664 return $_SERVER['QUERY_STRING'];
665 }
666
673 public function getRawPostString() {
674 if ( !$this->wasPosted() ) {
675 return '';
676 }
677 return $this->getRawInput();
678 }
679
687 public function getRawInput() {
688 static $input = null;
689 if ( $input === null ) {
690 $input = file_get_contents( 'php://input' );
691 }
692 return $input;
693 }
694
700 public function getMethod() {
701 return isset( $_SERVER['REQUEST_METHOD'] ) ? $_SERVER['REQUEST_METHOD'] : 'GET';
702 }
703
713 public function wasPosted() {
714 return $this->getMethod() == 'POST';
715 }
716
727 public function getSession() {
728 if ( $this->sessionId !== null ) {
729 $session = SessionManager::singleton()->getSessionById( (string)$this->sessionId, true, $this );
730 if ( $session ) {
731 return $session;
732 }
733 }
734
735 $session = SessionManager::singleton()->getSessionForRequest( $this );
736 $this->sessionId = $session->getSessionId();
737 return $session;
738 }
739
746 public function setSessionId( SessionId $sessionId ) {
747 $this->sessionId = $sessionId;
748 }
749
756 public function getSessionId() {
757 return $this->sessionId;
758 }
759
768 public function getCookie( $key, $prefix = null, $default = null ) {
769 if ( $prefix === null ) {
770 global $wgCookiePrefix;
771 $prefix = $wgCookiePrefix;
772 }
773 return $this->getGPCVal( $_COOKIE, $prefix . $key, $default );
774 }
775
783 public static function getGlobalRequestURL() {
784 if ( isset( $_SERVER['REQUEST_URI'] ) && strlen( $_SERVER['REQUEST_URI'] ) ) {
785 $base = $_SERVER['REQUEST_URI'];
786 } elseif ( isset( $_SERVER['HTTP_X_ORIGINAL_URL'] )
787 && strlen( $_SERVER['HTTP_X_ORIGINAL_URL'] )
788 ) {
789 // Probably IIS; doesn't set REQUEST_URI
790 $base = $_SERVER['HTTP_X_ORIGINAL_URL'];
791 } elseif ( isset( $_SERVER['SCRIPT_NAME'] ) ) {
792 $base = $_SERVER['SCRIPT_NAME'];
793 if ( isset( $_SERVER['QUERY_STRING'] ) && $_SERVER['QUERY_STRING'] != '' ) {
794 $base .= '?' . $_SERVER['QUERY_STRING'];
795 }
796 } else {
797 // This shouldn't happen!
798 throw new MWException( "Web server doesn't provide either " .
799 "REQUEST_URI, HTTP_X_ORIGINAL_URL or SCRIPT_NAME. Report details " .
800 "of your web server configuration to https://phabricator.wikimedia.org/" );
801 }
802 // User-agents should not send a fragment with the URI, but
803 // if they do, and the web server passes it on to us, we
804 // need to strip it or we get false-positive redirect loops
805 // or weird output URLs
806 $hash = strpos( $base, '#' );
807 if ( $hash !== false ) {
808 $base = substr( $base, 0, $hash );
809 }
810
811 if ( $base[0] == '/' ) {
812 // More than one slash will look like it is protocol relative
813 return preg_replace( '!^/+!', '/', $base );
814 } else {
815 // We may get paths with a host prepended; strip it.
816 return preg_replace( '!^[^:]+://[^/]+/+!', '/', $base );
817 }
818 }
819
827 public function getRequestURL() {
828 return self::getGlobalRequestURL();
829 }
830
841 public function getFullRequestURL() {
842 return wfExpandUrl( $this->getRequestURL(), PROTO_CURRENT );
843 }
844
850 public function appendQueryValue( $key, $value ) {
851 return $this->appendQueryArray( [ $key => $value ] );
852 }
853
860 public function appendQueryArray( $array ) {
861 $newquery = $this->getQueryValues();
862 unset( $newquery['title'] );
863 $newquery = array_merge( $newquery, $array );
864
865 return wfArrayToCgi( $newquery );
866 }
867
877 public function getLimitOffset( $deflimit = 50, $optionname = 'rclimit' ) {
878 global $wgUser;
879
880 $limit = $this->getInt( 'limit', 0 );
881 if ( $limit < 0 ) {
882 $limit = 0;
883 }
884 if ( ( $limit == 0 ) && ( $optionname != '' ) ) {
885 $limit = $wgUser->getIntOption( $optionname );
886 }
887 if ( $limit <= 0 ) {
888 $limit = $deflimit;
889 }
890 if ( $limit > 5000 ) {
891 $limit = 5000; # We have *some* limits...
892 }
893
894 $offset = $this->getInt( 'offset', 0 );
895 if ( $offset < 0 ) {
896 $offset = 0;
897 }
898
899 return [ $limit, $offset ];
900 }
901
908 public function getFileTempname( $key ) {
909 $file = new WebRequestUpload( $this, $key );
910 return $file->getTempName();
911 }
912
919 public function getUploadError( $key ) {
920 $file = new WebRequestUpload( $this, $key );
921 return $file->getError();
922 }
923
935 public function getFileName( $key ) {
936 $file = new WebRequestUpload( $this, $key );
937 return $file->getName();
938 }
939
946 public function getUpload( $key ) {
947 return new WebRequestUpload( $this, $key );
948 }
949
956 public function response() {
957 /* Lazy initialization of response object for this request */
958 if ( !is_object( $this->response ) ) {
959 $class = ( $this instanceof FauxRequest ) ? 'FauxResponse' : 'WebResponse';
960 $this->response = new $class();
961 }
962 return $this->response;
963 }
964
968 protected function initHeaders() {
969 if ( count( $this->headers ) ) {
970 return;
971 }
972
973 $apacheHeaders = function_exists( 'apache_request_headers' ) ? apache_request_headers() : false;
974 if ( $apacheHeaders ) {
975 foreach ( $apacheHeaders as $tempName => $tempValue ) {
976 $this->headers[strtoupper( $tempName )] = $tempValue;
977 }
978 } else {
979 foreach ( $_SERVER as $name => $value ) {
980 if ( substr( $name, 0, 5 ) === 'HTTP_' ) {
981 $name = str_replace( '_', '-', substr( $name, 5 ) );
982 $this->headers[$name] = $value;
983 } elseif ( $name === 'CONTENT_LENGTH' ) {
984 $this->headers['CONTENT-LENGTH'] = $value;
985 }
986 }
987 }
988 }
989
995 public function getAllHeaders() {
996 $this->initHeaders();
997 return $this->headers;
998 }
999
1012 public function getHeader( $name, $flags = 0 ) {
1013 $this->initHeaders();
1014 $name = strtoupper( $name );
1015 if ( !isset( $this->headers[$name] ) ) {
1016 return false;
1017 }
1018 $value = $this->headers[$name];
1019 if ( $flags & self::GETHEADER_LIST ) {
1020 $value = array_map( 'trim', explode( ',', $value ) );
1021 }
1022 return $value;
1023 }
1024
1032 public function getSessionData( $key ) {
1033 return $this->getSession()->get( $key );
1034 }
1035
1043 public function setSessionData( $key, $data ) {
1044 $this->getSession()->set( $key, $data );
1045 }
1046
1057 public function checkUrlExtension( $extWhitelist = [] ) {
1058 $extWhitelist[] = 'php';
1059 if ( IEUrlExtension::areServerVarsBad( $_SERVER, $extWhitelist ) ) {
1060 if ( !$this->wasPosted() ) {
1062 $this->getFullRequestURL(), $extWhitelist );
1063 if ( $newUrl !== false ) {
1064 $this->doSecurityRedirect( $newUrl );
1065 return false;
1066 }
1067 }
1068 throw new HttpError( 403,
1069 'Invalid file extension found in the path info or query string.' );
1070 }
1071 return true;
1072 }
1073
1081 protected function doSecurityRedirect( $url ) {
1082 header( 'Location: ' . $url );
1083 header( 'Content-Type: text/html' );
1084 $encUrl = htmlspecialchars( $url );
1085 echo <<<HTML
1086<!DOCTYPE html>
1087<html>
1088<head>
1089<title>Security redirect</title>
1090</head>
1091<body>
1092<h1>Security redirect</h1>
1093<p>
1094We can't serve non-HTML content from the URL you have requested, because
1095Internet Explorer would interpret it as an incorrect and potentially dangerous
1096content type.</p>
1097<p>Instead, please use <a href="$encUrl">this URL</a>, which is the same as the
1098URL you have requested, except that "&amp;*" is appended. This prevents Internet
1099Explorer from seeing a bogus file extension.
1100</p>
1101</body>
1102</html>
1103HTML;
1104 echo "\n";
1105 return true;
1106 }
1107
1117 public function getAcceptLang() {
1118 // Modified version of code found at
1119 // http://www.thefutureoftheweb.com/blog/use-accept-language-header
1120 $acceptLang = $this->getHeader( 'Accept-Language' );
1121 if ( !$acceptLang ) {
1122 return [];
1123 }
1124
1125 // Return the language codes in lower case
1126 $acceptLang = strtolower( $acceptLang );
1127
1128 // Break up string into pieces (languages and q factors)
1129 $lang_parse = null;
1130 preg_match_all(
1131 '/([a-z]{1,8}(-[a-z]{1,8})*|\*)\s*(;\s*q\s*=\s*(1(\.0{0,3})?|0(\.[0-9]{0,3})?)?)?/',
1132 $acceptLang,
1133 $lang_parse
1134 );
1135
1136 if ( !count( $lang_parse[1] ) ) {
1137 return [];
1138 }
1139
1140 $langcodes = $lang_parse[1];
1141 $qvalues = $lang_parse[4];
1142 $indices = range( 0, count( $lang_parse[1] ) - 1 );
1143
1144 // Set default q factor to 1
1145 foreach ( $indices as $index ) {
1146 if ( $qvalues[$index] === '' ) {
1147 $qvalues[$index] = 1;
1148 } elseif ( $qvalues[$index] == 0 ) {
1149 unset( $langcodes[$index], $qvalues[$index], $indices[$index] );
1150 }
1151 }
1152
1153 // Sort list. First by $qvalues, then by order. Reorder $langcodes the same way
1154 array_multisort( $qvalues, SORT_DESC, SORT_NUMERIC, $indices, $langcodes );
1155
1156 // Create a list like "en" => 0.8
1157 $langs = array_combine( $langcodes, $qvalues );
1158
1159 return $langs;
1160 }
1161
1170 protected function getRawIP() {
1171 if ( !isset( $_SERVER['REMOTE_ADDR'] ) ) {
1172 return null;
1173 }
1174
1175 if ( is_array( $_SERVER['REMOTE_ADDR'] ) || strpos( $_SERVER['REMOTE_ADDR'], ',' ) !== false ) {
1176 throw new MWException( __METHOD__
1177 . " : Could not determine the remote IP address due to multiple values." );
1178 } else {
1179 $ipchain = $_SERVER['REMOTE_ADDR'];
1180 }
1181
1182 return IP::canonicalize( $ipchain );
1183 }
1184
1194 public function getIP() {
1195 global $wgUsePrivateIPs;
1196
1197 # Return cached result
1198 if ( $this->ip !== null ) {
1199 return $this->ip;
1200 }
1201
1202 # collect the originating ips
1203 $ip = $this->getRawIP();
1204 if ( !$ip ) {
1205 throw new MWException( 'Unable to determine IP.' );
1206 }
1207
1208 # Append XFF
1209 $forwardedFor = $this->getHeader( 'X-Forwarded-For' );
1210 if ( $forwardedFor !== false ) {
1211 $proxyLookup = MediaWikiServices::getInstance()->getProxyLookup();
1212 $isConfigured = $proxyLookup->isConfiguredProxy( $ip );
1213 $ipchain = array_map( 'trim', explode( ',', $forwardedFor ) );
1214 $ipchain = array_reverse( $ipchain );
1215 array_unshift( $ipchain, $ip );
1216
1217 # Step through XFF list and find the last address in the list which is a
1218 # trusted server. Set $ip to the IP address given by that trusted server,
1219 # unless the address is not sensible (e.g. private). However, prefer private
1220 # IP addresses over proxy servers controlled by this site (more sensible).
1221 # Note that some XFF values might be "unknown" with Squid/Varnish.
1222 foreach ( $ipchain as $i => $curIP ) {
1223 $curIP = IP::sanitizeIP( IP::canonicalize( $curIP ) );
1224 if ( !$curIP || !isset( $ipchain[$i + 1] ) || $ipchain[$i + 1] === 'unknown'
1225 || !$proxyLookup->isTrustedProxy( $curIP )
1226 ) {
1227 break; // IP is not valid/trusted or does not point to anything
1228 }
1229 if (
1230 IP::isPublic( $ipchain[$i + 1] ) ||
1231 $wgUsePrivateIPs ||
1232 $proxyLookup->isConfiguredProxy( $curIP ) // T50919; treat IP as sane
1233 ) {
1234 // Follow the next IP according to the proxy
1235 $nextIP = IP::canonicalize( $ipchain[$i + 1] );
1236 if ( !$nextIP && $isConfigured ) {
1237 // We have not yet made it past CDN/proxy servers of this site,
1238 // so either they are misconfigured or there is some IP spoofing.
1239 throw new MWException( "Invalid IP given in XFF '$forwardedFor'." );
1240 }
1241 $ip = $nextIP;
1242 // keep traversing the chain
1243 continue;
1244 }
1245 break;
1246 }
1247 }
1248
1249 # Allow extensions to improve our guess
1250 Hooks::run( 'GetIP', [ &$ip ] );
1251
1252 if ( !$ip ) {
1253 throw new MWException( "Unable to determine IP." );
1254 }
1255
1256 wfDebug( "IP: $ip\n" );
1257 $this->ip = $ip;
1258 return $ip;
1259 }
1260
1266 public function setIP( $ip ) {
1267 $this->ip = $ip;
1268 }
1269
1282 public function hasSafeMethod() {
1283 if ( !isset( $_SERVER['REQUEST_METHOD'] ) ) {
1284 return false; // CLI mode
1285 }
1286
1287 return in_array( $_SERVER['REQUEST_METHOD'], [ 'GET', 'HEAD', 'OPTIONS', 'TRACE' ] );
1288 }
1289
1308 public function isSafeRequest() {
1309 if ( $this->markedAsSafe && $this->wasPosted() ) {
1310 return true; // marked as a "safe" POST
1311 }
1312
1313 return $this->hasSafeMethod();
1314 }
1315
1326 public function markAsSafeRequest() {
1327 $this->markedAsSafe = true;
1328 }
1329}
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 $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....
$wgUser
Definition Setup.php:817
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:35
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.
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 ...
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
Definition design.txt:57
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
Definition design.txt:79
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at etc Handles the details of getting and saving to the user table of the and dealing with sessions and cookies OutputPage Encapsulates the entire HTML page that will be sent in response to any server request It is used by calling its functions to add headers
Definition design.txt:18
it s the revision text itself In either if gzip is the revision text is gzipped $flags
Definition hooks.txt:2805
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:1975
Allows to change the fields on the form that will be generated $name
Definition hooks.txt:302
this hook is for auditing only $response
Definition hooks.txt:781
const PROTO_CURRENT
Definition Defines.php:223
$wgActionPaths
Definition img_auth.php:46
$wgArticlePath
Definition img_auth.php:45
if(is_array($mode)) switch( $mode) $input