Issues (1210)

Security Analysis    not enabled

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.

include/Text_Diff.php (33 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
 * Text_Diff
5
 *
6
 * General API for generating and formatting diffs - the differences between
7
 * two sequences of strings.
8
 *
9
 * The PHP diff code used in this package was originally written by Geoffrey
10
 * T. Dairiki and is used with his permission.
11
 *
12
 * $Horde: framework/Text_Diff/Diff.php,v 1.13 2005/05/26 20:26:06 selsky Exp $
13
 *
14
 * @package Text_Diff
15
 * @author  Geoffrey T. Dairiki <[email protected]>
16
 */
17
class Text_Diff
18
{
19
    /**
20
     * Array of changes.
21
     *
22
     * @var array
23
     */
24
    public $_edits;
25
26
    /**
27
     * Computes diffs between sequences of strings.
28
     *
29
     * @param array $from_lines An array of strings.  Tyapcally these are
30
     *                          lines from a file.
31
     * @param array $to_lines   An array of strings.
32
     */
33
    public function __construct($from_lines, $to_lines)
34
    {
35
        array_walk($from_lines, array($this, '_trimNewlines'));
36
        array_walk($to_lines, array($this, '_trimNewlines'));
37
38
        if (extension_loaded('xdiff')) {
39
            $engine = new Text_Diff_Engine_xdiff();
40
        } else {
41
            $engine = new Text_Diff_Engine_native();
42
        }
43
44
        $this->_edits = $engine->diff($from_lines, $to_lines);
45
    }
46
47
    /**
48
     * Returns the array of differences.
49
     */
50
    public function getDiff()
51
    {
52
        return $this->_edits;
53
    }
54
55
    /**
56
     * Computes a reversed diff.
57
     *
58
     * Example:
59
     * <code>
60
     * $diff = new Text_Diff($lines1, $lines2);
61
     * $rev = $diff->reverse();
62
     * </code>
63
     *
64
     * @return Text_Diff A Diff object representing the inverse of the
65
     *                   original diff.  Note that we purposely don't return a
66
     *                   reference here, since this essentially is a clone()
67
     *                   method.
68
     */
69
    public function reverse()
70
    {
71
        if (version_compare(zend_version(), '2', '>')) {
72
            $rev = clone $obj;
0 ignored issues
show
The variable $obj does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
73
        } else {
74
            $rev = $this;
75
        }
76
        $rev->_edits = array();
77
        foreach ($this->_edits as $edit) {
78
            $rev->_edits[] = $edit->reverse();
79
        }
80
81
        return $rev;
82
    }
83
84
    /**
85
     * Checks for an empty diff.
86
     *
87
     * @return boolean True if two sequences were identical.
88
     */
89
    public function isEmpty()
90
    {
91
        foreach ($this->_edits as $edit) {
92
            if (!is_a($edit, 'Text_Diff_Op_copy')) {
93
                return false;
94
            }
95
        }
96
97
        return true;
98
    }
99
100
    /**
101
     * Computes the length of the Longest Common Subsequence (LCS).
102
     *
103
     * This is mostly for diagnostic purposes.
104
     *
105
     * @return integer The length of the LCS.
106
     */
107
    public function lcs()
108
    {
109
        $lcs = 0;
110
        foreach ($this->_edits as $edit) {
111
            if (is_a($edit, 'Text_Diff_Op_copy')) {
112
                $lcs += count($edit->orig);
113
            }
114
        }
115
116
        return $lcs;
117
    }
118
119
    /**
120
     * Gets the original set of lines.
121
     *
122
     * This reconstructs the $from_lines parameter passed to the constructor.
123
     *
124
     * @return array The original sequence of strings.
125
     */
126 View Code Duplication
    public function getOriginal()
0 ignored issues
show
This method seems to be duplicated in 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...
127
    {
128
        $lines = array();
129
        foreach ($this->_edits as $edit) {
130
            if ($edit->orig) {
131
                array_splice($lines, count($lines), 0, $edit->orig);
132
            }
133
        }
134
135
        return $lines;
136
    }
137
138
    /**
139
     * Gets the final set of lines.
140
     *
141
     * This reconstructs the $to_lines parameter passed to the constructor.
142
     *
143
     * @return array The sequence of strings.
144
     */
145 View Code Duplication
    public function getFinal()
0 ignored issues
show
This method seems to be duplicated in 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...
146
    {
147
        $lines = array();
148
        foreach ($this->_edits as $edit) {
149
            if ($edit->final) {
150
                array_splice($lines, count($lines), 0, $edit->final);
151
            }
152
        }
153
154
        return $lines;
155
    }
156
157
    /**
158
     * Removes trailing newlines from a line of text. This is meant to be used
159
     * with array_walk().
160
     *
161
     * @param string  $line The line to trim.
162
     * @param integer $key  The index of the line in the array. Not used.
163
     */
164
    public function _trimNewlines(&$line, $key)
0 ignored issues
show
The parameter $key is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
165
    {
166
        $line = str_replace(array("\n", "\r"), '', $line);
167
    }
168
169
    /**
170
     * Checks a diff for validity.
171
     *
172
     * This is here only for debugging purposes.
173
     * @param $from_lines
174
     * @param $to_lines
175
     * @return bool
176
     */
177
    public function _check($from_lines, $to_lines)
178
    {
179
        if (serialize($from_lines) != serialize($this->getOriginal())) {
180
            trigger_error("Reconstructed original doesn't match", E_USER_ERROR);
181
        }
182
        if (serialize($to_lines) != serialize($this->getFinal())) {
183
            trigger_error("Reconstructed final doesn't match", E_USER_ERROR);
184
        }
185
186
        $rev = $this->reverse();
187
        if (serialize($to_lines) != serialize($rev->getOriginal())) {
188
            trigger_error("Reversed original doesn't match", E_USER_ERROR);
189
        }
190
        if (serialize($from_lines) != serialize($rev->getFinal())) {
191
            trigger_error("Reversed final doesn't match", E_USER_ERROR);
192
        }
193
194
        $prevtype = null;
195
        foreach ($this->_edits as $edit) {
196
            if ($prevtype == get_class($edit)) {
197
                trigger_error('Edit sequence is non-optimal', E_USER_ERROR);
198
            }
199
            $prevtype = get_class($edit);
200
        }
201
202
        return true;
203
    }
204
}
205
206
/**
207
 * $Horde: framework/Text_Diff/Diff.php,v 1.13 2005/05/26 20:26:06 selsky Exp $
208
 *
209
 * @package Text_Diff
210
 * @author  Geoffrey T. Dairiki <[email protected]>
211
 */
212
class Text_MappedDiff extends Text_Diff
213
{
214
    /**
215
     * Computes a diff between sequences of strings.
216
     *
217
     * This can be used to compute things like case-insensitve diffs, or diffs
218
     * which ignore changes in white-space.
219
     *
220
     * @param array $from_lines        An array of strings.
221
     * @param array $to_lines          An array of strings.
222
     * @param array $mapped_from_lines This array should have the same size
223
     *                                 number of elements as $from_lines.  The
224
     *                                 elements in $mapped_from_lines and
225
     *                                 $mapped_to_lines are what is actually
226
     *                                 compared when computing the diff.
227
     * @param array $mapped_to_lines   This array should have the same number
228
     *                                 of elements as $to_lines.
229
     */
230
    public function __construct($from_lines, $to_lines, $mapped_from_lines, $mapped_to_lines)
231
    {
232
        assert(count($from_lines) == count($mapped_from_lines));
233
        assert(count($to_lines) == count($mapped_to_lines));
234
235
        parent::__construct($mapped_from_lines, $mapped_to_lines);
236
237
        $xi = $yi = 0;
238
        for ($i = 0, $iMax = count($this->_edits); $i < $iMax; ++$i) {
239
            $orig = &$this->_edits[$i]->orig;
240
            if (is_array($orig)) {
241
                $orig = array_slice($from_lines, $xi, count($orig));
242
                $xi   += count($orig);
243
            }
244
245
            $final = &$this->_edits[$i]->final;
246
            if (is_array($final)) {
247
                $final = array_slice($to_lines, $yi, count($final));
248
                $yi    += count($final);
249
            }
250
        }
251
    }
252
}
253
254
/**
255
 * Class used internally by Diff to actually compute the diffs.  This class
256
 * uses the xdiff PECL package (http://pecl.php.net/package/xdiff) to compute
257
 * the differences between the two input arrays.
258
 *
259
 * @author  Jon Parise <[email protected]>
260
 * @package Text_Diff
261
 *
262
 * @access  private
263
 */
264
class Text_Diff_Engine_xdiff
265
{
266
    /**
267
     * @param $from_lines
268
     * @param $to_lines
269
     * @return array
270
     */
271
    public function diff($from_lines, $to_lines)
272
    {
273
        /* Convert the two input arrays into strings for xdiff processing. */
274
        $from_string = implode("\n", $from_lines);
275
        $to_string   = implode("\n", $to_lines);
276
277
        /* Diff the two strings and convert the result to an array. */
278
        $diff = xdiff_string_diff($from_string, $to_string, count($to_lines));
279
        $diff = explode("\n", $diff);
280
281
        /* Walk through the diff one line at a time.  We build the $edits
282
         * array of diff operations by reading the first character of the
283
         * xdiff output (which is in the "unified diff" format).
284
         *
285
         * Note that we don't have enough information to detect "changed"
286
         * lines using this approach, so we can't add Text_Diff_Op_changed
287
         * instances to the $edits array.  The result is still perfectly
288
         * valid, albeit a little less descriptive and efficient. */
289
        $edits = array();
290
        foreach ($diff as $line) {
291
            switch ($line[0]) {
292
                case ' ':
293
                    $edits[] = new Text_Diff_Op_copy(array(substr($line, 1)));
294
                    break;
295
296
                case '+':
297
                    $edits[] = new Text_Diff_Op_add(array(substr($line, 1)));
298
                    break;
299
300
                case '-':
301
                    $edits[] = new Text_Diff_Op_delete(array(substr($line, 1)));
302
                    break;
303
            }
304
        }
305
306
        return $edits;
307
    }
308
}
309
310
/**
311
 * Class used internally by Diff to actually compute the diffs.  This class is
312
 * implemented using native PHP code.
313
 *
314
 * The algorithm used here is mostly lifted from the perl module
315
 * Algorithm::Diff (version 1.06) by Ned Konz, which is available at:
316
 * http://www.perl.com/CPAN/authors/id/N/NE/NEDKONZ/Algorithm-Diff-1.06.zip
317
 *
318
 * More ideas are taken from:
319
 * http://www.ics.uci.edu/~eppstein/161/960229.html
320
 *
321
 * Some ideas (and a bit of code) are taken from analyze.c, of GNU
322
 * diffutils-2.7, which can be found at:
323
 * ftp://gnudist.gnu.org/pub/gnu/diffutils/diffutils-2.7.tar.gz
324
 *
325
 * Some ideas (subdivision by NCHUNKS > 2, and some optimizations) are from
326
 * Geoffrey T. Dairiki <[email protected]>. The original PHP version of this
327
 * code was written by him, and is used/adapted with his permission.
328
 *
329
 * @author  Geoffrey T. Dairiki <[email protected]>
330
 * @package Text_Diff
331
 *
332
 * @access  private
333
 */
334
class Text_Diff_Engine_native
335
{
336
    /**
337
     * @param $from_lines
338
     * @param $to_lines
339
     * @return array
340
     */
341
    public function diff($from_lines, $to_lines)
342
    {
343
        $n_from = count($from_lines);
344
        $n_to   = count($to_lines);
345
346
        $this->xchanged = $this->ychanged = array();
0 ignored issues
show
The property xchanged does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
The property ychanged does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
347
        $this->xv       = $this->yv = array();
0 ignored issues
show
The property xv does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
The property yv does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
348
        $this->xind     = $this->yind = array();
0 ignored issues
show
The property xind does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
The property yind does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
349
        unset($this->seq, $this->in_seq, $this->lcs);
350
351
        // Skip leading common lines.
352
        for ($skip = 0; $skip < $n_from && $skip < $n_to; ++$skip) {
353
            if ($from_lines[$skip] != $to_lines[$skip]) {
354
                break;
355
            }
356
            $this->xchanged[$skip] = $this->ychanged[$skip] = false;
357
        }
358
359
        // Skip trailing common lines.
360
        $xi = $n_from;
361
        $yi = $n_to;
362
        for ($endskip = 0; --$xi > $skip && --$yi > $skip; ++$endskip) {
363
            if ($from_lines[$xi] != $to_lines[$yi]) {
364
                break;
365
            }
366
            $this->xchanged[$xi] = $this->ychanged[$yi] = false;
367
        }
368
369
        // Ignore lines which do not exist in both files.
370
        for ($xi = $skip; $xi < $n_from - $endskip; ++$xi) {
371
            $xhash[$from_lines[$xi]] = 1;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$xhash was never initialized. Although not strictly required by PHP, it is generally a good practice to add $xhash = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
372
        }
373
        for ($yi = $skip; $yi < $n_to - $endskip; ++$yi) {
374
            $line = $to_lines[$yi];
375
            if ($this->ychanged[$yi] = empty($xhash[$line])) {
376
                continue;
377
            }
378
            $yhash[$line] = 1;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$yhash was never initialized. Although not strictly required by PHP, it is generally a good practice to add $yhash = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
379
            $this->yv[]   = $line;
380
            $this->yind[] = $yi;
381
        }
382
        for ($xi = $skip; $xi < $n_from - $endskip; ++$xi) {
383
            $line = $from_lines[$xi];
384
            if ($this->xchanged[$xi] = empty($yhash[$line])) {
385
                continue;
386
            }
387
            $this->xv[]   = $line;
388
            $this->xind[] = $xi;
389
        }
390
391
        // Find the LCS.
392
        $this->_compareseq(0, count($this->xv), 0, count($this->yv));
393
394
        // Merge edits when possible.
395
        $this->_shiftBoundaries($from_lines, $this->xchanged, $this->ychanged);
396
        $this->_shiftBoundaries($to_lines, $this->ychanged, $this->xchanged);
397
398
        // Compute the edit operations.
399
        $edits = array();
400
        $xi    = $yi = 0;
401
        while ($xi < $n_from || $yi < $n_to) {
402
            assert($yi < $n_to || $this->xchanged[$xi]);
403
            assert($xi < $n_from || $this->ychanged[$yi]);
404
405
            // Skip matching "snake".
406
            $copy = array();
407
            while ($xi < $n_from && $yi < $n_to && !$this->xchanged[$xi] && !$this->ychanged[$yi]) {
408
                $copy[] = $from_lines[$xi++];
409
                ++$yi;
410
            }
411
            if ($copy) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $copy of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
412
                $edits[] = new Text_Diff_Op_copy($copy);
413
            }
414
415
            // Find deletes & adds.
416
            $delete = array();
417
            while ($xi < $n_from && $this->xchanged[$xi]) {
418
                $delete[] = $from_lines[$xi++];
419
            }
420
421
            $add = array();
422
            while ($yi < $n_to && $this->ychanged[$yi]) {
423
                $add[] = $to_lines[$yi++];
424
            }
425
426
            if ($delete && $add) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $delete of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
Bug Best Practice introduced by
The expression $add of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
427
                $edits[] = new Text_Diff_Op_change($delete, $add);
428
            } elseif ($delete) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $delete of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
429
                $edits[] = new Text_Diff_Op_delete($delete);
430
            } elseif ($add) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $add of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
431
                $edits[] = new Text_Diff_Op_add($add);
432
            }
