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
$aand$care used. There was no need to assign$b.Instead, the list call could have been.