Completed
Push — master ( 58c9b2...61e000 )
by
unknown
26s
created

Request::__construct()   C

Complexity

Conditions 7
Paths 18

Size

Total Lines 33
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 10.7112

Importance

Changes 7
Bugs 0 Features 0
Metric Value
c 7
b 0
f 0
dl 0
loc 33
ccs 15
cts 26
cp 0.5769
rs 6.7272
cc 7
eloc 21
nc 18
nop 0
crap 10.7112
1
<?php
2
namespace Zewa;
3
4
/**
5
 * Handles everything relating to request variables/globals/properties
6
 *
7
 * @author Zechariah Walden<zech @ zewadesign.com>
8
 */
9
class Request
10
{
11
    /**
12
     * Reference to instantiated controller object.
13
     *
14
     * @var object
15
     */
16
    protected static $instance;
17
18
    /**
19
     * System configuration
20
     *
21
     * @var object
22
     */
23
    private $configuration;
24
25
26
    /**
27
     * normalized $_GET superglobal
28
     *
29
     * @var    array
30
     * @access private
31
     */
32
33
    private $getContainer = [];
34
35
    /**
36
     * normalized $_POST superglobal
37
     *
38
     * @var    array
39
     * @access private
40
     */
41
42
    private $postContainer = [];
43
44
    /**
45
     * normalized $_DELETE superglobal
46
     *
47
     * @var    array
48
     * @access private
49
     */
50
51
    private $deleteContainer = [];
52
53
    /**
54
     * normalized $_PUT superglobal
55
     *
56
     * @var    array
57
     * @access private
58
     */
59
60
    private $putContainer = [];
61
62
    /**
63
     * normalized $_SESSION superglobal
64
     *
65
     * @var    array
66
     * @access private
67
     */
68
69
    private $sessionContainer = [];
70
71
    /**
72
     * normalized $_COOKIE superglobal
73
     *
74
     * @var    array
75
     * @access private
76
     */
77
78
    private $cookieContainer = [];
79
80
    /**
81
     * normalized $_FILES superglobal
82
     *
83
     * @var    array
84
     * @access private
85
     */
86
87
    private $filesContainer = [];
88
89
    /**
90
     * normalized $_SERVER superglobal
91
     *
92
     * @var    array
93
     * @access private
94
     */
95
96
    private $serverContainer = [];
97
98
99
    /**
100
     * Flashdata container
101
     *
102
     * @var    array
103
     * @access private
104
     */
105
106
    private $flashdata = [];
107
108
    /**
109
     * Flashdata identifier
110
     *
111
     * @var    string
112
     * @access private
113
     * @TODO:  move flashdata to sessionhandler, make available here with other request vars still
114
     */
115
116
117
    private $flashdataId = '_z_session_flashdata';
118
119
120
    /**
121
     * Normalizes superglobals, handles flashdata
122
     */
123
124 18
    public function __construct()
0 ignored issues
show
Coding Style introduced by
__construct uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
__construct uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
__construct uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
__construct uses the super-global variable $_COOKIE which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
__construct uses the super-global variable $_FILES which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
__construct uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
125
    {
126 18
        self::$instance = $this;
127 18
        $app = App::getInstance();
128 18
        $this->configuration = $app->getConfiguration();
129
130 18
        if (!empty($this->configuration->session)) {
131
            if ($this->configuration->session !== false && $this->configuration->session->flashdataId) {
132
                $this->flashdataId = $this->configuration->session->flashdataId;
133
            }
134
        }
135
136
        //        $config = \HTMLPurifier_Config::createDefault();
0 ignored issues
show
Unused Code Comprehensibility introduced by
46% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
137
        //        $this->purifier = new \HTMLPurifier($config);
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
138
139 18
        if (!empty($_SESSION)) {
140
            $this->sessionContainer = $this->normalize($_SESSION);
141
        }
142 18
        $this->registerFlashdata();
143
144 18
        $this->getContainer = $this->normalize($_GET);
145 18
        $this->postContainer = $this->normalize($_POST);
146 18
        $this->cookieContainer = $this->normalize($_COOKIE);
147 18
        $this->filesContainer = $this->normalize($_FILES);
148 18
        $this->serverContainer = $this->normalize($_SERVER);
149 18
        if ($this->serverContainer['REQUEST_METHOD'] === 'PUT') {
150
            parse_str(file_get_contents('php://input', "r"), $PUT);
151
            $this->putContainer = $this->normalize($PUT);
152 18
        } elseif ($this->serverContainer['REQUEST_METHOD'] === 'DELETE') {
153
            parse_str(file_get_contents('php://input', "r"), $DELETE);
154
            $this->deleteContainer = $this->normalize($DELETE);
155
        }
156 18
    }
157
158
    /**
159
     * Processes current requests flashdata, recycles old.
160
     *
161
     * @access private
162
     */
163 18
    private function registerFlashdata()
0 ignored issues
show
Coding Style introduced by
registerFlashdata uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
164
    {
165 18
        if (!empty($this->sessionContainer[$this->flashdataId])) {
166
            $this->flashdata = unserialize(base64_decode($this->session($this->flashdataId)));
0 ignored issues
show
Bug introduced by
The method session() does not exist on Zewa\Request. Did you maybe mean removeSession()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
167
            // and destroy the temporary session variable
168
            unset($_SESSION[$this->flashdataId]);
169
170
171
            if (!empty($this->flashdata)) {
172
                // iterate through all the entries
173
                foreach ($this->flashdata as $variable => $data) {
174
                    // increment counter representing server requests
175
                    $this->flashdata[$variable]['inc'] ++;
176
177
                    // if we're past the first server request
178
                    if ($this->flashdata[$variable]['inc'] > 1) {
179
                        // unset the session variable
180
                        unset($_SESSION[$variable]);
181
182
                        // stop tracking
183
                        unset($this->flashdata[$variable]);
184
                    }
185
                }
186
187
                // if there is any flashdata left to be handled
188
                if (!empty($this->flashdata)) {
189
                    // store data in a temporary session variable
190
                    $_SESSION[$this->flashdataId] = base64_encode(serialize($this->flashdata));
191
                }
192
            }
193
        }
194 18
    }
195
196
    /**
197
     * Sets flashdata
198
     *
199
     * @access public
200
     *
201
     * @params string $name
202
     * @params mixed $value
203
     */
204
205
    public function setFlashdata($name, $value)
0 ignored issues
show
Coding Style introduced by
setFlashdata uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
206
    {
207
208
        // set session variable
209
        $this->sessionContainer[$name] = $value;
210
211
        // initialize the counter for this flashdata
212
        $this->flashdata[$name] = [
213
            'value' => $value,
214
            'inc'   => 0
215
        ];
216
217
        $_SESSION[$this->flashdataId] = base64_encode(serialize($this->flashdata));
218
    }
219
220
    /**
221
     * Gets flashdata
222
     *
223
     * @access public
224
     *
225
     * @params string $name
226
     */
227
228
    public function getFlashdata($name = false, $default = false)
229
    {
230
        if ($name === false && !empty($this->flashdata)) {
231
            return $this->flashdata;
232
        }
233
        if ($name !== false) {
234
            if (!empty($this->flashdata[$name]['value'])) {
235
                return $this->flashdata[$name]['value'];
236
            }
237
        }
238
239
        return $default;
240
    }
241
242
    /**
243
     * Remove session data
244
     *
245
     * @access public
246
     *
247
     * @params string $index
248
     */
249
    public function removeSession($index)
0 ignored issues
show
Coding Style introduced by
removeSession uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
250
    {
251
252
        unset($this->sessionContainer[$index]);
253
        unset($_SESSION[$index]);
254
    }
255
256
    /**
257
     * Set session data
258
     *
259
     * @access public
260
     *
261
     * @params string $index
262
     * @params mixed $value
263
     */
264
265
    public function setSession($index = false, $value = false)
0 ignored issues
show
Coding Style introduced by
setSession uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
266
    {
267
        if ((!is_array($index) && isset($value))
268
            && (!is_object($index) && isset($value))
269
        ) {
270
            $index = [$index => $value];
271
        }
272
273
        if (!is_array($index) && !is_object($index)) {
274
            throw new Exception\TypeException("Invalid session value");
275
        }
276
277
        foreach ($index as $k => $v) {
278
            $_SESSION[$k] = $v;
279
            $this->sessionContainer = $this->normalize($_SESSION);
280
        }
281
    }
282
283
    /**
284
     * Dumps all session data
285
     *
286
     * @access public
287
     */
288
    public function destroySession()
0 ignored issues
show
Coding Style introduced by
destroySession uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
289
    {
290
291
        $_SESSION = [];
292
293
        if (ini_get("session.use_cookies")) {
294
            $params = session_get_cookie_params();
295
            setcookie(
296
                session_name(),
297
                '',
298
                time() - 42000,
299
                $params["path"],
300
                $params["domain"],
301
                $params["secure"],
302
                $params["httponly"]
303
            );
304
        }
305
306
        session_destroy();
307
    }
308
309
    /**
310
     * Normalizes data
311
     *
312
     * @access public
313
     * @TODO:  expand functionality, set/perform based on configuration
314
     */
315 18
    public function normalize($data)
316
    {
317 18
        if (is_array($data)) {
318 18
            foreach ($data as $key => $value) {
319 18
                unset($data[$key]);
320 18
                $data[$this->normalize($key)] = $this->normalize($value);
321 18
            }
322 18
        } elseif (is_object($data)) {
323
            $new = new \stdClass();
324
            foreach ($data as $k => $v) {
325
                //                unset($data->{$k});
0 ignored issues
show
Unused Code Comprehensibility introduced by
90% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
326
                $key = $this->normalize($k);
327
                $new->{$key} = $this->normalize($v);
328
            }
329
            $data = $new;
330
        } else {
331 18
            $data = trim($data);
332
            //we need to review this.
333 18
            if (function_exists('iconv') && function_exists('mb_detect_encoding')) {
334 18
                $current_encoding = mb_detect_encoding($data);
335
336 18
                if ($current_encoding != 'UTF-8' && $current_encoding != 'UTF-16') {
337 18
                    $data = iconv($current_encoding, 'UTF-8', $data);
338 18
                }
339 18
            }
340
            // Global XXS?
341
            // This is not sanitary.  FILTER_SANITIZE_STRING doesn't do much.
342
343
            // $data = filter_var($data, FILTER_SANITIZE_STRING);
0 ignored issues
show
Unused Code Comprehensibility introduced by
47% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
344 18
            if (is_numeric($data)) {
345 18
                $int = intval($data);
346 18
                $float = floatval($data);
347 18
                $re = "~^-?[0-9]+(\.[0-9]+)?$~xD";
348
                //@TODO this will not accept all float values, this validates /against/ syntax
349
350 18
                if (($int === (int)trim($data, '-')) && strlen((string)(int)$data) === strlen($data)) {
351 18
                    $data = (int) $data;
352 18
                } elseif ($int !== $float && preg_match($re, $data) === 1) {
353 18
                    $data = floatval($data);
354 18
                }
355 18
            } else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
356
                //                $data = $this->purifier->purify($data);
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
357
            }
358
        }
359
360 18
        return $data;
361
    }
362
363
    public function __call($name, $arguments)
364
    {
365
        $accepted = ['post', 'put', 'delete', 'get', 'server', 'session'];
366
367
        if (in_array($name, $accepted)) {
368
            $container = $name . 'Container';
369
            $container = $this->$container;
370
371
            $argument = ! empty($arguments[0]) ? $arguments[0] : false;
372
373
            if ($argument === false && !empty($container)) {
374
                return $container;
375
            }
376
            if (! empty($container[$argument])) {
377
                if (!is_array($container[$argument])
378
                    && !is_object($container[$argument])
379
                    && strlen($container[$argument]) > 0
380
                    || is_array($container[$argument])
381
                    || is_object($container[$argument])
382
                ) {
383
                    return $container[$argument];
384
                }
385
            }
386
387
            return ! empty($arguments[1]) ? $arguments[1] : false;
388
        }
389
390
        throw new Exception\FunctionException('Method ' . $name . ' does not exist.');
391
    }
392
}
393