use MediaWiki\Session\Session;
use MediaWiki\Session\SessionId;
use MediaWiki\Session\SessionManager;
+use Wikimedia\AtEase\AtEase;
// The point of this class is to be a wrapper around super globals
// phpcs:disable MediaWiki.Usage.SuperGlobalsUsage.SuperGlobals
* @ingroup HTTP
*/
class WebRequest {
- protected $data, $headers = [];
+ /**
+ * The parameters from $_GET, $_POST and the path router
+ * @var array
+ */
+ protected $data;
+
+ /**
+ * The parameters from $_GET. The parameters from the path router are
+ * added by interpolateTitle() during Setup.php.
+ * @var array
+ */
+ protected $queryAndPathParams;
+
+ /**
+ * The parameters from $_GET only.
+ */
+ protected $queryParams;
+
+ /**
+ * Lazy-initialized request headers indexed by upper-case header name
+ * @var array
+ */
+ protected $headers = [];
/**
* Flag to make WebRequest::getHeader return an array of values.
// POST overrides GET data
// We don't use $_REQUEST here to avoid interference from cookies...
$this->data = $_POST + $_GET;
+
+ $this->queryAndPathParams = $this->queryParams = $_GET;
}
/**
* @return array Any query arguments found in path matches.
*/
public static function getPathInfo( $want = 'all' ) {
- global $wgUsePathInfo;
// PATH_INFO is mangled due to https://bugs.php.net/bug.php?id=31892
// And also by Apache 2.x, double slashes are converted to single slashes.
// So we will use REQUEST_URI if possible.
- $matches = [];
- if ( !empty( $_SERVER['REQUEST_URI'] ) ) {
+ if ( isset( $_SERVER['REQUEST_URI'] ) ) {
// Slurp out the path portion to examine...
$url = $_SERVER['REQUEST_URI'];
if ( !preg_match( '!^https?://!', $url ) ) {
$url = 'http://unused' . $url;
}
- Wikimedia\suppressWarnings();
+ AtEase::suppressWarnings();
$a = parse_url( $url );
- Wikimedia\restoreWarnings();
- if ( $a ) {
- $path = $a['path'] ?? '';
-
- global $wgScript;
- if ( $path == $wgScript && $want !== 'all' ) {
- // Script inside a rewrite path?
- // Abort to keep from breaking...
- return $matches;
- }
+ AtEase::restoreWarnings();
+ if ( !$a ) {
+ return [];
+ }
+ $path = $a['path'] ?? '';
- $router = new PathRouter;
+ global $wgScript;
+ if ( $path == $wgScript && $want !== 'all' ) {
+ // Script inside a rewrite path?
+ // Abort to keep from breaking...
+ return [];
+ }
- // Raw PATH_INFO style
- $router->add( "$wgScript/$1" );
+ $router = new PathRouter;
- if ( isset( $_SERVER['SCRIPT_NAME'] )
- && preg_match( '/\.php/', $_SERVER['SCRIPT_NAME'] )
- ) {
- # Check for SCRIPT_NAME, we handle index.php explicitly
- # But we do have some other .php files such as img_auth.php
- # Don't let root article paths clober the parsing for them
- $router->add( $_SERVER['SCRIPT_NAME'] . "/$1" );
- }
-
- global $wgArticlePath;
- if ( $wgArticlePath ) {
- $router->add( $wgArticlePath );
- }
+ // Raw PATH_INFO style
+ $router->add( "$wgScript/$1" );
- global $wgActionPaths;
- if ( $wgActionPaths ) {
- $router->add( $wgActionPaths, [ 'action' => '$key' ] );
- }
+ if ( isset( $_SERVER['SCRIPT_NAME'] )
+ && strpos( $_SERVER['SCRIPT_NAME'], '.php' ) !== false
+ ) {
+ // Check for SCRIPT_NAME, we handle index.php explicitly
+ // But we do have some other .php files such as img_auth.php
+ // Don't let root article paths clober the parsing for them
+ $router->add( $_SERVER['SCRIPT_NAME'] . "/$1" );
+ }
- global $wgVariantArticlePath;
- if ( $wgVariantArticlePath ) {
- $router->add( $wgVariantArticlePath,
- [ 'variant' => '$2' ],
- [ '$2' => MediaWikiServices::getInstance()->getContentLanguage()->
- getVariants() ]
- );
- }
+ global $wgArticlePath;
+ if ( $wgArticlePath ) {
+ $router->add( $wgArticlePath );
+ }
- Hooks::run( 'WebRequestPathInfoRouter', [ $router ] );
+ global $wgActionPaths;
+ $articlePaths = PathRouter::getActionPaths( $wgActionPaths, $wgArticlePath );
+ if ( $articlePaths ) {
+ $router->add( $articlePaths, [ 'action' => '$key' ] );
+ }
- $matches = $router->parse( $path );
+ global $wgVariantArticlePath;
+ if ( $wgVariantArticlePath ) {
+ $router->add( $wgVariantArticlePath,
+ [ 'variant' => '$2' ],
+ [ '$2' => MediaWikiServices::getInstance()->getContentLanguage()->
+ getVariants() ]
+ );
}
- } elseif ( $wgUsePathInfo ) {
- if ( isset( $_SERVER['ORIG_PATH_INFO'] ) && $_SERVER['ORIG_PATH_INFO'] != '' ) {
- // Mangled PATH_INFO
- // https://bugs.php.net/bug.php?id=31892
- // Also reported when ini_get('cgi.fix_pathinfo')==false
- $matches['title'] = substr( $_SERVER['ORIG_PATH_INFO'], 1 );
-
- } elseif ( isset( $_SERVER['PATH_INFO'] ) && $_SERVER['PATH_INFO'] != '' ) {
- // Regular old PATH_INFO yay
- $matches['title'] = substr( $_SERVER['PATH_INFO'], 1 );
+
+ Hooks::run( 'WebRequestPathInfoRouter', [ $router ] );
+
+ $matches = $router->parse( $path );
+ } else {
+ global $wgUsePathInfo;
+ $matches = [];
+ if ( $wgUsePathInfo ) {
+ if ( !empty( $_SERVER['ORIG_PATH_INFO'] ) ) {
+ // Mangled PATH_INFO
+ // https://bugs.php.net/bug.php?id=31892
+ // Also reported when ini_get('cgi.fix_pathinfo')==false
+ $matches['title'] = substr( $_SERVER['ORIG_PATH_INFO'], 1 );
+ } elseif ( !empty( $_SERVER['PATH_INFO'] ) ) {
+ // Regular old PATH_INFO yay
+ $matches['title'] = substr( $_SERVER['PATH_INFO'], 1 );
+ }
}
}
$matches = self::getPathInfo( 'title' );
foreach ( $matches as $key => $val ) {
- $this->data[$key] = $_GET[$key] = $_REQUEST[$key] = $val;
+ $this->data[$key] = $this->queryAndPathParams[$key] = $val;
}
}
# https://www.php.net/variables.external#language.variables.external.dot-in-names
# Work around PHP *feature* to avoid *bugs* elsewhere.
$name = strtr( $name, '.', '_' );
- if ( isset( $arr[$name] ) ) {
- $data = $arr[$name];
+
+ if ( !isset( $arr[$name] ) ) {
+ return $default;
+ }
+
+ $data = $arr[$name];
+ # Optimisation: Skip UTF-8 normalization and legacy transcoding for simple ASCII strings.
+ $isAsciiStr = ( is_string( $data ) && preg_match( '/[^\x20-\x7E]/', $data ) === 0 );
+ if ( !$isAsciiStr ) {
if ( isset( $_GET[$name] ) && is_string( $data ) ) {
# Check for alternate/legacy character encoding.
- $contLang = MediaWikiServices::getInstance()->getContentLanguage();
- $data = $contLang->checkTitleEncoding( $data );
+ $data = MediaWikiServices::getInstance()
+ ->getContentLanguage()
+ ->checkTitleEncoding( $data );
}
$data = $this->normalizeUnicode( $data );
- return $data;
- } else {
- return $default;
}
+
+ return $data;
}
/**
*
* @param string $name
* @param array|null $default Option default (or null)
- * @return array Array of ints
+ * @return int[]|null
*/
public function getIntArray( $name, $default = null ) {
$val = $this->getArray( $name, $default );
}
/**
- * Get the values passed in the query string.
+ * Get the values passed in the query string and the path router parameters.
* No transformation is performed on the values.
*
* @codeCoverageIgnore
* @return array
*/
public function getQueryValues() {
- return $_GET;
+ return $this->queryAndPathParams;
+ }
+
+ /**
+ * Get the values passed in the query string only, not including the path
+ * router parameters. This is less suitable for self-links to index.php but
+ * useful for other entry points. No transformation is performed on the
+ * values.
+ *
+ * @since 1.34
+ * @return array
+ */
+ public function getQueryValuesOnly() {
+ return $this->queryParams;
}
/**