ApiFormatJson   A
last analyzed

Complexity

Total Complexity 15

Size/Duplication

Total Lines 108
Duplicated Lines 13.89 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
dl 15
loc 108
rs 10
c 0
b 0
f 0
wmc 15
lcom 1
cbo 4

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 13 2
A getMimeType() 0 9 2
C execute() 15 53 9
B getAllowedParams() 0 25 2

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/**
3
 *
4
 *
5
 * Created on Sep 19, 2006
6
 *
7
 * Copyright © 2006 Yuri Astrakhan "<Firstname><Lastname>@gmail.com"
8
 *
9
 * This program is free software; you can redistribute it and/or modify
10
 * it under the terms of the GNU General Public License as published by
11
 * the Free Software Foundation; either version 2 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License along
20
 * with this program; if not, write to the Free Software Foundation, Inc.,
21
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22
 * http://www.gnu.org/copyleft/gpl.html
23
 *
24
 * @file
25
 */
26
27
/**
28
 * API JSON output formatter
29
 * @ingroup API
30
 */
31
class ApiFormatJson extends ApiFormatBase {
32
33
	private $isRaw;
34
35
	public function __construct( ApiMain $main, $format ) {
36
		parent::__construct( $main, $format );
37
		$this->isRaw = ( $format === 'rawfm' );
38
39
		if ( $this->getMain()->getCheck( 'callback' ) ) {
40
			# T94015: jQuery appends a useless '_' parameter in jsonp mode.
41
			# Mark the parameter as used in that case to avoid a warning that's
42
			# outside the control of the end user.
43
			# (and do it here because ApiMain::reportUnusedParams() gets called
44
			# before our ::execute())
45
			$this->getMain()->markParamsUsed( '_' );
46
		}
47
	}
48
49
	public function getMimeType() {
50
		$params = $this->extractRequestParams();
51
		// callback:
52
		if ( isset( $params['callback'] ) ) {
53
			return 'text/javascript';
54
		}
55
56
		return 'application/json';
57
	}
58
59
	public function execute() {
60
		$params = $this->extractRequestParams();
61
62
		$opt = 0;
63
		if ( $this->isRaw ) {
64
			$opt |= FormatJson::ALL_OK;
65
			$transform = [];
66
		} else {
67
			switch ( $params['formatversion'] ) {
68 View Code Duplication
				case 1:
69
					$opt |= $params['utf8'] ? FormatJson::ALL_OK : FormatJson::XMLMETA_OK;
70
					$transform = [
71
						'BC' => [],
72
						'Types' => [ 'AssocAsObject' => true ],
73
						'Strip' => 'all',
74
					];
75
					break;
76
77
				case 2:
78 View Code Duplication
				case 'latest':
79
					$opt |= $params['ascii'] ? FormatJson::XMLMETA_OK : FormatJson::ALL_OK;
80
					$transform = [
81
						'Types' => [ 'AssocAsObject' => true ],
82
						'Strip' => 'all',
83
					];
84
					break;
85
86
				default:
87
					$this->dieUsage( __METHOD__ .
88
						': Unknown value for \'formatversion\'', 'unknownformatversion' );
89
			}
90
		}
91
		$data = $this->getResult()->getResultData( null, $transform );
0 ignored issues
show
Bug introduced by
The variable $transform does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
92
		$json = FormatJson::encode( $data, $this->getIsHtml(), $opt );
93
94
		// Bug 66776: wfMangleFlashPolicy() is needed to avoid a nasty bug in
95
		// Flash, but what it does isn't friendly for the API, so we need to
96
		// work around it.
97
		if ( preg_match( '/\<\s*cross-domain-policy(?=\s|\>)/i', $json ) ) {
98
			$json = preg_replace(
99
				'/\<(\s*cross-domain-policy(?=\s|\>))/i', '\\u003C$1', $json
100
			);
101
		}
102
103
		if ( isset( $params['callback'] ) ) {
104
			$callback = preg_replace( "/[^][.\\'\\\"_A-Za-z0-9]/", '', $params['callback'] );
105
			# Prepend a comment to try to avoid attacks against content
106
			# sniffers, such as bug 68187.
107
			$this->printText( "/**/$callback($json)" );
108
		} else {
109
			$this->printText( $json );
0 ignored issues
show
Security Bug introduced by
It seems like $json defined by \FormatJson::encode($dat...his->getIsHtml(), $opt) on line 92 can also be of type false; however, ApiFormatBase::printText() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
110
		}
111
	}
112
113
	public function getAllowedParams() {
114
		if ( $this->isRaw ) {
115
			return parent::getAllowedParams();
116
		}
117
118
		$ret = parent::getAllowedParams() + [
119
			'callback' => [
120
				ApiBase::PARAM_HELP_MSG => 'apihelp-json-param-callback',
121
			],
122
			'utf8' => [
123
				ApiBase::PARAM_DFLT => false,
124
				ApiBase::PARAM_HELP_MSG => 'apihelp-json-param-utf8',
125
			],
126
			'ascii' => [
127
				ApiBase::PARAM_DFLT => false,
128
				ApiBase::PARAM_HELP_MSG => 'apihelp-json-param-ascii',
129
			],
130
			'formatversion' => [
131
				ApiBase::PARAM_TYPE => [ 1, 2, 'latest' ],
132
				ApiBase::PARAM_DFLT => 1,
133
				ApiBase::PARAM_HELP_MSG => 'apihelp-json-param-formatversion',
134
			],
135
		];
136
		return $ret;
137
	}
138
}
139