Issues (1751)

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.

lib/includes/diff/DiffEngine.php (40 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
 * @file
5
 * A PHP diff engine for phpwiki. (Taken from phpwiki-1.3.3)
6
 *
7
 * Copyright (C) 2000, 2001 Geoffrey T. Dairiki <[email protected]>
8
 * You may copy this code freely under the conditions of the GPL.
9
 */
10
11
define('USE_ASSERTS', FALSE);
12
13
/**
14
 * @todo document
15
 * @private
16
 * @subpackage DifferenceEngine
17
 */
18
class _DiffOp {
19
  var $type;
20
  var $orig;
21
  var $closing;
22
23
  function reverse() {
24
    trigger_error('pure virtual', E_USER_ERROR);
25
  }
26
27
  function norig() {
28
    return $this->orig ? sizeof($this->orig) : 0;
29
  }
30
31
  function nclosing() {
32
    return $this->closing ? sizeof($this->closing) : 0;
33
  }
34
}
35
36
/**
37
 * @todo document
38
 * @private
39
 * @subpackage DifferenceEngine
40
 */
41
class _DiffOp_Copy extends _DiffOp {
42
  var $type = 'copy';
43
44
  function __construct($orig, $closing = FALSE) {
45
    if (!is_array($closing)) {
46
      $closing = $orig;
47
    }
48
    $this->orig = $orig;
49
    $this->closing = $closing;
50
  }
51
52
  function reverse() {
53
    return new _DiffOp_Copy($this->closing, $this->orig);
54
  }
55
}
56
57
/**
58
 * @todo document
59
 * @private
60
 * @subpackage DifferenceEngine
61
 */
62 View Code Duplication
class _DiffOp_Delete extends _DiffOp {
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...
63
  var $type = 'delete';
64
65
  function __construct($lines) {
66
    $this->orig = $lines;
67
    $this->closing = FALSE;
68
  }
69
70
  function reverse() {
71
    return new _DiffOp_Add($this->orig);
72
  }
73
}
74
75
/**
76
 * @todo document
77
 * @private
78
 * @subpackage DifferenceEngine
79
 */
80 View Code Duplication
class _DiffOp_Add extends _DiffOp {
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...
81
  var $type = 'add';
82
83
  function __construct($lines) {
84
    $this->closing = $lines;
85
    $this->orig = FALSE;
86
  }
87
88
  function reverse() {
89
    return new _DiffOp_Delete($this->closing);
90
  }
91
}
92
93
/**
94
 * @todo document
95
 * @private
96
 * @subpackage DifferenceEngine
97
 */
98
class _DiffOp_Change extends _DiffOp {
99
  var $type = 'change';
100
101
  function __construct($orig, $closing) {
102
    $this->orig = $orig;
103
    $this->closing = $closing;
104
  }
105
106
  function reverse() {
107
    return new _DiffOp_Change($this->closing, $this->orig);
108
  }
109
}
110
111
112
/**
113
 * Class used internally by Diff to actually compute the diffs.
114
 *
115
 * The algorithm used here is mostly lifted from the perl module
116
 * Algorithm::Diff (version 1.06) by Ned Konz, which is available at:
117
 *   http://www.perl.com/CPAN/authors/id/N/NE/NEDKONZ/Algorithm-Diff-1.06.zip
118
 *
119
 * More ideas are taken from:
120
 *   http://www.ics.uci.edu/~eppstein/161/960229.html
121
 *
122
 * Some ideas are (and a bit of code) are from from analyze.c, from GNU
123
 * diffutils-2.7, which can be found at:
124
 *   ftp://gnudist.gnu.org/pub/gnu/diffutils/diffutils-2.7.tar.gz
125
 *
126
 * closingly, some ideas (subdivision by NCHUNKS > 2, and some optimizations)
127
 * are my own.
128
 *
129
 * Line length limits for robustness added by Tim Starling, 2005-08-31
130
 *
131
 * @author Geoffrey T. Dairiki, Tim Starling
132
 * @private
133
 * @subpackage DifferenceEngine
134
 */
135
class _DiffEngine {
136
  function MAX_XREF_LENGTH() {
137
    return 10000;
138
  }
139
140
  function diff($from_lines, $to_lines) {
141
142
    $n_from = sizeof($from_lines);
143
    $n_to = sizeof($to_lines);
144
145
    $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...
146
    $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...
147
    $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...
148
    unset($this->seq);
149
    unset($this->in_seq);
150
    unset($this->lcs);
151
152
    // Skip leading common lines.
153
    for ($skip = 0; $skip < $n_from && $skip < $n_to; $skip++) {
154
      if ($from_lines[$skip] !== $to_lines[$skip]) {
155
        break;
156
      }
157
      $this->xchanged[$skip] = $this->ychanged[$skip] = FALSE;
158
    }
159
    // Skip trailing common lines.
160
    $xi = $n_from;
161
    $yi = $n_to;
162
    for ($endskip = 0; --$xi > $skip && --$yi > $skip; $endskip++) {
163
      if ($from_lines[$xi] !== $to_lines[$yi]) {
164
        break;
165
      }
166
      $this->xchanged[$xi] = $this->ychanged[$yi] = FALSE;
167
    }
168
169
    // Ignore lines which do not exist in both files.
170
    for ($xi = $skip; $xi < $n_from - $endskip; $xi++) {
171
      $xhash[$this->_line_hash($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...
172
    }
173
174 View Code Duplication
    for ($yi = $skip; $yi < $n_to - $endskip; $yi++) {
175
      $line = $to_lines[$yi];
176
      if ($this->ychanged[$yi] = empty($xhash[$this->_line_hash($line)])) {
177
        continue;
178
      }
179
      $yhash[$this->_line_hash($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...
180
      $this->yv[] = $line;
181
      $this->yind[] = $yi;
182
    }
183 View Code Duplication
    for ($xi = $skip; $xi < $n_from - $endskip; $xi++) {
184
      $line = $from_lines[$xi];
185
      if ($this->xchanged[$xi] = empty($yhash[$this->_line_hash($line)])) {
186
        continue;
187
      }
188
      $this->xv[] = $line;
189
      $this->xind[] = $xi;
190
    }
191
192
    // Find the LCS.
193
    $this->_compareseq(0, sizeof($this->xv), 0, sizeof($this->yv));
194
195
    // Merge edits when possible
196
    $this->_shift_boundaries($from_lines, $this->xchanged, $this->ychanged);
197
    $this->_shift_boundaries($to_lines, $this->ychanged, $this->xchanged);
198
199
    // Compute the edit operations.
200
    $edits = array();
201
    $xi = $yi = 0;
202
    while ($xi < $n_from || $yi < $n_to) {
203
      USE_ASSERTS && assert($yi < $n_to || $this->xchanged[$xi]);
204
      USE_ASSERTS && assert($xi < $n_from || $this->ychanged[$yi]);
205
206
      // Skip matching "snake".
207
      $copy = array();
208
      while ( $xi < $n_from && $yi < $n_to && !$this->xchanged[$xi] && !$this->ychanged[$yi]) {
209
        $copy[] = $from_lines[$xi++];
210
        ++$yi;
211
      }
212
      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...
213
        $edits[] = new _DiffOp_Copy($copy);
214
      }
215
      // Find deletes & adds.
216
      $delete = array();
217
      while ($xi < $n_from && $this->xchanged[$xi]) {
218
        $delete[] = $from_lines[$xi++];
219
      }
220
      $add = array();
221
      while ($yi < $n_to && $this->ychanged[$yi]) {
222
        $add[] = $to_lines[$yi++];
223
      }
224
      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...
225
        $edits[] = new _DiffOp_Change($delete, $add);
226
      }
227
      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...
228
        $edits[] = new _DiffOp_Delete($delete);
229
      }
230
      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...
231
        $edits[] = new _DiffOp_Add($add);
232
      }
233
    }
234
    return $edits;
235
  }
236
237
  /**
238
   * Returns the whole line if it's small enough, or the MD5 hash otherwise.
239
   */
240
  function _line_hash($line) {
241
    if (strlen($line) > $this->MAX_XREF_LENGTH()) {
242
      return md5($line);
243
    }
244
    else {
245
      return $line;
246
    }
247
  }
248
249
250
  /**
251
   * Divide the Largest Common Subsequence (LCS) of the sequences
252
   * [XOFF, XLIM) and [YOFF, YLIM) into NCHUNKS approximately equally
253
   * sized segments.
254
   *
255
   * Returns (LCS, PTS).  LCS is the length of the LCS. PTS is an
256
   * array of NCHUNKS+1 (X, Y) indexes giving the diving points between
257
   * sub sequences.  The first sub-sequence is contained in [X0, X1),
258
   * [Y0, Y1), the second in [X1, X2), [Y1, Y2) and so on.  Note
259
   * that (X0, Y0) == (XOFF, YOFF) and
260
   * (X[NCHUNKS], Y[NCHUNKS]) == (XLIM, YLIM).
261
   *
262
   * This function assumes that the first lines of the specified portions
263
   * of the two files do not match, and likewise that the last lines do not
264
   * match.  The caller must trim matching lines from the beginning and end
265
   * of the portions it is going to specify.
266
   */
267
  function _diag($xoff, $xlim, $yoff, $ylim, $nchunks) {
268
    $flip = FALSE;
269
270
    if ($xlim - $xoff > $ylim - $yoff) {
271
      // Things seems faster (I'm not sure I understand why)
272
      // when the shortest sequence in X.
273
      $flip = TRUE;
274
      list($xoff, $xlim, $yoff, $ylim) = array($yoff, $ylim, $xoff, $xlim);
275
    }
276
277
    if ($flip) {
278
      for ($i = $ylim - 1; $i >= $yoff; $i--) {
279
        $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...
280
      }
281
    }
282
    else {
283
      for ($i = $ylim - 1; $i >= $yoff; $i--) {
284
        $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...
285
      }
286
    }
287
    $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...
288
    $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...
289
    $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...
290
    $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...
291
292
    $numer = $xlim - $xoff + $nchunks - 1;
293
    $x = $xoff;
294
    for ($chunk = 0; $chunk < $nchunks; $chunk++) {
295
      if ($chunk > 0) {
296
        for ($i = 0; $i <= $this->lcs; $i++) {
297
          $ymids[$i][$chunk-1] = $this->seq[$i];
298
        }
299
      }
300
301
      $x1 = $xoff + (int)(($numer + ($xlim-$xoff)*$chunk) / $nchunks);
302
      for ( ; $x < $x1; $x++) {
303
        $line = $flip ? $this->yv[$x] : $this->xv[$x];
304
        if (empty($ymatches[$line])) {
305
          continue;
306
        }
307
        $matches = $ymatches[$line];
308
        reset($matches);
309
        while (list ($junk, $y) = each($matches)) {
0 ignored issues
show
The assignment to $junk is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
310 View Code Duplication
          if (empty($this->in_seq[$y])) {
311
            $k = $this->_lcs_pos($y);
312
            USE_ASSERTS && assert($k > 0);
313
            $ymids[$k] = $ymids[$k-1];
314
            break;
315
          }
316
        }
317
        while (list ($junk, $y) = each($matches)) {
0 ignored issues
show
The assignment to $junk is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
318
          if ($y > $this->seq[$k-1]) {
319
            USE_ASSERTS && 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...
320
            // Optimization: this is a common case:
321
            // next match is just replacing previous match.
322
            $this->in_seq[$this->seq[$k]] = FALSE;
323
            $this->seq[$k] = $y;
324
            $this->in_seq[$y] = 1;
325
          }
326 View Code Duplication
          elseif (empty($this->in_seq[$y])) {
327
            $k = $this->_lcs_pos($y);
328
            USE_ASSERTS && assert($k > 0);
329
            $ymids[$k] = $ymids[$k-1];
330
          }
331
        }
332
      }
333
    }
334
335
    $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...
336
    $ymid = $ymids[$this->lcs];
337
    for ($n = 0; $n < $nchunks - 1; $n++) {
338
      $x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $n) / $nchunks);
339
      $y1 = $ymid[$n] + 1;
340
      $seps[] = $flip ? array($y1, $x1) : array($x1, $y1);
341
    }
342
    $seps[] = $flip ? array($ylim, $xlim) : array($xlim, $ylim);
343
344
    return array($this->lcs, $seps);
345
  }
