/[drupal]/drupal/modules/statistics/statistics.module
ViewVC logotype

Contents of /drupal/modules/statistics/statistics.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.323 - (show annotations) (download) (as text)
Sun Nov 1 12:11:10 2009 UTC (3 weeks, 4 days ago) by dries
Branch: MAIN
Changes since 1.322: +3 -3 lines
File MIME type: text/x-php
- Patch #595084 by c960657: use type hinting for .
1 <?php
2 // $Id: statistics.module,v 1.322 2009/10/29 07:17:22 webchick Exp $
3
4 /**
5 * @file
6 * Logs access statistics for your site.
7 */
8
9 /**
10 * Implement hook_help().
11 */
12 function statistics_help($path, $arg) {
13 switch ($path) {
14 case 'admin/help#statistics':
15 $output = '<p>' . t('The statistics module keeps track of numerous site usage statistics, including the number of times, and from where, each of your posts is viewed. These statistics are useful in determining how users are interacting with each other and with your site, and are required for the display of some Drupal blocks.') . '</p>';
16 $output .= '<p>' . t('The statistics module provides:') . '</p>';
17 $output .= '<ul><li>' . t('a counter for each post on your site that increments each time the post is viewed. (Enable <em>Count content views</em> on the <a href="@statistics-settings">statistics settings page</a>, and determine if the post access counters should be visible to any user roles on the <a href="@permissions">permissions page</a>.)', array('@statistics-settings' => url('admin/config/system/statistics'), '@permissions' => url('admin/config/people/permissions'))) . '</li>';
18 $output .= '<li>' . t('a <a href="@recent-hits">recent hits</a> log that displays information about the latest activity on your site, including the URL and title of the page accessed, the user name (if available) and IP address of the accessing party.', array('@recent-hits' => url('admin/reports/hits'))) . '</li>';
19 $output .= '<li>' . t('a <a href="@top-referrers">top referrers</a> log that displays the referring parties for your site visits (where your visitors came from).', array('@top-referrers' => url('admin/reports/referrers'))) . '</li>';
20 $output .= '<li>' . t('a <a href="@top-pages">top pages</a> log that displays site content in descending order by number of views.', array('@top-pages' => url('admin/reports/pages'))) . '</li>';
21 $output .= '<li>' . t('a <a href="@top-visitors">top visitors</a> log that displays the most active users on your site.', array('@top-visitors' => url('admin/reports/visitors'))) . '</li>';
22 $output .= '<li>' . t('a <em>Popular content</em> block that displays the day\'s most viewed content, the all-time most viewed content, and the last content viewed. (Enable the <em>Popular content</em> block on the <a href="@blocks">blocks administration page</a>.)', array('@blocks' => url('admin/structure/block'))) . '</li></ul>';
23 $output .= '<p>' . t('Configuring the statistics module') . '</p>';
24 $output .= '<ul><li>' . t('When the <em>Enable access log</em> setting on the <a href="@statistics-settings">statistics settings page</a> is enabled, data about every page accessed (including the remote host\'s IP address, referrer, node accessed, and user name) is stored in the access log. The access log must be enabled for the <a href="@recent-hits">recent hits</a>, <a href="@top-referrers">top referrers</a>, <a href="@top-pages">top pages</a>, and <a href="@top-visitors">top visitors</a> log pages to function. Enabling the access log adds one additional database call per page displayed by Drupal.', array('@statistics-settings' => url('admin/config/system/statistics'), '@recent-hits' => url('admin/reports/hits'), '@top-referrers' => url('admin/reports/referrers'), '@top-pages' => url('admin/reports/pages'), '@top-visitors' => url('admin/reports/visitors'))) . '</li>';
25 $output .= '<li>' . t('The <em>Discard access logs older than</em> setting on the <a href="@statistics-settings">statistics settings page</a> specifies the length of time entries are retained in the access log before they are deleted. Automatic access log entry deletion requires a correctly configured <a href="@cron">cron maintenance task</a>.', array('@statistics-settings' => url('admin/config/system/statistics'), '@cron' => url('admin/reports/status'))) . '</li>';
26 $output .= '<li>' . t('The <em>Count content views</em> setting on the <a href="@statistics-settings">statistics settings page</a> enables a counter for each post on your site that increments each time the post is viewed. This option must be enabled to provide post-specific access counts. Enabling this option adds one additional database call per each post displayed by Drupal.', array('@statistics-settings' => url('admin/config/system/statistics'))) . '</li></ul>';
27 $output .= '<p>' . t('For more information, see the online handbook entry for <a href="@statistics">Statistics module</a>.', array('@statistics' => 'http://drupal.org/handbook/modules/statistics/')) . '</p>';
28 return $output;
29 case 'admin/config/system/statistics':
30 return '<p>' . t('Settings for the statistical information that Drupal will keep about the site. See <a href="@statistics">site statistics</a> for the actual information.', array('@statistics' => url('admin/reports/hits'))) . '</p>';
31 case 'admin/reports/hits':
32 return '<p>' . t("This page displays the site's most recent hits.") . '</p>';
33 case 'admin/reports/referrers':
34 return '<p>' . t('This page displays all external referrers, or external references to your website.') . '</p>';
35 case 'admin/reports/visitors':
36 return '<p>' . t("When you ban a visitor, you prevent the visitor's IP address from accessing your site. Unlike blocking a user, banning a visitor works even for anonymous users. This is most commonly used to block resource-intensive bots or web crawlers.") . '</p>';
37 }
38 }
39
40 /**
41 * Implement hook_exit().
42 *
43 * This is where statistics are gathered on page accesses.
44 */
45 function statistics_exit() {
46 global $user;
47
48 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
49
50 if (variable_get('statistics_count_content_views', 0)) {
51 // We are counting content views.
52 if ((arg(0) == 'node') && is_numeric(arg(1)) && arg(2) == '') {
53 // A node has been viewed, so update the node's counters.
54 db_merge('node_counter')
55 ->key(array('nid' => arg(1)))
56 ->fields(array(
57 'daycount' => 1,
58 'totalcount' => 1,
59 'timestamp' => REQUEST_TIME,
60 ))
61 ->expression('daycount', 'daycount + 1')
62 ->expression('totalcount', 'totalcount + 1')
63 ->execute();
64 }
65 }
66 if (variable_get('statistics_enable_access_log', 0)) {
67 // Log this page access.
68 db_insert('accesslog')
69 ->fields(array(
70 'title' => strip_tags(drupal_get_title()),
71 'path' => $_GET['q'],
72 'url' => $_SERVER['HTTP_REFERER'],
73 'hostname' => ip_address(),
74 'uid' => $user->uid,
75 'sid' => session_id(),
76 'timer' => (int) timer_read('page'),
77 'timestamp' => REQUEST_TIME,
78 ))
79 ->execute();
80 }
81 }
82
83 /**
84 * Implement hook_permission().
85 */
86 function statistics_permission() {
87 return array(
88 'access statistics' => array(
89 'title' => t('Access statistics'),
90 'description' => t('View content access statistics.'),
91 ),
92 'administer statistics' => array(
93 'title' => t('Administer statistics'),
94 'description' => t('Configure statistics settings.'),
95 ),
96 'view post access counter' => array(
97 'title' => t('View post access counter'),
98 'description' => t('View the total number of times a piece of content has been accessed.'),
99 ),
100 );
101 }
102
103 /**
104 * Implement hook_node_view().
105 */
106 function statistics_node_view(stdClass $node, $build_mode) {
107 if ($build_mode != 'rss') {
108 $links = array();
109 if (user_access('view post access counter')) {
110 $statistics = statistics_get($node->nid);
111 if ($statistics) {
112 $links['statistics_counter']['title'] = format_plural($statistics['totalcount'], '1 read', '@count reads');
113 }
114 }
115
116 $node->content['links']['statistics'] = array(
117 '#theme' => 'links',
118 '#links' => $links,
119 '#attributes' => array('class' => array('links', 'inline')),
120 );
121 }
122 }
123
124 /**
125 * Implement hook_menu().
126 */
127 function statistics_menu() {
128 $items['admin/reports/hits'] = array(
129 'title' => 'Recent hits',
130 'description' => 'View pages that have recently been visited.',
131 'page callback' => 'statistics_recent_hits',
132 'access arguments' => array('access statistics'),
133 'file' => 'statistics.admin.inc',
134 );
135 $items['admin/reports/pages'] = array(
136 'title' => 'Top pages',
137 'description' => 'View pages that have been hit frequently.',
138 'page callback' => 'statistics_top_pages',
139 'access arguments' => array('access statistics'),
140 'weight' => 1,
141 'file' => 'statistics.admin.inc',
142 );
143 $items['admin/reports/visitors'] = array(
144 'title' => 'Top visitors',
145 'description' => 'View visitors that hit many pages.',
146 'page callback' => 'statistics_top_visitors',
147 'access arguments' => array('access statistics'),
148 'weight' => 2,
149 'file' => 'statistics.admin.inc',
150 );
151 $items['admin/reports/referrers'] = array(
152 'title' => 'Top referrers',
153 'description' => 'View top referrers.',
154 'page callback' => 'statistics_top_referrers',
155 'access arguments' => array('access statistics'),
156 'file' => 'statistics.admin.inc',
157 );
158 $items['admin/reports/access/%'] = array(
159 'title' => 'Details',
160 'description' => 'View access log.',
161 'page callback' => 'statistics_access_log',
162 'page arguments' => array(3),
163 'access arguments' => array('access statistics'),
164 'type' => MENU_CALLBACK,
165 'file' => 'statistics.admin.inc',
166 );
167 $items['admin/config/system/statistics'] = array(
168 'title' => 'Statistics',
169 'description' => 'Control details about what and how your site logs access statistics.',
170 'page callback' => 'drupal_get_form',
171 'page arguments' => array('statistics_settings_form'),
172 'access arguments' => array('administer statistics'),
173 'file' => 'statistics.admin.inc',
174 );
175 $items['user/%user/track/navigation'] = array(
176 'title' => 'Track page visits',
177 'page callback' => 'statistics_user_tracker',
178 'access callback' => 'user_access',
179 'access arguments' => array('access statistics'),
180 'type' => MENU_LOCAL_TASK,
181 'weight' => 2,
182 'file' => 'statistics.pages.inc',
183 );
184 $items['node/%node/track'] = array(
185 'title' => 'Track',
186 'page callback' => 'statistics_node_tracker',
187 'access callback' => 'user_access',
188 'access arguments' => array('access statistics'),
189 'type' => MENU_LOCAL_TASK,
190 'weight' => 2,
191 'file' => 'statistics.pages.inc',
192 );
193
194 return $items;
195 }
196
197 /**
198 * Implement hook_user_cancel().
199 */
200 function statistics_user_cancel($edit, $account, $method) {
201 switch ($method) {
202 case 'user_cancel_reassign':
203 db_update('accesslog')
204 ->fields(array('uid' => 0))
205 ->condition('uid', $account->uid)
206 ->execute();
207 break;
208
209 case 'user_cancel_delete':
210 db_delete('accesslog')
211 ->condition('uid', $account->uid)
212 ->execute();
213 break;
214 }
215 }
216
217 /**
218 * Implement hook_cron().
219 */
220 function statistics_cron() {
221 $statistics_timestamp = variable_get('statistics_day_timestamp', '');
222
223 if ((REQUEST_TIME - $statistics_timestamp) >= 86400) {
224 // Reset day counts.
225 db_update('node_counter')
226 ->fields(array('daycount' => 0))
227 ->execute();
228 variable_set('statistics_day_timestamp', REQUEST_TIME);
229 }
230
231 // Clean up expired access logs (if applicable).
232 if (variable_get('statistics_flush_accesslog_timer', 259200) > 0) {
233 db_delete('accesslog')
234 ->condition('timestamp', REQUEST_TIME - variable_get('statistics_flush_accesslog_timer', 259200), '<')
235 ->execute();
236 }
237 }
238
239 /**
240 * Returns all time or today top or last viewed node(s).
241 *
242 * @param $dbfield
243 * one of
244 * - 'totalcount': top viewed content of all time.
245 * - 'daycount': top viewed content for today.
246 * - 'timestamp': last viewed node.
247 *
248 * @param $dbrows
249 * number of rows to be returned.
250 *
251 * @return
252 * A query result containing n.nid, n.title, u.uid, u.name of the selected node(s)
253 * or FALSE if the query could not be executed correctly.
254 */
255 function statistics_title_list($dbfield, $dbrows) {
256 if (in_array($dbfield, array('totalcount', 'daycount', 'timestamp'))) {
257 $query = db_select('node', 'n');
258 $query->addTag('node_access');
259 $query->join('node_counter', 's', 'n.nid = s.nid');
260 $query->join('users', 'u', 'n.uid = u.uid');
261
262 return $query
263 ->fields('n', array('nid', 'title'))
264 ->fields('u', array('uid', 'name'))
265 ->condition($dbfield, 0, '<>')
266 ->condition('n.status', 1)
267 ->orderBy($dbfield, 'DESC')
268 ->range(0, $dbrows)
269 ->execute();
270 }
271 return FALSE;
272 }
273
274
275 /**
276 * Retrieves a node's "view statistics".
277 *
278 * @param $nid
279 * node ID
280 *
281 * @return
282 * An array with three entries: [0]=totalcount, [1]=daycount, [2]=timestamp
283 * - totalcount: count of the total number of times that node has been viewed.
284 * - daycount: count of the total number of times that node has been viewed "today".
285 * For the daycount to be reset, cron must be enabled.
286 * - timestamp: timestamp of when that node was last viewed.
287 */
288 function statistics_get($nid) {
289
290 if ($nid > 0) {
291 // Retrieve an array with both totalcount and daycount.
292 return db_query('SELECT totalcount, daycount, timestamp FROM {node_counter} WHERE nid = :nid', array(':nid' => $nid), array('target' => 'slave'))->fetchAssoc();
293 }
294 }
295
296 /**
297 * Implement hook_block_info().
298 */
299 function statistics_block_info() {
300 if (variable_get('statistics_count_content_views', 0)) {
301 $blocks['popular']['info'] = t('Popular content');
302 // Too dynamic to cache.
303 $blocks['popular']['cache'] = DRUPAL_NO_CACHE;
304 return $blocks;
305 }
306 }
307
308 /**
309 * Implement hook_block_configure().
310 */
311 function statistics_block_configure($delta = '') {
312 // Popular content block settings
313 $numbers = array('0' => t('Disabled')) + drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 40));
314 $form['statistics_block_top_day_num'] = array('#type' => 'select', '#title' => t("Number of day's top views to display"), '#default_value' => variable_get('statistics_block_top_day_num', 0), '#options' => $numbers, '#description' => t('How many content items to display in "day" list.'));
315 $form['statistics_block_top_all_num'] = array('#type' => 'select', '#title' => t('Number of all time views to display'), '#default_value' => variable_get('statistics_block_top_all_num', 0), '#options' => $numbers, '#description' => t('How many content items to display in "all time" list.'));
316 $form['statistics_block_top_last_num'] = array('#type' => 'select', '#title' => t('Number of most recent views to display'), '#default_value' => variable_get('statistics_block_top_last_num', 0), '#options' => $numbers, '#description' => t('How many content items to display in "recently viewed" list.'));
317 return $form;
318 }
319
320 /**
321 * Implement hook_block_save().
322 */
323 function statistics_block_save($delta = '', $edit = array()) {
324 variable_set('statistics_block_top_day_num', $edit['statistics_block_top_day_num']);
325 variable_set('statistics_block_top_all_num', $edit['statistics_block_top_all_num']);
326 variable_set('statistics_block_top_last_num', $edit['statistics_block_top_last_num']);
327 }
328
329 /**
330 * Implement hook_block_view().
331 */
332 function statistics_block_view($delta = '') {
333 if (user_access('access content')) {
334 $content = array();
335
336 $daytop = variable_get('statistics_block_top_day_num', 0);
337 if ($daytop && ($result = statistics_title_list('daycount', $daytop)) && ($node_title_list = node_title_list($result, t("Today's:")))) {
338 $content[] = $node_title_list;
339 }
340
341 $alltimetop = variable_get('statistics_block_top_all_num', 0);
342 if ($alltimetop && ($result = statistics_title_list('totalcount', $alltimetop)) && ($node_title_list = node_title_list($result, t('All time:')))) {
343 $content[] = $node_title_list;
344 }
345
346 $lasttop = variable_get('statistics_block_top_last_num', 0);
347 if ($lasttop && ($result = statistics_title_list('timestamp', $lasttop)) && ($node_title_list = node_title_list($result, t('Last viewed:')))) {
348 $content[] = $node_title_list;
349 }
350
351 if (count($content)) {
352 $block['content'] = implode('<br />', $content);
353 $block['subject'] = t('Popular content');
354 return $block;
355 }
356 }
357 }
358
359 /**
360 * It is possible to adjust the width of columns generated by the
361 * statistics module.
362 */
363 function _statistics_link($path, $width = 35) {
364 $title = drupal_get_path_alias($path);
365 $title = truncate_utf8($title, $width, FALSE, TRUE);
366 return l($title, $path);
367 }
368
369 function _statistics_format_item($title, $path) {
370 $path = ($path ? $path : '/');
371 $output = ($title ? "$title<br />" : '');
372 $output .= _statistics_link($path);
373 return $output;
374 }
375
376 /**
377 * Implement hook_node_delete().
378 */
379 function statistics_node_delete(stdClass $node) {
380 // clean up statistics table when node is deleted
381 db_delete('node_counter')
382 ->condition('nid', $node->nid)
383 ->execute();
384 }
385
386 /**
387 * Implement hook_ranking().
388 */
389 function statistics_ranking() {
390 if (variable_get('statistics_count_content_views', 0)) {
391 return array(
392 'views' => array(
393 'title' => t('Number of views'),
394 'join' => array(
395 'type' => 'LEFT',
396 'table' => 'node_counter',
397 'alias' => 'node_counter',
398 'on' => 'node_counter.nid = i.sid',
399 ),
400 // Inverse law that maps the highest view count on the site to 1 and 0 to 0.
401 'score' => '2.0 - 2.0 / (1.0 + node_counter.totalcount * CAST(:scale AS DECIMAL))',
402 'arguments' => array(':scale' => variable_get('node_cron_views_scale', 0)),
403 ),
404 );
405 }
406 }
407
408 /**
409 * Implement hook_update_index().
410 */
411 function statistics_update_index() {
412 variable_set('node_cron_views_scale', 1.0 / max(1, db_query('SELECT MAX(totalcount) FROM {node_counter}')->fetchField()));
413 }

  ViewVC Help
Powered by ViewVC 1.1.2