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