346
347
  function _lcs_pos($ypos) {
348
349
    $end = $this->lcs;
350
    if ($end == 0 || $ypos > $this->seq[$end]) {
351
      $this->seq[++$this->lcs] = $ypos;
352
      $this->in_seq[$ypos] = 1;
353
      return $this->lcs;
354
    }
355
356
    $beg = 1;
357
    while ($beg < $end) {
358
      $mid = (int)(($beg + $end) / 2);
359
      if ($ypos > $this->seq[$mid]) {
360
        $beg = $mid + 1;
361
      }
362
      else {
363
        $end = $mid;
364
      }
365
    }
366
367
    USE_ASSERTS && assert($ypos != $this->seq[$end]);
368
369
    $this->in_seq[$this->seq[$end]] = FALSE;
370
    $this->seq[$end] = $ypos;
371
    $this->in_seq[$ypos] = 1;
372
    return $end;
373
  }
374
375
  /**
376
   * Find LCS of two sequences.
377
   *
378
   * The results are recorded in the vectors $this->{x,y}changed[], by
379
   * storing a 1 in the element for each line that is an insertion
380
   * or deletion (ie. is not in the LCS).
381
   *
382
   * The subsequence of file 0 is [XOFF, XLIM) and likewise for file 1.
383
   *
384
   * Note that XLIM, YLIM are exclusive bounds.
385
   * All line numbers are origin-0 and discarded lines are not counted.
386
   */