433
        }
434
435
        return $edits;
436
    }
437
438
    /**
439
     * Divides the Largest Common Subsequence (LCS) of the sequences (XOFF,
440
     * XLIM) and (YOFF, YLIM) into NCHUNKS approximately equally sized
441
     * segments.
442
     *
443
     * Returns (LCS, PTS).  LCS is the length of the LCS. PTS is an array of
444
     * NCHUNKS+1 (X, Y) indexes giving the diving points between sub
445
     * sequences.  The first sub-sequence is contained in (X0, X1), (Y0, Y1),
446
     * the second in (X1, X2), (Y1, Y2) and so on.  Note that (X0, Y0) ==
447
     * (XOFF, YOFF) and (X[NCHUNKS], Y[NCHUNKS]) == (XLIM, YLIM).
448
     *
449
     * This function assumes that the first lines of the specified portions of
450
     * the two files do not match, and likewise that the last lines do not
451
     * match.  The caller must trim matching lines from the beginning and end
452
     * of the portions it is going to specify.
453
     * @param $xoff
454
     * @param $xlim
455
     * @param $yoff
456
     * @param $ylim
457
     * @param $nchunks
458
     * @return array
459
     */
460
    public function _diag($xoff, $xlim, $yoff, $ylim, $nchunks)
461
    {
462
        $flip = false;
463
464
        if ($xlim - $xoff > $ylim - $yoff) {
465
            /* Things seems faster (I'm not sure I understand why) when the
466
             * shortest sequence is in X. */
467
            $flip = true;
468
            list($xoff, $xlim, $yoff, $ylim) = array($yoff, $ylim, $xoff, $xlim);
469
        }
470
471
        if ($flip) {
472
            for ($i = $ylim - 1; $i >= $yoff; $i--) {
473
                $ymatches[$this->xv[$i]][] = $i;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$ymatches was never initialized. Although not strictly required by PHP, it is generally a good practice to add $ymatches = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
474
            }
475
        } else {
476
            for ($i = $ylim - 1; $i >= $yoff; $i--) {
477
                $ymatches[$this->yv[$i]][] = $i;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$ymatches was never initialized. Although not strictly required by PHP, it is generally a good practice to add $ymatches = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
478
            }
479
        }
480
481
        $this->lcs    = 0;
0 ignored issues
show
The property lcs does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
482
        $this->seq[0] = $yoff - 1;
0 ignored issues
show
The property seq does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
483
        $this->in_seq = array();
0 ignored issues
show
The property in_seq does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
484
        $ymids[0]     = array();
0 ignored issues
show
Coding Style Comprehensibility introduced by
$ymids was never initialized. Although not strictly required by PHP, it is generally a good practice to add $ymids = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
485
486
        $numer = $xlim - $xoff + $nchunks - 1;
487
        $x     = $xoff;
488
        for ($chunk = 0; $chunk < $nchunks; ++$chunk) {
489
            if ($chunk > 0) {
490
                for ($i = 0; $i <= $this->lcs; ++$i) {
491
                    $ymids[$i][$chunk - 1] = $this->seq[$i];
492
                }
493
            }
494
495
            $x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $chunk) / $nchunks);
