This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * Diff API: WP_Text_Diff_Renderer_Table class |
||
4 | * |
||
5 | * @package WordPress |
||
6 | * @subpackage Diff |
||
7 | * @since 4.7.0 |
||
8 | */ |
||
9 | |||
10 | /** |
||
11 | * Table renderer to display the diff lines. |
||
12 | * |
||
13 | * @since 2.6.0 |
||
14 | * @uses Text_Diff_Renderer Extends |
||
15 | */ |
||
16 | class WP_Text_Diff_Renderer_Table extends Text_Diff_Renderer { |
||
17 | |||
18 | /** |
||
19 | * @see Text_Diff_Renderer::_leading_context_lines |
||
20 | * @var int |
||
21 | * @access public |
||
22 | * @since 2.6.0 |
||
23 | */ |
||
24 | public $_leading_context_lines = 10000; |
||
25 | |||
26 | /** |
||
27 | * @see Text_Diff_Renderer::_trailing_context_lines |
||
28 | * @var int |
||
29 | * @access public |
||
30 | * @since 2.6.0 |
||
31 | */ |
||
32 | public $_trailing_context_lines = 10000; |
||
33 | |||
34 | /** |
||
35 | * Threshold for when a diff should be saved or omitted. |
||
36 | * |
||
37 | * @var float |
||
38 | * @access protected |
||
39 | * @since 2.6.0 |
||
40 | */ |
||
41 | protected $_diff_threshold = 0.6; |
||
42 | |||
43 | /** |
||
44 | * Inline display helper object name. |
||
45 | * |
||
46 | * @var string |
||
47 | * @access protected |
||
48 | * @since 2.6.0 |
||
49 | */ |
||
50 | protected $inline_diff_renderer = 'WP_Text_Diff_Renderer_inline'; |
||
51 | |||
52 | /** |
||
53 | * Should we show the split view or not |
||
54 | * |
||
55 | * @var string |
||
56 | * @access protected |
||
57 | * @since 3.6.0 |
||
58 | */ |
||
59 | protected $_show_split_view = true; |
||
60 | |||
61 | protected $compat_fields = array( '_show_split_view', 'inline_diff_renderer', '_diff_threshold' ); |
||
62 | |||
63 | /** |
||
64 | * Constructor - Call parent constructor with params array. |
||
65 | * |
||
66 | * This will set class properties based on the key value pairs in the array. |
||
67 | * |
||
68 | * @since 2.6.0 |
||
69 | * |
||
70 | * @param array $params |
||
71 | */ |
||
72 | public function __construct( $params = array() ) { |
||
73 | parent::__construct( $params ); |
||
74 | if ( isset( $params[ 'show_split_view' ] ) ) |
||
75 | $this->_show_split_view = $params[ 'show_split_view' ]; |
||
76 | } |
||
77 | |||
78 | /** |
||
79 | * @ignore |
||
80 | * |
||
81 | * @param string $header |
||
82 | * @return string |
||
83 | */ |
||
84 | public function _startBlock( $header ) { |
||
85 | return ''; |
||
86 | } |
||
87 | |||
88 | /** |
||
89 | * @ignore |
||
90 | * |
||
91 | * @param array $lines |
||
92 | * @param string $prefix |
||
93 | */ |
||
94 | public function _lines( $lines, $prefix=' ' ) { |
||
95 | } |
||
96 | |||
97 | /** |
||
98 | * @ignore |
||
99 | * |
||
100 | * @param string $line HTML-escape the value. |
||
101 | * @return string |
||
102 | */ |
||
103 | public function addedLine( $line ) { |
||
104 | return "<td class='diff-addedline'>{$line}</td>"; |
||
105 | |||
106 | } |
||
107 | |||
108 | /** |
||
109 | * @ignore |
||
110 | * |
||
111 | * @param string $line HTML-escape the value. |
||
112 | * @return string |
||
113 | */ |
||
114 | public function deletedLine( $line ) { |
||
115 | return "<td class='diff-deletedline'>{$line}</td>"; |
||
116 | } |
||
117 | |||
118 | /** |
||
119 | * @ignore |
||
120 | * |
||
121 | * @param string $line HTML-escape the value. |
||
122 | * @return string |
||
123 | */ |
||
124 | public function contextLine( $line ) { |
||
125 | return "<td class='diff-context'>{$line}</td>"; |
||
126 | } |
||
127 | |||
128 | /** |
||
129 | * @ignore |
||
130 | * |
||
131 | * @return string |
||
132 | */ |
||
133 | public function emptyLine() { |
||
134 | return '<td> </td>'; |
||
135 | } |
||
136 | |||
137 | /** |
||
138 | * @ignore |
||
139 | * @access public |
||
140 | * |
||
141 | * @param array $lines |
||
142 | * @param bool $encode |
||
143 | * @return string |
||
144 | */ |
||
145 | View Code Duplication | public function _added( $lines, $encode = true ) { |
|
146 | $r = ''; |
||
147 | foreach ($lines as $line) { |
||
148 | if ( $encode ) { |
||
149 | $processed_line = htmlspecialchars( $line ); |
||
150 | |||
151 | /** |
||
152 | * Contextually filters a diffed line. |
||
153 | * |
||
154 | * Filters TextDiff processing of diffed line. By default, diffs are processed with |
||
155 | * htmlspecialchars. Use this filter to remove or change the processing. Passes a context |
||
156 | * indicating if the line is added, deleted or unchanged. |
||
157 | * |
||
158 | * @since 4.1.0 |
||
159 | * |
||
160 | * @param String $processed_line The processed diffed line. |
||
161 | * @param String $line The unprocessed diffed line. |
||
162 | * @param string null The line context. Values are 'added', 'deleted' or 'unchanged'. |
||
163 | */ |
||
164 | $line = apply_filters( 'process_text_diff_html', $processed_line, $line, 'added' ); |
||
165 | } |
||
166 | |||
167 | if ( $this->_show_split_view ) { |
||
168 | $r .= '<tr>' . $this->emptyLine() . $this->emptyLine() . $this->addedLine( $line ) . "</tr>\n"; |
||
169 | } else { |
||
170 | $r .= '<tr>' . $this->addedLine( $line ) . "</tr>\n"; |
||
171 | } |
||
172 | } |
||
173 | return $r; |
||
174 | } |
||
175 | |||
176 | /** |
||
177 | * @ignore |
||
178 | * @access public |
||
179 | * |
||
180 | * @param array $lines |
||
181 | * @param bool $encode |
||
182 | * @return string |
||
183 | */ |
||
184 | View Code Duplication | public function _deleted( $lines, $encode = true ) { |
|
185 | $r = ''; |
||
186 | foreach ($lines as $line) { |
||
187 | if ( $encode ) { |
||
188 | $processed_line = htmlspecialchars( $line ); |
||
189 | |||
190 | /** This filter is documented in wp-includes/wp-diff.php */ |
||
191 | $line = apply_filters( 'process_text_diff_html', $processed_line, $line, 'deleted' ); |
||
192 | } |
||
193 | if ( $this->_show_split_view ) { |
||
194 | $r .= '<tr>' . $this->deletedLine( $line ) . $this->emptyLine() . $this->emptyLine() . "</tr>\n"; |
||
195 | } else { |
||
196 | $r .= '<tr>' . $this->deletedLine( $line ) . "</tr>\n"; |
||
197 | } |
||
198 | |||
199 | } |
||
200 | return $r; |
||
201 | } |
||
202 | |||
203 | /** |
||
204 | * @ignore |
||
205 | * @access public |
||
206 | * |
||
207 | * @param array $lines |
||
208 | * @param bool $encode |
||
209 | * @return string |
||
210 | */ |
||
211 | View Code Duplication | public function _context( $lines, $encode = true ) { |
|
212 | $r = ''; |
||
213 | foreach ($lines as $line) { |
||
214 | if ( $encode ) { |
||
215 | $processed_line = htmlspecialchars( $line ); |
||
216 | |||
217 | /** This filter is documented in wp-includes/wp-diff.php */ |
||
218 | $line = apply_filters( 'process_text_diff_html', $processed_line, $line, 'unchanged' ); |
||
219 | } |
||
220 | if ( $this->_show_split_view ) { |
||
221 | $r .= '<tr>' . $this->contextLine( $line ) . $this->emptyLine() . $this->contextLine( $line ) . "</tr>\n"; |
||
222 | } else { |
||
223 | $r .= '<tr>' . $this->contextLine( $line ) . "</tr>\n"; |
||
224 | } |
||
225 | } |
||
226 | return $r; |
||
227 | } |
||
228 | |||
229 | /** |
||
230 | * Process changed lines to do word-by-word diffs for extra highlighting. |
||
231 | * |
||
232 | * (TRAC style) sometimes these lines can actually be deleted or added rows. |
||
233 | * We do additional processing to figure that out |
||
234 | * |
||
235 | * @access public |
||
236 | * @since 2.6.0 |
||
237 | * |
||
238 | * @param array $orig |
||
239 | * @param array $final |
||
240 | * @return string |
||
241 | */ |
||
242 | public function _changed( $orig, $final ) { |
||
243 | $r = ''; |
||
244 | |||
245 | // Does the aforementioned additional processing |
||
246 | // *_matches tell what rows are "the same" in orig and final. Those pairs will be diffed to get word changes |
||
247 | // match is numeric: an index in other column |
||
248 | // match is 'X': no match. It is a new row |
||
249 | // *_rows are column vectors for the orig column and the final column. |
||
250 | // row >= 0: an indix of the $orig or $final array |
||
251 | // row < 0: a blank row for that column |
||
252 | list($orig_matches, $final_matches, $orig_rows, $final_rows) = $this->interleave_changed_lines( $orig, $final ); |
||
0 ignored issues
–
show
|
|||
253 | |||
254 | // These will hold the word changes as determined by an inline diff |
||
255 | $orig_diffs = array(); |
||
256 | $final_diffs = array(); |
||
257 | |||
258 | // Compute word diffs for each matched pair using the inline diff |
||
259 | foreach ( $orig_matches as $o => $f ) { |
||
260 | if ( is_numeric($o) && is_numeric($f) ) { |
||
261 | $text_diff = new Text_Diff( 'auto', array( array($orig[$o]), array($final[$f]) ) ); |
||
262 | $renderer = new $this->inline_diff_renderer; |
||
263 | $diff = $renderer->render( $text_diff ); |
||
264 | |||
265 | // If they're too different, don't include any <ins> or <dels> |
||
266 | if ( preg_match_all( '!(<ins>.*?</ins>|<del>.*?</del>)!', $diff, $diff_matches ) ) { |
||
267 | // length of all text between <ins> or <del> |
||
268 | $stripped_matches = strlen(strip_tags( join(' ', $diff_matches[0]) )); |
||
269 | // since we count lengith of text between <ins> or <del> (instead of picking just one), |
||
270 | // we double the length of chars not in those tags. |
||
271 | $stripped_diff = strlen(strip_tags( $diff )) * 2 - $stripped_matches; |
||
272 | $diff_ratio = $stripped_matches / $stripped_diff; |
||
273 | if ( $diff_ratio > $this->_diff_threshold ) |
||
274 | continue; // Too different. Don't save diffs. |
||
275 | } |
||
276 | |||
277 | // Un-inline the diffs by removing del or ins |
||
278 | $orig_diffs[$o] = preg_replace( '|<ins>.*?</ins>|', '', $diff ); |
||
279 | $final_diffs[$f] = preg_replace( '|<del>.*?</del>|', '', $diff ); |
||
280 | } |
||
281 | } |
||
282 | |||
283 | foreach ( array_keys($orig_rows) as $row ) { |
||
284 | // Both columns have blanks. Ignore them. |
||
285 | if ( $orig_rows[$row] < 0 && $final_rows[$row] < 0 ) |
||
286 | continue; |
||
287 | |||
288 | // If we have a word based diff, use it. Otherwise, use the normal line. |
||
289 | if ( isset( $orig_diffs[$orig_rows[$row]] ) ) |
||
290 | $orig_line = $orig_diffs[$orig_rows[$row]]; |
||
291 | elseif ( isset( $orig[$orig_rows[$row]] ) ) |
||
292 | $orig_line = htmlspecialchars($orig[$orig_rows[$row]]); |
||
293 | else |
||
294 | $orig_line = ''; |
||
295 | |||
296 | if ( isset( $final_diffs[$final_rows[$row]] ) ) |
||
297 | $final_line = $final_diffs[$final_rows[$row]]; |
||
298 | elseif ( isset( $final[$final_rows[$row]] ) ) |
||
299 | $final_line = htmlspecialchars($final[$final_rows[$row]]); |
||
300 | else |
||
301 | $final_line = ''; |
||
302 | |||
303 | if ( $orig_rows[$row] < 0 ) { // Orig is blank. This is really an added row. |
||
304 | $r .= $this->_added( array($final_line), false ); |
||
305 | } elseif ( $final_rows[$row] < 0 ) { // Final is blank. This is really a deleted row. |
||
306 | $r .= $this->_deleted( array($orig_line), false ); |
||
307 | } else { // A true changed row. |
||
308 | if ( $this->_show_split_view ) { |
||
309 | $r .= '<tr>' . $this->deletedLine( $orig_line ) . $this->emptyLine() . $this->addedLine( $final_line ) . "</tr>\n"; |
||
310 | } else { |
||
311 | $r .= '<tr>' . $this->deletedLine( $orig_line ) . "</tr><tr>" . $this->addedLine( $final_line ) . "</tr>\n"; |
||
312 | } |
||
313 | } |
||
314 | } |
||
315 | |||
316 | return $r; |
||
317 | } |
||
318 | |||
319 | /** |
||
320 | * Takes changed blocks and matches which rows in orig turned into which rows in final. |
||
321 | * |
||
322 | * Returns |
||
323 | * *_matches ( which rows match with which ) |
||
324 | * *_rows ( order of rows in each column interleaved with blank rows as |
||
325 | * necessary ) |
||
326 | * |
||
327 | * @since 2.6.0 |
||
328 | * |
||
329 | * @param array $orig |
||
330 | * @param array $final |
||
331 | * @return array |
||
0 ignored issues
–
show
|
|||
332 | */ |
||
333 | public function interleave_changed_lines( $orig, $final ) { |
||
334 | |||
335 | // Contains all pairwise string comparisons. Keys are such that this need only be a one dimensional array. |
||
336 | $matches = array(); |
||
337 | foreach ( array_keys($orig) as $o ) { |
||
338 | foreach ( array_keys($final) as $f ) { |
||
339 | $matches["$o,$f"] = $this->compute_string_distance( $orig[$o], $final[$f] ); |
||
340 | } |
||
341 | } |
||
342 | asort($matches); // Order by string distance. |
||
343 | |||
344 | $orig_matches = array(); |
||
345 | $final_matches = array(); |
||
346 | |||
347 | foreach ( $matches as $keys => $difference ) { |
||
348 | list($o, $f) = explode(',', $keys); |
||
349 | $o = (int) $o; |
||
350 | $f = (int) $f; |
||
351 | |||
352 | // Already have better matches for these guys |
||
353 | if ( isset($orig_matches[$o]) && isset($final_matches[$f]) ) |
||
354 | continue; |
||
355 | |||
356 | // First match for these guys. Must be best match |
||
357 | if ( !isset($orig_matches[$o]) && !isset($final_matches[$f]) ) { |
||
358 | $orig_matches[$o] = $f; |
||
359 | $final_matches[$f] = $o; |
||
360 | continue; |
||
361 | } |
||
362 | |||
363 | // Best match of this final is already taken? Must mean this final is a new row. |
||
364 | if ( isset($orig_matches[$o]) ) |
||
365 | $final_matches[$f] = 'x'; |
||
366 | |||
367 | // Best match of this orig is already taken? Must mean this orig is a deleted row. |
||
368 | elseif ( isset($final_matches[$f]) ) |
||
369 | $orig_matches[$o] = 'x'; |
||
370 | } |
||
371 | |||
372 | // We read the text in this order |
||
373 | ksort($orig_matches); |
||
374 | ksort($final_matches); |
||
375 | |||
376 | // Stores rows and blanks for each column. |
||
377 | $orig_rows = $orig_rows_copy = array_keys($orig_matches); |
||
378 | $final_rows = array_keys($final_matches); |
||
379 | |||
380 | // Interleaves rows with blanks to keep matches aligned. |
||
381 | // We may end up with some extraneous blank rows, but we'll just ignore them later. |
||
382 | foreach ( $orig_rows_copy as $orig_row ) { |
||
383 | $final_pos = array_search($orig_matches[$orig_row], $final_rows, true); |
||
384 | $orig_pos = (int) array_search($orig_row, $orig_rows, true); |
||
385 | |||
386 | if ( false === $final_pos ) { // This orig is paired with a blank final. |
||
387 | array_splice( $final_rows, $orig_pos, 0, -1 ); |
||
388 | } elseif ( $final_pos < $orig_pos ) { // This orig's match is up a ways. Pad final with blank rows. |
||
389 | $diff_pos = $final_pos - $orig_pos; |
||
390 | while ( $diff_pos < 0 ) |
||
391 | array_splice( $final_rows, $orig_pos, 0, $diff_pos++ ); |
||
392 | } elseif ( $final_pos > $orig_pos ) { // This orig's match is down a ways. Pad orig with blank rows. |
||
393 | $diff_pos = $orig_pos - $final_pos; |
||
394 | while ( $diff_pos < 0 ) |
||
395 | array_splice( $orig_rows, $orig_pos, 0, $diff_pos++ ); |
||
396 | } |
||
397 | } |
||
398 | |||
399 | // Pad the ends with blank rows if the columns aren't the same length |
||
400 | $diff_count = count($orig_rows) - count($final_rows); |
||
401 | if ( $diff_count < 0 ) { |
||
402 | while ( $diff_count < 0 ) |
||
403 | array_push($orig_rows, $diff_count++); |
||
404 | } elseif ( $diff_count > 0 ) { |
||
405 | $diff_count = -1 * $diff_count; |
||
406 | while ( $diff_count < 0 ) |
||
407 | array_push($final_rows, $diff_count++); |
||
408 | } |
||
409 | |||
410 | return array($orig_matches, $final_matches, $orig_rows, $final_rows); |
||
411 | } |
||
412 | |||
413 | /** |
||
414 | * Computes a number that is intended to reflect the "distance" between two strings. |
||
415 | * |
||
416 | * @since 2.6.0 |
||
417 | * |
||
418 | * @param string $string1 |
||
419 | * @param string $string2 |
||
420 | * @return int |
||
0 ignored issues
–
show
|
|||
421 | */ |
||
422 | public function compute_string_distance( $string1, $string2 ) { |
||
423 | // Vectors containing character frequency for all chars in each string |
||
424 | $chars1 = count_chars($string1); |
||
425 | $chars2 = count_chars($string2); |
||
426 | |||
427 | // L1-norm of difference vector. |
||
428 | $difference = array_sum( array_map( array($this, 'difference'), $chars1, $chars2 ) ); |
||
429 | |||
430 | // $string1 has zero length? Odd. Give huge penalty by not dividing. |
||
431 | if ( !$string1 ) |
||
432 | return $difference; |
||
433 | |||
434 | // Return distance per character (of string1). |
||
435 | return $difference / strlen($string1); |
||
436 | } |
||
437 | |||
438 | /** |
||
439 | * @ignore |
||
440 | * @since 2.6.0 |
||
441 | * |
||
442 | * @param int $a |
||
443 | * @param int $b |
||
444 | * @return int |
||
0 ignored issues
–
show
|
|||
445 | */ |
||
446 | public function difference( $a, $b ) { |
||
447 | return abs( $a - $b ); |
||
448 | } |
||
449 | |||
450 | /** |
||
451 | * Make private properties readable for backward compatibility. |
||
452 | * |
||
453 | * @since 4.0.0 |
||
454 | * @access public |
||
455 | * |
||
456 | * @param string $name Property to get. |
||
457 | * @return mixed Property. |
||
458 | */ |
||
459 | public function __get( $name ) { |
||
460 | if ( in_array( $name, $this->compat_fields ) ) { |
||
461 | return $this->$name; |
||
462 | } |
||
463 | } |
||
464 | |||
465 | /** |
||
466 | * Make private properties settable for backward compatibility. |
||
467 | * |
||
468 | * @since 4.0.0 |
||
469 | * @access public |
||
470 | * |
||
471 | * @param string $name Property to check if set. |
||
472 | * @param mixed $value Property value. |
||
473 | * @return mixed Newly-set property. |
||
474 | */ |
||
475 | public function __set( $name, $value ) { |
||
476 | if ( in_array( $name, $this->compat_fields ) ) { |
||
477 | return $this->$name = $value; |
||
478 | } |
||
479 | } |
||
480 | |||
481 | /** |
||
482 | * Make private properties checkable for backward compatibility. |
||
483 | * |
||
484 | * @since 4.0.0 |
||
485 | * @access public |
||
486 | * |
||
487 | * @param string $name Property to check if set. |
||
488 | * @return bool Whether the property is set. |
||
0 ignored issues
–
show
|
|||
489 | */ |
||
490 | public function __isset( $name ) { |
||
491 | if ( in_array( $name, $this->compat_fields ) ) { |
||
492 | return isset( $this->$name ); |
||
493 | } |
||
494 | } |
||
495 | |||
496 | /** |
||
497 | * Make private properties un-settable for backward compatibility. |
||
498 | * |
||
499 | * @since 4.0.0 |
||
500 | * @access public |
||
501 | * |
||
502 | * @param string $name Property to unset. |
||
503 | */ |
||
504 | public function __unset( $name ) { |
||
505 | if ( in_array( $name, $this->compat_fields ) ) { |
||
506 | unset( $this->$name ); |
||
507 | } |
||
508 | } |
||
509 | } |
||
510 |
This checks looks for assignemnts to variables using the
list(...)
function, where not all assigned variables are subsequently used.Consider the following code example.
Only the variables
$a
and$c
are used. There was no need to assign$b
.Instead, the list call could have been.