functions-analytics.php ➔ wpbo_db_sanitize_data()   B
last analyzed

Complexity

Conditions 8
Paths 8

Size

Total Lines 56
Code Lines 29

Duplication

Lines 10
Ratio 17.86 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 29
c 1
b 0
f 0
nc 8
nop 2
dl 10
loc 56
rs 7.3333

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Better Optin Analytics.
4
 *
5
 * BetterOptin Analytics API helping users interact
6
 * with the custom table where all popup related data
7
 * is recorded (impressions and conversions).
8
 *
9
 * @package   Better_Optin
10
 * @author    ThemeAvenue <[email protected]>
11
 * @license   GPL-2.0+
12
 * @link      http://themeavenue.net
13
 * @copyright 2014 ThemeAvenue
14
 */
15
16
/**
17
 * Create analytics table.
18
 *
19
 * @since  1.0.0
20
 * @return void
21
 */
22 View Code Duplication
function wpbo_create_table() {
0 ignored issues
show
Duplication introduced by
This function 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...
23
24
	global $wpdb;
25
26
	$table = wpbo_analytics_table;
27
28
	/* Prepare DB structure if not already existing */
29
	if ( $wpdb->get_var( "show tables like '$table'" ) != $table ) {
30
31
		$sql = "CREATE TABLE $table (
32
				data_id mediumint(9) NOT NULL AUTO_INCREMENT,
33
				time datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
34
				data_type VARCHAR(20) COLLATE utf8_general_ci NOT NULL,
35
				popup_id bigint(20) NOT NULL,
36
				user_agent VARCHAR(128) DEFAULT '' COLLATE utf8_general_ci NOT NULL,
37
				referer VARCHAR(256) DEFAULT '' COLLATE utf8_general_ci NOT NULL,
38
				ip_address VARCHAR(128) DEFAULT '0.0.0.0' COLLATE utf8_general_ci NOT NULL,
39
				UNIQUE KEY data_id (data_id)
40
				);";
41
42
		require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
43
		dbDelta( $sql );
44
45
	}
46
47
}
48
49
/**
50
 * Insert new data.
51
 *
52
 * Add a new row of data in the analytics table.
53
 *
54
 * @since  1.0.0
55
 *
56
 * @param  array   $data     Details of the data to add
57
 * @param  boolean $wp_error Allow the function to return a WP_Error object
58
 *
59
 * @return mixed          Data ID on success or WP_Error on failure
60
 */
61
function wpbo_db_insert_data( $data = array(), $wp_error = true ) {
62
63
	global $wpdb;
64
65
	$table_name = wpbo_analytics_table;
66
67
	$defaults = array(
68
		'data_id'    => false,
69
		'time'       => '',
70
		'data_type'  => apply_filters( 'wpbo_default_data_type', 'impression' ),
71
		'popup_id'   => false,
72
		'user_agent' => '',
73
		'referer'    => '',
74
		'ip_address' => '0.0.0.0',
75
	);
76
77
	$data = array_merge( $defaults, $data );
78
79
	/* Sanitize all data values */
80
	$clean = wpbo_db_sanitize_data( $data, $wp_error );
81
82
	/* If sanitization failed return the error */
83
	if ( is_wp_error( $clean ) ) {
84
		if ( $wp_error ) {
85
			return $clean;
86
		} else {
87
			return false;
88
		}
89
	}
90
91
	/**
92
	 * Are we updating or creating?
93
	 */
94
	if ( isset( $clean['data_id'] ) && false !== $clean['data_id'] && is_int( $clean['data_id'] ) ) {
95
		$insert = wpbo_db_update_data( $clean, $wp_error ); // @todo test the update through insert_data()
96
		return $insert;
97
	} else {
98
99
		$insert = $wpdb->insert( $table_name, $clean, array( '%s', '%s', '%d', '%s', '%s', '%s' ) );
100
101 View Code Duplication
		if ( false === $insert ) {
0 ignored issues
show
Duplication introduced by
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...
102
			if ( $wp_error ) {
103
				return new WP_Error( 'insert_failed', __( 'Whoops, we could not insert the data in the database.' ) );
104
			} else {
105
				return false;
106
			}
107
		} else {
108
			return $wpdb->insert_id;
109
		}
110
111
	}
112
113
}
114
115
/**
116
 * Remove a row.
117
 *
118
 * @since  1.0.0
119
 *
120
 * @param  boolean $data_id ID of the data to delete
121
 *
122
 * @return boolean          Returns true on success or false on failure
123
 */
