Issues (103)

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/functions-popup.php (1 issue)

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
 * BetterOptin Popup
4
 *
5
 * @package   BetterOptin/Popup
6
 * @author    ThemeAvenue <[email protected]>
7
 * @license   GPL-2.0+
8
 * @link      http://themeavenue.net
9
 * @copyright 2015 ThemeAvenue
10
 */
11
12
// If this file is called directly, abort.
13
if ( ! defined( 'WPINC' ) ) {
14
	die;
15
}
16
17
/**
18
 * Check if a popup is available for the current page.
19
 *
20
 * The function checks, in this order, if a popup is available for:
21
 * - The current post
22
 * - The current post type
23
 * - The whole site
24
 *
25
 * @since  1.0.0
26
 *
27
 * @param int $post_id Optional post ID to check for popup availability
28
 *
29
 * @return bool|int Popup ID if a popup is available, false otherwise
30
 */
31
function wpbo_page_has_popup( $post_id = 0 ) {
32
33
	/**
34
	 * Checks in order:
35
	 *
36
	 * 1. Front-page
37
	 * 2. Homepage
38
	 * 3. Archives
39
	 *  3.1 Search
40
	 *  3.2 Post type
41
	 * 4. 404
42
	 * 5. Singular
43
	 */
44
45
	$post_id = wpbo_get_post_id( $post_id );
46
47
	/**
48
	 * First of all let's check if the user is an admin
49
	 * and if popups are hidden for admins.
50
	 */
51
	if ( is_user_logged_in() && current_user_can( 'administrator' ) && true === (bool) wpbo_get_option( 'hide_admins', false ) ) {
52
		return false;
53
	}
54
55
	// Try to get the popup from the cache
56
	$popup_id = wpbo_get_cached_popup( $post_id );
57
58
	if ( false === $popup_id ) {
59
		$popup_id = wpbo_get_popup( $post_id );
60
	}
61
62
	// Cache popup ID to avoid calculating again on page refresh */
63
	if ( false !== $popup_id ) {
64
		wpbo_cache_popup( $popup_id, $post_id );
65
	}
66
67
	return $popup_id;
68
69
}
70
71
/**
72
 * Get the active popup for a given post, if any
73
 *
74
 * @since 2.0
75
 *
76
 * @param int $post_id Post ID
77
 *
78
 * @return bool|int
79
 */
80
function wpbo_get_popup( $post_id = 0 ) {
81
82
	$post_id  = wpbo_get_post_id( $post_id );
83
	$popup_id = false;
0 ignored issues
show
$popup_id is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
84
85
	if ( ! $post_id ) {
86
		return false;
87
	}
88
89
	// Get the global popups / posts relationships
90
	$relationships = get_option( 'wpbo_popup_relationships', array() );
91
92
	// Get current post type
93
	$post_type = get_post_type( $post_id );
94
95
	/**
96
	 * If this post ID is found in the relationships then it means it has a popup attached.
97
	 */
98
	if ( is_array( $relationships ) && array_key_exists( $post_id, $relationships ) && 'publish' == get_post_status( $relationships[ $post_id ] ) ) {
99
		return (int) $relationships[ $post_id ];
100
	} /**
101
	 * Let's check for more global popups
102
	 */
103
	else {
104
105
		// Check if there is a popup for the current post type first of all
106
		$popup_id = wpbo_get_post_type_popup( $post_type );
107
108
		if ( false === $popup_id ) {
109
			$popup_id = wpbo_get_sitewide_popup();
110
		}
111
112
	}
113
114
	return $popup_id;
115
116
}
117
118
/**
119
 * Get the popup for a given post type ONLY
120
 *
121
 * This means that we're looking for popups that are specifically set for the post type
122
 * and NOT set globally.
123
 *
124
 * @since 2.0
125
 *
126
 * @param string $post_type
127
 *
128
 * @return bool
129
 */