387
  function _compareseq($xoff, $xlim, $yoff, $ylim) {
388
389
    // Slide down the bottom initial diagonal.
390
    while ($xoff < $xlim && $yoff < $ylim && $this->xv[$xoff] == $this->yv[$yoff]) {
391
      ++$xoff;
392
      ++$yoff;
393
    }
394
395
    // Slide up the top initial diagonal.
396
    while ($xlim > $xoff && $ylim > $yoff && $this->xv[$xlim - 1] == $this->yv[$ylim - 1]) {
397
      --$xlim;
398
      --$ylim;
399
    }
400
401
    if ($xoff == $xlim || $yoff == $ylim) {
402
      $lcs = 0;
403
    }
404
    else {
405
      // This is ad hoc but seems to work well.
406
      //$nchunks = sqrt(min($xlim - $xoff, $ylim - $yoff) / 2.5);
407
      //$nchunks = max(2, min(8, (int)$nchunks));
408
      $nchunks = min(7, $xlim - $xoff, $ylim - $yoff) + 1;
409
      list($lcs, $seps)
410
      = $this->_diag($xoff, $xlim, $yoff, $ylim, $nchunks);
411
    }
412
413
    if ($lcs == 0) {
414
      // X and Y sequences have no common subsequence:
415
      // mark all changed.
416
      while ($yoff < $ylim) {
417
        $this->ychanged[$this->yind[$yoff++]] = 1;
418
      }
419
      while ($xoff < $xlim) {
420
        $this->xchanged[$this->xind[$xoff++]] = 1;
421
      }
422
    }
423
    else {
424
      // Use the partitions to split this problem into subproblems.
425
      reset($seps);
426
      $pt1 = $seps[0];
427
      while ($pt2 = next($seps)) {
428
        $this->_compareseq ($pt1[0], $pt2[0], $pt1[1], $pt2[1]);
429
        $pt1 = $pt2;
430
      }
431
    }
432
  }
