MediaWiki  1.32.0
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 
41 class WebRequest {
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  }
128  Wikimedia\suppressWarnings();
129  $a = parse_url( $url );
130  Wikimedia\restoreWarnings();
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 
165  global $wgVariantArticlePath;
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_array( $data ) ) {
391  # Check for alternate/legacy character encoding.
392  $contLang = MediaWikiServices::getInstance()->getContentLanguage();
393  if ( $contLang ) {
394  $data = $contLang->checkTitleEncoding( $data );
395  }
396  }
397  $data = $this->normalizeUnicode( $data );
398  return $data;
399  } else {
400  return $default;
401  }
402  }
403 
416  public function getRawVal( $name, $default = null ) {
417  $name = strtr( $name, '.', '_' ); // See comment in self::getGPCVal()
418  if ( isset( $this->data[$name] ) && !is_array( $this->data[$name] ) ) {
419  $val = $this->data[$name];
420  } else {
421  $val = $default;
422  }
423  if ( is_null( $val ) ) {
424  return $val;
425  } else {
426  return (string)$val;
427  }
428  }
429 
440  public function getVal( $name, $default = null ) {
441  $val = $this->getGPCVal( $this->data, $name, $default );
442  if ( is_array( $val ) ) {
443  $val = $default;
444  }
445  if ( is_null( $val ) ) {
446  return $val;
447  } else {
448  return (string)$val;
449  }
450  }
451 
459  public function setVal( $key, $value ) {
460  $ret = $this->data[$key] ?? null;
461  $this->data[$key] = $value;
462  return $ret;
463  }
464 
471  public function unsetVal( $key ) {
472  if ( !isset( $this->data[$key] ) ) {
473  $ret = null;
474  } else {
475  $ret = $this->data[$key];
476  unset( $this->data[$key] );
477  }
478  return $ret;
479  }
480 
490  public function getArray( $name, $default = null ) {
491  $val = $this->getGPCVal( $this->data, $name, $default );
492  if ( is_null( $val ) ) {
493  return null;
494  } else {
495  return (array)$val;
496  }
497  }
498 
509  public function getIntArray( $name, $default = null ) {
510  $val = $this->getArray( $name, $default );
511  if ( is_array( $val ) ) {
512  $val = array_map( 'intval', $val );
513  }
514  return $val;
515  }
516 
526  public function getInt( $name, $default = 0 ) {
527  return intval( $this->getRawVal( $name, $default ) );
528  }
529 
538  public function getIntOrNull( $name ) {
539  $val = $this->getRawVal( $name );
540  return is_numeric( $val )
541  ? intval( $val )
542  : null;
543  }
544 
555  public function getFloat( $name, $default = 0.0 ) {
556  return floatval( $this->getRawVal( $name, $default ) );
557  }
558 
568  public function getBool( $name, $default = false ) {
569  return (bool)$this->getRawVal( $name, $default );
570  }
571 
581  public function getFuzzyBool( $name, $default = false ) {
582  return $this->getBool( $name, $default )
583  && strcasecmp( $this->getRawVal( $name ), 'false' ) !== 0;
584  }
585 
594  public function getCheck( $name ) {
595  # Checkboxes and buttons are only present when clicked
596  # Presence connotes truth, absence false
597  return $this->getRawVal( $name, null ) !== null;
598  }
599 
610  public function getText( $name, $default = '' ) {
611  $val = $this->getVal( $name, $default );
612  return str_replace( "\r\n", "\n", $val );
613  }
614 
622  public function getValues() {
623  $names = func_get_args();
624  if ( count( $names ) == 0 ) {
625  $names = array_keys( $this->data );
626  }
627 
628  $retVal = [];
629  foreach ( $names as $name ) {
630  $value = $this->getGPCVal( $this->data, $name, null );
631  if ( !is_null( $value ) ) {
632  $retVal[$name] = $value;
633  }
634  }
635  return $retVal;
636  }
637 
644  public function getValueNames( $exclude = [] ) {
645  return array_diff( array_keys( $this->getValues() ), $exclude );
646  }
647 
655  public function getQueryValues() {
656  return $_GET;
657  }
658 
667  public function getPostValues() {
668  return $_POST;
669  }
670 
678  public function getRawQueryString() {
679  return $_SERVER['QUERY_STRING'];
680  }
681 
688  public function getRawPostString() {
689  if ( !$this->wasPosted() ) {
690  return '';
691  }
692  return $this->getRawInput();
693  }
694 
702  public function getRawInput() {
703  static $input = null;
704  if ( $input === null ) {
705  $input = file_get_contents( 'php://input' );
706  }
707  return $input;
708  }
709 
715  public function getMethod() {
716  return $_SERVER['REQUEST_METHOD'] ?? 'GET';
717  }
718 
728  public function wasPosted() {
729  return $this->getMethod() == 'POST';
730  }
731 
742  public function getSession() {
743  if ( $this->sessionId !== null ) {
744  $session = SessionManager::singleton()->getSessionById( (string)$this->sessionId, true, $this );
745  if ( $session ) {
746  return $session;
747  }
748  }
749 
750  $session = SessionManager::singleton()->getSessionForRequest( $this );
751  $this->sessionId = $session->getSessionId();
752  return $session;
753  }
754 
761  public function setSessionId( SessionId $sessionId ) {
762  $this->sessionId = $sessionId;
763  }
764 
771  public function getSessionId() {
772  return $this->sessionId;
773  }
774 
783  public function getCookie( $key, $prefix = null, $default = null ) {
784  if ( $prefix === null ) {
785  global $wgCookiePrefix;
786  $prefix = $wgCookiePrefix;
787  }
788  return $this->getGPCVal( $_COOKIE, $prefix . $key, $default );
789  }
790 
798  public static function getGlobalRequestURL() {
799  // This method is called on fatal errors; it should not depend on anything complex.
800 
801  if ( isset( $_SERVER['REQUEST_URI'] ) && strlen( $_SERVER['REQUEST_URI'] ) ) {
802  $base = $_SERVER['REQUEST_URI'];
803  } elseif ( isset( $_SERVER['HTTP_X_ORIGINAL_URL'] )
804  && strlen( $_SERVER['HTTP_X_ORIGINAL_URL'] )
805  ) {
806  // Probably IIS; doesn't set REQUEST_URI
807  $base = $_SERVER['HTTP_X_ORIGINAL_URL'];
808  } elseif ( isset( $_SERVER['SCRIPT_NAME'] ) ) {
809  $base = $_SERVER['SCRIPT_NAME'];
810  if ( isset( $_SERVER['QUERY_STRING'] ) && $_SERVER['QUERY_STRING'] != '' ) {
811  $base .= '?' . $_SERVER['QUERY_STRING'];
812  }
813  } else {
814  // This shouldn't happen!
815  throw new MWException( "Web server doesn't provide either " .
816  "REQUEST_URI, HTTP_X_ORIGINAL_URL or SCRIPT_NAME. Report details " .
817  "of your web server configuration to https://phabricator.wikimedia.org/" );
818  }
819  // User-agents should not send a fragment with the URI, but
820  // if they do, and the web server passes it on to us, we
821  // need to strip it or we get false-positive redirect loops
822  // or weird output URLs
823  $hash = strpos( $base, '#' );
824  if ( $hash !== false ) {
825  $base = substr( $base, 0, $hash );
826  }
827 
828  if ( $base[0] == '/' ) {
829  // More than one slash will look like it is protocol relative
830  return preg_replace( '!^/+!', '/', $base );
831  } else {
832  // We may get paths with a host prepended; strip it.
833  return preg_replace( '!^[^:]+://[^/]+/+!', '/', $base );
834  }
835  }
836 
844  public function getRequestURL() {
845  return self::getGlobalRequestURL();
846  }
847 
858  public function getFullRequestURL() {
859  return wfGetServerUrl( PROTO_CURRENT ) . $this->getRequestURL();
860  }
861 
867  public function appendQueryValue( $key, $value ) {
868  return $this->appendQueryArray( [ $key => $value ] );
869  }
870 
877  public function appendQueryArray( $array ) {
878  $newquery = $this->getQueryValues();
879  unset( $newquery['title'] );
880  $newquery = array_merge( $newquery, $array );
881 
882  return wfArrayToCgi( $newquery );
883  }
884 
894  public function getLimitOffset( $deflimit = 50, $optionname = 'rclimit' ) {
895  global $wgUser;
896 
897  $limit = $this->getInt( 'limit', 0 );
898  if ( $limit < 0 ) {
899  $limit = 0;
900  }
901  if ( ( $limit == 0 ) && ( $optionname != '' ) ) {
902  $limit = $wgUser->getIntOption( $optionname );
903  }
904  if ( $limit <= 0 ) {
905  $limit = $deflimit;
906  }
907  if ( $limit > 5000 ) {
908  $limit = 5000; # We have *some* limits...
909  }
910 
911  $offset = $this->getInt( 'offset', 0 );
912  if ( $offset < 0 ) {
913  $offset = 0;
914  }
915 
916  return [ $limit, $offset ];
917  }
918 
925  public function getFileTempname( $key ) {
926  $file = new WebRequestUpload( $this, $key );
927  return $file->getTempName();
928  }
929 
936  public function getUploadError( $key ) {
937  $file = new WebRequestUpload( $this, $key );
938  return $file->getError();
939  }
940 
952  public function getFileName( $key ) {
953  $file = new WebRequestUpload( $this, $key );
954  return $file->getName();
955  }
956 
963  public function getUpload( $key ) {
964  return new WebRequestUpload( $this, $key );
965  }
966 
973  public function response() {
974  /* Lazy initialization of response object for this request */
975  if ( !is_object( $this->response ) ) {
976  $class = ( $this instanceof FauxRequest ) ? FauxResponse::class : WebResponse::class;
977  $this->response = new $class();
978  }
979  return $this->response;
980  }
981 
985  protected function initHeaders() {
986  if ( count( $this->headers ) ) {
987  return;
988  }
989 
990  $apacheHeaders = function_exists( 'apache_request_headers' ) ? apache_request_headers() : false;
991  if ( $apacheHeaders ) {
992  foreach ( $apacheHeaders as $tempName => $tempValue ) {
993  $this->headers[strtoupper( $tempName )] = $tempValue;
994  }
995  } else {
996  foreach ( $_SERVER as $name => $value ) {
997  if ( substr( $name, 0, 5 ) === 'HTTP_' ) {
998  $name = str_replace( '_', '-', substr( $name, 5 ) );
999  $this->headers[$name] = $value;
1000  } elseif ( $name === 'CONTENT_LENGTH' ) {
1001  $this->headers['CONTENT-LENGTH'] = $value;
1002  }
1003  }
1004  }
1005  }
1006 
1012  public function getAllHeaders() {
1013  $this->initHeaders();
1014  return $this->headers;
1015  }
1016 
1029  public function getHeader( $name, $flags = 0 ) {
1030  $this->initHeaders();
1031  $name = strtoupper( $name );
1032  if ( !isset( $this->headers[$name] ) ) {
1033  return false;
1034  }
1035  $value = $this->headers[$name];
1036  if ( $flags & self::GETHEADER_LIST ) {
1037  $value = array_map( 'trim', explode( ',', $value ) );
1038  }
1039  return $value;
1040  }
1041 
1049  public function getSessionData( $key ) {
1050  return $this->getSession()->get( $key );
1051  }
1052 
1060  public function setSessionData( $key, $data ) {
1061  $this->getSession()->set( $key, $data );
1062  }
1063 
1074  public function checkUrlExtension( $extWhitelist = [] ) {
1075  $extWhitelist[] = 'php';
1076  if ( IEUrlExtension::areServerVarsBad( $_SERVER, $extWhitelist ) ) {
1077  if ( !$this->wasPosted() ) {
1078  $newUrl = IEUrlExtension::fixUrlForIE6(
1079  $this->getFullRequestURL(), $extWhitelist );
1080  if ( $newUrl !== false ) {
1081  $this->doSecurityRedirect( $newUrl );
1082  return false;
1083  }
1084  }
1085  throw new HttpError( 403,
1086  'Invalid file extension found in the path info or query string.' );
1087  }
1088  return true;
1089  }
1090 
1098  protected function doSecurityRedirect( $url ) {
1099  header( 'Location: ' . $url );
1100  header( 'Content-Type: text/html' );
1101  $encUrl = htmlspecialchars( $url );
1102  echo <<<HTML
1103 <!DOCTYPE html>
1104 <html>
1105 <head>
1106 <title>Security redirect</title>
1107 </head>
1108 <body>
1109 <h1>Security redirect</h1>
1110 <p>
1111 We can't serve non-HTML content from the URL you have requested, because
1112 Internet Explorer would interpret it as an incorrect and potentially dangerous
1113 content type.</p>
1114 <p>Instead, please use <a href="$encUrl">this URL</a>, which is the same as the
1115 URL you have requested, except that "&amp;*" is appended. This prevents Internet
1116 Explorer from seeing a bogus file extension.
1117 </p>
1118 </body>
1119 </html>
1120 HTML;
1121  echo "\n";
1122  return true;
1123  }
1124 
1134  public function getAcceptLang() {
1135  // Modified version of code found at
1136  // http://www.thefutureoftheweb.com/blog/use-accept-language-header
1137  $acceptLang = $this->getHeader( 'Accept-Language' );
1138  if ( !$acceptLang ) {
1139  return [];
1140  }
1141 
1142  // Return the language codes in lower case
1143  $acceptLang = strtolower( $acceptLang );
1144 
1145  // Break up string into pieces (languages and q factors)
1146  $lang_parse = null;
1147  preg_match_all(
1148  '/([a-z]{1,8}(-[a-z]{1,8})*|\*)\s*(;\s*q\s*=\s*(1(\.0{0,3})?|0(\.[0-9]{0,3})?)?)?/',
1149  $acceptLang,
1150  $lang_parse
1151  );
1152 
1153  if ( !count( $lang_parse[1] ) ) {
1154  return [];
1155  }
1156 
1157  $langcodes = $lang_parse[1];
1158  $qvalues = $lang_parse[4];
1159  $indices = range( 0, count( $lang_parse[1] ) - 1 );
1160 
1161  // Set default q factor to 1
1162  foreach ( $indices as $index ) {
1163  if ( $qvalues[$index] === '' ) {
1164  $qvalues[$index] = 1;
1165  } elseif ( $qvalues[$index] == 0 ) {
1166  unset( $langcodes[$index], $qvalues[$index], $indices[$index] );
1167  }
1168  }
1169 
1170  // Sort list. First by $qvalues, then by order. Reorder $langcodes the same way
1171  array_multisort( $qvalues, SORT_DESC, SORT_NUMERIC, $indices, $langcodes );
1172 
1173  // Create a list like "en" => 0.8
1174  $langs = array_combine( $langcodes, $qvalues );
1175 
1176  return $langs;
1177  }
1178 
1187  protected function getRawIP() {
1188  if ( !isset( $_SERVER['REMOTE_ADDR'] ) ) {
1189  return null;
1190  }
1191 
1192  if ( is_array( $_SERVER['REMOTE_ADDR'] ) || strpos( $_SERVER['REMOTE_ADDR'], ',' ) !== false ) {
1193  throw new MWException( __METHOD__
1194  . " : Could not determine the remote IP address due to multiple values." );
1195  } else {
1196  $ipchain = $_SERVER['REMOTE_ADDR'];
1197  }
1198 
1199  return IP::canonicalize( $ipchain );
1200  }
1201 
1211  public function getIP() {
1212  global $wgUsePrivateIPs;
1213 
1214  # Return cached result
1215  if ( $this->ip !== null ) {
1216  return $this->ip;
1217  }
1218 
1219  # collect the originating ips
1220  $ip = $this->getRawIP();
1221  if ( !$ip ) {
1222  throw new MWException( 'Unable to determine IP.' );
1223  }
1224 
1225  # Append XFF
1226  $forwardedFor = $this->getHeader( 'X-Forwarded-For' );
1227  if ( $forwardedFor !== false ) {
1228  $proxyLookup = MediaWikiServices::getInstance()->getProxyLookup();
1229  $isConfigured = $proxyLookup->isConfiguredProxy( $ip );
1230  $ipchain = array_map( 'trim', explode( ',', $forwardedFor ) );
1231  $ipchain = array_reverse( $ipchain );
1232  array_unshift( $ipchain, $ip );
1233 
1234  # Step through XFF list and find the last address in the list which is a
1235  # trusted server. Set $ip to the IP address given by that trusted server,
1236  # unless the address is not sensible (e.g. private). However, prefer private
1237  # IP addresses over proxy servers controlled by this site (more sensible).
1238  # Note that some XFF values might be "unknown" with Squid/Varnish.
1239  foreach ( $ipchain as $i => $curIP ) {
1240  $curIP = IP::sanitizeIP( IP::canonicalize( $curIP ) );
1241  if ( !$curIP || !isset( $ipchain[$i + 1] ) || $ipchain[$i + 1] === 'unknown'
1242  || !$proxyLookup->isTrustedProxy( $curIP )
1243  ) {
1244  break; // IP is not valid/trusted or does not point to anything
1245  }
1246  if (
1247  IP::isPublic( $ipchain[$i + 1] ) ||
1248  $wgUsePrivateIPs ||
1249  $proxyLookup->isConfiguredProxy( $curIP ) // T50919; treat IP as sane
1250  ) {
1251  // Follow the next IP according to the proxy
1252  $nextIP = IP::canonicalize( $ipchain[$i + 1] );
1253  if ( !$nextIP && $isConfigured ) {
1254  // We have not yet made it past CDN/proxy servers of this site,
1255  // so either they are misconfigured or there is some IP spoofing.
1256  throw new MWException( "Invalid IP given in XFF '$forwardedFor'." );
1257  }
1258  $ip = $nextIP;
1259  // keep traversing the chain
1260  continue;
1261  }
1262  break;
1263  }
1264  }
1265 
1266  # Allow extensions to improve our guess
1267  Hooks::run( 'GetIP', [ &$ip ] );
1268 
1269  if ( !$ip ) {
1270  throw new MWException( "Unable to determine IP." );
1271  }
1272 
1273  wfDebug( "IP: $ip\n" );
1274  $this->ip = $ip;
1275  return $ip;
1276  }
1277 
1283  public function setIP( $ip ) {
1284  $this->ip = $ip;
1285  }
1286 
1299  public function hasSafeMethod() {
1300  if ( !isset( $_SERVER['REQUEST_METHOD'] ) ) {
1301  return false; // CLI mode
1302  }
1303 
1304  return in_array( $_SERVER['REQUEST_METHOD'], [ 'GET', 'HEAD', 'OPTIONS', 'TRACE' ] );
1305  }
1306 
1325  public function isSafeRequest() {
1326  if ( $this->markedAsSafe && $this->wasPosted() ) {
1327  return true; // marked as a "safe" POST
1328  }
1329 
1330  return $this->hasSafeMethod();
1331  }
1332 
1343  public function markAsSafeRequest() {
1344  $this->markedAsSafe = true;
1345  }
1346 }
PathRouter\add
add( $path, $params=[], $options=[])
Add a new path pattern to the path router.
Definition: PathRouter.php:160
WebRequest\initHeaders
initHeaders()
Initialise the header list.
Definition: WebRequest.php:985
WebRequest\$sessionId
SessionId null $sessionId
Session ID to use for this request.
Definition: WebRequest.php:85
FauxRequest
WebRequest clone which takes values from a provided array.
Definition: FauxRequest.php:33
WebRequest\getSessionData
getSessionData( $key)
Get data from the session.
Definition: WebRequest.php:1049
$wgActionPaths
$wgActionPaths
Definition: img_auth.php:47
WebRequest\getValueNames
getValueNames( $exclude=[])
Returns the names of all input values excluding those in $exclude.
Definition: WebRequest.php:644
IP\combineHostAndPort
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.
Definition: IP.php:315
captcha-old.count
count
Definition: captcha-old.py:249
WebRequest\getSessionId
getSessionId()
Get the session id for this request, if any.
Definition: WebRequest.php:771
$wgScript
$wgScript
The URL path to index.php.
Definition: DefaultSettings.php:185
WebRequest\appendQueryValue
appendQueryValue( $key, $value)
Definition: WebRequest.php:867
WebRequest\interpolateTitle
interpolateTitle()
Check for title, action, and/or variant data in the URL and interpolate it into the GET variables.
Definition: WebRequest.php:314
WebRequest\setSessionId
setSessionId(SessionId $sessionId)
Set the session for this request.
Definition: WebRequest.php:761
WebRequest\getElapsedTime
getElapsedTime()
Get the number of seconds to have elapsed since request start, in fractional seconds,...
Definition: WebRequest.php:263
WebRequest\getIntOrNull
getIntOrNull( $name)
Fetch an integer value from the input or return null if empty.
Definition: WebRequest.php:538
IP
A collection of public static functions to play with IP address and IP ranges.
Definition: IP.php:67
WebRequest\getRawPostString
getRawPostString()
Return the contents of the POST with no decoding.
Definition: WebRequest.php:688
WebRequest\detectProtocol
static detectProtocol()
Detect the protocol from $_SERVER.
Definition: WebRequest.php:246
WebRequest\getGPCVal
getGPCVal( $arr, $name, $default)
Fetch a value from the given array or return $default if it's not set.
Definition: WebRequest.php:383
a
</source > ! result< div class="mw-highlight mw-content-ltr" dir="ltr">< pre >< span ></span >< span class="kd"> var</span >< span class="nx"> a</span >< span class="p"></span ></pre ></div > ! end ! test Multiline< source/> in lists !input *< source > a b</source > *foo< source > a b</source > ! html< ul >< li >< div class="mw-highlight mw-content-ltr" dir="ltr">< pre > a b</pre ></div ></li ></ul >< ul >< li > foo< div class="mw-highlight mw-content-ltr" dir="ltr">< pre > a b</pre ></div ></li ></ul > ! html tidy< ul >< li >< div class="mw-highlight mw-content-ltr" dir="ltr">< pre > a b</pre ></div ></li ></ul >< ul >< li > foo< div class="mw-highlight mw-content-ltr" dir="ltr">< pre > a b</pre ></div ></li ></ul > ! end ! test Custom attributes !input< source lang="javascript" id="foo" class="bar" dir="rtl" style="font-size: larger;"> var a
Definition: parserTests.txt:89
data
and how to run hooks for an and one after Each event has a preferably in CamelCase For ArticleDelete hook A clump of code and data that should be run when an event happens This can be either a function and a chunk of data
Definition: hooks.txt:6
$base
$base
Definition: generateLocalAutoload.php:11
WebRequest\$headers
$headers
Definition: WebRequest.php:42
HttpError
Show an error that looks like an HTTP server error.
Definition: HttpError.php:30
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
WebRequest\__construct
__construct()
Definition: WebRequest.php:93
WebRequest\getRawQueryString
getRawQueryString()
Return the contents of the Query with no decoding.
Definition: WebRequest.php:678
WebRequest\appendQueryArray
appendQueryArray( $array)
Appends or replaces value of query variables.
Definition: WebRequest.php:877
WebRequest\getFileTempname
getFileTempname( $key)
Return the path to the temporary file where PHP has stored the upload.
Definition: WebRequest.php:925
$wgAssumeProxiesUseDefaultProtocolPorts
bool $wgAssumeProxiesUseDefaultProtocolPorts
When the wiki is running behind a proxy and this is set to true, assumes that the proxy exposes the w...
Definition: DefaultSettings.php:87
WebRequest\getText
getText( $name, $default='')
Fetch a text string from the given array or return $default if it's not set.
Definition: WebRequest.php:610
WebRequest\$protocol
string $protocol
Cached URL protocol.
Definition: WebRequest.php:78
WebRequest\getMethod
getMethod()
Get the HTTP method used for this request.
Definition: WebRequest.php:715
MWException
MediaWiki exception.
Definition: MWException.php:26
WebRequest\getFileName
getFileName( $key)
Return the original filename of the uploaded file, as reported by the submitting user agent.
Definition: WebRequest.php:952
MediaWiki\Session\Session
Manages data for an an authenticated session.
Definition: Session.php:48
WebRequest\setVal
setVal( $key, $value)
Set an arbitrary value into our get/post data.
Definition: WebRequest.php:459
$input
if(is_array( $mode)) switch( $mode) $input
Definition: postprocess-phan.php:141
WebRequest\$reqId
static string $reqId
The unique request ID.
Definition: WebRequest.php:54
$matches
$matches
Definition: NoLocalSettings.php:24
WebRequest\getRawInput
getRawInput()
Return the raw request body, with no processing.
Definition: WebRequest.php:702
WebRequest\getUpload
getUpload( $key)
Return a WebRequestUpload object corresponding to the key.
Definition: WebRequest.php:963
WebRequest\getValues
getValues()
Extracts the given named values into an array.
Definition: WebRequest.php:622
WebRequest\getPathInfo
static getPathInfo( $want='all')
Extract relevant query arguments from the http request uri's path to be merged with the normal php pr...
Definition: WebRequest.php:116
PROTO_CURRENT
const PROTO_CURRENT
Definition: Defines.php:222
WebRequest\getFullRequestURL
getFullRequestURL()
Return the request URI with the canonical service and hostname, path, and query string.
Definition: WebRequest.php:858
WebRequest\getArray
getArray( $name, $default=null)
Fetch an array from the input or return $default if it's not set.
Definition: WebRequest.php:490
WebRequest\$response
WebResponse $response
Lazy-init response object.
Definition: WebRequest.php:60
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
WebRequest\getAllHeaders
getAllHeaders()
Get an array containing all request headers.
Definition: WebRequest.php:1012
array
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))
WebRequestUpload
Object to access the $_FILES array.
Definition: WebRequestUpload.php:30
WebRequest\normalizeUnicode
normalizeUnicode( $data)
Recursively normalizes UTF-8 strings in the given array.
Definition: WebRequest.php:362
WebRequest\getRawVal
getRawVal( $name, $default=null)
Fetch a scalar from the input without normalization, or return $default if it's not set.
Definition: WebRequest.php:416
WebRequest\$data
$data
Definition: WebRequest.php:42
IEUrlExtension\areServerVarsBad
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...
Definition: IEUrlExtension.php:62
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:302
WebRequest\getCheck
getCheck( $name)
Return true if the named value is set in the input, whatever that value is (even "0").
Definition: WebRequest.php:594
WebRequest\getProtocol
getProtocol()
Get the current URL protocol (http or https)
Definition: WebRequest.php:300
WebRequest\getSession
getSession()
Return the session for this request.
Definition: WebRequest.php:742
WebRequest\response
response()
Return a handle to WebResponse style object, for setting cookies, headers and other stuff,...
Definition: WebRequest.php:973
$value
$value
Definition: styleTest.css.php:49
IP\splitHostAndPort
static splitHostAndPort( $both)
Given a host/port string, like one might find in the host part of a URL per RFC 2732,...
Definition: IP.php:266
title
title
Definition: parserTests.txt:239
MediaWiki\Session\SessionManager
This serves as the entry point to the MediaWiki session handling system.
Definition: SessionManager.php:50
WebRequest\getLimitOffset
getLimitOffset( $deflimit=50, $optionname='rclimit')
Check for limit and offset parameters on the input, and return sensible defaults if not given.
Definition: WebRequest.php:894
WebRequest\checkUrlExtension
checkUrlExtension( $extWhitelist=[])
Check if Internet Explorer will detect an incorrect cache extension in PATH_INFO or QUERY_STRING.
Definition: WebRequest.php:1074
WebRequest\getIntArray
getIntArray( $name, $default=null)
Fetch an array of integers, or return $default if it's not set.
Definition: WebRequest.php:509
WebRequest\$requestTime
float $requestTime
The timestamp of the start of the request, with microsecond precision.
Definition: WebRequest.php:72
$ret
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:2036
IEUrlExtension\fixUrlForIE6
static fixUrlForIE6( $url, $extWhitelist=[])
Returns a variant of $url which will pass isUrlExtensionBad() but has the same GET parameters,...
Definition: IEUrlExtension.php:140
captcha-old.p
p
Definition: captcha-old.py:275
WebRequest\$markedAsSafe
bool $markedAsSafe
Whether this HTTP request is "safe" (even if it is an HTTP post)
Definition: WebRequest.php:88
WebRequest\getCookie
getCookie( $key, $prefix=null, $default=null)
Get a cookie from the $_COOKIE jar.
Definition: WebRequest.php:783
WebRequest
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form stripping il...
Definition: WebRequest.php:41
WebRequest\getUploadError
getUploadError( $key)
Return the upload error or 0.
Definition: WebRequest.php:936
$wgArticlePath
$wgArticlePath
Definition: img_auth.php:46
WebRequest\setSessionData
setSessionData( $key, $data)
Set session data.
Definition: WebRequest.php:1060
WebRequest\doSecurityRedirect
doSecurityRedirect( $url)
Attempt to redirect to a URL with a QUERY_STRING that's not dangerous in IE 6.
Definition: WebRequest.php:1098
WebRequest\GETHEADER_LIST
const GETHEADER_LIST
Flag to make WebRequest::getHeader return an array of values.
Definition: WebRequest.php:48
WebRequest\getVal
getVal( $name, $default=null)
Fetch a scalar from the input or return $default if it's not set.
Definition: WebRequest.php:440
WebRequest\getInt
getInt( $name, $default=0)
Fetch an integer value from the input or return $default if not set.
Definition: WebRequest.php:526
MediaWiki\Session\SessionId
Value object holding the session ID in a manner that can be globally updated.
Definition: SessionId.php:38
WebRequest\getRequestId
static getRequestId()
Get the unique request ID.
Definition: WebRequest.php:275
$path
$path
Definition: NoLocalSettings.php:25
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
WebRequest\getFloat
getFloat( $name, $default=0.0)
Fetch a floating point value from the input or return $default if not set.
Definition: WebRequest.php:555
WebRequest\detectServer
static detectServer()
Work out an appropriate URL prefix containing scheme and host, based on information detected from $_S...
Definition: WebRequest.php:200
WebRequest\getHeader
getHeader( $name, $flags=0)
Get a request header, or false if it isn't set.
Definition: WebRequest.php:1029
WebRequest\getGlobalRequestURL
static getGlobalRequestURL()
Return the path and query string portion of the main request URI.
Definition: WebRequest.php:798
WebRequest\$ip
string $ip
Cached client IP address.
Definition: WebRequest.php:66
WebRequest\getPostValues
getPostValues()
Get the values passed via POST.
Definition: WebRequest.php:667
class
you have access to all of the normal MediaWiki so you can get a DB use the etc For full docs on the Maintenance class
Definition: maintenance.txt:52
MediaWikiServices
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency MediaWikiServices
Definition: injection.txt:23
WebRequest\wasPosted
wasPosted()
Returns true if the present request was reached by a POST operation, false otherwise (GET,...
Definition: WebRequest.php:728
WebRequest\unsetVal
unsetVal( $key)
Unset an arbitrary value from our get/post data.
Definition: WebRequest.php:471
wfGetServerUrl
wfGetServerUrl( $proto)
Get the wiki's "server", i.e.
Definition: GlobalFunctions.php:590
WebRequest\getRequestURL
getRequestURL()
Return the path and query string portion of the request URI.
Definition: WebRequest.php:844
WebRequest\overrideRequestId
static overrideRequestId( $id)
Override the unique request ID.
Definition: WebRequest.php:292
WebRequest\extractTitle
static extractTitle( $path, $bases, $key=false)
URL rewriting function; tries to extract page title and, optionally, one other fixed parameter value ...
Definition: WebRequest.php:336
WebResponse
Allow programs to request this object from WebRequest::response() and handle all outputting (or lack ...
Definition: WebResponse.php:28
WebRequest\getQueryValues
getQueryValues()
Get the values passed in the query string.
Definition: WebRequest.php:655
WebRequest\getFuzzyBool
getFuzzyBool( $name, $default=false)
Fetch a boolean value from the input or return $default if not set.
Definition: WebRequest.php:581
Hooks\run
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:200
$wgVariantArticlePath
$wgVariantArticlePath
Like $wgArticlePath, but on multi-variant wikis, this provides a path format that describes which par...
Definition: DefaultSettings.php:3157
PathRouter
PathRouter class.
Definition: PathRouter.php:73
$wgCookiePrefix
$wgCookiePrefix
Cookies generated by MediaWiki have names starting with this prefix.
Definition: DefaultSettings.php:6047
redirect
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
Definition: All_system_messages.txt:1267
Language
Internationalisation code.
Definition: Language.php:35
WebRequest\getBool
getBool( $name, $default=false)
Fetch a boolean value from the input or return $default if not set.
Definition: WebRequest.php:568
$wgUsePathInfo
$wgUsePathInfo
Whether to support URLs like index.php/Page_title These often break when PHP is set up in CGI mode.
Definition: DefaultSettings.php:156
wfArrayToCgi
wfArrayToCgi( $array1, $array2=null, $prefix='')
This function takes one or two arrays as input, and returns a CGI-style string, e....
Definition: GlobalFunctions.php:368
wfRandomString
wfRandomString( $length=32)
Get a random string containing a number of pseudo-random hex characters.
Definition: GlobalFunctions.php:296