Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
58.00% |
29 / 50 |
|
66.67% |
2 / 3 |
CRAP | |
0.00% |
0 / 1 |
| ApiEntryPoint | |
58.00% |
29 / 50 |
|
66.67% |
2 / 3 |
10.63 | |
0.00% |
0 / 1 |
| __construct | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
| getContext | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
| execute | |
51.16% |
22 / 43 |
|
0.00% |
0 / 1 |
7.91 | |||
| 1 | <?php |
| 2 | /** |
| 3 | * Entry point implementation for all %Action API queries, handled by ApiMain |
| 4 | * and ApiBase subclasses. |
| 5 | * |
| 6 | * @see /api.php The corresponding HTTP entry point. |
| 7 | * |
| 8 | * @license GPL-2.0-or-later |
| 9 | * @file |
| 10 | * @ingroup entrypoint |
| 11 | * @ingroup API |
| 12 | */ |
| 13 | |
| 14 | namespace MediaWiki\Api; |
| 15 | |
| 16 | use LogicException; |
| 17 | use MediaWiki\Context\RequestContext; |
| 18 | use MediaWiki\EntryPointEnvironment; |
| 19 | use MediaWiki\HookContainer\HookRunner; |
| 20 | use MediaWiki\MediaWikiEntryPoint; |
| 21 | use MediaWiki\MediaWikiServices; |
| 22 | use MediaWiki\Title\Title; |
| 23 | use Throwable; |
| 24 | |
| 25 | /** |
| 26 | * Implementation of the API entry point, for web browser navigations, usually via an |
| 27 | * Action or SpecialPage subclass. |
| 28 | * |
| 29 | * This is used by bots to fetch content and information about the wiki, |
| 30 | * its pages, and its users. See <https://www.mediawiki.org/wiki/API> for more |
| 31 | * information. |
| 32 | * |
| 33 | * @see /api.php The corresponding HTTP entry point. |
| 34 | * @internal |
| 35 | */ |
| 36 | class ApiEntryPoint extends MediaWikiEntryPoint { |
| 37 | |
| 38 | public function __construct( |
| 39 | RequestContext $context, |
| 40 | EntryPointEnvironment $environment, |
| 41 | MediaWikiServices $services |
| 42 | ) { |
| 43 | parent::__construct( |
| 44 | $context, |
| 45 | $environment, |
| 46 | $services |
| 47 | ); |
| 48 | } |
| 49 | |
| 50 | /** |
| 51 | * Overwritten to narrow the return type to RequestContext |
| 52 | */ |
| 53 | protected function getContext(): RequestContext { |
| 54 | /** @var RequestContext $context */ |
| 55 | $context = parent::getContext(); |
| 56 | |
| 57 | // @phan-suppress-next-line PhanTypeMismatchReturnSuperType see $context in the constructor |
| 58 | return $context; |
| 59 | } |
| 60 | |
| 61 | /** |
| 62 | * Executes a request to the action API. |
| 63 | * |
| 64 | * It begins by constructing a new ApiMain using the parameter passed to it |
| 65 | * as an argument in the URL ('?action='). It then invokes "execute()" on the |
| 66 | * ApiMain object instance, which produces output in the format specified in |
| 67 | * the URL. |
| 68 | */ |
| 69 | protected function execute() { |
| 70 | // phpcs:ignore MediaWiki.Usage.DeprecatedGlobalVariables.Deprecated$wgTitle |
| 71 | global $wgTitle; |
| 72 | |
| 73 | $context = $this->getContext(); |
| 74 | $request = $this->getRequest(); |
| 75 | |
| 76 | $services = $this->getServiceContainer(); |
| 77 | |
| 78 | // PATH_INFO can be used for stupid things. We don't support it for api.php at |
| 79 | // all, so error out if it's present. (T128209) |
| 80 | $pathInfo = $this->environment->getServerInfo( 'PATH_INFO', '' ); |
| 81 | if ( $pathInfo != '' ) { |
| 82 | $correctUrl = wfAppendQuery( |
| 83 | wfScript( 'api' ), |
| 84 | $request->getQueryValuesOnly() |
| 85 | ); |
| 86 | $correctUrl = (string)$services->getUrlUtils()->expand( |
| 87 | $correctUrl, |
| 88 | PROTO_CANONICAL |
| 89 | ); |
| 90 | $this->header( |
| 91 | "Location: $correctUrl", |
| 92 | true, |
| 93 | 301 |
| 94 | ); |
| 95 | $this->print( |
| 96 | 'This endpoint does not support "path info", i.e. extra text ' . |
| 97 | 'between "api.php" and the "?". Remove any such text and try again.' |
| 98 | ); |
| 99 | $this->exit( 1 ); |
| 100 | } |
| 101 | |
| 102 | // Set a dummy $wgTitle, because $wgTitle == null breaks various things |
| 103 | // In a perfect world this wouldn't be necessary |
| 104 | $wgTitle = Title::makeTitle( |
| 105 | NS_SPECIAL, |
| 106 | 'Badtitle/dummy title for API calls set in api.php' |
| 107 | ); |
| 108 | |
| 109 | // RequestContext will read from $wgTitle, but it will also whine about it. |
| 110 | // In a perfect world this wouldn't be necessary either. |
| 111 | $context->setTitle( $wgTitle ); |
| 112 | |
| 113 | try { |
| 114 | // Construct an ApiMain with the arguments passed via the URL. What we get back |
| 115 | // is some form of an ApiMain, possibly even one that produces an error message, |
| 116 | // but we don't care here, as that is handled by the constructor. |
| 117 | $processor = new ApiMain( |
| 118 | $context, |
| 119 | true, |
| 120 | false |
| 121 | ); |
| 122 | |
| 123 | // Last chance hook before executing the API |
| 124 | ( new HookRunner( $services->getHookContainer() ) )->onApiBeforeMain( $processor ); |
| 125 | if ( !$processor instanceof ApiMain ) { |
| 126 | throw new LogicException( |
| 127 | 'ApiBeforeMain hook set $processor to a non-ApiMain class' |
| 128 | ); |
| 129 | } |
| 130 | } catch ( Throwable $e ) { |
| 131 | // Crap. Try to report the exception in API format to be friendly to clients. |
| 132 | ApiMain::handleApiBeforeMainException( $e ); |
| 133 | $processor = false; |
| 134 | } |
| 135 | |
| 136 | // Process data & print results |
| 137 | if ( $processor ) { |
| 138 | $processor->execute(); |
| 139 | } |
| 140 | } |
| 141 | } |