496
            for (; $x < $x1; ++$x) {
497
                $line = $flip ? $this->yv[$x] : $this->xv[$x];
498
                if (empty($ymatches[$line])) {
499
                    continue;
500
                }
501
                $matches = $ymatches[$line];
502
                foreach ($matches as $y) {
503 View Code Duplication
                    if (empty($this->in_seq[$y])) {
0 ignored issues
show
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...
504
                        $k = $this->_lcsPos($y);
505
                        assert($k > 0);
506
                        $ymids[$k] = $ymids[$k - 1];
507
                        break;
508
                    }
509
                }
510
511
                //                while (list($junk, $y) = each($matches)) {
512
                foreach ($matches as $junk => $y) {
513
                    if ($y > $this->seq[$k - 1]) {
514
                        assert($y < $this->seq[$k]);
0 ignored issues
show
The variable $k 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...
515
                        /* Optimization: this is a common case: next match is
516
                         * just replacing previous match. */
517
                        $this->in_seq[$this->seq[$k]] = false;
518
                        $this->seq[$k]                = $y;
519
                        $this->in_seq[$y]             = 1;
520 View Code Duplication
                    } elseif (empty($this->in_seq[$y])) {
0 ignored issues
show
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...
521
                        $k = $this->_lcsPos($y);
522
                        assert($k > 0);
523
                        $ymids[$k] = $ymids[$k - 1];
524
                    }
525
                }
526
            }