433
434
  /**
435
   * Adjust inserts/deletes of identical lines to join changes
436
   * as much as possible.
437
   *
438
   * We do something when a run of changed lines include a
439
   * line at one end and has an excluded, identical line at the other.
440
   * We are free to choose which identical line is included.
441
   * `compareseq' usually chooses the one at the beginning,
442
   * but usually it is cleaner to consider the following identical line
443
   * to be the "change".
444
   *
445
   * This is extracted verbatim from analyze.c (GNU diffutils-2.7).
446
   */
447
  function _shift_boundaries($lines, &$changed, $other_changed) {
448
    $i = 0;
449
    $j = 0;
450
451
    USE_ASSERTS && assert('sizeof($lines) == sizeof($changed)');
452
    $len = sizeof($lines);
453
    $other_len = sizeof($other_changed);
454
455
    while (1) {
456
      /*
457
       * Scan forwards to find beginning of another run of changes.
458
       * Also keep track of the corresponding point in the other file.
459
       *
460
       * Throughout this code, $i and $j are adjusted together so that
461
       * the first $i elements of $changed and the first $j elements
462
       * of $other_changed both contain the same number of zeros
463
       * (unchanged lines).
464
       * Furthermore, $j is always kept so that $j == $other_len or
465
       * $other_changed[$j] == FALSE.
466
       */
467
      while ($j < $other_len && $other_changed[$j]) {
468
        $j++;
469
      }
470
      while ($i < $len && ! $changed[$i]) {
471
        USE_ASSERTS && assert('$j < $other_len && ! $other_changed[$j]');
472
        $i++;
473
        $j++;
474
        while ($j < $other_len && $other_changed[$j]) {
475
          $j++;
476
        }
477
      }
478
479
      if ($i == $len) {
480
        break;
481
      }
482
      $start = $i;
483
484
      // Find the end of this run of changes.
485
      while (++$i < $len && $changed[$i]) {
486
        continue;
487
      }
488
489
      do {
490
        /*
491
         * Record the length of this run of changes, so that
492
         * we can later determine whether the run has grown.
493
         */
494
        $runlength = $i - $start;
495
496
        /*
497
         * Move the changed region back, so long as the
498
         * previous unchanged line matches the last changed one.
499
         * This merges with previous changed regions.
500
         */
501
        while ($start > 0 && $lines[$start - 1] == $lines[$i - 1]) {
502
          $changed[--$start] = 1;
503
          $changed[--$i] = FALSE;
504
          while ($start > 0 && $changed[$start - 1]) {
505
            $start--;
506
          }
507
          USE_ASSERTS && assert('$j > 0');
508
          while ($other_changed[--$j]) {
509
            continue;
510
          }
511
          USE_ASSERTS && assert('$j >= 0 && !$other_changed[$j]');
512
        }
513
514
        /*
515
         * Set CORRESPONDING to the end of the changed run, at the last
516
         * point where it corresponds to a changed run in the other file.
517
         * CORRESPONDING == LEN means no such point has been found.
518
         */
519
        $corresponding = $j < $other_len ? $i : $len;
520
521
        /*
522
         * Move the changed region forward, so long as the
523
         * first changed line matches the following unchanged one.
524
         * This merges with following changed regions.
525
         * Do this second, so that if there are no merges,
526
         * the changed region is moved forward as far as possible.
527
         */
528
        while ($i < $len && $lines[$start] == $lines[$i]) {
529
          $changed[$start++] = FALSE;
530
          $changed[$i++] = 1;
531
          while ($i < $len && $changed[$i]) {
532
            $i++;
533
          }
534
          USE_ASSERTS && assert('$j < $other_len && ! $other_changed[$j]');
535
          $j++;
536
          if ($j < $other_len && $other_changed[$j]) {
537
            $corresponding = $i;
538
            while ($j < $other_len && $other_changed[$j]) {
539
              $j++;
540
            }
541
          }
542
        }
543
      } while ($runlength != $i - $start);
544
545
      /*
546
       * If possible, move the fully-merged run of changes
547
       * back to a corresponding run in the other file.
548
       */
549
      while ($corresponding < $i) {
550
        $changed[--$start] = 1;
551
        $changed[--$i] = 0;
552
        USE_ASSERTS && assert('$j > 0');
553
        while ($other_changed[--$j]) {
554
          continue;
555
        }
556
        USE_ASSERTS && assert('$j >= 0 && !$other_changed[$j]');
557
      }
558
    }
559
  }