124
function wpbo_db_remove_data( $data_id = false ) {
125
126
	if ( false === $data_id || ! is_int( $data_id ) ) {
127
		return false;
128
	}
129
130
	global $wpdb;
131
132
	$table_name = wpbo_analytics_table;
133
134
	$delete = $wpdb->delete( $table_name, array( 'data_id' => $data_id ), array( '%d' ) );
135
136
	return $delete;
137
}
138
139
/**
140
 * Update data row.
141
 *
142
 * @since  1.0.0
143
 *
144
 * @param  array   $data     Default array of data elements
145
 * @param  boolean $wp_error Is the function allowed to return a WP_Error object
146
 *
147
 * @return string
148
 */
149
function wpbo_db_update_data( $data = array(), $wp_error = true ) {
150
151
	global $wpdb;
152
153
	$defaults = array(
154
		'data_id' => '',
155
	);
156
157
	$data = array_merge( $defaults, $data );
158
159
	/**
160
	 * Check the popup ID (required).
161
	 */
162
	if ( empty( $data['data_id'] ) || ! is_int( $data['data_id'] ) ) {
163
		if ( $wp_error ) {
164
			return new WP_Error( 'no_data_id', __( 'Whoops, no data ID was provided.' ) );
165
		} else {
166
			return false;
167
		}
168
	}
169
170
	$table_name = wpbo_analytics_table;
171
	$ID         = (int) $data['data_id'];
172
173
	if ( false === $ID || ! is_int( $ID ) ) {
174
		if ( true === $wp_error ) {
175
			return new WP_Error( 'no_id', __( 'You did not pass the ID of the data to update.' ) );
176
		} else {
177
			return false;
178
		}
179
	}
180
181
	/* Previous data row */
182
	$prev = wpbo_db_get_data( $ID );
183
184
	$data = array_merge( $prev, $data );
185
186
	/* Sanitize all data values */
187
	$clean = wpbo_db_sanitize_data( $data, $wp_error );
188
189
	/* Do the update */
190
	$update = $wpdb->update( $table_name, $clean, array( 'data_id' => $ID ) );
191
192
	if ( false === $update ) {
193
		if ( true === $wp_error ) {
194
			return new WP_Error( 'update_error', __( 'An error occured while trying to update the data.' ) );
195
		} else {
196
			return false;
197
		}
198
	} else {
199
		return $update;
200
	}
201
202
}
203
204
/**
205
 * Sanitize data row.
206
 *
207
 * @param  array $data     Array of data elements to sanitize
208
 * @param bool   $wp_error Whether or not to return a WP_Error object in case of problem
209
 *
210
 * @return array        A clean array of data elements
211
 */
212
function wpbo_db_sanitize_data( $data = array(), $wp_error = true ) {
213
214
	$defaults = array( 'data_id'    => false,
215
	                   'time'       => false,
216
	                   'data_type'  => false,
217
	                   'popup_id'   => false,
218
	                   'user_agent' => false,
219
	                   'referer'    => false,
220
	                   'ip_address' => false
221
	);
222
223
	$data = array_merge( $defaults, $data );
224
225 View Code Duplication
	if ( empty( $data['time'] ) || '0000-00-00 00:00:00' == $data['time'] ) {
0 ignored issues
show
Duplication introduced by
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...
226
		$data['time'] = current_time( 'mysql' );
227
	}
228
229
	/**
230
	 * Validate the date
231
	 */
232
	$valid_date = wpbo_check_date( $data['time'] );
233
234 View Code Duplication
	if ( ! $valid_date ) {
0 ignored issues
show
Duplication introduced by
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...
235
		if ( $wp_error ) {
236
			return new WP_Error( 'invalid_date', __( 'Whoops, the provided date is invalid.' ) );
237
		} else {
238
			return false;
239
		}
240
	}
241
242
	/**
243
	 * Possibly filter the IP address
244
	 */
245
	if ( '1' == wpbo_get_option( 'anonymize_ip', false ) && false !== $data['ip_address'] && '0.0.0.0' !== $data['ip_address'] ) {
246
247
		$ip_breakdown       = explode( '.', $data['ip_address'] );
248
		$ip_breakdown[3]    = '*';
249
		$data['ip_address'] = implode( '.', $ip_breakdown );
250
251
	}
252
253
	/**
254
	 * Recreate the sanitized array of data elements
255
	 */
256
	$clean = array(
257
		'time'       => $data['time'],
258
		'data_type'  => $data['data_type'],
259
		'popup_id'   => $data['popup_id'],
260
		'user_agent' => $data['user_agent'],
261
		'referer'    => $data['referer'],
262
		'ip_address' => $data['ip_address'],
263
	);
264
265
	return $clean;
266
267
}
268
269
/**
270
 * Get data.
271
 *
272
 * Get the entire row for a specific data.
273
 *
274
 * @since  1.0.0
275
 *
276
 * @param  integer $data_id ID of the data to retrieve
277
 * @param  string  $output  Type of data the user want to be returned
278
 *
279
 * @return mixed            Data of type $output
280
 */