527
        }
528
529
        $seps[] = $flip ? array($yoff, $xoff) : array($xoff, $yoff);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$seps was never initialized. Although not strictly required by PHP, it is generally a good practice to add $seps = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
530
        $ymid   = $ymids[$this->lcs];
531
        for ($n = 0; $n < $nchunks - 1; ++$n) {
532
            $x1     = $xoff + (int)(($numer + ($xlim - $xoff) * $n) / $nchunks);
533
            $y1     = $ymid[$n] + 1;
534
            $seps[] = $flip ? array($y1, $x1) : array($x1, $y1);
535
        }
536
537
        $seps[] = $flip ? array($ylim, $xlim) : array($xlim, $ylim);
538
539
        return array($this->lcs, $seps);
540
    }
541
542
    /**
543
     * @param $ypos
544
     * @return int
545
     */
546
    public function _lcsPos($ypos)
547
    {
548
        $end = $this->lcs;
549
        if ($end == 0 || $ypos > $this->seq[$end]) {
550
            $this->seq[++$this->lcs] = $ypos;
551
            $this->in_seq[$ypos]     = 1;
552
553
            return $this->lcs;
554
        }
555
556
        $beg = 1;
557
        while ($beg < $end) {
558
            $mid = (int)(($beg + $end) / 2);
559
            if ($ypos > $this->seq[$mid]) {
560
                $beg = $mid + 1;
561
            } else {
562
                $end = $mid;
563
            }
564
        }
565
566
        assert($ypos != $this->seq[$end]);
567
568
        $this->in_seq[$this->seq[$end]] = false;
569
        $this->seq[$end]                = $ypos;
570
        $this->in_seq[$ypos]            = 1;
571
572
        return $end;
573
    }
