Completed
Pull Request — master (#83)
by
unknown
11:18
created

Request::setFlashdata()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 14
ccs 0
cts 7
cp 0
rs 9.4285
cc 1
eloc 6
nc 1
nop 2
crap 2
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
     * normalized $_GET superglobal
13
     *
14
     * @var    array
15
     * @access private
16
     */
17
18
    private $getContainer = [];
19
20
    /**
21
     * normalized $_POST superglobal
22
     *
23
     * @var    array
24
     * @access private
25
     */
26
27
    private $postContainer = [];
28
29
    /**
30
     * normalized $_DELETE superglobal
31
     *
32
     * @var    array
33
     * @access private
34
     */
35
36
    private $deleteContainer = [];
37
38
    /**
39
     * normalized $_PUT superglobal
40
     *
41
     * @var    array
42
     * @access private
43
     */
44
45
    private $putContainer = [];
46
47
    /**
48
     * normalized $_SESSION superglobal
49
     *
50
     * @var    array
51
     * @access private
52
     */
53
54
    private $sessionContainer = [];
55
56
    /**
57
     * normalized $_COOKIE superglobal
58
     *
59
     * @var    array
60
     * @access private
61
     */
62
63
    private $cookieContainer = [];
64
65
    /**
66
     * normalized $_FILES superglobal
67
     *
68
     * @var    array
69
     * @access private
70
     */
71
72
    private $filesContainer = [];
73
74
    /**
75
     * normalized $_SERVER superglobal
76
     *
77
     * @var    array
78
     * @access private
79
     */
80
81
    private $serverContainer = [];
82
83
84
    /**
85
     * Flashdata container
86
     *
87
     * @var    array
88
     * @access private
89
     */
90
91
    private $flashdata = [];
92
93
    /**
94
     * Flashdata identifier
95
     *
96
     * @var    string
97
     * @access private
98
     * @TODO:  move flashdata to sessionhandler, make available here with other request vars still
99
     */
100
101
102
    private $flashdataId = '_z_session_flashdata';
103
104
105
    /**
106
     * Normalizes superglobals, handles flashdata
107
     *
108
     * @param $config
109
     * @todo: pass PSR7 HTTP messages to constructor.
110
     */
111 18
    public function __construct(Config $config)
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...
112
    {
113 18
        $sessionConfig = $config->get('session');
114
115 18
        if (!empty($sessionConfig) && !empty($sessionConfig->flashdataId)) {
116
            $this->flashdataId = $sessionConfig->flashdataId;
117
        }
118
119 18
        if (!empty($_SESSION)) {
120
            $this->sessionContainer = $this->normalize($_SESSION);
121
        }
122
//echo "<PRE>";
0 ignored issues
show
Unused Code Comprehensibility introduced by
74% 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...
123
//        print_r($_SESSION);die();
124 18
        $this->registerFlashdata();
125
126 18
        $this->getContainer = $this->normalize($_GET);
127 18
        $this->postContainer = $this->normalize($_POST);
128 18
        $this->cookieContainer = $this->normalize($_COOKIE);
129 18
        $this->filesContainer = $this->normalize($_FILES);
130 18
        $this->serverContainer = $this->normalize($_SERVER);
131 18
        if ($this->serverContainer['REQUEST_METHOD'] === 'PUT') {
132
            parse_str(file_get_contents('php://input', "r"), $PUT);
133
            $this->putContainer = $this->normalize($PUT);
134 18
        } elseif ($this->serverContainer['REQUEST_METHOD'] === 'DELETE') {
135
            parse_str(file_get_contents('php://input', "r"), $DELETE);
136
            $this->deleteContainer = $this->normalize($DELETE);
137
        }
138 18
    }
139
140
    /**
141
     * Processes current requests flashdata, recycles old.
142
     *
143
     * @access private
144
     */
145 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...
146
    {
147 18
        if (!empty($this->sessionContainer[$this->flashdataId])) {
148
            $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...
149
            // and destroy the temporary session variable
150
            unset($_SESSION[$this->flashdataId]);
151
152
153
            if (!empty($this->flashdata)) {
154
                // iterate through all the entries
155
                foreach ($this->flashdata as $variable => $data) {
156
                    // increment counter representing server requests
157
                    $this->flashdata[$variable]['inc'] ++;
158
159
                    // if we're past the first server request
160
                    if ($this->flashdata[$variable]['inc'] > 1) {
161
                        // unset the session variable
162
                        unset($_SESSION[$variable]);
163
164
                        // stop tracking
165
                        unset($this->flashdata[$variable]);
166
                    }
167
                }
168
169
                // if there is any flashdata left to be handled
170
                if (!empty($this->flashdata)) {
171
                    // store data in a temporary session variable
172
                    $_SESSION[$this->flashdataId] = base64_encode(serialize($this->flashdata));
173
                }
174
            }
175
        }
176 18
    }
177
178
    /**
179
     * Sets flashdata
180
     *
181
     * @access public
182
     *
183
     * @params string $name
184
     * @params mixed $value
185
     */
186
187
    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...
188
    {
189
190
        // set session variable
191
        $this->sessionContainer[$name] = $value;
192
193
        // initialize the counter for this flashdata
194
        $this->flashdata[$name] = [
195
            'value' => $value,
196
            'inc'   => 0
197
        ];
198
199
        $_SESSION[$this->flashdataId] = base64_encode(serialize($this->flashdata));
200
    }
201
202
    /**
203
     * Gets flashdata
204
     *
205
     * @access public
206
     *
207
     * @params string $name
208
     */
209
210
    public function getFlashdata($name = false, $default = false)
211
    {
212
        if ($name === false && !empty($this->flashdata)) {
213
            return $this->flashdata;
214
        }
215
        if ($name !== false) {
216
            if (!empty($this->flashdata[$name]['value'])) {
217
                return $this->flashdata[$name]['value'];
218
            }
219
        }
220
221
        return $default;
222
    }
223
224
    /**
225
     * Remove session data
226
     *
227
     * @access public
228
     *
229
     * @params string $index
230
     */
231
    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...
232
    {
233
234
        unset($this->sessionContainer[$index]);
235
        unset($_SESSION[$index]);
236
    }
237
238
    /**
239
     * Set session data
240
     *
241
     * @access public
242
     *
243
     * @params string $index
244
     * @params mixed $value
245
     */
246
247
    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...
248
    {
249
        if ((!is_array($index) && isset($value))
250
            && (!is_object($index) && isset($value))
251
        ) {
252
            $index = [$index => $value];
253
        }
254
255
        if (!is_array($index) && !is_object($index)) {
256
            throw new Exception\TypeException("Invalid session value");
257
        }
258
259
        foreach ($index as $k => $v) {
260
            $_SESSION[$k] = $v;
261
            $this->sessionContainer = $this->normalize($_SESSION);
262
        }
263
    }
264
265
    /**
266
     * Dumps all session data
267
     *
268
     * @access public
269
     */
270
    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...
271
    {
272
273
        $_SESSION = [];
274
275
        if (ini_get("session.use_cookies")) {
276
            $params = session_get_cookie_params();
277
            setcookie(
278
                session_name(),
279
                '',
280
                time() - 42000,
281
                $params["path"],
282
                $params["domain"],
283
                $params["secure"],
284
                $params["httponly"]
285
            );
286
        }
287
288
        session_destroy();
289
    }
290
291
    /**
292
     * Normalizes data
293
     *
294
     * @access public
295
     * @TODO:  expand functionality, set/perform based on configuration
296
     */
297 18
    public function normalize($data)
298
    {
299 18
        if (is_array($data)) {
300 18
            foreach ($data as $key => $value) {
301 18
                unset($data[$key]);
302 18
                $data[$this->normalize($key)] = $this->normalize($value);
303
            }
304 18
        } elseif (is_object($data)) {
305
            $new = new \stdClass();
306
            foreach ($data as $k => $v) {
307
                //                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...
308
                $key = $this->normalize($k);
309
                $new->{$key} = $this->normalize($v);
310
            }
311
            $data = $new;
312
        } else {
313 18
            $data = trim($data);
314
            //we need to review this.
315 18
            if (function_exists('iconv') && function_exists('mb_detect_encoding')) {
316 18
                $current_encoding = mb_detect_encoding($data);
317
318 18
                if ($current_encoding != 'UTF-8' && $current_encoding != 'UTF-16') {
319 18
                    $data = iconv($current_encoding, 'UTF-8', $data);
320
                }
321
            }
322
            // Global XXS?
323
            // This is not sanitary.  FILTER_SANITIZE_STRING doesn't do much.
324
325
            // $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...
326 18
            if (is_numeric($data)) {
327 18
                $int = intval($data);
328 18
                $float = floatval($data);
329 18
                $re = "~^-?[0-9]+(\.[0-9]+)?$~xD";
330
                //@TODO this will not accept all float values, this validates /against/ syntax
331
332 18
                if (($int === (int)trim($data, '-')) && strlen((string)(int)$data) === strlen($data)) {
333 18
                    $data = (int) $data;
334 18
                } elseif ($int !== $float && preg_match($re, $data) === 1) {
335 18
                    $data = floatval($data);
336
                }
337
            } 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...
338
                //                $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...
339
            }
340
        }
341
342 18
        return $data;
343
    }
344
345
    public function __call($name, $arguments)
346
    {
347
        $accepted = ['post', 'put', 'delete', 'get', 'server', 'session'];
348
349
        if (in_array($name, $accepted)) {
350
            $container = $name . 'Container';
351
            $container = $this->$container;
352
353
            $argument = ! empty($arguments[0]) ? $arguments[0] : false;
354
355
            if ($argument === false && !empty($container)) {
356
                return $container;
357
            }
358
            if (! empty($container[$argument])) {
359
                if (!is_array($container[$argument])
360
                    && !is_object($container[$argument])
361
                    && strlen($container[$argument]) > 0
362
                    || is_array($container[$argument])
363
                    || is_object($container[$argument])
364
                ) {
365
                    return $container[$argument];
366
                }
367
            }
368
369
            return ! empty($arguments[1]) ? $arguments[1] : false;
370
        }
371
372
        throw new Exception\FunctionException('Method ' . $name . ' does not exist.');
373
    }
374
}
375