Completed
Push — fix/comments-photon ( fff68e...a2496c )
by
unknown
52:12 queued 43:46
created

Highlander_Comments_Base::comments_array()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 27
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 17
nc 4
nop 1
dl 0
loc 27
rs 8.5806
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * All the code shared between WP.com Highlander and Jetpack Highlander
5
 */
6
class Highlander_Comments_Base {
7
	function __construct() {
8
		$this->setup_globals();
9
		$this->setup_actions();
10
		$this->setup_filters();
11
	}
12
13
	/**
14
	 * Set any global variables or class variables
15
	 * @since JetpackComments (1.4)
16
	 */
17
	protected function setup_globals() {}
18
19
	/**
20
	 * Setup actions for methods in this class
21
	 * @since JetpackComments (1.4)
22
	 */
23
	protected function setup_actions() {
24
		// Before a comment is posted
25
		add_action( 'pre_comment_on_post', array( $this, 'allow_logged_out_user_to_comment_as_external' ) );
26
27
		// After a comment is posted
28
		add_action( 'comment_post', array( $this, 'set_comment_cookies' ) );
29
	}
30
31
	/**
32
	 * Setup filters for methods in this class
33
	 * @since JetpackComments (1.4)
34
	 */
35
	protected function setup_filters() {
36
		add_filter( 'comments_array',     array( $this, 'comments_array' ) );
37
		add_filter( 'preprocess_comment', array( $this, 'allow_logged_in_user_to_comment_as_guest' ), 0 );
38
	}
39
40
	/**
41
	 * Is this a Highlander POST request?
42
	 * Optionally restrict to one or more credentials slug (facebook, twitter, ...)
43
	 *
44
	 * @param string Comment credentials slug
45
	 * @param ...
46
	 * @return false|string false if it's not a Highlander POST request.  The matching credentials slug if it is.
47
	 */
48
	function is_highlander_comment_post() {
49
		if ( empty( $_POST['hc_post_as'] ) ) {
50
			return false;
51
		}
52
53
		if ( func_num_args() ) {
54
			foreach ( func_get_args() as $id_source ) {
55
				if ( $id_source === $_POST['hc_post_as'] ) {
56
					return $id_source;
57
				}
58
			}
59
			return false;
60
		}
61
62
		return is_string( $_POST['hc_post_as'] ) && in_array( $_POST['hc_post_as'], $this->id_sources ) ? $_POST['hc_post_as'] : false;
0 ignored issues
show
Bug introduced by
The property id_sources 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...
63
	}
64
65
	/**
66
	 * Signs an array of scalars with the self-hosted blog's Jetpack Token
67
	 *
68
	 * @param array $parameters
69
	 * @param string $key
70
	 * @return string HMAC
71
	 */
72
	static function sign_remote_comment_parameters( $parameters, $key ) {
73
		unset(
74
			$parameters['sig'],       // Don't sign the signature
75
			$parameters['replytocom'] // This parameter is unsigned - it changes dynamically as the comment form moves from parent comment to parent comment
76
		);
77
78
		ksort( $parameters );
79
80
		$signing = array();
81
		foreach ( $parameters as $k => $v ) {
82
			if ( !is_scalar( $v ) ) {
83
				return new WP_Error( 'invalid_input', __( 'Invalid request', 'jetpack' ) );
84
			}
85
86
			$signing[] = "{$k}={$v}";
87
		}
88
89
		return hash_hmac( 'sha1', implode( ':', $signing ), $key );
90
	}
91
92
	/*
93
 	 * After commenting as a guest while logged in, the user needs to see both:
94
	 *
95
	 * ( user_id = blah AND comment_approved = 0 )
96
	 * and
97
	 * ( comment_author_email = blah AND comment_approved = 0 )
98
	 *
99
 	 * Core only does the first since the user is logged in.
100
 	 *
101
 	 * Add the second to the comments array.
102
 	 */
103
	function comments_array( $comments ) {
104
		global $wpdb, $post;
105
106
		$commenter = $this->get_current_commenter();
107
108
		if ( !$commenter['user_id'] )
109
			return $comments;
110
111
		if ( !$commenter['comment_author'] )
112
			return $comments;
113
114
		$in_moderation_comments = $wpdb->get_results( $wpdb->prepare(
115
			"SELECT * FROM `$wpdb->comments` WHERE `comment_post_ID` = %d AND `user_id` = 0 AND `comment_author` = %s AND `comment_author_email` = %s AND `comment_approved` = '0' ORDER BY `comment_date_gmt` /* Highlander_Comments_Base::comments_array() */",
116
			$post->ID,
117
			wp_specialchars_decode( $commenter['comment_author'], ENT_QUOTES ),
118
			$commenter['comment_author_email']
119
		) );
120
121
		if ( !$in_moderation_comments )
122
			return $comments;
123
124
		// @todo ZOMG this is a bad idea
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
125
		$comments = array_merge( $comments, $in_moderation_comments );
126
		usort( $comments, array( $this, 'sort_comments_by_comment_date_gmt' ) );
127
128
		return $comments;
129
	}
130
131
	/**
132
	 * Comment sort comparator: comment_date_gmt
133
	 *
134
	 * @since JetpackComments (1.4)
135
	 * @param object $a
136
	 * @param object $b
137
	 * @return int
138
	 */
139
	public function sort_comments_by_comment_date_gmt( $a, $b ) {
140
		if ( $a->comment_date_gmt == $b->comment_date_gmt ) {
141
			return 0;
142
		}
143
144
		return $a->comment_date_gmt < $b->comment_date_gmt ? -1 : 1;
145
	}
146
147
	/**
148
	 * Get the current commenter's information from their cookie
149
	 *
150
	 * @since JetpackComments (1.4)
151
	 * @return array Commenters information from cookie
152
	 */
153
	protected function get_current_commenter() {
154
		// Defaults
155
		$user_id              = 0;
156
		$comment_author       = '';
157
		$comment_author_email = '';
158
		$comment_author_url   = '';
159
160
		if ( isset( $_COOKIE['comment_author_' . COOKIEHASH] ) ) {
161
			$comment_author = $_COOKIE['comment_author_' . COOKIEHASH];
162
		}
163
164
		if ( isset( $_COOKIE['comment_author_email_' . COOKIEHASH] ) ) {
165
			$comment_author_email = $_COOKIE['comment_author_email_' . COOKIEHASH];
166
		}
167
168
		if ( isset( $_COOKIE['comment_author_url_' . COOKIEHASH] ) ) {
169
			$comment_author_url = $_COOKIE['comment_author_url_' . COOKIEHASH];
170
		}
171
172
		if ( is_user_logged_in() ) {
173
			$user    = wp_get_current_user();
174
			$user_id = $user->ID;
175
		}
176
177
		return compact( 'comment_author', 'comment_author_email', 'comment_author_url', 'user_id' );
178
	}
179
180
	/**
181
	 * Allows a logged out user to leave a comment as a facebook or twitter credentialed user.
182
	 * Overrides WordPress' core comment_registration option to treat these commenters as "registered" (verified) users.
183
	 *
184
	 * @since JetpackComments (1.4)
185
	 * @return If no
186
	 */
187
	function allow_logged_out_user_to_comment_as_external() {
188
		if ( !$this->is_highlander_comment_post( 'facebook', 'twitter', 'googleplus' ) ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->is_highlander_com...twitter', 'googleplus') of type false|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
189
			return;
190
		}
191
192
		add_filter( 'pre_option_comment_registration', '__return_zero' );
193
	}
194
195
	/**
196
	 * Allow a logged in user to post as a guest, FB, or twitter credentialed request.
197
	 * Bypasses WordPress' core overrides that force a logged in user to comment as that user.
198
	 * Respects comment_registration option.
199
	 *
200
	 * @since JetpackComments (1.4)
201
	 * @param array $comment_data
202
	 * @return int
203
	 */
204
	function allow_logged_in_user_to_comment_as_guest( $comment_data ) {
205
		// Bail if user registration is allowed
206
		if ( get_option( 'comment_registration' ) ) {
207
			return $comment_data;
208
		}
209
210
		// Bail if user is not logged in or not a post request
211
		if ( 'POST' != strtoupper( $_SERVER['REQUEST_METHOD'] ) || !is_user_logged_in() ) {
212
			return $comment_data;
213
		}
214
215
		// Bail if this is not a guest or external service credentialed request
216
		if ( !$this->is_highlander_comment_post( 'guest', 'facebook', 'twitter', 'googleplus' ) ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->is_highlander_com...twitter', 'googleplus') of type false|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
217
			return $comment_data;
218
		}
219
220
		$user = wp_get_current_user();
221
222
		foreach ( array( 'comment_author' => 'display_name', 'comment_author_email' => 'user_email', 'comment_author_url' => 'user_url' ) as $comment_field => $user_field ) {
223
			if ( $comment_data[$comment_field] != addslashes( $user->$user_field ) ) {
224
				return $comment_data; // some other plugin already did something funky
225
			}
226
		}
227
228
		if ( get_option( 'require_name_email' ) ) {
229
			if ( 6 > strlen( $_POST['email'] ) || empty( $_POST['author'] ) ) {
230
				wp_die( __( 'Error: please fill the required fields (name, email).', 'jetpack' ) );
231
			} elseif ( ! is_email( $_POST['email'] ) ) {
232
				wp_die( __( 'Error: please enter a valid email address.', 'jetpack' ) );
233
			}
234
		}
235
236
		$author_change = false;
237
		foreach ( array( 'comment_author' => 'author', 'comment_author_email' => 'email', 'comment_author_url' => 'url' ) as $comment_field => $post_field ) {
238
			if ( $comment_data[$comment_field] != $_POST[$post_field] && 'url' != $post_field ) {
239
				$author_change = true;
240
			}
241
			$comment_data[$comment_field] = $_POST[$post_field];
242
		}
243
244
		// Mark as guest comment if name or email were changed
245
		if ( $author_change ) {
246
			$comment_data['user_id'] = $comment_data['user_ID'] = 0;
247
		}
248
249
		return $comment_data;
250
	}
251
252
	/**
253
	 * Set the comment cookies or bail if comment is invalid
254
	 *
255
	 * @since JetpackComments (1.4)
256
	 * @param type $comment_id
257
	 * @return If comment is invalid
258
	 */
259
	public function set_comment_cookies( $comment_id ) {
260
		// Get comment and bail if it's invalid somehow
261
		$comment = get_comment( $comment_id );
262
		if ( empty( $comment ) || is_wp_error( $comment ) ) {
263
			return;
264
		}
265
266
		$id_source = $this->is_highlander_comment_post();
267
		if ( empty( $id_source ) ) {
268
			return;
269
		}
270
271
		// Set comment author cookies
272
		if ( ( 'wordpress' != $id_source ) && is_user_logged_in() ) {
273
			/** This filter is already documented in core/wp-includes/comment-functions.php */
274
			$comment_cookie_lifetime = apply_filters( 'comment_cookie_lifetime', 30000000 );
275
			setcookie( 'comment_author_'       . COOKIEHASH, $comment->comment_author, time() + $comment_cookie_lifetime,              COOKIEPATH, COOKIE_DOMAIN );
276
			setcookie( 'comment_author_email_' . COOKIEHASH, $comment->comment_author_email, time() + $comment_cookie_lifetime,        COOKIEPATH, COOKIE_DOMAIN );
277
			setcookie( 'comment_author_url_'   . COOKIEHASH, esc_url($comment->comment_author_url), time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN );
278
		}
279
	}
280
281
	/**
282
 	 * Get an avatar from Photon
283
 	 *
284
 	 * @since JetpackComments (1.4)
285
 	 * @param string $url
286
 	 * @param int $size
287
 	 * @return string
288
 	 */
289
	protected function photon_avatar( $url, $size ) {
290
		$size = (int) $size;
291
292
		return jetpack_photon_url( $url, array( 'resize' => "$size,$size" ) );
293
	}
294
}
295