574
575
    /**
576
     * Finds LCS of two sequences.
577
     *
578
     * The results are recorded in the vectors $this->{x,y}changed[], by
579
     * storing a 1 in the element for each line that is an insertion or
580
     * deletion (ie. is not in the LCS).
581
     *
582
     * The subsequence of file 0 is (XOFF, XLIM) and likewise for file 1.
583
     *
584
     * Note that XLIM, YLIM are exclusive bounds.  All line numbers are
585
     * origin-0 and discarded lines are not counted.
586
     * @param $xoff
587
     * @param $xlim
588
     * @param $yoff
589
     * @param $ylim
590
     */
591
    public function _compareseq($xoff, $xlim, $yoff, $ylim)
592
    {
593
        /* Slide down the bottom initial diagonal. */
594
        while ($xoff < $xlim && $yoff < $ylim && $this->xv[$xoff] == $this->yv[$yoff]) {
595
            ++$xoff;
596
            ++$yoff;
597
        }
598
599
        /* Slide up the top initial diagonal. */
600
        while ($xlim > $xoff && $ylim > $yoff && $this->xv[$xlim - 1] == $this->yv[$ylim - 1]) {
601
            --$xlim;
602
            --$ylim;
603
        }
604
605
        if ($xoff == $xlim || $yoff == $ylim) {
606
            $lcs = 0;
607
        } else {
608
            /* This is ad hoc but seems to work well.  $nchunks =
609
             * sqrt(min($xlim - $xoff, $ylim - $yoff) / 2.5); $nchunks =
610
             * max(2,min(8,(int) $nchunks)); */
611
            $nchunks = min(7, $xlim - $xoff, $ylim - $yoff) + 1;
612
            list($lcs, $seps) = $this->_diag($xoff, $xlim, $yoff, $ylim, $nchunks);
613
        }
614
615
        if ($lcs == 0) {
616
            /* X and Y sequences have no common subsequence: mark all
617
             * changed. */
618
            while ($yoff < $ylim) {
619
                $this->ychanged[$this->yind[$yoff++]] = 1;
620
            }
621
            while ($xoff < $xlim) {
622
                $this->xchanged[$this->xind[$xoff++]] = 1;
623
            }
624
        } else {
625
            /* Use the partitions to split this problem into subproblems. */
626
            reset($seps);
627
            $pt1 = $seps[0];
628
            while ($pt2 = next($seps)) {
629
                $this->_compareseq($pt1[0], $pt2[0], $pt1[1], $pt2[1]);
630
                $pt1 = $pt2;
631
            }
632
        }
633
    }
