Completed
Push — master ( f88b10...3f0b0b )
by Lars
05:42
created

Bootup::initAll()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 3
cts 3
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
3
namespace voku\helper;
4
5
/**
6
 * Class Bootup
7
 *
8
 * this is a bootstrap for the polyfills (iconv / intl / mbstring / normalizer / xml)
9
 *
10
 * @package voku\helper
11
 */
12
class Bootup
13
{
14
  /**
15
   * filter request inputs
16
   *
17
   * Ensures inputs are well formed UTF-8
18
   * When not, assumes Windows-1252 and converts to UTF-8
19
   * Tests only values, not keys
20
   *
21
   * @param int    $normalization_form
22
   * @param string $leading_combining
23
   */
24 1
  public static function filterRequestInputs($normalization_form = 4 /* n::NFC */, $leading_combining = '◌')
0 ignored issues
show
Coding Style introduced by
filterRequestInputs 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
filterRequestInputs uses the super-global variable $_ENV 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
filterRequestInputs 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
filterRequestInputs 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
filterRequestInputs 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
filterRequestInputs 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...
Coding Style introduced by
filterRequestInputs uses the super-global variable $_REQUEST 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...
25
  {
26
    $a = array(
27 1
        &$_FILES,
28 1
        &$_ENV,
29 1
        &$_GET,
30 1
        &$_POST,
31 1
        &$_COOKIE,
32 1
        &$_SERVER,
33 1
        &$_REQUEST,
34 1
    );
35
36
    /** @noinspection ReferenceMismatchInspection */
37
    /** @noinspection ForeachSourceInspection */
38 1
    foreach ($a[0] as &$r) {
39 1
      $a[] = array(
40 1
          &$r['name'],
41 1
          &$r['type'],
42
      );
43 1
    }
44 1
    unset($r, $a[0]);
45
46 1
    $len = count($a) + 1;
47 1
    for ($i = 1; $i < $len; ++$i) {
48
      /** @noinspection ReferenceMismatchInspection */
49
      /** @noinspection ForeachSourceInspection */
50 1
      foreach ($a[$i] as &$r) {
51
        /** @noinspection ReferenceMismatchInspection */
52 1
        $s = $r; // $r is a reference, $s a copy
53 1
        if (is_array($s)) {
54 1
          $a[$len++] = &$r;
55 1
        } else {
56 1
          $r = self::filterString($s, $normalization_form, $leading_combining);
57
        }
58 1
      }
59 1
      unset($r, $a[$i]);
60 1
    }
61 1
  }
62
63
  /**
64
   * Filter current REQUEST_URI .
65
   *
66
   * @param string|null $uri <p>If null is set, then the server REQUEST_URI will be used.</p>
67
   * @param bool        $exit
68
   *
69
   * @return mixed
70
   */
71 1
  public static function filterRequestUri($uri = null, $exit = true)
0 ignored issues
show
Coding Style introduced by
filterRequestUri 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...
72
  {
73 1
    if (!isset($uri)) {
74
75 1
      if (!isset($_SERVER['REQUEST_URI'])) {
76 1
        return false;
77
      }
78
79 1
      $uri = $_SERVER['REQUEST_URI'];
80 1
    }
81
82 1
    $uriOrig = $uri;
83
84
    //
85
    // Ensures the URL is well formed UTF-8
86
    //
87
88 1
    if (preg_match('//u', urldecode($uri))) {
89 1
      return $uri;
90
    }
91
92
    //
93
    // When not, assumes Windows-1252 and redirects to the corresponding UTF-8 encoded URL
94
    //
95
96 1
    $uri = preg_replace_callback(
97 1
        '/[\x80-\xFF]+/',
98
        function ($m) {
99 1
          return urlencode($m[0]);
100 1
        },
101
        $uri
102 1
    );
103
104 1
    $uri = preg_replace_callback(
105 1
        '/(?:%[89A-F][0-9A-F])+/i',
106 1
        function ($m) {
107 1
          return urlencode(UTF8::encode('UTF-8', urldecode($m[0])));
108 1
        },
109
        $uri
110 1
    );
111
112
    if (
113
        $uri !== $uriOrig
114 1
        &&
115
        $exit === true
116 1
        &&
117
        headers_sent() === false
118 1
    ) {
119
      // Use ob_start() to buffer content and avoid problem of headers already sent...
120
      $severProtocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1');
121
      header($severProtocol . ' 301 Moved Permanently');
122
      header('Location: ' . $uri);
0 ignored issues
show
Security Response Splitting introduced by
'Location: ' . $uri can contain request data and is used in response header context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

  1. Fetching key REQUEST_URI from $_SERVER, and $uri is assigned
    in src/voku/helper/Bootup.php on line 79
  2. $uri is passed through preg_replace_callback()
    in src/voku/helper/Bootup.php on line 101
  3. $uri is assigned
    in src/voku/helper/Bootup.php on line 96
  4. $uri is passed through preg_replace_callback()
    in src/voku/helper/Bootup.php on line 109
  5. $uri is assigned
    in src/voku/helper/Bootup.php on line 104

Response Splitting Attacks

Allowing an attacker to set a response header, opens your application to response splitting attacks; effectively allowing an attacker to send any response, he would like.

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
123
      exit();
0 ignored issues
show
Coding Style Compatibility introduced by
The method filterRequestUri() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
124
    }
125
126 1
    return $uri;
127
  }
128
129
  /**
130
   * Normalizes to UTF-8 NFC, converting from WINDOWS-1252 when needed.
131
   *
132
   * @param string $s
133
   * @param int    $normalization_form
134
   * @param string $leading_combining
135
   *
136
   * @return string
137
   */
138 1
  public static function filterString($s, $normalization_form = 4 /* n::NFC */, $leading_combining = '◌')
139
  {
140 1
    return UTF8::filter($s, $normalization_form, $leading_combining);
141
  }
142
143
  /**
144
   * Get random bytes via "random_bytes()" (+ polyfill).
145
   *
146
   * @ref https://github.com/paragonie/random_compat/
147
   *
148
   * @param  int $length Output length
149
   *
150
   * @return  string|false false on error
151
   */
152 1
  public static function get_random_bytes($length)
153
  {
154 1
    if (!$length) {
155 1
      return false;
156
    }
157
158 1
    $length = (int)$length;
159
160 1
    if ($length <= 0) {
161 1
      return false;
162
    }
163
164 1
    return random_bytes($length);
165
  }
166
167
  /**
168
   * bootstrap
169
   */
170 1
  public static function initAll()
171
  {
172 1
    ini_set('default_charset', 'UTF-8');
173
174
    // everything is init via composer, so we are done here ...
175 1
  }
176
177
  /**
178
   * Determines if the current version of PHP is equal to or greater than the supplied value.
179
   *
180
   * @param string $version
181
   *
182
   * @return bool <p>Return <strong>true</strong> if the current version is $version or higher</p>
183
   */
184 36
  public static function is_php($version)
185
  {
186 36
    static $_IS_PHP;
187
188 36
    $version = (string)$version;
189
190 36
    if (!isset($_IS_PHP[$version])) {
191 5
      $_IS_PHP[$version] = version_compare(PHP_VERSION, $version, '>=');
192 5
    }
193
194 36
    return $_IS_PHP[$version];
195
  }
196
}
197