MediaWiki  1.29.1
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 = 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' ) {
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 
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 
154  if ( $wgArticlePath ) {
155  $router->add( $wgArticlePath );
156  }
157 
159  if ( $wgActionPaths ) {
160  $router->add( $wgActionPaths, [ 'action' => '$key' ] );
161  }
162 
163  global $wgVariantArticlePath, $wgContLang;
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 {
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] ) ) {
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 ) {
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() ) {
1061  $newUrl = IEUrlExtension::fixUrlForIE6(
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>
1094 We can't serve non-HTML content from the URL you have requested, because
1095 Internet Explorer would interpret it as an incorrect and potentially dangerous
1096 content type.</p>
1097 <p>Instead, please use <a href="$encUrl">this URL</a>, which is the same as the
1098 URL you have requested, except that "&amp;*" is appended. This prevents Internet
1099 Explorer from seeing a bogus file extension.
1100 </p>
1101 </body>
1102 </html>
1103 HTML;
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 }
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:968
WebRequest\$sessionId
SessionId null $sessionId
Session ID to use for this request.
Definition: WebRequest.php:82
$wgUser
$wgUser
Definition: Setup.php:781
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:1032
$wgActionPaths
$wgActionPaths
Definition: img_auth.php:46
$wgCookiePrefix
if( $wgLocalInterwiki) if( $wgSharedPrefix===false) if( $wgSharedSchema===false) if(! $wgCookiePrefix) $wgCookiePrefix
Definition: Setup.php:326
WebRequest\getValueNames
getValueNames( $exclude=[])
Returns the names of all input values excluding those in $exclude.
Definition: WebRequest.php:641
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:303
captcha-old.count
count
Definition: captcha-old.py:225
WebRequest\getSessionId
getSessionId()
Get the session id for this request, if any.
Definition: WebRequest.php:756
$wgScript
$wgScript
The URL path to index.php.
Definition: DefaultSettings.php:202
WebRequest\appendQueryValue
appendQueryValue( $key, $value)
Definition: WebRequest.php:850
WebRequest\interpolateTitle
interpolateTitle()
Check for title, action, and/or variant data in the URL and interpolate it into the GET variables.
Definition: WebRequest.php:310
WebRequest\setSessionId
setSessionId(SessionId $sessionId)
Set the session for this request.
Definition: WebRequest.php:746
WebRequest\getElapsedTime
getElapsedTime()
Get the number of seconds to have elapsed since request start, in fractional seconds,...
Definition: WebRequest.php:260
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:535
IP
A collection of public static functions to play with IP address and IP blocks.
Definition: IP.php:67
WebRequest\getRawPostString
getRawPostString()
Return the contents of the POST with no decoding.
Definition: WebRequest.php:673
WebRequest\detectProtocol
static detectProtocol()
Detect the protocol from $_SERVER.
Definition: WebRequest.php:243
WebRequest\getGPCVal
getGPCVal( $arr, $name, $default)
Fetch a value from the given array or return $default if it's not set.
Definition: WebRequest.php:380
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:304
$base
$base
Definition: generateLocalAutoload.php:10
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:663
WebRequest\appendQueryArray
appendQueryArray( $array)
Appends or replaces value of query variables.
Definition: WebRequest.php:860
WebRequest\getFileTempname
getFileTempname( $key)
Return the path to the temporary file where PHP has stored the upload.
Definition: WebRequest.php:908
$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:91
WebRequest\getText
getText( $name, $default='')
Fetch a text string from the given array or return $default if it's not set.
Definition: WebRequest.php:607
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:700
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:935
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
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:456
$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:687
WebRequest\getUpload
getUpload( $key)
Return a WebRequestUpload object corresponding to the key.
Definition: WebRequest.php:946
WebRequest\getValues
getValues()
Extracts the given named values into an array.
Definition: WebRequest.php:619
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:114
PROTO_CURRENT
const PROTO_CURRENT
Definition: Defines.php:220
$limit
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist Do not use this to implement individual filters if they are compatible with the ChangesListFilter and ChangesListFilterGroup structure use sub classes of those in conjunction with the ChangesListSpecialPageStructuredFilters hook This hook can be used to implement filters that do not implement that or custom behavior that is not an individual filter e g Watchlist and Watchlist you will want to construct new ChangesListBooleanFilter or ChangesListStringOptionsFilter objects When constructing you specify which group they belong to You can reuse existing or create your you must register them with $special registerFilterGroup removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context the output can only depend on parameters provided to this hook not on global state indicating whether full HTML should be generated If generation of HTML may be but other information should still be present in the ParserOutput object to manipulate or replace but no entry for that model exists in $wgContentHandlers please use GetContentModels hook to make them known to core if desired whether it is OK to use $contentModel on $title Handler functions that modify $ok should generally return false to prevent further hooks from further modifying $ok inclusive $limit
Definition: hooks.txt:1049
WebRequest\getFullRequestURL
getFullRequestURL()
Return the request URI with the canonical service and hostname, path, and query string.
Definition: WebRequest.php:841
WebRequest\getArray
getArray( $name, $default=null)
Fetch an array from the input or return $default if it's not set.
Definition: WebRequest.php:487
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:995
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:358
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:413
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:591
WebRequest\getProtocol
getProtocol()
Get the current URL protocol (http or https)
Definition: WebRequest.php:296
WebRequest\getSession
getSession()
Return the session for this request.
Definition: WebRequest.php:727
WebRequest\response
response()
Return a handle to WebResponse style object, for setting cookies, headers and other stuff,...
Definition: WebRequest.php:956
$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:254
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:211
MediaWiki\Session\SessionManager
This serves as the entry point to the MediaWiki session handling system.
Definition: SessionManager.php:49
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:877
WebRequest\checkUrlExtension
checkUrlExtension( $extWhitelist=[])
Check if Internet Explorer will detect an incorrect cache extension in PATH_INFO or QUERY_STRING.
Definition: WebRequest.php:1057
WebRequest\getIntArray
getIntArray( $name, $default=null)
Fetch an array of integers, or return $default if it's not set.
Definition: WebRequest.php:506
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:1956
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
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:768
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:919
$wgArticlePath
$wgArticlePath
Definition: img_auth.php:45
WebRequest\setSessionData
setSessionData( $key, $data)
Set session data.
Definition: WebRequest.php:1043
WebRequest\doSecurityRedirect
doSecurityRedirect( $url)
Attempt to redirect to a URL with a QUERY_STRING that's not dangerous in IE 6.
Definition: WebRequest.php:1081
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:437
WebRequest\getInt
getInt( $name, $default=0)
Fetch an integer value from the input or return $default if not set.
Definition: WebRequest.php:523
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:272
$path
$path
Definition: NoLocalSettings.php:26
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:552
WebRequest\detectServer
static detectServer()
Work out an appropriate URL prefix containing scheme and host, based on information detected from $_S...
Definition: WebRequest.php:197
WebRequest\getHeader
getHeader( $name, $flags=0)
Get a request header, or false if it isn't set.
Definition: WebRequest.php:1012
WebRequest\getGlobalRequestURL
static getGlobalRequestURL()
Return the path and query string portion of the main request URI.
Definition: WebRequest.php:783
WebRequest\$ip
string $ip
Cached client IP address.
Definition: WebRequest.php:63
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:713
WebRequest\unsetVal
unsetVal( $key)
Unset an arbitrary value from our get/post data.
Definition: WebRequest.php:468
WebRequest\getRequestURL
getRequestURL()
Return the path and query string portion of the request URI.
Definition: WebRequest.php:827
WebRequest\overrideRequestId
static overrideRequestId( $id)
Override the unique request ID.
Definition: WebRequest.php:288
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:332
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:652
WebRequest\getFuzzyBool
getFuzzyBool( $name, $default=false)
Fetch a boolean value from the input or return $default if not set.
Definition: WebRequest.php:578
Hooks\run
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:131
PathRouter
PathRouter class.
Definition: PathRouter.php:73
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
$flags
it s the revision text itself In either if gzip is the revision text is gzipped $flags
Definition: hooks.txt:2749
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:565
wfExpandUrl
wfExpandUrl( $url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL.
Definition: GlobalFunctions.php:552
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:160
$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:408
wfRandomString
wfRandomString( $length=32)
Get a random string containing a number of pseudo-random hex characters.
Definition: GlobalFunctions.php:336