Issues (4296)

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.

includes/class-give-comment.php (14 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
 * Class for managing comments
5
 *
6
 * @package     Give
7
 * @subpackage  Classes/Give_Cache
8
 * @copyright   Copyright (c) 2018, WordImpress
9
 * @license     https://opensource.org/licenses/gpl-license GNU Public License
10
 * @since       2.2.0
11
 */
12
class Give_Comment {
0 ignored issues
show
Since you have declared the constructor as private, maybe you should also declare the class as final.
Loading history...
13
	/**
14
	 * Instance.
15
	 *
16
	 * @since  2.2.0
17
	 * @access private
18
	 * @var
19
	 */
20
	static private $instance;
21
22
	/**
23
	 * Comment Types.
24
	 *
25
	 * @since  2.2.0
26
	 * @access private
27
	 * @var array
28
	 */
29
	private $comment_types;
30
31
	/**
32
	 * Singleton pattern.
33
	 *
34
	 * @since  2.2.0
35
	 * @access private
36
	 */
37
	private function __construct() {
38
	}
39
40
41
	/**
42
	 * Get instance.
43
	 *
44
	 * @since  2.2.0
45
	 * @access pu
46
	 * @return Give_Comment
47
	 */
48 View Code Duplication
	public static function get_instance() {
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...
49
		if ( null === static::$instance ) {
50
			self::$instance = new static();
51
			self::$instance->init();
52
		}
53
54
		return self::$instance;
55
	}
56
57
	/**
58
	 * Initialize
59
	 *
60
	 * @since  2.2.0
61
	 * @access private
62
	 */
63
	private function init() {
64
		/**
65
		 * Filter the comment type
66
		 *
67
		 * @since 2.2.0
68
		 */
69
		$this->comment_types = apply_filters(
70
			'give_comment_type',
71
			self::get_comment_types( array( 'payment', 'donor' ) )
72
		);
73
74
		add_action( 'pre_get_comments', array( $this, 'hide_comments' ), 10 );
75
		add_filter( 'comments_clauses', array( $this, 'hide_comments_pre_wp_41' ), 10, 1 );
76
		add_filter( 'comment_feed_where', array( $this, 'hide_comments_from_feeds' ), 10, 1 );
77
		add_filter( 'wp_count_comments', array( $this, 'remove_comments_from_comment_counts' ), 10, 2 );
78
		add_filter( 'get_comment_author', array( $this, '__get_comment_author' ), 10, 3 );
79
	}
80
81
	/**
82
	 * Insert/Update comment
83
	 *
84
	 * @since  2.2.0
85
	 * @access public
86
	 *
87
	 * @param int    $id           Payment|Donor ID.
88
	 * @param string $note         Comment Text
89
	 * @param string $comment_type Value can ve donor|payment
90
	 * @param array  $comment_args Comment arguments
91
	 *
92
	 * @return int|WP_Error
93
	 */
94
	public static function add( $id, $note, $comment_type, $comment_args = array() ) {
95
		// Bailout
96
		if ( empty( $id ) || empty( $note ) || empty( $comment_type ) ) {
97
			return new WP_Error( 'give_invalid_required_param', __( 'This comment has invalid ID or comment text or cooment type', 'give' ) );
98
		}
99
100
		$is_existing_comment = array_key_exists( 'comment_ID', $comment_args ) && ! empty( $comment_args['comment_ID'] );
101
		$action_type         = $is_existing_comment ? 'update' : 'insert';
102
103
		/**
104
		 * Fires before inserting/updating payment|donor comment.
105
		 *
106
		 * @param int    $id   Payment|Donor ID.
107
		 * @param string $note Comment text.
108
		 *
109
		 * @since 1.0
110
		 */
111
		do_action( "give_pre_{$action_type}_{$comment_type}_note", $id, $note );
112
113
		$comment_args = wp_parse_args(
114
			$comment_args,
115
			array(
116
				'comment_post_ID'      => $id,
117
				'comment_content'      => $note,
118
				'user_id'              => is_admin() ? get_current_user_id() : 0,
119
				'comment_date'         => current_time( 'mysql' ),
120
				'comment_date_gmt'     => current_time( 'mysql', 1 ),
121
				'comment_approved'     => 1,
122
				'comment_parent'       => 0,
123
				'comment_author'       => '',
124
				'comment_author_IP'    => '',
125
				'comment_author_url'   => '',
126
				'comment_author_email' => '',
127
				'comment_type'         => "give_{$comment_type}_note",
128
129
			)
130
		);
131
0 ignored issues
show
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
132
133
		// Check comment max length.
134
		$error = wp_check_comment_data_max_lengths( $comment_args );
135
		if( is_wp_error( $error ) ) {
0 ignored issues
show
Space after opening control structure is required
Loading history...
No space before opening parenthesis is prohibited
Loading history...
136
			return $error;
137
		}
138
139
		// Remove moderation emails when comment posted.
140
		remove_action( 'comment_post', 'wp_new_comment_notify_moderator' );
141
		remove_action( 'comment_post', 'wp_new_comment_notify_postauthor' );
142
143
		// Remove comment flood check.
144
		remove_action( 'check_comment_flood', 'check_comment_flood_db', 10 );
145
146
		$comment_id = $is_existing_comment
147
			? wp_update_comment( $comment_args )
148
			: wp_new_comment( $comment_args, true );
149
150
		// Add moderation emails when comment posted.
151
		add_action( 'comment_post', 'wp_new_comment_notify_moderator' );
152
		add_action( 'comment_post', 'wp_new_comment_notify_postauthor' );
153
154
		// Add comment flood check.
155
		add_action( 'check_comment_flood', 'check_comment_flood_db', 10, 4 );
156
157
		update_comment_meta( $comment_id, "_give_{$comment_type}_id", $id );
158
159
		/**
160
		 * Fires after payment|donor comment inserted/updated.
161
		 *
162
		 * @param int    $comment_id Comment ID.
163
		 * @param int    $id         Payment|Donor ID.
164
		 * @param string $note       Comment text.
165
		 *
166
		 * @since 1.0
167
		 */
168
		do_action( "give_{$action_type}_{$comment_type}_note", $comment_id, $id, $note );
169
170
		return $comment_id;
171
	}
172
173
174
	/**
175
	 * Delete comment
176
	 *
177
	 * @since  2.2.0
178
	 * @access public
179
	 *
180
	 * @param int    $comment_id   The comment ID to delete.
181
	 * @param int    $id           The payment|Donor ID the note is connected to.
182
	 * @param string $comment_type Value can ve donor|payment.
183
	 *
184
	 * @since  1.0
185
	 *
186
	 * @return bool True on success, false otherwise.
187
	 */
188
	public static function delete( $comment_id, $id, $comment_type ) {
189
		$ret = false;
190
191
		// Bailout
192
		if ( empty( $id ) || empty( $comment_id ) || empty( $comment_type ) ) {
193
			return $ret;
194
		}
195
196
		/**
197
		 * Fires before deleting donation note.
198
		 *
199
		 * @param int $comment_id Comment ID.
200
		 * @param int $id         Payment|Donor ID.
201
		 *
202
		 * @since 1.0
203
		 */
204
		do_action( "give_pre_delete_{$comment_type}_note", $comment_id, $id );
205
206
		$ret = wp_delete_comment( $comment_id, true );
207
208
		/**
209
		 * Fires after donation note deleted.
210
		 *
211
		 * @param int  $comment_id Note ID.
212
		 * @param int  $id         Payment|Donor ID.
213
		 * @param bool $ret        Flag to check if comment deleted or not.
214
		 *
215
		 * @since 1.0
216
		 */
217
		do_action( "give_post_delete_{$comment_type}_note", $comment_id, $id, $ret );
218
219
		return $ret;
220
	}
221
222
223
	/**
224
	 * Get comments
225
	 *
226
	 * @since  2.2.0
227
	 * @access public
228
	 *
229
	 * @param int    $id
230
	 * @param string $comment_type
231
	 * @param array  $comment_args
232
	 * @param string $search
233
	 *
234
	 * @return array
235
	 */
236
	public static function get( $id, $comment_type, $comment_args = array(), $search = '' ) {
237
		$comments = array();
238
239
		// Set default meta_query value.
240
		if ( ! isset( $comment_args['meta_query'] ) ) {
241
			$comment_args['meta_query'] = array();
0 ignored issues
show
Detected usage of meta_query, possible slow query.
Loading history...
242
		}
243
244
		// Bailout
245
		if ( empty( $id ) || empty( $comment_type ) ) {
246
			return $comments;
247
		}
248
249
		remove_action( 'pre_get_comments', array( self::$instance, 'hide_comments' ), 10 );
250
		remove_filter( 'comments_clauses', array( self::$instance, 'hide_comments_pre_wp_41' ), 10 );
251
252
		switch ( $comment_type ) {
253 View Code Duplication
			case 'payment':
0 ignored issues
show
This code seems to be duplicated across your project.

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

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

Loading history...
254
				$comment_args['meta_query'] = ! empty( $comment_args['meta_query'] )
0 ignored issues
show
Detected usage of meta_query, possible slow query.
Loading history...
255
					? $comment_args['meta_query']
256
					: array(
257
						array(
258
							'key'     => '_give_donor_id',
259
							'compare' => 'NOT EXISTS'
260
						)
261
					);
262
263
				$comments = get_comments( wp_parse_args(
264
					$comment_args,
265
					array(
266
						'post_id' => $id,
267
						'order'   => 'ASC',
268
						'search'  => $search,
269
						'type'    => 'give_payment_note'
270
					)
271
				) );
272
				break;
273
274 View Code Duplication
			case 'donor':
0 ignored issues
show
This code seems to be duplicated across your project.

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

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

Loading history...
275
				$comment_args['meta_query'] = ! empty( $comment_args['meta_query'] )
0 ignored issues
show
Detected usage of meta_query, possible slow query.
Loading history...
276
					? $comment_args['meta_query']
277
					: array(
278
						array(
279
							'key'   => "_give_{$comment_type}_id",
280
							'value' => $id
281
						)
282
					);
283
284
				$comments = get_comments( wp_parse_args(
285
					$comment_args,
286
					array(
287
						'order'  => 'ASC',
288
						'search' => $search,
289
						'type'   => 'give_donor_note'
290
					)
291
				) );
292
				break;
293
		}
294
295
		add_action( 'pre_get_comments', array( self::$instance, 'hide_comments' ), 10, 1 );
296
		add_filter( 'comments_clauses', array( self::$instance, 'hide_comments_pre_wp_41' ), 10, 1 );
297
298
		return $comments;
299
	}
300
301
	/**
302
	 * Exclude comments from showing in Recent
303
	 * Comments widgets
304
	 *
305
	 * @since  2.2.0
306
	 * @access public
307
	 *
308
	 * @param object $query WordPress Comment Query Object.
309
	 *
310
	 * @return void
311
	 */
312
	public function hide_comments( $query ) {
313
		if ( version_compare( floatval( get_bloginfo( 'version' ) ), '4.1', '>=' ) ) {
314
			$types = isset( $query->query_vars['type__not_in'] ) ? $query->query_vars['type__not_in'] : array();
315
			if ( ! is_array( $types ) ) {
316
				$types = array( $types );
317
			}
318
319
			$types = array_filter( array_merge( $types, $this->comment_types ) );
320
321
			$query->query_vars['type__not_in'] = $types;
322
		}
323
	}
324
325
	/**
326
	 * Exclude notes (comments) from showing in Recent Comments widgets
327
	 *
328
	 * @since  2.2.0
329
	 * @access public
330
	 *
331
	 * @param array $clauses Comment clauses for comment query.
332
	 *
333
	 * @return array $clauses Updated comment clauses.
334
	 */
335
	public function hide_comments_pre_wp_41( $clauses ) {
336
		if ( version_compare( floatval( get_bloginfo( 'version' ) ), '4.1', '<' ) ) {
337
			foreach ( $this->comment_types as $comment_type ) {
338
				$clauses['where'] .= " AND comment_type != \"{$comment_type}\"";
339
			}
340
		}
341
342
		return $clauses;
343
	}
344
345
	/**
346
	 * Exclude notes (comments) from showing in comment feeds
347
	 *
348
	 * @since  2.2.0
349
	 * @access public
350
	 *
351
	 * @param string $where
352
	 *
353
	 * @return string $where
354
	 */
355
	public function hide_comments_from_feeds( $where ) {
356
		global $wpdb;
357
358
		foreach ( $this->comment_types as $comment_type ) {
359
			$where .= $wpdb->prepare( ' AND comment_type!=%s', $comment_type );
360
		}
361
362
		return $where;
363
	}
364
365
	/**
366
	 * Remove Give Comments from the wp_count_comments function
367
	 *
368
	 * @since  2.2.0
369
	 * @access public
370
	 *
371
	 * @param array $stats   (empty from core filter).
372
	 * @param int   $post_id Post ID.
373
	 *
374
	 * @return array|object Array of comment counts.
375
	 */
376
	public function remove_comments_from_comment_counts( $stats, $post_id ) {
377
		global $wpdb;
378
379
		$post_id = (int) $post_id;
380
381
		if ( apply_filters( 'give_count_payment_notes_in_comments', false ) ) {
382
			return $stats;
383
		}
384
385
		$stats = Give_Cache::get_group( "comments-{$post_id}", 'counts' );
386
387
		// Return result from cache.
388
		if ( ! is_null( $stats ) ) {
389
			return $stats;
390
		}
391
392
		$where = 'WHERE';
393
394
		foreach ( $this->comment_types as $index => $comment_type ) {
395
			$where .= ( $index ? ' AND ' : ' ' ) . "comment_type != \"{$comment_type}\"";
396
		}
397
398
		if ( $post_id > 0 ) {
399
			$where .= $wpdb->prepare( ' AND comment_post_ID = %d', $post_id );
400
		}
401
402
		$count = $wpdb->get_results(
0 ignored issues
show
Usage of a direct database call is discouraged.
Loading history...
Usage of a direct database call without caching is prohibited. Use wp_cache_get / wp_cache_set.
Loading history...
403
			"
404
				  SELECT comment_approved, COUNT( * ) AS num_comments
405
				  FROM {$wpdb->comments} {$where}
406
				  GROUP BY comment_approved
407
				  ",
408
			ARRAY_A
409
		);
410
411
		$total    = 0;
412
		$approved = array(
413
			'0'            => 'moderated',
0 ignored issues
show
Detected usage of 0, possible slow query.
Loading history...
414
			'1'            => 'approved',
415
			'spam'         => 'spam',
416
			'trash'        => 'trash',
417
			'post-trashed' => 'post-trashed',
418
		);
419
420
		foreach ( (array) $count as $row ) {
421
			// Don't count post-trashed toward totals.
422
			if ( 'post-trashed' != $row['comment_approved'] && 'trash' != $row['comment_approved'] ) {
423
				$total += $row['num_comments'];
424
			}
425
			if ( isset( $approved[ $row['comment_approved'] ] ) ) {
426
				$stats[ $approved[ $row['comment_approved'] ] ] = $row['num_comments'];
427
			}
428
		}
429
430
		$stats['total_comments'] = $stats['all'] = $total;
431
		foreach ( $approved as $key ) {
432
			if ( empty( $stats[ $key ] ) ) {
433
				$stats[ $key ] = 0;
434
			}
435
		}
436
437
		$stats = (object) $stats;
438
439
		Give_Cache::set_group( "comments-{$post_id}", $stats, 'counts' );
440
441
		return $stats;
442
	}
443
444
	/**
445
	 * Get donor name
446
	 *
447
	 * @since  2.2.0
448
	 * @access public
449
	 *
450
	 * @param string     $author
451
	 * @param int        $comment_id
452
	 * @param WP_Comment $comment
453
	 *
454
	 * @return mixed
455
	 */
456
	public function __get_comment_author( $author, $comment_id, $comment ) {
0 ignored issues
show
Method name "Give_Comment::__get_comment_author" is invalid; only PHP magic methods should be prefixed with a double underscore
Loading history...
457
		if ( in_array( $comment->comment_type, $this->comment_types ) ) {
458
			switch ( $comment->comment_type ) {
459
				case 'give_payment_note':
460
					if ( get_comment_meta( $comment_id, '_give_donor_id', true ) ) {
461
						$author = give_get_donor_name_by( $comment->comment_post_ID );
462
					}
463
			}
464
		}
465
466
		return $author;
467
	}
468
469
470
	/**
471
	 * Get comment types
472
	 *
473
	 * @since  2.2.0
474
	 * @access public
475
	 *
476
	 * @param array @comment_types
477
	 *
478
	 * @return array
479
	 */
480
	public static function get_comment_types( $comment_types ) {
481
		$_comment_types = array();
482
		foreach ( $comment_types as $comment_type ) {
483
			$_comment_types[] = "give_{$comment_type}_note";
484
		}
485
486
		return $_comment_types;
487
	}
488
}
489