130
function wpbo_get_post_type_popup( $post_type = '' ) {
131
132
	if ( empty( $post_type ) ) {
133
		return false;
134
	}
135
136
	if ( ! post_type_exists( $post_type ) ) {
137
		return false;
138
	}
139
140
	$query_args = array(
141
		'post_type'              => 'wpbo-popup',
142
		'post_status'            => 'publish',
143
		'order'                  => 'DESC',
144
		'orderby'                => 'date',
145
		'posts_per_page'         => 1,
146
		'no_found_rows'          => true,
147
		'cache_results'          => false,
148
		'update_post_term_cache' => false,
149
		'update_post_meta_cache' => false,
150
		'meta_query'             => array(
151
			'relation' => 'AND',
152
			array(
153
				'key'     => '_wpbo_display_' . $post_type,
154
				'value'   => 'all',
155
				'type'    => 'CHAR',
156
				'compare' => '='
157
			),
158
			array(
159
				'key'     => '_wpbo_display_all', // We want to exclude popups set globally
160
				'value'   => 'no',
161
				'type'    => 'CHAR',
162
				'compare' => '='
163
			)
164
		),
165
	);
166
167
	$query = new WP_Query( $query_args );
168
169
	if ( isset( $query->post ) ) {
170
		return $query->post->ID;
171
	}
172
173
	return false;
174
175
}
176
177
/**
178
 * Get site-wide popup
179
 *
180
 * @since 2.0
181
 * @return bool|int
182
 */
183
function wpbo_get_sitewide_popup() {
184
185
	$query_args = array(
186
		'post_type'              => 'wpbo-popup',
187
		'post_status'            => 'publish',
188
		'order'                  => 'DESC',
189
		'orderby'                => 'date',
190
		'posts_per_page'         => 1,
191
		'no_found_rows'          => true,
192
		'cache_results'          => false,
193
		'update_post_term_cache' => false,
194
		'update_post_meta_cache' => false,
195
		'meta_query'             => array(
196
			array(
197
				'key'     => '_wpbo_display_all',
198
				'value'   => 'yes',
199
				'type'    => 'CHAR',
200
				'compare' => '='
201
			)
202
		),
203
	);
204
205
	$query = new WP_Query( $query_args );
206
207
	if ( isset( $query->post ) ) {
208
		return $query->post->ID;
209
	}
210
211
	return false;
212
213
}
214
215
/**
216
 * Get the cached popup for a specific page
217
 *
218
 * @since 2.0
219
 *
220
 * @param int $post_id Post ID
221
 *
222
 * @return bool|int
223
 */
224
function wpbo_get_cached_popup( $post_id = 0 ) {
225
226
	$post_id  = wpbo_get_post_id( $post_id );
227
	$popup_id = false;
228
229
	if ( ! $post_id ) {
230
		return false;
231
	}
232
233
	if ( isset( $_SESSION['wpbo'][ $post_id ] ) ) {
234
235
		$popup_id = (int) $_SESSION['wpbo'][ $post_id ];
236
237
		if ( ! WPBO_Popup::popup_exists( $popup_id ) ) {
238
			return false;
239
		}
240
241
		$status = get_post_status( $popup_id );
242
243
		/* Make sure the popup hasn't been disabled while browsing */
244
		if ( 'publish' != $status ) {
245
246
			unset( $_SESSION['wpbo'][ $post_id ] );
247
248
			return false;
249
250
		}
251
252
	}
253
254
	return $popup_id;
255
256
}
257
258
/**
259
 * Cache the ID of an available popup for a specific post
260
 *
261
 * @since 2.0
262
 *
263
 * @param int $popup_id ID of the popup ot cache
264
 * @param int $post_id  ID of the post where it's available
265
 *
266
 * @return void
267
 */
268
function wpbo_cache_popup( $popup_id, $post_id ) {
269
	$_SESSION['wpbo'][ $post_id ] = $popup_id;
270
}
271
272
add_action( 'before_delete_post', 'wpbo_delete_post_relationships' );
273
/**
274
 * Delete Post Relationships.
275
 *
276
 * Delete all relationships when a popup
277
 * is deleted by the user.
278
 *
279
 * @since  1.0.0
280
 *
281
 * @param  bool $post_id ID of the post to be deleted
282
 */
