Issues (2010)

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.

wp-includes/wp-diff.php (3 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
 * WordPress Diff bastard child of old MediaWiki Diff Formatter.
4
 *
5
 * Basically all that remains is the table structure and some method names.
6
 *
7
 * @package WordPress
8
 * @subpackage Diff
9
 */
10
11
if ( ! class_exists( 'Text_Diff', false ) ) {
12
	/** Text_Diff class */
13
	require( dirname(__FILE__).'/Text/Diff.php' );
14
	/** Text_Diff_Renderer class */
15
	require( dirname(__FILE__).'/Text/Diff/Renderer.php' );
16
	/** Text_Diff_Renderer_inline class */
17
	require( dirname(__FILE__).'/Text/Diff/Renderer/inline.php' );
18
}
19
20
/**
21
 * Table renderer to display the diff lines.
22
 *
23
 * @since 2.6.0
24
 * @uses Text_Diff_Renderer Extends
25
 */
26
class WP_Text_Diff_Renderer_Table extends Text_Diff_Renderer {
27
28
	/**
29
	 * @see Text_Diff_Renderer::_leading_context_lines
30
	 * @var int
31
	 * @access public
32
	 * @since 2.6.0
33
	 */
34
	public $_leading_context_lines  = 10000;
35
36
	/**
37
	 * @see Text_Diff_Renderer::_trailing_context_lines
38
	 * @var int
39
	 * @access public
40
	 * @since 2.6.0
41
	 */
42
	public $_trailing_context_lines = 10000;
43
44
	/**
45
	 * Threshold for when a diff should be saved or omitted.
46
	 *
47
	 * @var float
48
	 * @access protected
49
	 * @since 2.6.0
50
	 */
51
	protected $_diff_threshold = 0.6;
52
53
	/**
54
	 * Inline display helper object name.
55
	 *
56
	 * @var string
57
	 * @access protected
58
	 * @since 2.6.0
59
	 */
60
	protected $inline_diff_renderer = 'WP_Text_Diff_Renderer_inline';
61
62
	/**
63
	 * Should we show the split view or not
64
	 *
65
	 * @var string
66
	 * @access protected
67
	 * @since 3.6.0
68
	 */
69
	protected $_show_split_view = true;
70
71
	protected $compat_fields = array( '_show_split_view', 'inline_diff_renderer', '_diff_threshold' );
72
73
	/**
74
	 * Constructor - Call parent constructor with params array.
75
	 *
76
	 * This will set class properties based on the key value pairs in the array.
77
	 *
78
	 * @since 2.6.0
79
	 *
80
	 * @param array $params
81
	 */
82
	public function __construct( $params = array() ) {
83
		parent::__construct( $params );
84
		if ( isset( $params[ 'show_split_view' ] ) )
85
			$this->_show_split_view = $params[ 'show_split_view' ];
86
	}
87
88
	/**
89
	 * @ignore
90
	 *
91
	 * @param string $header
92
	 * @return string
93
	 */
94
	public function _startBlock( $header ) {
95
		return '';
96
	}
97
98
	/**
99
	 * @ignore
100
	 *
101
	 * @param array $lines
102
	 * @param string $prefix
103
	 */
104
	public function _lines( $lines, $prefix=' ' ) {
105
	}
106
107
	/**
108
	 * @ignore
109
	 *
110
	 * @param string $line HTML-escape the value.
111
	 * @return string
112
	 */
113
	public function addedLine( $line ) {
114
		return "<td class='diff-addedline'>{$line}</td>";
115
116
	}
117
118
	/**
119
	 * @ignore
120
	 *
121
	 * @param string $line HTML-escape the value.
122
	 * @return string
123
	 */
124
	public function deletedLine( $line ) {
125
		return "<td class='diff-deletedline'>{$line}</td>";
126
	}
127
128
	/**
129
	 * @ignore
130
	 *
131
	 * @param string $line HTML-escape the value.
132
	 * @return string
133
	 */
134
	public function contextLine( $line ) {
135
		return "<td class='diff-context'>{$line}</td>";
136
	}
137
138
	/**
139
	 * @ignore
140
	 *
141
	 * @return string
142
	 */
143
	public function emptyLine() {
144
		return '<td>&nbsp;</td>';
145
	}
146
147
	/**
148
	 * @ignore
149
	 * @access public
150
	 *
151
	 * @param array $lines
152
	 * @param bool $encode
153
	 * @return string
154
	 */
155 View Code Duplication
	public function _added( $lines, $encode = true ) {
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
156
		$r = '';
157
		foreach ($lines as $line) {
158
			if ( $encode ) {
159
				$processed_line = htmlspecialchars( $line );
160
161
				/**
162
				 * Contextually filters a diffed line.
163
				 *
164
				 * Filters TextDiff processing of diffed line. By default, diffs are processed with
165
				 * htmlspecialchars. Use this filter to remove or change the processing. Passes a context
166
				 * indicating if the line is added, deleted or unchanged.
167
				 *
168
				 * @since 4.1.0
169
				 *
170
				 * @param String $processed_line The processed diffed line.
171
				 * @param String $line           The unprocessed diffed line.
172
		 		 * @param string null            The line context. Values are 'added', 'deleted' or 'unchanged'.
173
				 */
174
				$line = apply_filters( 'process_text_diff_html', $processed_line, $line, 'added' );
175
			}
176
177
			if ( $this->_show_split_view ) {
178
				$r .= '<tr>' . $this->emptyLine() . $this->emptyLine() . $this->addedLine( $line ) . "</tr>\n";
179
			} else {
180
				$r .= '<tr>' . $this->addedLine( $line ) . "</tr>\n";
181
			}
182
		}
183
		return $r;
184
	}
185
186
	/**
187
	 * @ignore
188
	 * @access public
189
	 *
190
	 * @param array $lines
191
	 * @param bool $encode
192
	 * @return string
193
	 */
194 View Code Duplication
	public function _deleted( $lines, $encode = true ) {
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
195
		$r = '';
196
		foreach ($lines as $line) {
197
			if ( $encode ) {
198
				$processed_line = htmlspecialchars( $line );
199
200
				/** This filter is documented in wp-includes/wp-diff.php */
201
				$line = apply_filters( 'process_text_diff_html', $processed_line, $line, 'deleted' );
202
			}
203
			if ( $this->_show_split_view ) {
204
				$r .= '<tr>' . $this->deletedLine( $line ) . $this->emptyLine() . $this->emptyLine() . "</tr>\n";
205
			} else {
206
				$r .= '<tr>' . $this->deletedLine( $line ) . "</tr>\n";
207
			}
208
209
		}
210
		return $r;
211
	}
212
213
	/**
214
	 * @ignore
215
	 * @access public
216
	 *
217
	 * @param array $lines
218
	 * @param bool $encode
219
	 * @return string
220
	 */
221 View Code Duplication
	public function _context( $lines, $encode = true ) {
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
222
		$r = '';
223
		foreach ($lines as $line) {
224
			if ( $encode ) {
225
				$processed_line = htmlspecialchars( $line );
226
227
				/** This filter is documented in wp-includes/wp-diff.php */
228
				$line = apply_filters( 'process_text_diff_html', $processed_line, $line, 'unchanged' );
229
			}
230
			if (  $this->_show_split_view ) {
231
				$r .= '<tr>' . $this->contextLine( $line ) . $this->emptyLine() . $this->contextLine( $line )  . "</tr>\n";
232
			} else {
233
				$r .= '<tr>' . $this->contextLine( $line ) . "</tr>\n";
234
			}
235
		}
236
		return $r;
237
	}
238
239
	/**
240
	 * Process changed lines to do word-by-word diffs for extra highlighting.
241
	 *
242
	 * (TRAC style) sometimes these lines can actually be deleted or added rows.
243
	 * We do additional processing to figure that out
244
	 *
245
	 * @access public
246
	 * @since 2.6.0
247
	 *
248
	 * @param array $orig
249
	 * @param array $final
250
	 * @return string
251
	 */
252
	public function _changed( $orig, $final ) {
253
		$r = '';
254
255
		// Does the aforementioned additional processing
256
		// *_matches tell what rows are "the same" in orig and final. Those pairs will be diffed to get word changes
257
		//	match is numeric: an index in other column
258
		//	match is 'X': no match. It is a new row
259
		// *_rows are column vectors for the orig column and the final column.
260
		//	row >= 0: an indix of the $orig or $final array
261
		//	row  < 0: a blank row for that column
262
		list($orig_matches, $final_matches, $orig_rows, $final_rows) = $this->interleave_changed_lines( $orig, $final );
263
264
		// These will hold the word changes as determined by an inline diff
265
		$orig_diffs  = array();
266
		$final_diffs = array();
267
268
		// Compute word diffs for each matched pair using the inline diff
269
		foreach ( $orig_matches as $o => $f ) {
270
			if ( is_numeric($o) && is_numeric($f) ) {
271
				$text_diff = new Text_Diff( 'auto', array( array($orig[$o]), array($final[$f]) ) );
272
				$renderer = new $this->inline_diff_renderer;
273
				$diff = $renderer->render( $text_diff );
274
275
				// If they're too different, don't include any <ins> or <dels>
276
				if ( preg_match_all( '!(<ins>.*?</ins>|<del>.*?</del>)!', $diff, $diff_matches ) ) {
277
					// length of all text between <ins> or <del>
278
					$stripped_matches = strlen(strip_tags( join(' ', $diff_matches[0]) ));
279
					// since we count lengith of text between <ins> or <del> (instead of picking just one),
280
					//	we double the length of chars not in those tags.
281
					$stripped_diff = strlen(strip_tags( $diff )) * 2 - $stripped_matches;
282
					$diff_ratio = $stripped_matches / $stripped_diff;
283
					if ( $diff_ratio > $this->_diff_threshold )
284
						continue; // Too different. Don't save diffs.
285
				}
286
287
				// Un-inline the diffs by removing del or ins
288
				$orig_diffs[$o]  = preg_replace( '|<ins>.*?</ins>|', '', $diff );
289
				$final_diffs[$f] = preg_replace( '|<del>.*?</del>|', '', $diff );
290
			}
291
		}
292
293
		foreach ( array_keys($orig_rows) as $row ) {
294
			// Both columns have blanks. Ignore them.
295
			if ( $orig_rows[$row] < 0 && $final_rows[$row] < 0 )
296
				continue;
297
298
			// If we have a word based diff, use it. Otherwise, use the normal line.
299
			if ( isset( $orig_diffs[$orig_rows[$row]] ) )
300
				$orig_line = $orig_diffs[$orig_rows[$row]];
301
			elseif ( isset( $orig[$orig_rows[$row]] ) )
302
				$orig_line = htmlspecialchars($orig[$orig_rows[$row]]);
303
			else
304
				$orig_line = '';
305
306
			if ( isset( $final_diffs[$final_rows[$row]] ) )
307
				$final_line = $final_diffs[$final_rows[$row]];
308
			elseif ( isset( $final[$final_rows[$row]] ) )
309
				$final_line = htmlspecialchars($final[$final_rows[$row]]);
310
			else
311
				$final_line = '';
312
313
			if ( $orig_rows[$row] < 0 ) { // Orig is blank. This is really an added row.
314
				$r .= $this->_added( array($final_line), false );
315
			} elseif ( $final_rows[$row] < 0 ) { // Final is blank. This is really a deleted row.
316
				$r .= $this->_deleted( array($orig_line), false );
317
			} else { // A true changed row.
318
				if ( $this->_show_split_view ) {
319
					$r .= '<tr>' . $this->deletedLine( $orig_line ) . $this->emptyLine() . $this->addedLine( $final_line ) . "</tr>\n";
320
				} else {
321
					$r .= '<tr>' . $this->deletedLine( $orig_line ) . "</tr><tr>" . $this->addedLine( $final_line ) . "</tr>\n";
322
				}
323
			}
324
		}
325
326
		return $r;
327
	}
328
329
	/**
330
	 * Takes changed blocks and matches which rows in orig turned into which rows in final.
331
	 *
332
	 * Returns
333
	 *	*_matches ( which rows match with which )
334
	 *	*_rows ( order of rows in each column interleaved with blank rows as
335
	 *		necessary )
336
	 *
337
	 * @since 2.6.0
338
	 *
339
	 * @param array $orig
340
	 * @param array $final
341
	 * @return array
342
	 */
343
	public function interleave_changed_lines( $orig, $final ) {
344
345
		// Contains all pairwise string comparisons. Keys are such that this need only be a one dimensional array.
346
		$matches = array();
347
		foreach ( array_keys($orig) as $o ) {
348
			foreach ( array_keys($final) as $f ) {
349
				$matches["$o,$f"] = $this->compute_string_distance( $orig[$o], $final[$f] );
350
			}
351
		}
352
		asort($matches); // Order by string distance.
353
354
		$orig_matches  = array();
355
		$final_matches = array();
356
357
		foreach ( $matches as $keys => $difference ) {
358
			list($o, $f) = explode(',', $keys);
359
			$o = (int) $o;
360
			$f = (int) $f;
361
362
			// Already have better matches for these guys
363
			if ( isset($orig_matches[$o]) && isset($final_matches[$f]) )
364
				continue;
365
366
			// First match for these guys. Must be best match
367
			if ( !isset($orig_matches[$o]) && !isset($final_matches[$f]) ) {
368
				$orig_matches[$o] = $f;
369
				$final_matches[$f] = $o;
370
				continue;
371
			}
372
373
			// Best match of this final is already taken?  Must mean this final is a new row.
374
			if ( isset($orig_matches[$o]) )
375
				$final_matches[$f] = 'x';
376
377
			// Best match of this orig is already taken?  Must mean this orig is a deleted row.
378
			elseif ( isset($final_matches[$f]) )
379
				$orig_matches[$o] = 'x';
380
		}
381
382
		// We read the text in this order
383
		ksort($orig_matches);
384
		ksort($final_matches);
385
386
		// Stores rows and blanks for each column.
387
		$orig_rows = $orig_rows_copy = array_keys($orig_matches);
388
		$final_rows = array_keys($final_matches);
389
390
		// Interleaves rows with blanks to keep matches aligned.
391
		// We may end up with some extraneous blank rows, but we'll just ignore them later.
392
		foreach ( $orig_rows_copy as $orig_row ) {
393
			$final_pos = array_search($orig_matches[$orig_row], $final_rows, true);
394
			$orig_pos = (int) array_search($orig_row, $orig_rows, true);
395
396
			if ( false === $final_pos ) { // This orig is paired with a blank final.
397
				array_splice( $final_rows, $orig_pos, 0, -1 );
398
			} elseif ( $final_pos < $orig_pos ) { // This orig's match is up a ways. Pad final with blank rows.
399
				$diff_pos = $final_pos - $orig_pos;
400
				while ( $diff_pos < 0 )
401
					array_splice( $final_rows, $orig_pos, 0, $diff_pos++ );
402
			} elseif ( $final_pos > $orig_pos ) { // This orig's match is down a ways. Pad orig with blank rows.
403
				$diff_pos = $orig_pos - $final_pos;
404
				while ( $diff_pos < 0 )
405
					array_splice( $orig_rows, $orig_pos, 0, $diff_pos++ );
406
			}
407
		}
408
409
		// Pad the ends with blank rows if the columns aren't the same length
410
		$diff_count = count($orig_rows) - count($final_rows);
411
		if ( $diff_count < 0 ) {
412
			while ( $diff_count < 0 )
413
				array_push($orig_rows, $diff_count++);
414
		} elseif ( $diff_count > 0 ) {
415
			$diff_count = -1 * $diff_count;
416
			while ( $diff_count < 0 )
417
				array_push($final_rows, $diff_count++);
418
		}
419
420
		return array($orig_matches, $final_matches, $orig_rows, $final_rows);
421
	}
422
423
	/**
424
	 * Computes a number that is intended to reflect the "distance" between two strings.
425
	 *
426
	 * @since 2.6.0
427
	 *
428
	 * @param string $string1
429
	 * @param string $string2
430
	 * @return int
431
	 */
432
	public function compute_string_distance( $string1, $string2 ) {
433
		// Vectors containing character frequency for all chars in each string
434
		$chars1 = count_chars($string1);
435
		$chars2 = count_chars($string2);
436
437
		// L1-norm of difference vector.
438
		$difference = array_sum( array_map( array($this, 'difference'), $chars1, $chars2 ) );
439
440
		// $string1 has zero length? Odd. Give huge penalty by not dividing.
441
		if ( !$string1 )
442
			return $difference;
443
444
		// Return distance per character (of string1).
445
		return $difference / strlen($string1);
446
	}
447
448
	/**
449
	 * @ignore
450
	 * @since 2.6.0
451
	 *
452
	 * @param int $a
453
	 * @param int $b
454
	 * @return int
455
	 */
456
	public function difference( $a, $b ) {
457
		return abs( $a - $b );
458
	}
459
460
	/**
461
	 * Make private properties readable for backward compatibility.
462
	 *
463
	 * @since 4.0.0
464
	 * @access public
465
	 *
466
	 * @param string $name Property to get.
467
	 * @return mixed Property.
468
	 */
469
	public function __get( $name ) {
470
		if ( in_array( $name, $this->compat_fields ) ) {
471
			return $this->$name;
472
		}
473
	}
474
475
	/**
476
	 * Make private properties settable for backward compatibility.
477
	 *
478
	 * @since 4.0.0
479
	 * @access public
480
	 *
481
	 * @param string $name  Property to check if set.
482
	 * @param mixed  $value Property value.
483
	 * @return mixed Newly-set property.
484
	 */
485
	public function __set( $name, $value ) {
486
		if ( in_array( $name, $this->compat_fields ) ) {
487
			return $this->$name = $value;
488
		}
489
	}
490
491
	/**
492
	 * Make private properties checkable for backward compatibility.
493
	 *
494
	 * @since 4.0.0
495
	 * @access public
496
	 *
497
	 * @param string $name Property to check if set.
498
	 * @return bool Whether the property is set.
499
	 */
500
	public function __isset( $name ) {
501
		if ( in_array( $name, $this->compat_fields ) ) {
502
			return isset( $this->$name );
503
		}
504
	}
505
506
	/**
507
	 * Make private properties un-settable for backward compatibility.
508
	 *
509
	 * @since 4.0.0
510
	 * @access public
511
	 *
512
	 * @param string $name Property to unset.
513
	 */
514
	public function __unset( $name ) {
515
		if ( in_array( $name, $this->compat_fields ) ) {
516
			unset( $this->$name );
517
		}
518
	}
519
}
520
521
/**
522
 * Better word splitting than the PEAR package provides.
523
 *
524
 * @since 2.6.0
525
 * @uses Text_Diff_Renderer_inline Extends
526
 */
527
class WP_Text_Diff_Renderer_inline extends Text_Diff_Renderer_inline {
528
529
	/**
530
	 * @ignore
531
	 * @since 2.6.0
532
	 *
533
	 * @param string $string
534
	 * @param string $newlineEscape
535
	 * @return string
536
	 */
537
	public function _splitOnWords($string, $newlineEscape = "\n") {
538
		$string = str_replace("\0", '', $string);
539
		$words  = preg_split( '/([^\w])/u', $string, -1, PREG_SPLIT_DELIM_CAPTURE );
540
		$words  = str_replace( "\n", $newlineEscape, $words );
541
		return $words;
542
	}
543
544
}
545