281
function wpbo_db_get_data( $data_id = null, $output = 'ARRAY_A' ) {
282
283
	global $wpdb;
284
285
	if ( is_null( $data_id ) || ! is_int( $data_id ) ) {
286
		return false;
287
	}
288
289
	$row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM %s WHERE data_id = %s", wpbo_analytics_table, $data_id ), $output );
290
291
	return $row;
292
293
}
294
295
/**
296
 * Get a set of datas.
297
 *
298
 * Retrieve a set of datas based on the user
299
 * criterias. This function can return one or
300
 * more row(s) of data depending on the arguments;
301
 *
302
 * @param  array $args   Arguments
303
 * @param string $output Desired output format
304
 *
305
 * @return mixed
306
 */
307
function wpbo_db_get_datas( $args, $output = 'OBJECT' ) {
308
309
	global $wpdb;
310
311
	$table_name = wpbo_analytics_table;
312
	$query      = array();
313
314
	$defaults = array(
315
		'data_type'  => 'any',
316
		'user_agent' => '',
317
		'referer'    => '',
318
		'popup_id'   => '',
319
		'date'       => array(),
320
		'limit'      => 5,
321
		'period'     => ''
322
	);
323
324
	$args = array_merge( $defaults, $args );
325
326
	/**
327
	 * Handle the limit
328
	 */
329
	if ( - 1 === $args['limit'] ) {
330
		$args['limit'] = 1000;
331
	}
332
333
	/**
334
	 * Handle data type first
335
	 */
336
	if ( is_array( $args['data_type'] ) ) {
337
338
		$relation = ( isset( $args['data_type']['relation'] ) && in_array( $args['data_type']['relation'], array(
339
				'IN',
340
				'NOT IN'
341
			) ) ) ? $args['data_type']['relation'] : 'IN';
342
		$types    = array();
343
344
		foreach ( $args['data_type']['type'] as $type ) {
345
			array_push( $types, "'$type'" );
346
		}
347
348
		$types = implode( ',', $types );
349
		array_push( $query, "data_type $relation ($types)" );
350
351
	} elseif ( '' != $args['data_type'] ) {
352
		if ( 'any' == $args['data_type'] ) {
353
			array_push( $query, "data_type IN ( 'impression', 'conversion' )" );
354
		} else {
355
			array_push( $query, "data_type = '{$args['data_type']}'" );
356
		}
357
	}
358
359
	/**
360
	 * Handle the popup_id
361
	 *
362
	 * @todo test
363
	 */
364
	if ( is_array( $args['popup_id'] ) ) {
365
366
		$relation = ( isset( $args['popup_id']['relation'] ) && in_array( $args['popup_id']['relation'], array(
367
				'IN',
368
				'NOT IN'
369
			) ) ) ? $args['popup_id']['relation'] : 'IN';
370
		$popups   = array();
371
372
		foreach ( $args['popup_id']['ids'] as $popup ) {
373
			array_push( $popups, "$popup" );
374
		}
375
376
		$popups = implode( ',', $popups );
377
		array_push( $query, "popup_id $relation ($popups)" );
378
379
	} elseif ( '' != $args['popup_id'] ) {
380
		array_push( $query, "popup_id = {$args['popup_id']}" );
381
	}
382
383
	/**
384
	 * Handle the period.
385
	 */
386
	if ( '' != $args['period'] ) {
387
388
		if ( is_array( $args['period'] ) ) {
389
390
			$start = isset( $args['period']['from'] ) ? date( "Y-m-d", $args['period']['from'] ) : date( "Y-m-d", time() );
391
			$end   = isset( $args['period']['to'] ) ? date( "Y-m-d", $args['period']['to'] ) : date( "Y-m-d", time() );
392
393
			$start = ( true === wpbo_check_date( $start ) ) ? $start . ' 00:00:00' : date( "Y-m-d", time() ) . ' 00:00:00';
394
			$end   = ( true === wpbo_check_date( $end ) ) ? $end . ' 23:59:59' : date( "Y-m-d", time() ) . ' 23:59:59';
395
396
			array_push( $query, "time BETWEEN '$start' AND '$end'" );
397
398
		} else {
399
400
			/* Get datetime format */
401
			$date  = date( "Y-m-d", $args['period'] );
402
			$start = "$date 00:00:00";
403
			$end   = "$date 23:59:59";
404
405
			array_push( $query, "time BETWEEN '$start' AND '$end'" );
406
407
		}
408
409
	}
410
411
	/* Merge the query */
412
	$limit = (int) $args['limit'];
413
	$query = implode( ' AND ', $query );
414
	$rows  = $wpdb->get_results( "SELECT * FROM $table_name WHERE $query LIMIT $limit", $output );
415
416
	return $rows;
417
418
}
419
420
/*----------------------------------------------------------------------------*
421
 * Helper Functions
422
 *----------------------------------------------------------------------------*/