283
function wpbo_delete_post_relationships( $post_id ) {
284
285
	$relationships = $new = get_option( 'wpbo_popup_relationships', array() );
286
	$post_types    = get_post_types( array( 'public' => true ) );
287
	$except        = array( 'attachment', 'wpbo-popup' );
288
289
	/* Iterate through all allowed post types */
290
	foreach ( $post_types as $key => $pt ) {
291
292
		if ( in_array( $key, $except ) ) {
293
			continue;
294
		}
295
296
		/* Get relationships for this post type */
297
		$display = get_post_meta( $post_id, '_wpbo_display_' . $pt, true );
298
299
		if ( is_array( $display ) ) {
300
301
			foreach ( $display as $key => $post ) {
302
303
				/* Remove deprecated relations */
304
				if ( isset( $new[ $post ] ) ) {
305
					unset( $new[ $post ] );
306
				}
307
308
			}
309
310
		}
311
312
	}
313
314
	/* Update relationships if needed only */
315
	if ( serialize( $relationships ) !== serialize( $new ) ) {
316
		update_option( 'wpbo_popup_relationships', $new );
317
	}
318
319
}
320
321
add_action( 'admin_notices', 'wpbo_unpublished_popup_notice' );
322
/**
323
 * Unpublished notice.
324
 *
325
 * Warn the user when the popup is not published yet.
326
 *
327
 * @since  1.0.0
328
 */
329
function wpbo_unpublished_popup_notice() {
330
331
	global $typenow, $post;
332
333
	if( 'wpbo-popup' == $typenow && isset( $_GET['post'] ) && isset( $post ) && 'draft' == $post->post_status ): ?>
334
335
		<div class="error">
336
			<p><?php _e( 'This popup is still in draft mode and is <strong>not visible on the site</strong>. Don\'t forget to publish it when you\'re ready.', 'betteroptin' ); ?></p>
337
		</div>
338
339
	<?php endif;
340
341
}
342
343
add_filter( 'wp_insert_post_data', 'wpbo_save_before_publish', 99, 2 );
344
/**
345
 * Prevent from publishing new popups.
346
 *
347
 * When a new popup is created, it is saved as a draft
348
 * in order to avoid publishing a non customized popup.
349
 *
350
 * @since  1.0.0
351
 *
352
 * @param  array $data    Sanitized post data
353
 * @param  array $postarr Raw post data
354
 *
355
 * @return array          Updated $data
356
 */
357
function wpbo_save_before_publish( $data, $postarr ) {
358
359
	if ( 'wpbo-popup' == $postarr['post_type'] && isset( $postarr['original_post_status'] ) ) {
360
361
		if ( 'auto-draft' == $postarr['original_post_status'] ) {
362
			$data['post_status'] = 'draft';
363
		}
364
365
		if ( 'draft' == $postarr['original_post_status'] ) {
366
367
			$customized = get_post_meta( $postarr['ID'], '_wpbo_template_display', true );
368
369
			if ( '' == $customized ) {
370
				$data['post_status'] = 'draft';
371
			}
372
373
		}
374
375
	}
376
377
	return apply_filters( 'wpbo_publish_button_action', $data, $postarr );
378
379
}
380
381
/**
382
 * Dismiss a popup.
383
 *
384
 * Set a cookie to prevent a specific popup from showing up
385
 * on the site. This function was made for other plugins to
386
 * have an easy way to hide a popup if needed.
387
 *
388
 * @since  1.0.1
389
 *
390
 * @param  integer $popup_id        ID of the popup to dismiss
391
 * @param  integer $cookie_lifetime Lifetime of the cookie in days
392
 *
393
 * @return boolean                  Result of the cookie insertion
394
 */
395
function wpbo_dismiss_popup( $popup_id = 0, $cookie_lifetime = 30 ) {
396
397
	if ( 0 === $popup_id ) {
398
		return false;
399
	}
400
401
	$cookie_lifetime = apply_filters( 'wpbo_cookie_lifetime', $cookie_lifetime, $popup_id );
402
403
	/* Set the cookie */
404
405
	return setcookie( 'wpbo_' . $popup_id, strtotime( date( 'Y-m-d H:i:s' ) ), time() + 60 * 60 * $cookie_lifetime, '/' );
406
407
}
408
409
/**
410
 * Check if a popup has been dismissed by the visitor
411
 *
412
 * @since 2.0
413
 *
414
 * @param int $popup_id Popup ID
415
 *
416
 * @return bool
417
 */
418
function wpbo_is_popup_dismissed( $popup_id ) {
419
420
	if ( ! WPBO_Popup::popup_exists( $popup_id ) ) {
421
		return false;
422
	}
423
424
	if ( isset( $_COOKIE["wpbo_$popup_id"] ) ) {
425
		return true;
426
	}
427
428
	return false;
429
430
}
431
432
add_action( 'wp_footer', 'wpbo_maybe_load_popup' );
433
/**
434
 * Check if the current page has a popup and if the current visitor hasn't dismissed it already
435
 *
436
 * @since 2.0
437
 * @return void
438
 */