560
}
561
562
/**
563
 * Class representing a 'diff' between two sequences of strings.
564
 * @todo document
565
 * @private
566
 * @subpackage DifferenceEngine
567
 */
568
class Diff {
569
  var $edits;
570
571
  /**
572
   * Constructor.
573
   * Computes diff between sequences of strings.
574
   *
575
   * @param $from_lines array An array of strings.
576
   *      (Typically these are lines from a file.)
577
   * @param $to_lines array An array of strings.
578
   */
579
  function __construct($from_lines, $to_lines) {
580
    $eng = new _DiffEngine;
581
    $this->edits = $eng->diff($from_lines, $to_lines);
582
    //$this->_check($from_lines, $to_lines);
583
  }
584
585
  /**
586
   * Compute reversed Diff.
587
   *
588
   * SYNOPSIS:
589
   *
590
   *  $diff = new Diff($lines1, $lines2);
591
   *  $rev = $diff->reverse();
592
   * @return object A Diff object representing the inverse of the
593
   *          original diff.
594
   */
595
  function reverse() {
596
    $rev = $this;
597
    $rev->edits = array();
598
    foreach ($this->edits as $edit) {
599
      $rev->edits[] = $edit->reverse();
600
    }
601
    return $rev;
602
  }
603
604
  /**
605
   * Check for empty diff.
606
   *
607
   * @return bool True iff two sequences were identical.
608
   */
609
  function isEmpty() {
610
    foreach ($this->edits as $edit) {
611
      if ($edit->type != 'copy') {
612
        return FALSE;
613
      }
614
    }
615
    return TRUE;
616
  }
617
618
  /**
619
   * Compute the length of the Longest Common Subsequence (LCS).
620
   *
621
   * This is mostly for diagnostic purposed.
622
   *
623
   * @return int The length of the LCS.
624
   */
625
  function lcs() {
626
    $lcs = 0;
627
    foreach ($this->edits as $edit) {
628
      if ($edit->type == 'copy') {
629
        $lcs += sizeof($edit->orig);
630
      }
631
    }
632
    return $lcs;
633
  }
634
635
  /**
636
   * Get the original set of lines.
637
   *
638
   * This reconstructs the $from_lines parameter passed to the
639
   * constructor.
640
   *
641
   * @return array The original sequence of strings.
642
   */
643 View Code Duplication
  function orig() {
644
    $lines = array();
645
646
    foreach ($this->edits as $edit) {
647
      if ($edit->orig) {
648
        array_splice($lines, sizeof($lines), 0, $edit->orig);
649
      }
650
    }
651
    return $lines;
652
  }
653
654
  /**
655
   * Get the closing set of lines.
656
   *
657
   * This reconstructs the $to_lines parameter passed to the
658
   * constructor.
659
   *
660
   * @return array The sequence of strings.
661
   */
662 View Code Duplication
  function closing() {
663
    $lines = array();
664
665
    foreach ($this->edits as $edit) {
666
      if ($edit->closing) {
667
        array_splice($lines, sizeof($lines), 0, $edit->closing);
668
      }
669
    }
670
    return $lines;
671
  }
672
673
  /**
674
   * Check a Diff for validity.
675
   *
676
   * This is here only for debugging purposes.
677
   */
678
  function _check($from_lines, $to_lines) {
679
    if (serialize($from_lines) != serialize($this->orig())) {
680
      trigger_error("Reconstructed original doesn't match", E_USER_ERROR);
681
    }
682
    if (serialize($to_lines) != serialize($this->closing())) {
683
      trigger_error("Reconstructed closing doesn't match", E_USER_ERROR);
684
    }
685
686
    $rev = $this->reverse();
687
    if (serialize($to_lines) != serialize($rev->orig())) {
688
      trigger_error("Reversed original doesn't match", E_USER_ERROR);
689
    }
690
    if (serialize($from_lines) != serialize($rev->closing())) {
691
      trigger_error("Reversed closing doesn't match", E_USER_ERROR);
692
    }
693
694
695
    $prevtype = 'none';
696
    foreach ($this->edits as $edit) {
697
      if ( $prevtype == $edit->type ) {
698
        trigger_error("Edit sequence is non-optimal", E_USER_ERROR);
699
      }
700
      $prevtype = $edit->type;
701
    }
702
703
    $lcs = $this->lcs();
704
    trigger_error('Diff okay: LCS = '. $lcs, E_USER_NOTICE);
705
  }
706
}
707
708
/**
709
 * FIXME: bad name.
710
 * @todo document
711
 * @private
712
 * @subpackage DifferenceEngine
713
 */
