Passed
Push — master ( 3f508b...939a62 )
by El
05:26
created

Request::__construct()   D

Complexity

Conditions 19
Paths 40

Size

Total Lines 40
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 19

Importance

Changes 0
Metric Value
dl 0
loc 40
ccs 25
cts 25
cp 1
rs 4.9141
c 0
b 0
f 0
cc 19
eloc 28
nc 40
nop 0
crap 19

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * PrivateBin
4
 *
5
 * a zero-knowledge paste bin
6
 *
7
 * @link      https://github.com/PrivateBin/PrivateBin
8
 * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
9
 * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
10
 * @version   1.1.1
11
 */
12
13
namespace PrivateBin;
14
15
/**
16
 * Request
17
 *
18
 * parses request parameters and provides helper functions for routing
19
 */
20
class Request
21
{
22
    /**
23
     * MIME type for JSON
24
     *
25
     * @const string
26
     */
27
    const MIME_JSON = 'application/json';
28
29
    /**
30
     * MIME type for HTML
31
     *
32
     * @const string
33
     */
34
    const MIME_HTML = 'text/html';
35
36
    /**
37
     * MIME type for XHTML
38
     *
39
     * @const string
40
     */
41
    const MIME_XHTML = 'application/xhtml+xml';
42
43
    /**
44
     * Input stream to use for PUT parameter parsing
45
     *
46
     * @access private
47
     * @var string
48
     */
49
    private static $_inputStream = 'php://input';
50
51
    /**
52
     * Operation to perform
53
     *
54
     * @access private
55
     * @var string
56
     */
57
    private $_operation = 'view';
58
59
    /**
60
     * Request parameters
61
     *
62
     * @access private
63
     * @var array
64
     */
65
    private $_params = array();
66
67
    /**
68
     * If we are in a JSON API context
69
     *
70
     * @access private
71
     * @var bool
72
     */
73
    private $_isJsonApi = false;
74
75
    /**
76
     * Constructor
77
     *
78
     * @access public
79
     */
80 107
    public function __construct()
81
    {
82
        // decide if we are in JSON API or HTML context
83 107
        $this->_isJsonApi = $this->_detectJsonRequest();
84
85
        // parse parameters, depending on request type
86 107
        switch (array_key_exists('REQUEST_METHOD', $_SERVER) ? $_SERVER['REQUEST_METHOD'] : 'GET') {
87 107
            case 'DELETE':
88 106
            case 'PUT':
89 3
                parse_str(file_get_contents(self::$_inputStream), $this->_params);
90 3
                break;
91 104
            case 'POST':
92 50
                $this->_params = $_POST;
93 50
                break;
94
            default:
95 54
                $this->_params = $_GET;
96
        }
97
        if (
98 107
            !array_key_exists('pasteid', $this->_params) &&
99 107
            !array_key_exists('jsonld', $this->_params) &&
100 107
            array_key_exists('QUERY_STRING', $_SERVER) &&
101 107
            !empty($_SERVER['QUERY_STRING'])
102
        ) {
103 34
            $this->_params['pasteid'] = $_SERVER['QUERY_STRING'];
104
        }
105
106
        // prepare operation, depending on current parameters
107
        if (
108 107
            (array_key_exists('data', $this->_params) && !empty($this->_params['data'])) ||
109 107
            (array_key_exists('attachment', $this->_params) && !empty($this->_params['attachment']))
110
        ) {
111 46
            $this->_operation = 'create';
112 61
        } elseif (array_key_exists('pasteid', $this->_params) && !empty($this->_params['pasteid'])) {
113 47
            if (array_key_exists('deletetoken', $this->_params) && !empty($this->_params['deletetoken'])) {
114 20
                $this->_operation = 'delete';
115
            } else {
116 47
                $this->_operation = 'read';
117
            }
118 14
        } elseif (array_key_exists('jsonld', $this->_params) && !empty($this->_params['jsonld'])) {
119 5
            $this->_operation = 'jsonld';
120
        }
121 107
    }
122
123
    /**
124
     * Get current operation
125
     *
126
     * @access public
127
     * @return string
128
     */
129 107
    public function getOperation()
130
    {
131 107
        return $this->_operation;
132
    }
133
134
    /**
135
     * Get a request parameter
136
     *
137
     * @access public
138
     * @param  string $param
139
     * @param  string $default
140
     * @return string
141
     */
142 98
    public function getParam($param, $default = '')
143
    {
144 98
        return array_key_exists($param, $this->_params) ?
145 98
            $this->_params[$param] : $default;
146
    }
147
148
    /**
149
     * Get request URI
150
     *
151
     * @access public
152
     * @return string
153
     */
154 96
    public function getRequestUri()
155
    {
156 96
        return array_key_exists('REQUEST_URI', $_SERVER) ?
157 96
            htmlspecialchars($_SERVER['REQUEST_URI']) : '/';
158
    }
159
160
    /**
161
     * If we are in a JSON API context
162
     *
163
     * @access public
164
     * @return bool
165
     */
166 102
    public function isJsonApiCall()
167
    {
168 102
        return $this->_isJsonApi;
169
    }
170
171
    /**
172
     * Override the default input stream source, used for unit testing
173
     *
174
     * @param string $input
175
     */
176 3
    public static function setInputStream($input)
177
    {
178 3
        self::$_inputStream = $input;
179 3
    }
180
181
    /**
182
     * Detect the clients supported media type and decide if its a JSON API call or not
183
     *
184
     * Adapted from: https://stackoverflow.com/questions/3770513/detect-browser-language-in-php#3771447
185
     *
186
     * @access private
187
     * @return bool
188
     */
189 107
    private function _detectJsonRequest()
190
    {
191 107
        $hasAcceptHeader = array_key_exists('HTTP_ACCEPT', $_SERVER);
192 107
        $acceptHeader    = $hasAcceptHeader ? $_SERVER['HTTP_ACCEPT'] : '';
193
194
        // simple cases
195
        if (
196 107
            (array_key_exists('HTTP_X_REQUESTED_WITH', $_SERVER) &&
197 57
                $_SERVER['HTTP_X_REQUESTED_WITH'] == 'JSONHttpRequest') ||
198 50
            ($hasAcceptHeader &&
199 50
                strpos($acceptHeader, self::MIME_JSON) !== false &&
200 50
                strpos($acceptHeader, self::MIME_HTML) === false &&
201 107
                strpos($acceptHeader, self::MIME_XHTML) === false)
202
        ) {
203 59
            return true;
204
        }
205
206
        // advanced case: media type negotiation
207 48
        $mediaTypes = array();
208 48
        if ($hasAcceptHeader) {
209 4
            $mediaTypeRanges = explode(',', trim($acceptHeader));
210 4
            foreach ($mediaTypeRanges as $mediaTypeRange) {
211 4
                if (preg_match(
212 4
                    '#(\*/\*|[a-z\-]+/[a-z\-+*]+(?:\s*;\s*[^q]\S*)*)(?:\s*;\s*q\s*=\s*(0(?:\.\d{0,3})|1(?:\.0{0,3})))?#',
213 4
                    trim($mediaTypeRange), $match
214
                )) {
215 4
                    if (!isset($match[2])) {
216 4
                        $match[2] = '1.0';
217
                    } else {
218 4
                        $match[2] = (string) floatval($match[2]);
219
                    }
220 4
                    if (!isset($mediaTypes[$match[2]])) {
221 4
                        $mediaTypes[$match[2]] = array();
222
                    }
223 4
                    $mediaTypes[$match[2]][] = strtolower($match[1]);
224
                }
225
            }
226 4
            krsort($mediaTypes);
227 4
            foreach ($mediaTypes as $acceptedQuality => $acceptedValues) {
228 4
                if ($acceptedQuality === 0.0) {
229
                    continue;
230
                }
231 4
                foreach ($acceptedValues as $acceptedValue) {
232
                    if (
233 4
                        strpos($acceptedValue, self::MIME_HTML) === 0 ||
234 4
                        strpos($acceptedValue, self::MIME_XHTML) === 0
235
                    ) {
236 2
                        return false;
237 2
                    } elseif (strpos($acceptedValue, self::MIME_JSON) === 0) {
238 2
                        return true;
239
                    }
240
                }
241
            }
242
        }
243 45
        return false;
244
    }
245
}
246