Completed
Push — master ( 82ec76...807838 )
by Lars
11:59
created

Bootup   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 188
Duplicated Lines 11.7 %

Coupling/Cohesion

Components 0
Dependencies 3

Test Coverage

Coverage 71.43%

Importance

Changes 20
Bugs 10 Features 1
Metric Value
wmc 26
lcom 0
cbo 3
dl 22
loc 188
c 20
b 10
f 1
ccs 80
cts 112
cp 0.7143
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A initAll() 0 4 1
A get_random_bytes() 0 14 3
A is_php() 0 11 2
C filterRequestUri() 0 43 7
B filterRequestInputs() 0 35 5
C filterString() 22 28 8

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
namespace voku\helper;
4
5
use Patchwork\PHP\Shim\Normalizer;
6
7
/**
8
 * Class Bootup
9
 *
10
 * this is a bootstrap for the polyfills (iconv / intl / mbstring / normalizer / xml)
11
 *
12
 * @package voku\helper
13
 */
14
class Bootup
15
{
16
  /**
17
   * bootstrap
18
   */
19
  public static function initAll()
20
  {
21
    \Patchwork\Utf8\Bootup::initAll();
22
  }
23
24
  /**
25
   * Get random bytes
26
   *
27
   * @ref https://github.com/paragonie/random_compat/
28
   *
29 1
   * @param  int $length Output length
30
   *
31 1
   * @return  string|false false on error
32
   */
33 1
  public static function get_random_bytes($length)
34 1
  {
35 1
    if (!$length) {
36 1
      return false;
37 1
    }
38 1
39 1
    $length = (int)$length;
40 1
41
    if ($length <= 0) {
42
      return false;
43
    }
44
45 1
    return random_bytes($length);
0 ignored issues
show
Unused Code introduced by
The call to random_bytes() has too many arguments starting with $length.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
46
  }
47 1
48 1
  /**
49
   * Determines if the current version of PHP is equal to or greater than the supplied value
50
   *
51
   * @param  string
52
   * @param string $version
53 1
   *
54
   * @return  bool  TRUE if the current version is $version or higher
55 1
   */
56 1
  public static function is_php($version)
57
  {
58
    static $_is_php;
59
60
    $version = (string)$version;
61 1
    if (!isset($_is_php[$version])) {
62
      $_is_php[$version] = version_compare(PHP_VERSION, $version, '>=');
63 1
    }
64 1
65 1
    return $_is_php[$version];
66 1
  }
67
68 1
  /**
69 1
   * filter request-uri
70 1
   *
71
   * @param null $uri
72 1
   * @param bool $exit
73 1
   *
74 1
   * @return bool|mixed|null
75 1
   */
76
  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...
77
  {
78 1
    if (!isset($uri)) {
79
      if (!isset($_SERVER['REQUEST_URI'])) {
80
        return false;
81
      } else {
82
        $uri = $_SERVER['REQUEST_URI'];
83 1
      }
84
    }
85 1
86
    // Ensures the URL is well formed UTF-8
87
    // When not, assumes Windows-1252 and redirects to the corresponding UTF-8 encoded URL
88 1
89
    if (!preg_match('//u', urldecode($uri))) {
90 1
      $uri = preg_replace_callback(
91 1
          '/[\x80-\xFF]+/',
92
          function($m) {
93 1
            return urlencode($m[0]);
94 1
          },
95 1
          $uri
96 1
      );
97
98 1
      $uri = preg_replace_callback(
99 1
          '/(?:%[89A-F][0-9A-F])+/i',
100 1
          function($m) {
101
            return urlencode(UTF8::encode('UTF-8', urldecode($m[0])));
102
          },
103
          $uri
104
      );
105
106
      if ($exit === true) {
107
        // Use ob_start() to buffer content and avoid problem of headers already sent...
108
        if (headers_sent() === false) {
109
          $severProtocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1');
110 1
          header($severProtocol . ' 301 Moved Permanently');
111
          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.

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...
112
          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...
113
        }
114
      }
115
    }
116
117 1
    return $uri;
118
  }
119
120
  /**
121 1
   * filter request inputs
122 1
   *
123 1
   * Ensures inputs are well formed UTF-8
124 1
   * When not, assumes Windows-1252 and converts to UTF-8
125
   * Tests only values, not keys
126 1
   *
127
   * @param int    $normalization_form
128
   * @param string $leading_combining
129
   */
130 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...
131 1
  {
132 1
    $a = array(
133
        &$_FILES,
134 1
        &$_ENV,
135 1
        &$_GET,
136
        &$_POST,
137 1
        &$_COOKIE,
138 1
        &$_SERVER,
139 1
        &$_REQUEST,
140
    );
141 1
142 1
    foreach ($a[0] as &$r) {
143
      $a[] = array(
144
          &$r['name'],
145
          &$r['type'],
146 1
      );
147 1
    }
148
    unset($r);
149 1
    unset($a[0]);
150 1
151 1
    $len = count($a) + 1;
152
    for ($i = 1; $i < $len; ++$i) {
153 1
      foreach ($a[$i] as &$r) {
154 1
        $s = $r; // $r is a ref, $s a copy
155
        if (is_array($s)) {
156
          $a[$len++] = & $r;
157 1
        } else {
158
          $r = self::filterString($s, $normalization_form, $leading_combining);
159
        }
160
      }
161
      unset($r);
162 1
      unset($a[$i]);
163
    }
164
  }
165
166
  /**
167 1
   * @param        $s
168
   * @param int    $normalization_form
169 1
   * @param string $leading_combining
170 1
   *
171 1
   * @return array|bool|mixed|string
172 1
   */
173
  public static function filterString($s, $normalization_form = 4 /* n::NFC */, $leading_combining = '◌')
174 1
  {
175 View Code Duplication
    if (false !== strpos($s, "\r")) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
176
      // Workaround https://bugs.php.net/65732
177 1
      $s = str_replace(array("\r\n", "\r"), "\n", $s);
178 1
    }
179
180 View Code Duplication
    if (preg_match('/[\x80-\xFF]/', $s)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
181
      if (Normalizer::isNormalized($s, $normalization_form)) {
182
        $n = '-';
183 1
      } else {
184
        $n = Normalizer::normalize($s, $normalization_form);
185 1
        if (isset($n[0])) {
186
          $s = $n;
187
        } else {
188
          $s = UTF8::encode('UTF-8', $s);
189 1
        }
190
      }
191 1
192
      if ($s[0] >= "\x80" && isset($n[0], $leading_combining[0]) && preg_match('/^\p{Mn}/u', $s)) {
193
        // Prevent leading combining chars
194
        // for NFC-safe concatenations.
195
        $s = $leading_combining . $s;
196
      }
197 1
    }
198
199
    return $s;
200
  }
201
}
202