Completed
Pull Request — master (#2278)
by ྅༻ Ǭɀħ
14:42
created

includes/functions-infos.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
/**
4
 * Echoes an image tag of Google Charts map from sorted array of 'country_code' => 'number of visits' (sort by DESC)
5
 *
6
 */
7
function yourls_stats_countries_map( $countries, $id = null ) {
8
9
	yourls_do_action( 'pre_stats_countries_map' );
10
	
11
	// if $id is null then assign a random string
12
	if( $id === null )
13
		$id = uniqid ( 'yourls_stats_map_' );
14
15
	$data = array_merge( array( 'Country' => 'Hits' ), $countries );
16
	$data = yourls_google_array_to_data_table( $data );
17
18
	$options = array(
19
		'backgroundColor' => "white",
20
		'colorAxis'       => "{colors:['A8D0ED','99C4E4','8AB8DB','7BACD2','6BA1C9','5C95C0','4D89B7','3E7DAE','2E72A5','1F669C']}",
21
		'width'           => "550",
22
		'height'          => "340",
23
		'theme'           => 'maximized'
24
	);
25
	$options = yourls_apply_filter( 'stats_countries_map_options', $options );
26
	
27
	$map = yourls_google_viz_code( 'GeoChart', $data, $options, $id );
28
29
	echo yourls_apply_filter( 'stats_countries_map', $map, $countries, $options, $id );
30
}
31
32
/**
33
 * Echoes an image tag of Google Charts pie from sorted array of 'data' => 'value' (sort by DESC). Optional $limit = (integer) limit list of X first countries, sorted by most visits
34
 *
35
 */
36
function yourls_stats_pie( $data, $limit = 10, $size = '340x220', $id = null ) {
37
38
	yourls_do_action( 'pre_stats_pie' );
39
	
40
	// if $id is null then assign a random string
41
	if( $id === null )
42
		$id = uniqid ( 'yourls_stats_pie_' );
43
44
	// Trim array: $limit first item + the sum of all others
45
	if ( count( $data ) > $limit ) {
46
		$i= 0;
47
		$trim_data = array( 'Others' => 0 );
48
		foreach( $data as $item=>$value ) {
49
			$i++;
50
			if( $i <= $limit ) {
51
				$trim_data[$item] = $value;
52
			} else {
53
				$trim_data['Others'] += $value;
54
			}
55
		}
56
		$data = $trim_data;
57
	}
58
	
59
	// Scale items
60
	$_data = yourls_scale_data( $data );
61
	
62
	list($width, $height) = explode( 'x', $size );
63
	
64
	$options = array(
65
		'theme'  => 'maximized',
66
		'width'   => $width,
67
		'height'   => $height,
68
		'colors'    => "['A8D0ED','99C4E4','8AB8DB','7BACD2','6BA1C9','5C95C0','4D89B7','3E7DAE','2E72A5','1F669C']",
69
		'legend'     => 'none',
70
		'chartArea'   => '{top: "5%", height: "90%"}',
71
		'pieSliceText' => 'label',
72
	);
73
	$options = yourls_apply_filter( 'stats_pie_options', $options );
74
75
	$script_data = array_merge( array( 'Country' => 'Value' ), $_data );
76
	$script_data = yourls_google_array_to_data_table( $script_data );
77
78
	$pie = yourls_google_viz_code( 'PieChart', $script_data, $options, $id );
79
80
	echo yourls_apply_filter( 'stats_pie', $pie, $data, $limit, $size, $options, $id );
81
}
82
83
/**
84
 * Build a list of all daily values between d1/m1/y1 to d2/m2/y2.
85
 *
86
 */
87
function yourls_build_list_of_days( $dates ) {
88
	/* Say we have an array like:
89
	$dates = array (
90
		2009 => array (
91
			'08' => array (
92
				29 => 15,
93
				30 => 5,
94
				),
95
			'09' => array (
96
				'02' => 3,
97
				'03' => 5,
98
				'04' => 2,
99
				'05' => 99,
100
				),
101
			),
102
		)
103
	*/
104
	
105
	if( !$dates )
106
		return array();
107
108
	// Get first & last years from our range. In our example: 2009 & 2009
109
	$first_year = key( $dates );
110
	$_keys      = array_keys( $dates );
111
	$last_year  = end( $_keys );
112
	reset( $dates );
113
114
	// Get first & last months from our range. In our example: 08 & 09
115
	$first_month = key( $dates[ $first_year ] );
116
	$_keys       = array_keys( $dates[ $last_year ] );
117
	$last_month  = end( $_keys );
118
	reset( $dates );
119
	
120
	// Get first & last days from our range. In our example: 29 & 05
121
	$first_day = key( $dates[ $first_year ][ $first_month ] );
122
	$_keys     = array_keys( $dates[ $last_year ][ $last_month ] );
123
	$last_day  = end( $_keys );
124
	
125
	unset( $_keys );
126
127
	// Now build a list of all years (2009), month (08 & 09) and days (all from 2009-08-29 to 2009-09-05)
128
	$list_of_years  = array();
129
	$list_of_months = array();
130
	$list_of_days   = array();
131
	for ( $year = $first_year; $year <= $last_year; $year++ ) {
132
		$_year = sprintf( '%04d', $year );
133
		$list_of_years[ $_year ] = $_year;
134
		$current_first_month = ( $year == $first_year ? $first_month : '01' );
135
		$current_last_month  = ( $year == $last_year ? $last_month : '12' );
136
		for ( $month = $current_first_month; $month <= $current_last_month; $month++ ) {
137
			$_month = sprintf( '%02d', $month );
138
			$list_of_months[ $_month ] = $_month;
139
			$current_first_day = ( $year == $first_year && $month == $first_month ? $first_day : '01' );
140
			$current_last_day  = ( $year == $last_year && $month == $last_month ? $last_day : yourls_days_in_month( $month, $year) );
141
			for ( $day = $current_first_day; $day <= $current_last_day; $day++ ) {
142
				$day = sprintf( '%02d', $day );
143
				$key = date( 'M d, Y', mktime( 0, 0, 0, $_month, $day, $_year ) );
144
				$list_of_days[ $key ] = isset( $dates[$_year][$_month][$day] ) ? $dates[$_year][$_month][$day] : 0;
145
			}
146
		}
147
	}
148
	
149
	return array(
150
		'list_of_days'   => $list_of_days,
151
		'list_of_months' => $list_of_months,
152
		'list_of_years'  => $list_of_years,
153
	);
154
}
155
156
/**
157
 * Echoes an image tag of Google Charts line graph from array of values (eg 'number of clicks').
158
 * 
159
 * $legend1_list & legend2_list are values used for the 2 x-axis labels. $id is an HTML/JS id
160
 *
161
 */
162
function yourls_stats_line( $values, $id = null ) {
163
164
	yourls_do_action( 'pre_stats_line' );
165
	
166
	// if $id is null then assign a random string
167
	if( $id === null )
168
		$id = uniqid ( 'yourls_stats_line_' );
169
		
170
	// If we have only 1 day of data, prepend a fake day with 0 hits for a prettier graph
171
	if ( count( $values ) == 1 )
172
		array_unshift( $values, 0 );
173
		
174
	// Keep only a subset of values to keep graph smooth
175
	$values = yourls_array_granularity( $values, 30 );
176
	
177
	$data = array_merge( array( 'Time' => 'Hits' ), $values );
178
	$data = yourls_google_array_to_data_table( $data );
179
	
180
	$options = array(
181
		"legend"      => "none",
182
		"pointSize"   => "3",
183
		"theme"       => "maximized",
184
		"curveType"   => "function",
185
		"width"       => 430,
186
		"height"	  => 220,
187
		"hAxis"       => "{minTextSpacing: 80, maxTextLines: 1, maxAlternation: 1}",
188
		"vAxis"       => "{minValue: 0, format: '#'}",
189
		"colors"	  => "['#2a85b3']",
190
	);
191
	$options = yourls_apply_filter( 'stats_line_options', $options );
192
	
193
	$lineChart = yourls_google_viz_code( 'LineChart', $data, $options, $id );
194
195
	echo yourls_apply_filter( 'stats_line', $lineChart, $values, $options, $id );
196
}
197
198
/**
199
 * Return the number of days in a month. From php.net, used if PHP built without calendar functions
200
 *
201
 */
202
function yourls_days_in_month( $month, $year ) {
203
	// calculate number of days in a month
204
	return $month == 2 ? ( $year % 4 ? 28 : ( $year % 100 ? 29 : ( $year % 400 ? 28 : 29 ) ) ) : ( ( $month - 1 ) % 7 % 2 ? 30 : 31 );
205
}
206
207
/**
208
 * Get max value from date array of 'Aug 12, 2012' = '1337'
209
 *
210
 */
211
function yourls_stats_get_best_day( $list_of_days ) {
212
	$max = max( $list_of_days );
213
	foreach( $list_of_days as $k=>$v ) {
214
		if ( $v == $max )
215
			return array( 'day' => $k, 'max' => $max );
216
	}
217
}
218
219
/**
220
 * Return domain of a URL
221
 *
222
 */
223
function yourls_get_domain( $url, $include_scheme = false ) {
224
	$parse = @parse_url( $url ); // Hiding ugly stuff coming from malformed referrer URLs
225
226
	// Get host & scheme. Fall back to path if not found.
227
	$host = isset( $parse['host'] ) ? $parse['host'] : '';
228
	$scheme = isset( $parse['scheme'] ) ? $parse['scheme'] : '';
229
	$path = isset( $parse['path'] ) ? $parse['path'] : '';
230
	if( !$host )
231
		$host = $path;	
232
		
233
	if ( $include_scheme && $scheme )
234
		$host = $scheme.'://'.$host;
235
		
236
	return $host;
237
}
238
239
/**
240
 * Return favicon URL
241
 *
242
 */
243
function yourls_get_favicon_url( $url ) {
244
	return yourls_match_current_protocol( 'http://www.google.com/s2/favicons?domain=' . yourls_get_domain( $url, false ) );
245
}
246
247
/**
248
 * Scale array of data from 0 to 100 max
249
 *
250
 */
251
function yourls_scale_data( $data ) {
252
	$max = max( $data );
253
	if( $max > 100 ) {
254
		foreach( $data as $k=>$v ) {
255
			$data[$k] = intval( $v / $max * 100 );
256
		}
257
	}
258
	return $data;
259
}
260
261
/**
262
 * Tweak granularity of array $array: keep only $grain values. This make less accurate but less messy graphs when too much values. See http://code.google.com/apis/chart/formats.html#granularity
263
 *
264
 */
265
function yourls_array_granularity( $array, $grain = 100, $preserve_max = true ) {
266
	if ( count( $array ) > $grain ) {
267
		$max = max( $array );
268
		$step = intval( count( $array ) / $grain );
269
		$i = 0;
270
		// Loop through each item and unset except every $step (optional preserve the max value)
271
		foreach( $array as $k=>$v ) {
272
			$i++;
273
			if ( $i % $step != 0 ) {
274
				if ( $preserve_max == false ) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
275
					unset( $array[$k] );
276
				} else {
277
					if ( $v < $max )
278
						unset( $array[$k] );
279
				}
280
			}
281
		}
282
	}
283
	return $array;
284
}
285
286
/**
287
 * Transform data array to data table for Google API
288
 *
289
 */