634
635
    /**
636
     * Adjusts inserts/deletes of identical lines to join changes as much as
637
     * possible.
638
     *
639
     * We do something when a run of changed lines include a line at one end
640
     * and has an excluded, identical line at the other.  We are free to
641
     * choose which identical line is included.  `compareseq' usually chooses
642
     * the one at the beginning, but usually it is cleaner to consider the
643
     * following identical line to be the "change".
644
     *
645
     * This is extracted verbatim from analyze.c (GNU diffutils-2.7).
646
     * @param $lines
647
     * @param $changed
648
     * @param $other_changed
649
     */
650
    public function _shiftBoundaries($lines, &$changed, $other_changed)
651
    {
652
        $i = 0;
653
        $j = 0;
654
655
        assert('count($lines) == count($changed)');
656
        $len       = count($lines);
657
        $other_len = count($other_changed);
658
659
        while (1) {
660
            /* Scan forward to find the beginning of another run of
661
             * changes. Also keep track of the corresponding point in the
662
             * other file.
663
             *
664
             * Throughout this code, $i and $j are adjusted together so that
665
             * the first $i elements of $changed and the first $j elements of
666
             * $other_changed both contain the same number of zeros (unchanged
667
             * lines).
668
             *
669
             * Furthermore, $j is always kept so that $j == $other_len or
670
             * $other_changed[$j] === false. */
671
            while ($j < $other_len && $other_changed[$j]) {
672
                ++$j;
673
            }
674
675
            while ($i < $len && !$changed[$i]) {
676
                assert('$j < $other_len && ! $other_changed[$j]');
677
                ++$i;
678
                ++$j;
679
                while ($j < $other_len && $other_changed[$j]) {
680
                    ++$j;
681
                }
682
            }
683
684
            if ($i == $len) {
685
                break;
686
            }
687
688
            $start = $i;
689
690
            /* Find the end of this run of changes. */
691
            while (++$i < $len && $changed[$i]) {
692
                continue;
693
            }
694
695
            do {
696
                /* Record the length of this run of changes, so that we can
697
                 * later determine whether the run has grown. */
698
                $runlength = $i - $start;
699
700
                /* Move the changed region back, so long as the previous
701
                 * unchanged line matches the last changed one.  This merges
702
                 * with previous changed regions. */
703
                while ($start > 0 && $lines[$start - 1] == $lines[$i - 1]) {
704
                    $changed[--$start] = 1;
705
                    $changed[--$i]     = false;
706
                    while ($start > 0 && $changed[$start - 1]) {
707
                        $start--;
708
                    }
709
                    assert('$j > 0');
710
                    while ($other_changed[--$j]) {
711
                        continue;
712
                    }
713
                    assert('$j >= 0 && !$other_changed[$j]');
714
                }
715
716
                /* Set CORRESPONDING to the end of the changed run, at the
717
                 * last point where it corresponds to a changed run in the
718
                 * other file. CORRESPONDING == LEN means no such point has
719
                 * been found. */
720
                $corresponding = $j < $other_len ? $i : $len;
721
722
                /* Move the changed region forward, so long as the first
723
                 * changed line matches the following unchanged one.  This
724
                 * merges with following changed regions.  Do this second, so
725
                 * that if there are no merges, the changed region is moved
726
                 * forward as far as possible. */
727
                while ($i < $len && $lines[$start] == $lines[$i]) {
728
                    $changed[$start++] = false;
729
                    $changed[$i++]     = 1;
730
                    while ($i < $len && $changed[$i]) {
731
                        ++$i;
732
                    }
733
734
                    assert('$j < $other_len && ! $other_changed[$j]');
735
                    ++$j;
736
                    if ($j < $other_len && $other_changed[$j]) {
737
                        $corresponding = $i;
738
                        while ($j < $other_len && $other_changed[$j]) {
739
                            ++$j;
740
                        }
741
                    }
742
                }
743
            } while ($runlength != $i - $start);
744
745
            /* If possible, move the fully-merged run of changes back to a
746
             * corresponding run in the other file. */
747
            while ($corresponding < $i) {
748
                $changed[--$start] = 1;
749
                $changed[--$i]     = 0;
750
                assert('$j > 0');
751
                while ($other_changed[--$j]) {
752
                    continue;
753
                }
754
                assert('$j >= 0 && !$other_changed[$j]');
755
            }
756
        }
757
    }
