30 private bool $mIsHtml;
31 private string $mFormat;
32 private string $mBuffer =
'';
33 private bool $mDisabled =
false;
35 private $mIsWrappedHtml =
false;
37 private $mHttpStatus =
false;
48 parent::__construct( $main, $format );
50 $this->mIsHtml = str_ends_with( $format,
'fm' );
51 if ( $this->mIsHtml ) {
52 $this->mFormat = substr( $format, 0, -2 );
53 $this->mIsWrappedHtml = $this->
getMain()->getCheck(
'wrappedhtml' );
55 $this->mFormat = $format;
57 $this->mFormat = strtoupper( $this->mFormat );
80 return 'api-result-wrapped.json';
84 return 'api-result.html';
88 $ext = $mimeAnalyzer->getExtensionFromMimeTypeOrNull( $this->
getMimeType() )
89 ?? strtolower( $this->mFormat );
90 return "api-result.$ext";
99 return $this->mFormat;
109 return $this->mIsHtml;
119 return $this->mIsWrappedHtml;
128 $this->mDisabled =
true;
137 return $this->mDisabled;
159 $this->mForceDefaultParams =
true;
168 if ( !$this->mForceDefaultParams ) {
169 return parent::getParameterFromSettings( $paramName, $paramSettings, $parseLimit );
172 if ( !is_array( $paramSettings ) ) {
173 return $paramSettings;
176 return $paramSettings[ParamValidator::PARAM_DEFAULT] ??
null;
185 if ( $this->mDisabled ) {
190 $this->mHttpStatus = $code;
192 $this->
getMain()->getRequest()->response()->statusHeader( $code );
201 if ( $this->mDisabled ) {
205 if ( $this->
getIsHtml() && $this->
getMain()->getCacheMode() ===
'public' ) {
207 $this->
getMain()->setCacheMode(
'anon-public-user-private' );
211 ?
'text/mediawiki-api-prettyprint-wrapped'
216 if ( $mime ===
null ) {
220 if ( $mime !==
'text/html' ) {
221 ContentSecurityPolicy::sendRestrictiveHeader();
223 $this->
getMain()->getRequest()->response()->header(
"Content-Type: $mime; charset=utf-8" );
227 if ( $apiFrameOptions ) {
228 $this->
getMain()->getRequest()->response()->header(
"X-Frame-Options: $apiFrameOptions" );
233 $header =
'Content-Disposition: inline';
235 $compatFilename = mb_convert_encoding( $filename,
'ISO-8859-1' );
236 if ( preg_match(
'/^[0-9a-zA-Z!#$%&\'*+\-.^_`|~]+$/', $compatFilename ) ) {
237 $header .=
'; filename=' . $compatFilename;
239 $header .=
'; filename="'
240 . preg_replace(
'/([\0-\x1f"\x5c\x7f])/',
'\\\\$1', $compatFilename ) .
'"';
242 if ( $compatFilename !== $filename ) {
243 $value =
"UTF-8''" . rawurlencode( $filename );
245 $value = strtr( $value, [
246 '%21' =>
'!',
'%23' =>
'#',
'%24' =>
'$',
'%26' =>
'&',
'%2B' =>
'+',
'%5E' =>
'^',
247 '%60' =>
'`',
'%7C' =>
'|',
249 $header .=
'; filename*=' . $value;
251 $this->
getMain()->getRequest()->response()->header( $header );
258 if ( $this->mDisabled ) {
263 if ( $this->
getIsHtml() && $mime !==
null ) {
265 $lcformat = strtolower( $format );
270 $context->setSkin( $skinFactory->makeSkin(
'apioutput' ) );
273 $context->setOutput( $out );
275 $out->setRobotPolicy(
'noindex,nofollow' );
276 $out->disallowUserJs();
277 $out->reduceAllowedModules(
RL\Module::TYPE_SCRIPTS,
RL\Module::ORIGIN_NONE );
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 $format, $lcformat, $nonHtmlUrl );
290 $msg = $context->msg(
'api-format-prettyprint-header', $format, $lcformat );
293 $msg = $context->msg(
'api-format-prettyprint-header-only-html', $format );
296 $header = $msg->parseAsBlock();
298 Html::rawElement(
'div', [
'class' =>
'api-pretty-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 $codeLang = match ( $mime ) {
319 'text/javascript',
'application/json' =>
'javascript',
326 classes: [
'api-pretty-content' ],
328 $out->addHTML( $highlightOutput->getHtml() );
329 $highlightOutput->getMetadata()->addToOutputPage( $out );
334 $time = $this->
getMain()->getRequest()->getElapsedTime();
335 echo FormatJson::encode(
337 'status' => (
int)( $this->mHttpStatus ?: 200 ),
338 'statustext' => HttpStatus::getMessage( $this->mHttpStatus ?: 200 ),
339 'html' => $out->getHTML(),
340 'modules' => array_values( array_unique( array_merge(
342 $out->getModuleStyles()
344 'continue' => $this->
getResult()->getResultData(
'continue' ),
345 'time' => round( $time * 1000 ),
347 false, FormatJson::ALL_OK
352 $out->getMetadata()->setPreventClickjacking(
false );
370 $this->mBuffer .= $text;
379 return $this->mBuffer;
386 $ret[
'wrappedhtml'] = [
387 ParamValidator::PARAM_DEFAULT =>
false,
397 'action=query&meta=siteinfo&siprop=namespaces&format=' . $this->
getModuleName()
398 => [
'apihelp-format-example-generic', $this->
getFormat() ]
404 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Data_formats';
415class_alias( ApiFormatBase::class,
'ApiFormatBase' );
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.
const ApiFrameOptions
Name constant for the ApiFrameOptions setting, for use with Config::get()
This is one of the Core classes and should be read at least once by any new developers.
Handle sending Content-Security-Policy headers.
Parent class for all special pages.
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...