38 private bool $mIsHtml;
39 private string $mFormat;
40 private string $mBuffer =
'';
41 private bool $mDisabled =
false;
42 private $mIsWrappedHtml =
false;
43 private $mHttpStatus =
false;
53 parent::__construct( $main, $format );
55 $this->mIsHtml = str_ends_with( $format,
'fm' );
56 if ( $this->mIsHtml ) {
57 $this->mFormat = substr( $format, 0, -2 );
58 $this->mIsWrappedHtml = $this->
getMain()->getCheck(
'wrappedhtml' );
60 $this->mFormat = $format;
62 $this->mFormat = strtoupper( $this->mFormat );
85 return 'api-result-wrapped.json';
89 return 'api-result.html';
92 $mimeAnalyzer = MediaWikiServices::getInstance()->getMimeAnalyzer();
93 $ext = $mimeAnalyzer->getExtensionFromMimeTypeOrNull( $this->
getMimeType() )
94 ?? strtolower( $this->mFormat );
95 return "api-result.$ext";
104 return $this->mFormat;
114 return $this->mIsHtml;
124 return $this->mIsWrappedHtml;
133 $this->mDisabled =
true;
142 return $this->mDisabled;
164 $this->mForceDefaultParams =
true;
173 if ( !$this->mForceDefaultParams ) {
174 return parent::getParameterFromSettings( $paramName, $paramSettings, $parseLimit );
177 if ( !is_array( $paramSettings ) ) {
178 return $paramSettings;
181 return $paramSettings[ParamValidator::PARAM_DEFAULT] ??
null;
190 if ( $this->mDisabled ) {
195 $this->mHttpStatus = $code;
197 $this->
getMain()->getRequest()->response()->statusHeader( $code );
206 if ( $this->mDisabled ) {
210 if ( $this->
getIsHtml() && $this->
getMain()->getCacheMode() ===
'public' ) {
212 $this->
getMain()->setCacheMode(
'anon-public-user-private' );
216 ?
'text/mediawiki-api-prettyprint-wrapped'
221 if ( $mime ===
null ) {
225 $this->
getMain()->getRequest()->response()->header(
"Content-Type: $mime; charset=utf-8" );
228 $apiFrameOptions = $this->
getConfig()->get( MainConfigNames::ApiFrameOptions );
229 if ( $apiFrameOptions ) {
230 $this->
getMain()->getRequest()->response()->header(
"X-Frame-Options: $apiFrameOptions" );
235 $header =
'Content-Disposition: inline';
237 $compatFilename = mb_convert_encoding( $filename,
'ISO-8859-1' );
238 if ( preg_match(
'/^[0-9a-zA-Z!#$%&\'*+\-.^_`|~]+$/', $compatFilename ) ) {
239 $header .=
'; filename=' . $compatFilename;
242 . preg_replace(
'/([\0-\x1f"\x5c\x7f])/',
'\\\\$1', $compatFilename ) .
'"';
244 if ( $compatFilename !== $filename ) {
245 $value =
"UTF-8''" . rawurlencode( $filename );
247 $value = strtr( $value, [
248 '%21' =>
'!',
'%23' =>
'#',
'%24' =>
'$',
'%26' =>
'&',
'%2B' =>
'+',
'%5E' =>
'^',
249 '%60' =>
'`',
'%7C' =>
'|',
251 $header .=
'; filename*=' . $value;
260 if ( $this->mDisabled ) {
265 if ( $this->
getIsHtml() && $mime !==
null ) {
267 $lcformat = strtolower( $format );
271 $skinFactory = MediaWikiServices::getInstance()->getSkinFactory();
272 $context->setSkin( $skinFactory->makeSkin(
'apioutput' ) );
273 $context->setTitle( SpecialPage::getTitleFor(
'ApiHelp' ) );
275 $context->setOutput( $out );
277 $out->setRobotPolicy(
'noindex,nofollow' );
278 $out->addModuleStyles(
'mediawiki.apipretty' );
279 $out->setPageTitleMsg( $context->msg(
'api-format-title' ) );
285 $nonHtmlUrl = strtok( $this->
getRequest()->getFullRequestURL(),
'?' )
286 .
'?' . $this->
getRequest()->appendQueryValue(
'format', $lcformat );
287 $msg = $context->msg(
'api-format-prettyprint-header-hyperlinked' )
288 ->params( $format, $lcformat, $nonHtmlUrl );
290 $msg = $context->msg(
'api-format-prettyprint-header' )->params( $format, $lcformat );
293 $msg = $context->msg(
'api-format-prettyprint-header-only-html' )->params( $format );
296 $header = $msg->parseAsBlock();
298 Html::rawElement(
'div', [
'class' =>
'api-pretty-header' ],
299 ApiHelp::fixHelpLinks(
$header )
303 if ( $this->mHttpStatus && $this->mHttpStatus !== 200 ) {
305 Html::rawElement(
'div', [
'class' => [
'api-pretty-header',
'api-pretty-status' ] ],
307 'api-format-prettyprint-status',
309 HttpStatus::getMessage( $this->mHttpStatus )
316 if ( $this->
getHookRunner()->onApiFormatHighlight( $context, $result, $mime, $format ) ) {
318 Html::element(
'pre', [
'class' =>
'api-pretty-content' ], $result )
324 $time = $this->
getMain()->getRequest()->getElapsedTime();
325 echo FormatJson::encode(
327 'status' => (
int)( $this->mHttpStatus ?: 200 ),
328 'statustext' => HttpStatus::getMessage( $this->mHttpStatus ?: 200 ),
329 'html' => $out->getHTML(),
330 'modules' => array_values( array_unique( array_merge(
332 $out->getModuleStyles()
334 'continue' => $this->
getResult()->getResultData(
'continue' ),
335 'time' => round( $time * 1000 ),
337 false, FormatJson::ALL_OK
342 $out->setPreventClickjacking(
false );
360 $this->mBuffer .= $text;
369 return $this->mBuffer;
375 $ret[
'wrappedhtml'] = [
376 ParamValidator::PARAM_DEFAULT =>
false,
385 'action=query&meta=siteinfo&siprop=namespaces&format=' . $this->
getModuleName()
386 => [
'apihelp-format-example-generic', $this->
getFormat() ]
391 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Data_formats';
This abstract class implements many basic API functions, and is the base of all API classes.
getModuleManager()
Get the module manager, or null if this module has no submodules.
getMain()
Get the main module.
getResult()
Get the result object.
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
getModuleName()
Get the name of the module being executed by this instance.
getHookRunner()
Get an ApiHookRunner for running core API hooks.
This is the main API class, used for both external and internal processing.
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
An IContextSource implementation which will inherit context from another source but allow individual ...
A class containing constants representing the names of configuration variables.
This is one of the Core classes and should be read at least once by any new developers.
Parent class for all special pages.