439
function wpbo_maybe_load_popup() {
440
441
	// If the provider is not ready we don't display the popup at all
442
	if ( ! wpbo_is_provider_ready() ) {
443
		return;
444
	}
445
446
	$popup_id = wpbo_page_has_popup();
447
	$post_id  = wpbo_get_post_id();
448
449
	if ( false === $popup_id ) {
450
		return;
451
	}
452
453
	if ( wpbo_is_popup_dismissed( $popup_id ) ) {
454
455
		if ( false === $post_id ) {
456
			return;
457
		}
458
459
		$post = get_post( $post_id );
460
461
		if ( is_null( $post ) ) {
462
			return;
463
		}
464
465
		/**
466
		 * Because the popups can be triggered by a button (generated by a shortcode), we want to load the popup markup
467
		 * EVEN IF it has been dismissed when the trigger button is present in the post content.
468
		 */
469
		if ( ! has_shortcode( $post->post_content, 'wpbo_popup' ) ) {
470
			return;
471
		}
472
473
	}
474
475
	$popup = new WPBO_Popup( $popup_id );
476
477
	$popup->popup();
478
479
}
480
481
add_action( 'plugins_loaded', 'wpbo_maybe_submit' );
482
/**
483
 * Maybe submit a popup
484
 *
485
 * If a popup has been submitted we process the submission
486
 * and then redirect the user based on the submission result.
487
 *
488
 * @since 2.0
489
 * @return bool|void
490
 */
491
function wpbo_maybe_submit() {
492
493
	if ( ! isset( $_POST['wpbo_nonce'] ) || ! wp_verify_nonce( $_POST['wpbo_nonce'], 'subscribe' ) ) {
494
		return;
495
	}
496
497
	if ( ! isset( $_POST['wpbo_email'] ) || ! isset( $_POST['wpbo_id'] ) ) {
498
		return;
499
	}
500
501
	$popup_id = filter_input( INPUT_POST, 'wpbo_id', FILTER_SANITIZE_NUMBER_INT );
502
503
	if ( ! WPBO_Popup::popup_exists( $popup_id ) ) {
504
		return;
505
	}
506
507
	$popup = new WPBO_Popup( $popup_id );
508
	$popup->submit();
509
510
}
511
512
/**
513
 * Get all allowed form fields
514
 *
515
 * @since 2.0
516
 * @return array
517
 */
518
function wpbo_get_form_fields() {
519
520
	$fields = apply_filters( 'wpbo_form_fields', array(
521
		'email'      => array(
522
			'form_name'         => 'wpbo_email',
523
			'sanitize_callback' => 'sanitize_email'
524
		),
525
		'first_name' => array(
526
			'form_name'         => 'wpbo_first_name',
527
			'sanitize_callback' => 'sanitize_text_field'
528
		),
529
		'last_name'  => array(
530
			'form_name'         => 'wpbo_first_name',
531
			'sanitize_callback' => 'sanitize_text_field'
532
		),
533
		'name'       => array(
534
			'form_name'         => 'wpbo_name',
535
			'sanitize_callback' => 'sanitize_text_field'
536
		),
537
		'wpbo_id'    => array(
538
			'form_name'         => 'wpbo_id',
539
			'sanitize_callback' => 'intval'
540
		),
541
		'post_id'    => array(
542
			'form_name'         => 'post_id',
543
			'sanitize_callback' => 'intval'
544
		),
545
	) );
546
547
	return $fields;
548
549
}
550
551
/**
552
 * Helper function to get a popup's return URL
553
 *
554
 * @since 2.0.2
555
 *
556
 * @param int $popup_id Popup post ID
557
 *
558
 * @return bool|string
559
 */
560
function wpbo_get_return_url( $popup_id ) {
561
562
	$popup = get_post( $popup_id );
563
564
	if ( ! is_a( $popup, 'WP_Post' ) || 'wpbo-popup' !== $popup->post_type ) {
565
		return false;
566
	}
567
568
	$object = new WPBO_Popup( $popup->ID );
569
570
	return $object->get_return_url();
571
572
}