714
class MappedDiff extends Diff {
715
  /**
716
   * Constructor.
717
   *
718
   * Computes diff between sequences of strings.
719
   *
720
   * This can be used to compute things like
721
   * case-insensitve diffs, or diffs which ignore
722
   * changes in white-space.
723
   *
724
   * @param $from_lines array An array of strings.
725
   *  (Typically these are lines from a file.)
726
   *
727
   * @param $to_lines array An array of strings.
728
   *
729
   * @param $mapped_from_lines array This array should
730
   *  have the same size number of elements as $from_lines.
731
   *  The elements in $mapped_from_lines and
732
   *  $mapped_to_lines are what is actually compared
733
   *  when computing the diff.
734
   *
735
   * @param $mapped_to_lines array This array should
736
   *  have the same number of elements as $to_lines.
737
   */
738
  function __construct($from_lines, $to_lines, $mapped_from_lines, $mapped_to_lines) {
739
740
    assert(sizeof($from_lines) == sizeof($mapped_from_lines));
741
    assert(sizeof($to_lines) == sizeof($mapped_to_lines));
742
743
    $this->Diff($mapped_from_lines, $mapped_to_lines);
0 ignored issues
show
The method Diff() does not seem to exist on object<MappedDiff>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
744
745
    $xi = $yi = 0;
746
    for ($i = 0; $i < sizeof($this->edits); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function sizeof() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
747
      $orig = &$this->edits[$i]->orig;
748
      if (is_array($orig)) {
749
        $orig = array_slice($from_lines, $xi, sizeof($orig));
750
        $xi += sizeof($orig);
751
      }
752
753
      $closing = &$this->edits[$i]->closing;
754
      if (is_array($closing)) {
755
        $closing = array_slice($to_lines, $yi, sizeof($closing));
756
        $yi += sizeof($closing);
757
      }
758
    }
759
  }
760
}
761
762
/**
763
 * A class to format Diffs
764
 *
765
 * This class formats the diff in classic diff format.
766
 * It is intended that this class be customized via inheritance,
767
 * to obtain fancier outputs.
768
 * @todo document
769
 * @private
770
 * @subpackage DifferenceEngine
771
 */