758
}
759
760
/**
761
 * @package Text_Diff
762
 * @author  Geoffrey T. Dairiki <[email protected]>
763
 *
764
 * @access  private
765
 */
766
class Text_Diff_Op
767
{
768
    public $orig;
769
    public $final;
770
771
    public function reverse()
772
    {
773
        trigger_error('Abstract method', E_USER_ERROR);
774
    }
775
776
    /**
777
     * @return int
778
     */
779
    public function norig()
780
    {
781
        return $this->orig ? count($this->orig) : 0;
782
    }
783
784
    /**
785
     * @return int
786
     */
787
    public function nfinal()
788
    {
789
        return $this->final ? count($this->final) : 0;
790
    }
791
}
792
793
/**
794
 * @package Text_Diff
795
 * @author  Geoffrey T. Dairiki <[email protected]>
796
 *
797
 * @access  private
798
 */
799
class Text_Diff_Op_copy extends Text_Diff_Op
800
{
801
    /**
802
     * Text_Diff_Op_copy constructor.
803
     * @param      $orig
804
     * @param bool $final
805
     */
806
    public function __construct($orig, $final = false)
807
    {
808
        if (!is_array($final)) {
809
            $final = $orig;
810
        }
811
        $this->orig  = $orig;
812
        $this->final = $final;
813
    }
814
815
    /**
816
     * @return Text_Diff_Op_copy
817
     */
818
    public function &reverse()
819
    {
820
        return $reverse = new Text_Diff_Op_copy($this->final, $this->orig);
0 ignored issues
show
$reverse 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...
821
    }
822
}
823
824
/**
825
 * @package Text_Diff
826
 * @author  Geoffrey T. Dairiki <[email protected]>
827
 *
828
 * @access  private
829
 */
