Issues (165)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

Includes/limeCoverage.php (4 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * lime_coverage class.
5
 *
6
 * @extends lime_registration
7
 * @package lime
8
 */
9
class lime_coverage extends lime_registration
10
{
11
    public $files = array();
12
    public $extension = '.php';
13
    public $base_dir = '';
14
    public $harness = null;
15
    public $verbose = false;
16
    protected $coverage = array();
17
18
    /**
19
     * @param $harness
20
     * @throws Exception
21
     */
22
    public function __construct($harness)
23
    {
24
        $this->harness = $harness;
25
26
        if (!function_exists('xdebug_start_code_coverage')) {
27
            throw new Exception('You must install and enable xdebug before using lime coverage.');
28
        }
29
30
        if (!ini_get('xdebug.extended_info')) {
31
            throw new Exception('You must set xdebug.extended_info to 1 in your php.ini to use lime coverage.');
32
        }
33
    }
34
35
    /**
36
     * @throws Exception
37
     */
38
    public function run()
39
    {
40
        if (!count($this->harness->files)) {
41
            throw new Exception('You must register some test files before running coverage!');
42
        }
43
44
        if (!count($this->files)) {
45
            throw new Exception('You must register some files to cover!');
46
        }
47
48
        $this->coverage = array();
49
50
        $this->process($this->harness->files);
51
52
        $this->output($this->files);
53
    }
54
55
    /**
56
     * @param $files
57
     * @throws Exception
58
     */
59
    public function process($files)
60
    {
61
        if (!is_array($files)) {
62
            $files = array($files);
63
        }
64
65
        $tmp_file = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'test.php';
66
        foreach ($files as $file) {
67
            $tmp = <<<EOF
68
<?php
69
xdebug_start_code_coverage(XDEBUG_CC_UNUSED | XDEBUG_CC_DEAD_CODE);
70
include('$file');
71
echo '<PHP_SER>'.serialize(xdebug_get_code_coverage()).'</PHP_SER>';
72
EOF;
73
            file_put_contents($tmp_file, $tmp);
74
            ob_start();
75
            // see http://trac.symfony-project.org/ticket/5437 for the explanation on the weird "cd" thing
76
            passthru(sprintf('cd & %s %s 2>&1', escapeshellarg($this->harness->php_cli), escapeshellarg($tmp_file)),
77
                $return);
78
            $retval = ob_get_clean();
79
80
            if (0 != $return) // test exited without success
0 ignored issues
show
It seems like you are loosely comparing $return of type integer|null to 0; this is ambiguous as not only 0 == 0 is true, but null == 0 is true, too. Consider using a strict comparison ===.
Loading history...
81
            {
82
                // something may have gone wrong, we should warn the user so they know
83
                // it's a bug in their code and not symfony's
84
85
                $this->harness->output->echoln(sprintf('Warning: %s returned status %d, results may be inaccurate',
86
                    $file, $return), 'ERROR');
87
            }
88
89
            if (false === $cov = @unserialize(substr($retval, strpos($retval, '<PHP_SER>') + 9,
90
                    strpos($retval, '</PHP_SER>') - 9))
91
            ) {
92
                if (0 == $return) {
0 ignored issues
show
It seems like you are loosely comparing $return of type integer|null to 0; this is ambiguous as not only 0 == 0 is true, but null == 0 is true, too. Consider using a strict comparison ===.
Loading history...
93
                    // failed to serialize, but PHP said it should of worked.
94
                    // something is seriously wrong, so abort with exception
95
                    throw new Exception(sprintf('Unable to unserialize coverage for file "%s"', $file));
96
                } else {
97
                    // failed to serialize, but PHP warned us that this might have happened.
98
                    // so we should ignore and move on
99
                    continue; // continue foreach loop through $this->harness->files
100
                }
101
            }
102
103
            foreach ($cov as $file => $lines) {
104
                if (!isset($this->coverage[$file])) {
105
                    $this->coverage[$file] = $lines;
106
                    continue;
107
                }
108
109
                foreach ($lines as $line => $flag) {
110
                    if ($flag == 1) {
111
                        $this->coverage[$file][$line] = 1;
112
                    }
113
                }
114
            }
115
        }
116
117
        if (file_exists($tmp_file)) {
118
            unlink($tmp_file);
119
        }
120
    }
121
122
    /**
123
     * @param $files
124
     */
125
    public function output($files)
126
    {
127
        ksort($this->coverage);
128
        $total_php_lines = 0;
129
        $total_covered_lines = 0;
130
        foreach ($files as $file) {
131
            $file = realpath($file);
132
            $is_covered = isset($this->coverage[$file]);
133
            $cov = isset($this->coverage[$file]) ? $this->coverage[$file] : array();
134
            $covered_lines = array();
135
            $missing_lines = array();
136
            $output = null;
0 ignored issues
show
$output is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
137
138
            foreach ($cov as $line => $flag) {
139
                switch ($flag) {
140
                    case 1:
141
                        $covered_lines[] = $line;
142
                        break;
143
                    case -1:
144
                        $missing_lines[] = $line;
145
                        break;
146
                }
147
            }
148
149
            $total_lines = count($covered_lines) + count($missing_lines);
150
            if (!$total_lines) {
151
                // probably means that the file is not covered at all!
152
                $total_lines = count($this->get_php_lines(file_get_contents($file)));
153
            }
154
155
            $output = $this->harness->output;
156
            $percent = $total_lines ? count($covered_lines) * 100 / $total_lines : 0;
157
158
            $total_php_lines += $total_lines;
159
            $total_covered_lines += count($covered_lines);
160
161
            $relative_file = $this->get_relative_file($file);
162
            $output->echoln(sprintf("%-70s %3.0f%%", substr($relative_file, -min(70, strlen($relative_file))),
163
                $percent), $percent == 100 ? 'INFO' : ($percent > 90 ? 'PARAMETER' : ($percent < 20 ? 'ERROR' : '')));
164
            if ($this->verbose && $is_covered && $percent != 100) {
165
                $output->comment(sprintf("missing: %s", $this->format_range($missing_lines)));
166
            }
167
        }
168
169
        $output->echoln(sprintf("TOTAL COVERAGE: %3.0f%%",
0 ignored issues
show
The variable $output does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
170
            $total_php_lines ? $total_covered_lines * 100 / $total_php_lines : 0));
171
    }
172
173
    /**
174
     * @param $content
175
     * @return array
176
     */
177
    public static function get_php_lines($content)
178
    {
179
        if (is_readable($content)) {
180
            $content = file_get_contents($content);
181
        }
182
183
        $tokens = token_get_all($content);
184
        $php_lines = array();
185
        $current_line = 1;
186
        $in_class = false;
187
        $in_function = false;
188
        $in_function_declaration = false;
189
        $end_of_current_expr = true;
190
        $open_braces = 0;
191
        foreach ($tokens as $token) {
192
            if (is_string($token)) {
193
                switch ($token) {
194
                    case '=':
195
                        if (false === $in_class || (false !== $in_function && !$in_function_declaration)) {
196
                            $php_lines[$current_line] = true;
197
                        }
198
                        break;
199
                    case '{':
200
                        ++$open_braces;
201
                        $in_function_declaration = false;
202
                        break;
203
                    case ';':
204
                        $in_function_declaration = false;
205
                        $end_of_current_expr = true;
206
                        break;
207
                    case '}':
208
                        $end_of_current_expr = true;
209
                        --$open_braces;
210
                        if ($open_braces == $in_class) {
211
                            $in_class = false;
212
                        }
213
                        if ($open_braces == $in_function) {
214
                            $in_function = false;
215
                        }
216
                        break;
217
                }
218
219
                continue;
220
            }
221
222
            list($id, $text) = $token;
223
224
            switch ($id) {
225
                case T_CURLY_OPEN:
226
                case T_DOLLAR_OPEN_CURLY_BRACES:
227
                    ++$open_braces;
228
                    break;
229
                case T_WHITESPACE:
230
                case T_OPEN_TAG:
231
                case T_CLOSE_TAG:
232
                    $end_of_current_expr = true;
233
                    $current_line += count(explode("\n", $text)) - 1;
234
                    break;
235
                case T_COMMENT:
236
                case T_DOC_COMMENT:
237
                    $current_line += count(explode("\n", $text)) - 1;
238
                    break;
239
                case T_CLASS:
240
                    $in_class = $open_braces;
241
                    break;
242
                case T_FUNCTION:
243
                    $in_function = $open_braces;
244
                    $in_function_declaration = true;
245
                    break;
246
                case T_AND_EQUAL:
247
                case T_BREAK:
248
                case T_CASE:
249
                case T_CATCH:
250
                case T_CLONE:
251
                case T_CONCAT_EQUAL:
252
                case T_CONTINUE:
253
                case T_DEC:
254
                case T_DECLARE:
255
                case T_DEFAULT:
256
                case T_DIV_EQUAL:
257
                case T_DO:
258
                case T_ECHO:
259
                case T_ELSEIF:
260
                case T_EMPTY:
261
                case T_ENDDECLARE:
262
                case T_ENDFOR:
263
                case T_ENDFOREACH:
264
                case T_ENDIF:
265
                case T_ENDSWITCH:
266
                case T_ENDWHILE:
267
                case T_EVAL:
268
                case T_EXIT:
269
                case T_FOR:
270
                case T_FOREACH:
271
                case T_GLOBAL:
272
                case T_IF:
273
                case T_INC:
274
                case T_INCLUDE:
275
                case T_INCLUDE_ONCE:
276
                case T_INSTANCEOF:
277
                case T_ISSET:
278
                case T_IS_EQUAL:
279
                case T_IS_GREATER_OR_EQUAL:
280
                case T_IS_IDENTICAL:
281
                case T_IS_NOT_EQUAL:
282
                case T_IS_NOT_IDENTICAL:
283
                case T_IS_SMALLER_OR_EQUAL:
284
                case T_LIST:
285
                case T_LOGICAL_AND:
286
                case T_LOGICAL_OR:
287
                case T_LOGICAL_XOR:
288
                case T_MINUS_EQUAL:
289
                case T_MOD_EQUAL:
290
                case T_MUL_EQUAL:
291
                case T_NEW:
292
                case T_OBJECT_OPERATOR:
293
                case T_OR_EQUAL:
294
                case T_PLUS_EQUAL:
295
                case T_PRINT:
296
                case T_REQUIRE:
297
                case T_REQUIRE_ONCE:
298
                case T_RETURN:
299
                case T_SL:
300
                case T_SL_EQUAL:
301
                case T_SR:
302
                case T_SR_EQUAL:
303
                case T_SWITCH:
304
                case T_THROW:
305
                case T_TRY:
306
                case T_UNSET:
307
                case T_UNSET_CAST:
308
                case T_USE:
309
                case T_WHILE:
310
                case T_XOR_EQUAL:
311
                    $php_lines[$current_line] = true;
312
                    $end_of_current_expr = false;
313
                    break;
314
                default:
315
                    if (false === $end_of_current_expr) {
316
                        $php_lines[$current_line] = true;
317
                    }
318
            }
319
        }
320
321
        return $php_lines;
322
    }
323
324
    /**
325
     * @param $content
326
     * @param $cov
327
     * @return array
328
     */
329
    public function compute($content, $cov)
330
    {
331
        $php_lines = self::get_php_lines($content);
332
333
        // we remove from $cov non php lines
334
        foreach (array_diff_key($cov, $php_lines) as $line => $tmp) {
335
            unset($cov[$line]);
336
        }
337
338
        return array($cov, $php_lines);
339
    }
340
341
    /**
342
     * @param $lines
343
     * @return string
344
     */
345
    public function format_range($lines)
346
    {
347
        sort($lines);
348
        $formatted = '';
349
        $first = -1;
350
        $last = -1;
351
        foreach ($lines as $line) {
352
            if ($last + 1 != $line) {
353
                if ($first != -1) {
354
                    $formatted .= $first == $last ? "$first " : "[$first - $last] ";
355
                }
356
                $first = $line;
357
                $last = $line;
358
            } else {
359
                $last = $line;
360
            }
361
        }
362
        if ($first != -1) {
363
            $formatted .= $first == $last ? "$first " : "[$first - $last] ";
364
        }
365
366
        return $formatted;
367
    }
368
}
369