423
424
/**
425
 * Today's Conversion Rate.
426
 *
427
 * Get today's conversion rate using the stats class.
428
 *
429
 * @since  1.2.2
430
 *
431
 * @param  integer $decimals      Number of decimal to return for the conversion rate
432
 * @param  string  $dec_point     Separator for the decimal point
433
 * @param  string  $thousands_sep Separator for the thousands
434
 *
435
 * @return integer                Conversion rate for the day
436
 */
437
function wpbo_today_conversion( $decimals = 2, $dec_point = '.', $thousands_sep = ',' ) {
438
439
	/* Prepare the query. */
440
	$query = array( 'data_type' => 'any', 'limit' => - 1, 'period' => strtotime( 'today' ) );
441
442
	/* Get the datas. */
443
	$datas = wpbo_db_get_datas( $query, 'OBJECT' );
444
445
	/* Set the count vars. */
446
	$impressions = 0;
447
	$conversions = 0;
448
449
	/* Check the number of conversions. */
450
	foreach ( $datas as $data ) {
451
452
		/* Increment conversions */
453
		if ( 'conversion' == $data->data_type ) {
454
			++ $conversions;
455
		}
456
457
		/* Increment impressions */
458
		if ( 'impression' == $data->data_type ) {
459
			++ $impressions;
460
		}
461
462
	}
463
464
	/* Get the conversion rate. */
465
	$rate = ( 0 === $conversions || 0 === $impressions ) ? 0 : ( $conversions * 100 ) / $impressions;
466
467
	return number_format( $rate, $decimals, $dec_point, $thousands_sep );
468
469
}
470
471
/**
472
 * Fills an entire period with specific time points
473
 *
474
 * Takes an array of data (either impressions or conversions) and populates all the hits
475
 * on a specific period of time. If the data array doesn't contain data for one or more
476
 * time points, then the empty points are set to 0.
477
 *
478
 * @param array  $data        Impressions or conversions data
479
 * @param int    $min         Timestamp at the beginning for the timeframe
480
 * @param int    $max         Timestamp at the end of the timeframe
481
 * @param string $increment   Increment delay (eg. 1 hour, 1 day...)
482
 * @param string $date_format Date format for the given timeframe
483
 *
484
 * @return array
485
 */
486
function wpbo_fill_hits_period( $data, $min, $max, $increment, $date_format ) {
487
488
	$timeframe = array();
489
490
	for ( $date = $min; $date <= $max; $date = strtotime( date( $date_format, $date ) . " + $increment" ) ) {
491
		$timeframe[ $date ] = array_key_exists( $date, $data ) ? $data[ $date ] : 0;
492
	}
493
494
	return wpbo_float_format( $timeframe );
495
496
}
497
498
/**
499
 * Format our timeframe array for jQuery Flot
500
 *
501
 * Flot uses a very specific format where the data must be an array of arrays.
502
 * Also, all timestamps must be in milliseconds. This functions does all the formatting.
503
 *
504
 * @param array $array Data in a predefined timeframe
505
 *
506
 * @return array array Data formatted for Flot
507
 */
508
function wpbo_float_format( $array ) {
509
510
	$new = array();
511
	
512
	foreach ( $array as $timestamp => $hits ) {
513
		array_push( $new, array( $timestamp * 1000, $hits ) ); // Timestamp must be in miliseconds
514
	}
515
516
	return $new;
517
518
}