MediaWiki  1.31.0
WebRequest.php
Go to the documentation of this file.
1 <?php
30 
38 class WebRequest {
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 = $_SERVER['REQUEST_TIME_FLOAT'];
92 
93  // POST overrides GET data
94  // We don't use $_REQUEST here to avoid interference from cookies...
95  $this->data = $_POST + $_GET;
96  }
97 
113  public static function getPathInfo( $want = 'all' ) {
115  // PATH_INFO is mangled due to https://bugs.php.net/bug.php?id=31892
116  // And also by Apache 2.x, double slashes are converted to single slashes.
117  // So we will use REQUEST_URI if possible.
118  $matches = [];
119  if ( !empty( $_SERVER['REQUEST_URI'] ) ) {
120  // Slurp out the path portion to examine...
121  $url = $_SERVER['REQUEST_URI'];
122  if ( !preg_match( '!^https?://!', $url ) ) {
123  $url = 'http://unused' . $url;
124  }
125  Wikimedia\suppressWarnings();
126  $a = parse_url( $url );
127  Wikimedia\restoreWarnings();
128  if ( $a ) {
129  $path = isset( $a['path'] ) ? $a['path'] : '';
130 
132  if ( $path == $wgScript && $want !== 'all' ) {
133  // Script inside a rewrite path?
134  // Abort to keep from breaking...
135  return $matches;
136  }
137 
138  $router = new PathRouter;
139 
140  // Raw PATH_INFO style
141  $router->add( "$wgScript/$1" );
142 
143  if ( isset( $_SERVER['SCRIPT_NAME'] )
144  && preg_match( '/\.php/', $_SERVER['SCRIPT_NAME'] )
145  ) {
146  # Check for SCRIPT_NAME, we handle index.php explicitly
147  # But we do have some other .php files such as img_auth.php
148  # Don't let root article paths clober the parsing for them
149  $router->add( $_SERVER['SCRIPT_NAME'] . "/$1" );
150  }
151 
153  if ( $wgArticlePath ) {
154  $router->add( $wgArticlePath );
155  }
156 
158  if ( $wgActionPaths ) {
159  $router->add( $wgActionPaths, [ 'action' => '$key' ] );
160  }
161 
163  if ( $wgVariantArticlePath ) {
164  $router->add( $wgVariantArticlePath,
165  [ 'variant' => '$2' ],
166  [ '$2' => $wgContLang->getVariants() ]
167  );
168  }
169 
170  Hooks::run( 'WebRequestPathInfoRouter', [ $router ] );
171 
172  $matches = $router->parse( $path );
173  }
174  } elseif ( $wgUsePathInfo ) {
175  if ( isset( $_SERVER['ORIG_PATH_INFO'] ) && $_SERVER['ORIG_PATH_INFO'] != '' ) {
176  // Mangled PATH_INFO
177  // https://bugs.php.net/bug.php?id=31892
178  // Also reported when ini_get('cgi.fix_pathinfo')==false
179  $matches['title'] = substr( $_SERVER['ORIG_PATH_INFO'], 1 );
180 
181  } elseif ( isset( $_SERVER['PATH_INFO'] ) && $_SERVER['PATH_INFO'] != '' ) {
182  // Regular old PATH_INFO yay
183  $matches['title'] = substr( $_SERVER['PATH_INFO'], 1 );
184  }
185  }
186 
187  return $matches;
188  }
189 
196  public static function detectServer() {
198 
199  $proto = self::detectProtocol();
200  $stdPort = $proto === 'https' ? 443 : 80;
201 
202  $varNames = [ 'HTTP_HOST', 'SERVER_NAME', 'HOSTNAME', 'SERVER_ADDR' ];
203  $host = 'localhost';
204  $port = $stdPort;
205  foreach ( $varNames as $varName ) {
206  if ( !isset( $_SERVER[$varName] ) ) {
207  continue;
208  }
209 
210  $parts = IP::splitHostAndPort( $_SERVER[$varName] );
211  if ( !$parts ) {
212  // Invalid, do not use
213  continue;
214  }
215 
216  $host = $parts[0];
217  if ( $wgAssumeProxiesUseDefaultProtocolPorts && isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) ) {
218  // T72021: Assume that upstream proxy is running on the default
219  // port based on the protocol. We have no reliable way to determine
220  // the actual port in use upstream.
221  $port = $stdPort;
222  } elseif ( $parts[1] === false ) {
223  if ( isset( $_SERVER['SERVER_PORT'] ) ) {
224  $port = $_SERVER['SERVER_PORT'];
225  } // else leave it as $stdPort
226  } else {
227  $port = $parts[1];
228  }
229  break;
230  }
231 
232  return $proto . '://' . IP::combineHostAndPort( $host, $port, $stdPort );
233  }
234 
242  public static function detectProtocol() {
243  if ( ( !empty( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] !== 'off' ) ||
244  ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) &&
245  $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https' ) ) {
246  return 'https';
247  } else {
248  return 'http';
249  }
250  }
251 
259  public function getElapsedTime() {
260  return microtime( true ) - $this->requestTime;
261  }
262 
271  public static function getRequestId() {
272  // This method is called from various error handlers and should be kept simple.
273 
274  if ( !self::$reqId ) {
275  self::$reqId = isset( $_SERVER['UNIQUE_ID'] )
276  ? $_SERVER['UNIQUE_ID'] : wfRandomString( 24 );
277  }
278 
279  return self::$reqId;
280  }
281 
289  public static function overrideRequestId( $id ) {
290  self::$reqId = $id;
291  }
292 
297  public function getProtocol() {
298  if ( $this->protocol === null ) {
299  $this->protocol = self::detectProtocol();
300  }
301  return $this->protocol;
302  }
303 
311  public function interpolateTitle() {
312  // T18019: title interpolation on API queries is useless and sometimes harmful
313  if ( defined( 'MW_API' ) ) {
314  return;
315  }
316 
317  $matches = self::getPathInfo( 'title' );
318  foreach ( $matches as $key => $val ) {
319  $this->data[$key] = $_GET[$key] = $_REQUEST[$key] = $val;
320  }
321  }
322 
333  static function extractTitle( $path, $bases, $key = false ) {
334  foreach ( (array)$bases as $keyValue => $base ) {
335  // Find the part after $wgArticlePath
336  $base = str_replace( '$1', '', $base );
337  $baseLen = strlen( $base );
338  if ( substr( $path, 0, $baseLen ) == $base ) {
339  $raw = substr( $path, $baseLen );
340  if ( $raw !== '' ) {
341  $matches = [ 'title' => rawurldecode( $raw ) ];
342  if ( $key ) {
343  $matches[$key] = $keyValue;
344  }
345  return $matches;
346  }
347  }
348  }
349  return [];
350  }
351 
359  public function normalizeUnicode( $data ) {
360  if ( is_array( $data ) ) {
361  foreach ( $data as $key => $val ) {
362  $data[$key] = $this->normalizeUnicode( $val );
363  }
364  } else {
366  $data = isset( $wgContLang ) ?
367  $wgContLang->normalize( $data ) :
368  UtfNormal\Validator::cleanUp( $data );
369  }
370  return $data;
371  }
372 
381  private function getGPCVal( $arr, $name, $default ) {
382  # PHP is so nice to not touch input data, except sometimes:
383  # https://secure.php.net/variables.external#language.variables.external.dot-in-names
384  # Work around PHP *feature* to avoid *bugs* elsewhere.
385  $name = strtr( $name, '.', '_' );
386  if ( isset( $arr[$name] ) ) {
388  $data = $arr[$name];
389  if ( isset( $_GET[$name] ) && !is_array( $data ) ) {
390  # Check for alternate/legacy character encoding.
391  if ( isset( $wgContLang ) ) {
392  $data = $wgContLang->checkTitleEncoding( $data );
393  }
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 = isset( $this->data[$key] ) ? $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 
664  public function getRawQueryString() {
665  return $_SERVER['QUERY_STRING'];
666  }
667 
674  public function getRawPostString() {
675  if ( !$this->wasPosted() ) {
676  return '';
677  }
678  return $this->getRawInput();
679  }
680 
688  public function getRawInput() {
689  static $input = null;
690  if ( $input === null ) {
691  $input = file_get_contents( 'php://input' );
692  }
693  return $input;
694  }
695 
701  public function getMethod() {
702  return isset( $_SERVER['REQUEST_METHOD'] ) ? $_SERVER['REQUEST_METHOD'] : 'GET';
703  }
704 
714  public function wasPosted() {
715  return $this->getMethod() == 'POST';
716  }
717 
728  public function getSession() {
729  if ( $this->sessionId !== null ) {
730  $session = SessionManager::singleton()->getSessionById( (string)$this->sessionId, true, $this );
731  if ( $session ) {
732  return $session;
733  }
734  }
735 
736  $session = SessionManager::singleton()->getSessionForRequest( $this );
737  $this->sessionId = $session->getSessionId();
738  return $session;
739  }
740 
747  public function setSessionId( SessionId $sessionId ) {
748  $this->sessionId = $sessionId;
749  }
750 
757  public function getSessionId() {
758  return $this->sessionId;
759  }
760 
769  public function getCookie( $key, $prefix = null, $default = null ) {
770  if ( $prefix === null ) {
772  $prefix = $wgCookiePrefix;
773  }
774  return $this->getGPCVal( $_COOKIE, $prefix . $key, $default );
775  }
776 
784  public static function getGlobalRequestURL() {
785  // This method is called on fatal errors; it should not depend on anything complex.
786 
787  if ( isset( $_SERVER['REQUEST_URI'] ) && strlen( $_SERVER['REQUEST_URI'] ) ) {
788  $base = $_SERVER['REQUEST_URI'];
789  } elseif ( isset( $_SERVER['HTTP_X_ORIGINAL_URL'] )
790  && strlen( $_SERVER['HTTP_X_ORIGINAL_URL'] )
791  ) {
792  // Probably IIS; doesn't set REQUEST_URI
793  $base = $_SERVER['HTTP_X_ORIGINAL_URL'];
794  } elseif ( isset( $_SERVER['SCRIPT_NAME'] ) ) {
795  $base = $_SERVER['SCRIPT_NAME'];
796  if ( isset( $_SERVER['QUERY_STRING'] ) && $_SERVER['QUERY_STRING'] != '' ) {
797  $base .= '?' . $_SERVER['QUERY_STRING'];
798  }
799  } else {
800  // This shouldn't happen!
801  throw new MWException( "Web server doesn't provide either " .
802  "REQUEST_URI, HTTP_X_ORIGINAL_URL or SCRIPT_NAME. Report details " .
803  "of your web server configuration to https://phabricator.wikimedia.org/" );
804  }
805  // User-agents should not send a fragment with the URI, but
806  // if they do, and the web server passes it on to us, we
807  // need to strip it or we get false-positive redirect loops
808  // or weird output URLs
809  $hash = strpos( $base, '#' );
810  if ( $hash !== false ) {
811  $base = substr( $base, 0, $hash );
812  }
813 
814  if ( $base[0] == '/' ) {
815  // More than one slash will look like it is protocol relative
816  return preg_replace( '!^/+!', '/', $base );
817  } else {
818  // We may get paths with a host prepended; strip it.
819  return preg_replace( '!^[^:]+://[^/]+/+!', '/', $base );
820  }
821  }
822 
830  public function getRequestURL() {
831  return self::getGlobalRequestURL();
832  }
833 
844  public function getFullRequestURL() {
845  return wfExpandUrl( $this->getRequestURL(), PROTO_CURRENT );
846  }
847 
853  public function appendQueryValue( $key, $value ) {
854  return $this->appendQueryArray( [ $key => $value ] );
855  }
856 
863  public function appendQueryArray( $array ) {
864  $newquery = $this->getQueryValues();
865  unset( $newquery['title'] );
866  $newquery = array_merge( $newquery, $array );
867 
868  return wfArrayToCgi( $newquery );
869  }
870 
880  public function getLimitOffset( $deflimit = 50, $optionname = 'rclimit' ) {
881  global $wgUser;
882 
883  $limit = $this->getInt( 'limit', 0 );
884  if ( $limit < 0 ) {
885  $limit = 0;
886  }
887  if ( ( $limit == 0 ) && ( $optionname != '' ) ) {
888  $limit = $wgUser->getIntOption( $optionname );
889  }
890  if ( $limit <= 0 ) {
891  $limit = $deflimit;
892  }
893  if ( $limit > 5000 ) {
894  $limit = 5000; # We have *some* limits...
895  }
896 
897  $offset = $this->getInt( 'offset', 0 );
898  if ( $offset < 0 ) {
899  $offset = 0;
900  }
901 
902  return [ $limit, $offset ];
903  }
904 
911  public function getFileTempname( $key ) {
912  $file = new WebRequestUpload( $this, $key );
913  return $file->getTempName();
914  }
915 
922  public function getUploadError( $key ) {
923  $file = new WebRequestUpload( $this, $key );
924  return $file->getError();
925  }
926 
938  public function getFileName( $key ) {
939  $file = new WebRequestUpload( $this, $key );
940  return $file->getName();
941  }
942 
949  public function getUpload( $key ) {
950  return new WebRequestUpload( $this, $key );
951  }
952 
959  public function response() {
960  /* Lazy initialization of response object for this request */
961  if ( !is_object( $this->response ) ) {
962  $class = ( $this instanceof FauxRequest ) ? FauxResponse::class : WebResponse::class;
963  $this->response = new $class();
964  }
965  return $this->response;
966  }
967 
971  protected function initHeaders() {
972  if ( count( $this->headers ) ) {
973  return;
974  }
975 
976  $apacheHeaders = function_exists( 'apache_request_headers' ) ? apache_request_headers() : false;
977  if ( $apacheHeaders ) {
978  foreach ( $apacheHeaders as $tempName => $tempValue ) {
979  $this->headers[strtoupper( $tempName )] = $tempValue;
980  }
981  } else {
982  foreach ( $_SERVER as $name => $value ) {
983  if ( substr( $name, 0, 5 ) === 'HTTP_' ) {
984  $name = str_replace( '_', '-', substr( $name, 5 ) );
985  $this->headers[$name] = $value;
986  } elseif ( $name === 'CONTENT_LENGTH' ) {
987  $this->headers['CONTENT-LENGTH'] = $value;
988  }
989  }
990  }
991  }
992 
998  public function getAllHeaders() {
999  $this->initHeaders();
1000  return $this->headers;
1001  }
1002 
1015  public function getHeader( $name, $flags = 0 ) {
1016  $this->initHeaders();
1017  $name = strtoupper( $name );
1018  if ( !isset( $this->headers[$name] ) ) {
1019  return false;
1020  }
1021  $value = $this->headers[$name];
1022  if ( $flags & self::GETHEADER_LIST ) {
1023  $value = array_map( 'trim', explode( ',', $value ) );
1024  }
1025  return $value;
1026  }
1027 
1035  public function getSessionData( $key ) {
1036  return $this->getSession()->get( $key );
1037  }
1038 
1046  public function setSessionData( $key, $data ) {
1047  $this->getSession()->set( $key, $data );
1048  }
1049 
1060  public function checkUrlExtension( $extWhitelist = [] ) {
1061  $extWhitelist[] = 'php';
1062  if ( IEUrlExtension::areServerVarsBad( $_SERVER, $extWhitelist ) ) {
1063  if ( !$this->wasPosted() ) {
1064  $newUrl = IEUrlExtension::fixUrlForIE6(
1065  $this->getFullRequestURL(), $extWhitelist );
1066  if ( $newUrl !== false ) {
1067  $this->doSecurityRedirect( $newUrl );
1068  return false;
1069  }
1070  }
1071  throw new HttpError( 403,
1072  'Invalid file extension found in the path info or query string.' );
1073  }
1074  return true;
1075  }
1076 
1084  protected function doSecurityRedirect( $url ) {
1085  header( 'Location: ' . $url );
1086  header( 'Content-Type: text/html' );
1087  $encUrl = htmlspecialchars( $url );
1088  echo <<<HTML
1089 <!DOCTYPE html>
1090 <html>
1091 <head>
1092 <title>Security redirect</title>
1093 </head>
1094 <body>
1095 <h1>Security redirect</h1>
1096 <p>
1097 We can't serve non-HTML content from the URL you have requested, because
1098 Internet Explorer would interpret it as an incorrect and potentially dangerous
1099 content type.</p>
1100 <p>Instead, please use <a href="$encUrl">this URL</a>, which is the same as the
1101 URL you have requested, except that "&amp;*" is appended. This prevents Internet
1102 Explorer from seeing a bogus file extension.
1103 </p>
1104 </body>
1105 </html>
1106 HTML;
1107  echo "\n";
1108  return true;
1109  }
1110 
1120  public function getAcceptLang() {
1121  // Modified version of code found at
1122  // http://www.thefutureoftheweb.com/blog/use-accept-language-header
1123  $acceptLang = $this->getHeader( 'Accept-Language' );
1124  if ( !$acceptLang ) {
1125  return [];
1126  }
1127 
1128  // Return the language codes in lower case
1129  $acceptLang = strtolower( $acceptLang );
1130 
1131  // Break up string into pieces (languages and q factors)
1132  $lang_parse = null;
1133  preg_match_all(
1134  '/([a-z]{1,8}(-[a-z]{1,8})*|\*)\s*(;\s*q\s*=\s*(1(\.0{0,3})?|0(\.[0-9]{0,3})?)?)?/',
1135  $acceptLang,
1136  $lang_parse
1137  );
1138 
1139  if ( !count( $lang_parse[1] ) ) {
1140  return [];
1141  }
1142 
1143  $langcodes = $lang_parse[1];
1144  $qvalues = $lang_parse[4];
1145  $indices = range( 0, count( $lang_parse[1] ) - 1 );
1146 
1147  // Set default q factor to 1
1148  foreach ( $indices as $index ) {
1149  if ( $qvalues[$index] === '' ) {
1150  $qvalues[$index] = 1;
1151  } elseif ( $qvalues[$index] == 0 ) {
1152  unset( $langcodes[$index], $qvalues[$index], $indices[$index] );
1153  }
1154  }
1155 
1156  // Sort list. First by $qvalues, then by order. Reorder $langcodes the same way
1157  array_multisort( $qvalues, SORT_DESC, SORT_NUMERIC, $indices, $langcodes );
1158 
1159  // Create a list like "en" => 0.8
1160  $langs = array_combine( $langcodes, $qvalues );
1161 
1162  return $langs;
1163  }
1164 
1173  protected function getRawIP() {
1174  if ( !isset( $_SERVER['REMOTE_ADDR'] ) ) {
1175  return null;
1176  }
1177 
1178  if ( is_array( $_SERVER['REMOTE_ADDR'] ) || strpos( $_SERVER['REMOTE_ADDR'], ',' ) !== false ) {
1179  throw new MWException( __METHOD__
1180  . " : Could not determine the remote IP address due to multiple values." );
1181  } else {
1182  $ipchain = $_SERVER['REMOTE_ADDR'];
1183  }
1184 
1185  return IP::canonicalize( $ipchain );
1186  }
1187 
1197  public function getIP() {
1198  global $wgUsePrivateIPs;
1199 
1200  # Return cached result
1201  if ( $this->ip !== null ) {
1202  return $this->ip;
1203  }
1204 
1205  # collect the originating ips
1206  $ip = $this->getRawIP();
1207  if ( !$ip ) {
1208  throw new MWException( 'Unable to determine IP.' );
1209  }
1210 
1211  # Append XFF
1212  $forwardedFor = $this->getHeader( 'X-Forwarded-For' );
1213  if ( $forwardedFor !== false ) {
1214  $proxyLookup = MediaWikiServices::getInstance()->getProxyLookup();
1215  $isConfigured = $proxyLookup->isConfiguredProxy( $ip );
1216  $ipchain = array_map( 'trim', explode( ',', $forwardedFor ) );
1217  $ipchain = array_reverse( $ipchain );
1218  array_unshift( $ipchain, $ip );
1219 
1220  # Step through XFF list and find the last address in the list which is a
1221  # trusted server. Set $ip to the IP address given by that trusted server,
1222  # unless the address is not sensible (e.g. private). However, prefer private
1223  # IP addresses over proxy servers controlled by this site (more sensible).
1224  # Note that some XFF values might be "unknown" with Squid/Varnish.
1225  foreach ( $ipchain as $i => $curIP ) {
1226  $curIP = IP::sanitizeIP( IP::canonicalize( $curIP ) );
1227  if ( !$curIP || !isset( $ipchain[$i + 1] ) || $ipchain[$i + 1] === 'unknown'
1228  || !$proxyLookup->isTrustedProxy( $curIP )
1229  ) {
1230  break; // IP is not valid/trusted or does not point to anything
1231  }
1232  if (
1233  IP::isPublic( $ipchain[$i + 1] ) ||
1234  $wgUsePrivateIPs ||
1235  $proxyLookup->isConfiguredProxy( $curIP ) // T50919; treat IP as sane
1236  ) {
1237  // Follow the next IP according to the proxy
1238  $nextIP = IP::canonicalize( $ipchain[$i + 1] );
1239  if ( !$nextIP && $isConfigured ) {
1240  // We have not yet made it past CDN/proxy servers of this site,
1241  // so either they are misconfigured or there is some IP spoofing.
1242  throw new MWException( "Invalid IP given in XFF '$forwardedFor'." );
1243  }
1244  $ip = $nextIP;
1245  // keep traversing the chain
1246  continue;
1247  }
1248  break;
1249  }
1250  }
1251 
1252  # Allow extensions to improve our guess
1253  Hooks::run( 'GetIP', [ &$ip ] );
1254 
1255  if ( !$ip ) {
1256  throw new MWException( "Unable to determine IP." );
1257  }
1258 
1259  wfDebug( "IP: $ip\n" );
1260  $this->ip = $ip;
1261  return $ip;
1262  }
1263 
1269  public function setIP( $ip ) {
1270  $this->ip = $ip;
1271  }
1272 
1285  public function hasSafeMethod() {
1286  if ( !isset( $_SERVER['REQUEST_METHOD'] ) ) {
1287  return false; // CLI mode
1288  }
1289 
1290  return in_array( $_SERVER['REQUEST_METHOD'], [ 'GET', 'HEAD', 'OPTIONS', 'TRACE' ] );
1291  }
1292 
1311  public function isSafeRequest() {
1312  if ( $this->markedAsSafe && $this->wasPosted() ) {
1313  return true; // marked as a "safe" POST
1314  }
1315 
1316  return $this->hasSafeMethod();
1317  }
1318 
1329  public function markAsSafeRequest() {
1330  $this->markedAsSafe = true;
1331  }
1332 }
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:971
WebRequest\$sessionId
SessionId null $sessionId
Session ID to use for this request.
Definition: WebRequest.php:82
$wgUser
$wgUser
Definition: Setup.php:894
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:1035
$wgActionPaths
$wgActionPaths
Definition: img_auth.php:46
WebRequest\getValueNames
getValueNames( $exclude=[])
Returns the names of all input values excluding those in $exclude.
Definition: WebRequest.php:642
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:757
$wgScript
$wgScript
The URL path to index.php.
Definition: DefaultSettings.php:185
WebRequest\appendQueryValue
appendQueryValue( $key, $value)
Definition: WebRequest.php:853
WebRequest\interpolateTitle
interpolateTitle()
Check for title, action, and/or variant data in the URL and interpolate it into the GET variables.
Definition: WebRequest.php:311
WebRequest\setSessionId
setSessionId(SessionId $sessionId)
Set the session for this request.
Definition: WebRequest.php:747
WebRequest\getElapsedTime
getElapsedTime()
Get the number of seconds to have elapsed since request start, in fractional seconds,...
Definition: WebRequest.php:259
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\getIntOrNull
getIntOrNull( $name)
Fetch an integer value from the input or return null if empty.
Definition: WebRequest.php:536
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:674
WebRequest\detectProtocol
static detectProtocol()
Detect the protocol from $_SERVER.
Definition: WebRequest.php:242
WebRequest\getGPCVal
getGPCVal( $arr, $name, $default)
Fetch a value from the given array or return $default if it's not set.
Definition: WebRequest.php:381
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
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:302
$base
$base
Definition: generateLocalAutoload.php:11
WebRequest\$headers
$headers
Definition: WebRequest.php:39
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:90
WebRequest\getRawQueryString
getRawQueryString()
Return the contents of the Query with no decoding.
Definition: WebRequest.php:664
WebRequest\appendQueryArray
appendQueryArray( $array)
Appends or replaces value of query variables.
Definition: WebRequest.php:863
WebRequest\getFileTempname
getFileTempname( $key)
Return the path to the temporary file where PHP has stored the upload.
Definition: WebRequest.php:911
$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:608
WebRequest\$protocol
string $protocol
Cached URL protocol.
Definition: WebRequest.php:75
WebRequest\getMethod
getMethod()
Get the HTTP method used for this request.
Definition: WebRequest.php:701
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:938
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:457
$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:51
$matches
$matches
Definition: NoLocalSettings.php:24
WebRequest\getRawInput
getRawInput()
Return the raw request body, with no processing.
Definition: WebRequest.php:688
WebRequest\getUpload
getUpload( $key)
Return a WebRequestUpload object corresponding to the key.
Definition: WebRequest.php:949
WebRequest\getValues
getValues()
Extracts the given named values into an array.
Definition: WebRequest.php:620
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:113
PROTO_CURRENT
const PROTO_CURRENT
Definition: Defines.php:223
WebRequest\getFullRequestURL
getFullRequestURL()
Return the request URI with the canonical service and hostname, path, and query string.
Definition: WebRequest.php:844
WebRequest\getArray
getArray( $name, $default=null)
Fetch an array from the input or return $default if it's not set.
Definition: WebRequest.php:488
WebRequest\$response
WebResponse $response
Lazy-init response object.
Definition: WebRequest.php:57
WebRequest\getAllHeaders
getAllHeaders()
Get an array containing all request headers.
Definition: WebRequest.php:998
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:93
WebRequestUpload
Object to access the $_FILES array.
Definition: WebRequestUpload.php:28
WebRequest\normalizeUnicode
normalizeUnicode( $data)
Recursively normalizes UTF-8 strings in the given array.
Definition: WebRequest.php:359
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:414
WebRequest\$data
$data
Definition: WebRequest.php:39
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
WebRequest\getCheck
getCheck( $name)
Return true if the named value is set in the input, whatever that value is (even "0").
Definition: WebRequest.php:592
WebRequest\getProtocol
getProtocol()
Get the current URL protocol (http or https)
Definition: WebRequest.php:297
WebRequest\getSession
getSession()
Return the session for this request.
Definition: WebRequest.php:728
WebRequest\response
response()
Return a handle to WebResponse style object, for setting cookies, headers and other stuff,...
Definition: WebRequest.php:959
$value
$value
Definition: styleTest.css.php:45
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
some
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
title
title
Definition: parserTests.txt:219
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:880
WebRequest\checkUrlExtension
checkUrlExtension( $extWhitelist=[])
Check if Internet Explorer will detect an incorrect cache extension in PATH_INFO or QUERY_STRING.
Definition: WebRequest.php:1060
WebRequest\getIntArray
getIntArray( $name, $default=null)
Fetch an array of integers, or return $default if it's not set.
Definition: WebRequest.php:507
WebRequest\$requestTime
float $requestTime
The timestamp of the start of the request, with microsecond precision.
Definition: WebRequest.php:69
$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:1987
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:85
WebRequest\getCookie
getCookie( $key, $prefix=null, $default=null)
Get a cookie from the $_COOKIE jar.
Definition: WebRequest.php:769
WebRequest
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form stripping il...
Definition: WebRequest.php:38
WebRequest\getUploadError
getUploadError( $key)
Return the upload error or 0.
Definition: WebRequest.php:922
$wgArticlePath
$wgArticlePath
Definition: img_auth.php:45
WebRequest\setSessionData
setSessionData( $key, $data)
Set session data.
Definition: WebRequest.php:1046
WebRequest\doSecurityRedirect
doSecurityRedirect( $url)
Attempt to redirect to a URL with a QUERY_STRING that's not dangerous in IE 6.
Definition: WebRequest.php:1084
WebRequest\GETHEADER_LIST
const GETHEADER_LIST
Flag to make WebRequest::getHeader return an array of values.
Definition: WebRequest.php:45
WebRequest\getVal
getVal( $name, $default=null)
Fetch a scalar from the input or return $default if it's not set.
Definition: WebRequest.php:438
WebRequest\getInt
getInt( $name, $default=0)
Fetch an integer value from the input or return $default if not set.
Definition: WebRequest.php:524
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:271
$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:553
WebRequest\detectServer
static detectServer()
Work out an appropriate URL prefix containing scheme and host, based on information detected from $_S...
Definition: WebRequest.php:196
WebRequest\getHeader
getHeader( $name, $flags=0)
Get a request header, or false if it isn't set.
Definition: WebRequest.php:1015
WebRequest\getGlobalRequestURL
static getGlobalRequestURL()
Return the path and query string portion of the main request URI.
Definition: WebRequest.php:784
WebRequest\$ip
string $ip
Cached client IP address.
Definition: WebRequest.php:63
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:714
WebRequest\unsetVal
unsetVal( $key)
Unset an arbitrary value from our get/post data.
Definition: WebRequest.php:469
WebRequest\getRequestURL
getRequestURL()
Return the path and query string portion of the request URI.
Definition: WebRequest.php:830
WebRequest\overrideRequestId
static overrideRequestId( $id)
Override the unique request ID.
Definition: WebRequest.php:289
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:333
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:653
WebRequest\getFuzzyBool
getFuzzyBool( $name, $default=false)
Fetch a boolean value from the input or return $default if not set.
Definition: WebRequest.php:579
Hooks\run
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:203
$wgVariantArticlePath
$wgVariantArticlePath
Like $wgArticlePath, but on multi-variant wikis, this provides a path format that describes which par...
Definition: DefaultSettings.php:3083
PathRouter
PathRouter class.
Definition: PathRouter.php:73
$wgCookiePrefix
$wgCookiePrefix
Cookies generated by MediaWiki have names starting with this prefix.
Definition: DefaultSettings.php:6003
headers
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:12
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
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
WebRequest\getBool
getBool( $name, $default=false)
Fetch a boolean value from the input or return $default if not set.
Definition: WebRequest.php:566
wfExpandUrl
wfExpandUrl( $url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL.
Definition: GlobalFunctions.php:521
array
the array() calling protocol came about after MediaWiki 1.4rc1.
$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
$wgContLang
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 content language as $wgContLang
Definition: design.txt:56
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:377
wfRandomString
wfRandomString( $length=32)
Get a random string containing a number of pseudo-random hex characters.
Definition: GlobalFunctions.php:305