290
function yourls_google_array_to_data_table( $data ){
291
	$str  = "var data = google.visualization.arrayToDataTable([\n";
292
	foreach( $data as $label => $values ){
293
		if( !is_array( $values ) ) {
294
			$values = array( $values );
295
		}
296
		$str .= "\t['$label',"; 
297 View Code Duplication
		foreach( $values as $value ){
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...
298
			if( !is_numeric( $value ) && strpos( $value, '[' ) !== 0 && strpos( $value, '{' ) !== 0 ) { 
299
				$value = "'$value'";
300
			}
301
			$str .= "$value";
302
		}		
303
		$str .= "],\n";
304
	}
305
	$str = substr( $str, 0, -2 ) . "\n"; // remove the trailing comma/return, reappend the return
306
	$str .= "]);\n"; // wrap it up	
307
	return $str;
308
}
309
310
/**
311
 * Return javascript code that will display the Google Chart
312
 *
313
 */
314
function yourls_google_viz_code( $graph_type, $data, $options, $id ) {
315
	$function_name = 'yourls_graph' . $id;
316
	$code  = "\n<script id=\"$function_name\" type=\"text/javascript\">\n";
317
	$code .= "function $function_name() { \n";
318
319
	$code .= "$data\n";
320
321
	$code .= "var options = {\n";
322 View Code Duplication
	foreach( $options as $field => $value ) {
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...
323
		if( !is_numeric( $value ) && strpos( $value, '[' ) !== 0 && strpos( $value, '{' ) !== 0 ) { 
324
			$value = "\"$value\"";
325
		}
326
		$code .= "\t'$field': $value,\n";
327
	}
328
	$code  = substr( $code, 0, -2 ) . "\n"; // remove the trailing comma/return, reappend the return
329
	$code .= "\t}\n";
330
331
	$code .= "new google.visualization.$graph_type( document.getElementById('visualization_$id') ).draw( data, options );";
332
	$code .= "}\n";
333
	$code .= "google.setOnLoadCallback( $function_name );\n";
334
	$code .= "</script>\n";
335
	$code .= "<div id=\"visualization_$id\"></div>\n";
336
	
337
	return $code;
338
}
339
340