830 View Code Duplication
class Text_Diff_Op_delete extends Text_Diff_Op
0 ignored issues
show
This class seems to be duplicated in 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...
831
{
832
    /**
833
     * Text_Diff_Op_delete constructor.
834
     * @param $lines
835
     */
836
    public function __construct($lines)
837
    {
838
        $this->orig  = $lines;
839
        $this->final = false;
840
    }
841
842
    /**
843
     * @return Text_Diff_Op_add
844
     */
845
    public function &reverse()
846
    {
847
        return $reverse = new Text_Diff_Op_add($this->orig);
0 ignored issues
show
$reverse 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...
848
    }
849
}
850
851
/**
852
 * @package Text_Diff
853
 * @author  Geoffrey T. Dairiki <[email protected]>
854
 *
855
 * @access  private
856
 */
857 View Code Duplication
class Text_Diff_Op_add extends Text_Diff_Op
0 ignored issues
show
This class seems to be duplicated in 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...
858
{
859
    /**
860
     * Text_Diff_Op_add constructor.
861
     * @param $lines
862
     */
863
    public function __construct($lines)
864
    {
865
        $this->final = $lines;
866
        $this->orig  = false;
867
    }
868
869
    /**
870
     * @return Text_Diff_Op_delete
871
     */
872
    public function &reverse()
873
    {
874
        return $reverse = new Text_Diff_Op_delete($this->final);
0 ignored issues
show
$reverse 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...
875
    }
876
}
877
878
/**
879
 * @package Text_Diff
880
 * @author  Geoffrey T. Dairiki <[email protected]>
881
 *
882
 * @access  private
883
 */
884
class Text_Diff_Op_change extends Text_Diff_Op
885
{
886
    /**
887
     * Text_Diff_Op_change constructor.
888
     * @param $orig
889
     * @param $final
890
     */
891
    public function __construct($orig, $final)
892
    {
893
        $this->orig  = $orig;
894
        $this->final = $final;
895
    }
896
897
    /**
898
     * @return Text_Diff_Op_change
899
     */
900
    public function &reverse()
901
    {
902
        return $reverse = new Text_Diff_Op_change($this->final, $this->orig);
0 ignored issues
show
$reverse 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...
903
    }
904
}
905