772
class DiffFormatter {
773
  /**
774
   * Should a block header be shown?
775
   */
776
  var $show_header = TRUE;
777
778
  /**
779
   * Number of leading context "lines" to preserve.
780
   *
781
   * This should be left at zero for this class, but subclasses
782
   * may want to set this to other values.
783
   */
784
  var $leading_context_lines = 0;
785
786
  /**
787
   * Number of trailing context "lines" to preserve.
788
   *
789
   * This should be left at zero for this class, but subclasses
790
   * may want to set this to other values.
791
   */
792
  var $trailing_context_lines = 0;
793
794
  /**
795
   * Format a diff.
796
   *
797
   * @param $diff object A Diff object.
798
   * @return string The formatted output.
799
   */
800
  function format($diff) {
801
802
    $xi = $yi = 1;
803
    $block = FALSE;
804
    $context = array();
805
806
    $nlead = $this->leading_context_lines;
807
    $ntrail = $this->trailing_context_lines;
808
809
    $this->_start_diff();
810
811
    foreach ($diff->edits as $edit) {
812
      if ($edit->type == 'copy') {
813
        if (is_array($block)) {
814
          if (sizeof($edit->orig) <= $nlead + $ntrail) {
815
            $block[] = $edit;
816
          }
817
          else {
818
            if ($ntrail) {
819
              $context = array_slice($edit->orig, 0, $ntrail);
820
              $block[] = new _DiffOp_Copy($context);
821
            }
822
            $this->_block($x0, $ntrail + $xi - $x0, $y0, $ntrail + $yi - $y0, $block);
0 ignored issues
show
The variable $x0 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...
The variable $y0 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...
823
            $block = FALSE;
824
          }
825
        }
826
        $context = $edit->orig;
827
      }
828
      else {
829
        if (! is_array($block)) {
830
          $context = array_slice($context, sizeof($context) - $nlead);
831
          $x0 = $xi - sizeof($context);
832
          $y0 = $yi - sizeof($context);
833
          $block = array();
834
          if ($context) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $context 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...
835
            $block[] = new _DiffOp_Copy($context);
836
          }
837
        }
838
        $block[] = $edit;
839
      }
840
841
      if ($edit->orig) {
842
        $xi += sizeof($edit->orig);
843
      }
844
      if ($edit->closing) {
845
        $yi += sizeof($edit->closing);
846
      }
847
    }
848
849
    if (is_array($block)) {
850
      $this->_block($x0, $xi - $x0, $y0, $yi - $y0, $block);
851
    }
852
    $end = $this->_end_diff();
853
    return $end;
854
  }
855
856
  function _block($xbeg, $xlen, $ybeg, $ylen, &$edits) {
857
    $this->_start_block($this->_block_header($xbeg, $xlen, $ybeg, $ylen));
858
    foreach ($edits as $edit) {
859
      if ($edit->type == 'copy') {
860
        $this->_context($edit->orig);
861
      }
862
      elseif ($edit->type == 'add') {
863
        $this->_added($edit->closing);
864
      }
865
      elseif ($edit->type == 'delete') {
866
        $this->_deleted($edit->orig);
867
      }
868
      elseif ($edit->type == 'change') {
869
        $this->_changed($edit->orig, $edit->closing);
870
      }
871
      else {
872
        trigger_error('Unknown edit type', E_USER_ERROR);
873
      }
874
    }
875
    $this->_end_block();
876
  }
877
878
  function _start_diff() {
879
    ob_start();
880
  }
881
882
  function _end_diff() {
883
    $val = ob_get_contents();
884
    ob_end_clean();
885
    return $val;
886
  }
887
888
  function _block_header($xbeg, $xlen, $ybeg, $ylen) {
889
    if ($xlen > 1) {
890
      $xbeg .= "," . ($xbeg + $xlen - 1);
891
    }
892
    if ($ylen > 1) {
893
      $ybeg .= "," . ($ybeg + $ylen - 1);
894
    }
895
896
    return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg;
897
  }
898
899
  function _start_block($header) {
900
    if ($this->show_header) {
901
      echo $header . "\n";
902
    }
903
  }
904
905
  function _end_block() {
906
  }
907
908
  function _lines($lines, $prefix = ' ') {
909
    foreach ($lines as $line) {
910
      echo "$prefix $line\n";
911
    }
912
  }
913
914
  function _context($lines) {
915
    $this->_lines($lines);
916
  }
917
918
  function _added($lines) {
919
    $this->_lines($lines, '>');
920
  }
921
  function _deleted($lines) {
922
    $this->_lines($lines, '<');
923
  }
924
925
  function _changed($orig, $closing) {
926
    $this->_deleted($orig);
927
    echo "---\n";
928
    $this->_added($closing);
929
  }
930
}
931
932
933
/**
934
 *  Additions by Axel Boldt follow, partly taken from diff.php, phpwiki-1.3.3
935
 *
936
 */
937
938
define('NBSP', '&#160;');      // iso-8859-x non-breaking space.
939
940
/**
941
 * @todo document
942
 * @private
943
 * @subpackage DifferenceEngine
944
 */
