Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
93.65% covered (success)
93.65%
59 / 63
50.00% covered (danger)
50.00%
2 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
ApiFormatJson
95.16% covered (success)
95.16%
59 / 62
50.00% covered (danger)
50.00%
2 / 4
16
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 getMimeType
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 execute
93.10% covered (success)
93.10%
27 / 29
0.00% covered (danger)
0.00%
0 / 1
10.03
 getAllowedParams
96.00% covered (success)
96.00%
24 / 25
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * Copyright © 2006 Yuri Astrakhan "<Firstname><Lastname>@gmail.com"
4 *
5 * @license GPL-2.0-or-later
6 * @file
7 */
8
9namespace MediaWiki\Api;
10
11use MediaWiki\Json\FormatJson;
12use Wikimedia\ParamValidator\ParamValidator;
13
14/**
15 * API JSON output formatter
16 * @ingroup API
17 */
18class ApiFormatJson extends ApiFormatBase {
19
20    /** @var bool */
21    private $isRaw;
22
23    public function __construct( ApiMain $main, string $format ) {
24        parent::__construct( $main, $format );
25        $this->isRaw = ( $format === 'rawfm' );
26
27        if ( $this->getMain()->getCheck( 'callback' ) ) {
28            # T94015: jQuery appends a useless '_' parameter in jsonp mode.
29            # Mark the parameter as used in that case to avoid a warning that's
30            # outside the control of the end user.
31            # (and do it here because ApiMain::reportUnusedParams() gets called
32            # before our ::execute())
33            $this->getMain()->markParamsUsed( '_' );
34        }
35    }
36
37    /** @inheritDoc */
38    public function getMimeType() {
39        $params = $this->extractRequestParams();
40        // callback:
41        if ( isset( $params['callback'] ) ) {
42            return 'text/javascript';
43        }
44
45        return 'application/json';
46    }
47
48    public function execute() {
49        $params = $this->extractRequestParams();
50
51        $opt = 0;
52        if ( $this->isRaw ) {
53            $opt |= FormatJson::ALL_OK;
54            $transform = [];
55        } else {
56            switch ( $params['formatversion'] ) {
57                case 1:
58                    $opt |= $params['utf8'] ? FormatJson::ALL_OK : FormatJson::XMLMETA_OK;
59                    $transform = [
60                        'BC' => [],
61                        'Types' => [ 'AssocAsObject' => true ],
62                        'Strip' => 'all',
63                    ];
64                    break;
65
66                case 2:
67                case 'latest':
68                    $opt |= $params['ascii'] ? FormatJson::XMLMETA_OK : FormatJson::ALL_OK;
69                    $transform = [
70                        'Types' => [ 'AssocAsObject' => true ],
71                        'Strip' => 'all',
72                    ];
73                    break;
74
75                default:
76                    // Should have been caught during parameter validation
77                    // @codeCoverageIgnoreStart
78                    self::dieDebug( __METHOD__, 'Unknown value for \'formatversion\'' );
79                    // @codeCoverageIgnoreEnd
80            }
81        }
82        $data = $this->getResult()->getResultData( null, $transform );
83        $json = FormatJson::encode( $data, $this->getIsHtml(), $opt );
84        if ( $json === false ) {
85            // This should never happen, but it's a bug which could crop up
86            // if you use ApiResult::NO_VALIDATE for instance.
87            // @codeCoverageIgnoreStart
88            self::dieDebug( __METHOD__, 'Unable to encode API result as JSON' );
89            // @codeCoverageIgnoreEnd
90        }
91
92        if ( isset( $params['callback'] ) ) {
93            $callback = preg_replace( "/[^][.\\'\\\"_A-Za-z0-9]/", '', $params['callback'] );
94            # Prepend a comment to try to avoid attacks against content
95            # sniffers, such as T70187.
96            $this->printText( "/**/$callback($json)" );
97        } else {
98            $this->printText( $json );
99        }
100    }
101
102    /** @inheritDoc */
103    public function getAllowedParams() {
104        if ( $this->isRaw ) {
105            return parent::getAllowedParams();
106        }
107
108        return parent::getAllowedParams() + [
109            'callback' => [
110                ApiBase::PARAM_HELP_MSG => 'apihelp-json-param-callback',
111            ],
112            'utf8' => [
113                ParamValidator::PARAM_DEFAULT => false,
114                ApiBase::PARAM_HELP_MSG => 'apihelp-json-param-utf8',
115            ],
116            'ascii' => [
117                ParamValidator::PARAM_DEFAULT => false,
118                ApiBase::PARAM_HELP_MSG => 'apihelp-json-param-ascii',
119            ],
120            'formatversion' => [
121                ParamValidator::PARAM_TYPE => [ '1', '2', 'latest' ],
122                ParamValidator::PARAM_DEFAULT => '1',
123                ApiBase::PARAM_HELP_MSG => 'apihelp-json-param-formatversion',
124                ApiBase::PARAM_HELP_MSG_PER_VALUE => [
125                    '1' => 'apihelp-json-paramvalue-formatversion-1',
126                    '2' => 'apihelp-json-paramvalue-formatversion-2',
127                    'latest' => 'apihelp-json-paramvalue-formatversion-latest',
128                ],
129            ],
130        ];
131    }
132}
133
134/** @deprecated class alias since 1.43 */
135class_alias( ApiFormatJson::class, 'ApiFormatJson' );