945
class _HWLDF_WordAccumulator {
946
  function __construct() {
947
    $this->_lines = array();
0 ignored issues
show
The property _lines 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...
948
    $this->_line = '';
0 ignored issues
show
The property _line does not seem to exist. Did you mean _lines?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
949
    $this->_group = '';
0 ignored issues
show
The property _group 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...
950
    $this->_tag = '';
0 ignored issues
show
The property _tag 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...
951
  }
952
953
  function _flushGroup($new_tag) {
954
    if ($this->_group !== '') {
955
      if ($this->_tag == 'mark') {
956
        $this->_line .= '<span class="diffchange">'. check_plain($this->_group) .'</span>';
0 ignored issues
show
The property _line does not seem to exist. Did you mean _lines?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
957
      }
958
      else {
959
        $this->_line .= check_plain($this->_group);
0 ignored issues
show
The property _line does not seem to exist. Did you mean _lines?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
960
      }
961
    }
962
    $this->_group = '';
963
    $this->_tag = $new_tag;
964
  }
965
966
  function _flushLine($new_tag) {
967
    $this->_flushGroup($new_tag);
968
    if ($this->_line != '') {
0 ignored issues
show
The property _line does not seem to exist. Did you mean _lines?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
969
      array_push($this->_lines, $this->_line);
0 ignored issues
show
The property _line does not seem to exist. Did you mean _lines?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
970
    }
971
    else {
972
      // make empty lines visible by inserting an NBSP
973
      array_push($this->_lines, NBSP);
974
    }
975
    $this->_line = '';
0 ignored issues
show
The property _line does not seem to exist. Did you mean _lines?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
976
  }
977
978
  function addWords($words, $tag = '') {
979
    if ($tag != $this->_tag) {
980
      $this->_flushGroup($tag);
981
    }
982
    foreach ($words as $word) {
983
      // new-line should only come as first char of word.
984
      if ($word == '') {
985
        continue;
986
      }
987
      if ($word[0] == "\n") {
988
        $this->_flushLine($tag);
989
        $word = substr($word, 1);
990
      }
991
      assert(!strstr($word, "\n"));
992
      $this->_group .= $word;
993
    }
994
  }
995
996
  function getLines() {
997
    $this->_flushLine('~done');
998
    return $this->_lines;
999
  }
1000
}
1001
1002
/**
1003
 * @todo document
1004
 * @private
1005
 * @subpackage DifferenceEngine
1006
 */
1007
class WordLevelDiff extends MappedDiff {
1008
  function MAX_LINE_LENGTH() {
1009
    return 10000;
1010
  }
1011
1012
  function __construct($orig_lines, $closing_lines) {
1013
    list($orig_words, $orig_stripped) = $this->_split($orig_lines);
1014
    list($closing_words, $closing_stripped) = $this->_split($closing_lines);
1015
1016
    $this->MappedDiff($orig_words, $closing_words, $orig_stripped, $closing_stripped);
0 ignored issues
show
The method MappedDiff() does not seem to exist on object<WordLevelDiff>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1017
  }
1018
1019
  function _split($lines) {
1020
    $words = array();
1021
    $stripped = array();
1022
    $first = TRUE;
1023
    foreach ($lines as $line) {
1024
      // If the line is too long, just pretend the entire line is one big word
1025
      // This prevents resource exhaustion problems
1026
      if ( $first ) {
1027
        $first = FALSE;
1028
      }
1029
      else {
1030
        $words[] = "\n";
1031
        $stripped[] = "\n";
1032
      }
1033
      if ( strlen( $line ) > $this->MAX_LINE_LENGTH() ) {
1034
        $words[] = $line;
1035
        $stripped[] = $line;
1036
      }
1037
      else {
1038
        if (preg_match_all('/ ( [^\S\n]+ | [0-9_A-Za-z\x80-\xff]+ | . ) (?: (?!< \n) [^\S\n])? /xs', $line, $m)) {
1039
          $words = array_merge($words, $m[0]);
1040
          $stripped = array_merge($stripped, $m[1]);
1041
        }
1042
      }
1043
    }
1044
    return array($words, $stripped);
1045
  }
1046
1047 View Code Duplication
  function orig() {
1048
    $orig = new _HWLDF_WordAccumulator;
1049
1050
    foreach ($this->edits as $edit) {
1051
      if ($edit->type == 'copy') {
1052
        $orig->addWords($edit->orig);
1053
      }
1054
      elseif ($edit->orig) {
1055
        $orig->addWords($edit->orig, 'mark');
1056
      }
1057
    }
1058
    $lines = $orig->getLines();
1059
    return $lines;
1060
  }
1061
1062 View Code Duplication
  function closing() {
1063
    $closing = new _HWLDF_WordAccumulator;
1064
1065
    foreach ($this->edits as $edit) {
1066
      if ($edit->type == 'copy') {
1067
        $closing->addWords($edit->closing);
1068
      }
1069
      elseif ($edit->closing) {
1070
        $closing->addWords($edit->closing, 'mark');
1071
      }
1072
    }
1073
    $lines = $closing->getLines();
1074
    return $lines;
1075
  }
1076
}
1077