[ Index ] |
|
Code source de Drupal 5.3 |
1 <?php 2 // $Id: statistics.module,v 1.249 2007/01/10 15:17:51 dries Exp $ 3 4 /** 5 * @file 6 * Logs access statistics for your site. 7 */ 8 9 /** 10 * Implementation of hook_help(). 11 */ 12 function statistics_help($section) { 13 switch ($section) { 14 case 'admin/help#statistics': 15 $output = '<p>'. t('The statistics module keeps track of numerous statistics of site usage. It counts how many times, and from where each of your posts is viewed. The statistics module can be used to learn many useful things about how users are interacting with each other and with your site.') .'</p>'; 16 $output .= t('<p>Statistics module features</p> 17 <ul> 18 <li>Logs show statistics for how many times your site and specific content on your site has been accessed.</li> 19 <li>Referrers tells you from where visitors came from (referrer URL).</li> 20 <li>Top pages shows you what\'s hot, what is the most popular content on your site.</li> 21 <li>Top users shows you the most active users for your site.</li> 22 <li>Recent hits displays information about the latest activity on your site.</li> 23 <li>Node count displays the number of times a node has been accessed in the node\'s link section next to <em># comments</em>.</li> 24 <li>Popular content block creates a block that can display the day\'s top viewed content, the all time top viewed content, and the last content viewed.</li> 25 </ul> 26 '); 27 $output .= t('<p>Configuring the statistics module</p> 28 <ul> 29 <li>Enable access log allows you to turn the access log on and off. This log is used to store data about every page accessed, such as the remote host\'s IP address, where they came from (referrer), what node they\'ve viewed, and their user name. Enabling the log adds one database call per page displayed by Drupal.</li> 30 <li>Discard access logs older than allows you to configure how long an access log entry is saved, after which time it is deleted from the database table. To use this you need to run <em>cron.php</em></li> 31 <li>Enable node view counter allows you to turn on and off the node-counting functionality of this module. If it is turned on, an extra database query is added for each node displayed, which increments a counter.</li> 32 </ul> 33 '); 34 $output .= '<p>'. t('For more information please read the configuration and customization handbook <a href="@statistics">Statistics page</a>.', array('@statistics' => 'http://drupal.org/handbook/modules/statistics/')) .'</p>'; 35 return $output; 36 case 'admin/logs/settings': 37 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/logs/hits'))) .'</p>'; 38 case 'admin/logs/hits': 39 return '<p>'. t('This page shows you the most recent hits.') .'</p>'; 40 case 'admin/logs/referrers': 41 return '<p>'. t('This page shows you all external referrers. These are links pointing to your web site from outside your web site.') .'</p>'; 42 case 'admin/logs/visitors': 43 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. The most common use for this is to block bots/web crawlers that are consuming too many resources.") .'</p>'; 44 } 45 } 46 47 /** 48 * Implementation of hook_exit(). 49 * 50 * This is where statistics are gathered on page accesses. 51 */ 52 function statistics_exit() { 53 global $user, $recent_activity; 54 55 drupal_bootstrap(DRUPAL_BOOTSTRAP_PATH); 56 57 if (variable_get('statistics_count_content_views', 0)) { 58 // We are counting content views. 59 if ((arg(0) == 'node') && is_numeric(arg(1)) && arg(2) == '') { 60 // A node has been viewed, so update the node's counters. 61 db_query('UPDATE {node_counter} SET daycount = daycount + 1, totalcount = totalcount + 1, timestamp = %d WHERE nid = %d', time(), arg(1)); 62 // If we affected 0 rows, this is the first time viewing the node. 63 if (!db_affected_rows()) { 64 // We must create a new row to store counters for the new node. 65 db_query('INSERT INTO {node_counter} (nid, daycount, totalcount, timestamp) VALUES (%d, 1, 1, %d)', arg(1), time()); 66 } 67 } 68 } 69 if ((variable_get('statistics_enable_access_log', 0)) && (module_invoke('throttle', 'status') == 0)) { 70 // Log this page access. 71 db_query("INSERT INTO {accesslog} (title, path, url, hostname, uid, sid, timer, timestamp) values('%s', '%s', '%s', '%s', %d, '%s', %d, %d)", strip_tags(drupal_get_title()), $_GET['q'], referer_uri(), $_SERVER['REMOTE_ADDR'], $user->uid, session_id(), timer_read('page'), time()); 72 } 73 } 74 75 /** 76 * Implementation of hook_perm(). 77 */ 78 function statistics_perm() { 79 return array('access statistics', 'view post access counter'); 80 } 81 82 /** 83 * Implementation of hook_link(). 84 */ 85 function statistics_link($type, $node = NULL, $teaser = FALSE) { 86 global $id; 87 $links = array(); 88 89 if ($type != 'comment' && user_access('view post access counter')) { 90 $statistics = statistics_get($node->nid); 91 if ($statistics) { 92 $links['statistics_counter']['title'] = format_plural($statistics['totalcount'], '1 read', '@count reads'); 93 } 94 } 95 96 return $links; 97 } 98 99 /** 100 * Implementation of hook_menu(). 101 */ 102 function statistics_menu($may_cache) { 103 $items = array(); 104 105 $access = user_access('access statistics'); 106 if ($may_cache) { 107 $items[] = array( 108 'path' => 'admin/logs/hits', 109 'title' => t('Recent hits'), 110 'description' => t('View pages that have recently been visited.'), 111 'callback' => 'statistics_recent_hits', 112 'access' => $access); 113 $items[] = array( 114 'path' => 'admin/logs/pages', 115 'title' => t('Top pages'), 116 'description' => t('View pages that have been hit frequently.'), 117 'callback' => 'statistics_top_pages', 118 'access' => $access, 119 'weight' => 1); 120 $items[] = array( 121 'path' => 'admin/logs/visitors', 122 'title' => t('Top visitors'), 123 'description' => t('View visitors that hit many pages.'), 124 'callback' => 'statistics_top_visitors', 125 'access' => $access, 126 'weight' => 2); 127 $items[] = array( 128 'path' => 'admin/logs/referrers', 129 'title' => t('Top referrers'), 130 'description' => t('View top referrers.'), 131 'callback' => 'statistics_top_referrers', 132 'access' => $access); 133 $items[] = array( 134 'path' => 'admin/logs/access', 135 'title' => t('Details'), 136 'description' => t('View access log.'), 137 'callback' => 'statistics_access_log', 138 'access' => $access, 139 'type' => MENU_CALLBACK); 140 $items[] = array( 141 'path' => 'admin/logs/settings', 142 'title' => t('Access log settings'), 143 'description' => t('Control details about what and how your site logs.'), 144 'callback' => 'drupal_get_form', 145 'callback arguments' => array('statistics_access_logging_settings'), 146 'access' => user_access('administer site configuration'), 147 'type' => MENU_NORMAL_ITEM, 148 'weight' => 3); 149 } 150 else { 151 if (arg(0) == 'user' && is_numeric(arg(1)) && variable_get('statistics_enable_access_log', 0)) { 152 $items[] = array( 153 'path' => 'user/'. arg(1) .'/track/navigation', 154 'title' => t('Track page visits'), 155 'callback' => 'statistics_user_tracker', 156 'access' => $access, 157 'type' => MENU_LOCAL_TASK, 158 'weight' => 2); 159 } 160 if (arg(0) == 'node' && is_numeric(arg(1)) && variable_get('statistics_enable_access_log', 0)) { 161 $items[] = array( 162 'path' => 'node/'. arg(1) .'/track', 163 'title' => t('Track'), 164 'callback' => 'statistics_node_tracker', 165 'access' => $access, 166 'type' => MENU_LOCAL_TASK, 167 'weight' => 2); 168 } 169 } 170 171 return $items; 172 } 173 174 /** 175 * Implementation of hook_user(). 176 */ 177 function statistics_user($op, &$edit, &$user) { 178 if ($op == 'delete') { 179 db_query('UPDATE {accesslog} SET uid = 0 WHERE uid = %d', $user->uid); 180 } 181 } 182 183 function statistics_access_log($aid) { 184 $result = db_query('SELECT a.*, u.name FROM {accesslog} a LEFT JOIN {users} u ON a.uid = u.uid WHERE aid = %d', $aid); 185 if ($access = db_fetch_object($result)) { 186 $output = '<table border="1" cellpadding="2" cellspacing="2">'; 187 $output .= ' <tr><th>'. t('URL') ."</th><td>". l(url($access->path, NULL, NULL, TRUE), $access->path) ."</td></tr>"; 188 $output .= ' <tr><th>'. t('Title') .'</th><td>'. $access->title .'</td></tr>'; // safe because it comes from drupal_get_title() 189 $output .= ' <tr><th>'. t('Referrer') ."</th><td>". ($access->url ? l($access->url, $access->url) : '') ."</td></tr>"; 190 $output .= ' <tr><th>'. t('Date') .'</th><td>'. format_date($access->timestamp, 'large') .'</td></tr>'; 191 $output .= ' <tr><th>'. t('User') .'</th><td>'. theme('username', $access) .'</td></tr>'; 192 $output .= ' <tr><th>'. t('Hostname') .'</th><td>'. check_plain($access->hostname) .'</td></tr>'; 193 $output .= '</table>'; 194 return $output; 195 } 196 else { 197 drupal_not_found(); 198 } 199 } 200 201 function statistics_node_tracker() { 202 if ($node = node_load(arg(1))) { 203 204 $header = array( 205 array('data' => t('Time'), 'field' => 'a.timestamp', 'sort' => 'desc'), 206 array('data' => t('Referrer'), 'field' => 'a.url'), 207 array('data' => t('User'), 'field' => 'u.name'), 208 array('data' => t('Operations'))); 209 210 $result = pager_query('SELECT a.aid, a.timestamp, a.url, a.uid, u.name FROM {accesslog} a LEFT JOIN {users} u ON a.uid = u.uid WHERE a.path LIKE \'node/%d%%\'' . tablesort_sql($header), 30, 0, NULL, $node->nid); 211 while ($log = db_fetch_object($result)) { 212 $rows[] = array( 213 array('data' => format_date($log->timestamp, 'small'), 'class' => 'nowrap'), 214 _statistics_link($log->url), 215 theme('username', $log), 216 l(t('details'), "admin/logs/access/$log->aid")); 217 } 218 219 drupal_set_title(check_plain($node->title)); 220 $output = theme('table', $header, $rows); 221 $output .= theme('pager', NULL, 30, 0); 222 return $output; 223 } 224 else { 225 drupal_not_found(); 226 } 227 } 228 229 function statistics_user_tracker() { 230 if ($account = user_load(array('uid' => arg(1)))) { 231 232 $header = array( 233 array('data' => t('Timestamp'), 'field' => 'timestamp', 'sort' => 'desc'), 234 array('data' => t('Page'), 'field' => 'path'), 235 array('data' => t('Operations'))); 236 237 $result = pager_query('SELECT aid, timestamp, path, title FROM {accesslog} WHERE uid = %d' . tablesort_sql($header), 30, 0, NULL, $account->uid); 238 while ($log = db_fetch_object($result)) { 239 $rows[] = array( 240 array('data' => format_date($log->timestamp, 'small'), 'class' => 'nowrap'), 241 _statistics_format_item($log->title, $log->path), 242 l(t('details'), "admin/logs/access/$log->aid")); 243 } 244 245 drupal_set_title(check_plain($account->name)); 246 $output = theme('table', $header, $rows); 247 $output .= theme('pager', NULL, 30, 0); 248 return $output; 249 } 250 else { 251 drupal_not_found(); 252 } 253 } 254 255 /** 256 * Menu callback; presents the "recent hits" page. 257 */ 258 function statistics_recent_hits() { 259 $header = array( 260 array('data' => t('Timestamp'), 'field' => 'a.timestamp', 'sort' => 'desc'), 261 array('data' => t('Page'), 'field' => 'a.path'), 262 array('data' => t('User'), 'field' => 'u.name'), 263 array('data' => t('Operations')) 264 ); 265 266 $sql = 'SELECT a.aid, a.path, a.title, a.uid, u.name, a.timestamp FROM {accesslog} a LEFT JOIN {users} u ON u.uid = a.uid' . tablesort_sql($header); 267 268 $result = pager_query($sql, 30); 269 while ($log = db_fetch_object($result)) { 270 $rows[] = array( 271 array('data' => format_date($log->timestamp, 'small'), 'class' => 'nowrap'), 272 _statistics_format_item($log->title, $log->path), 273 theme('username', $log), 274 l(t('details'), "admin/logs/access/$log->aid")); 275 } 276 277 $output = theme('table', $header, $rows); 278 $output .= theme('pager', NULL, 30, 0); 279 return $output; 280 } 281 282 /** 283 * Menu callback; presents the "top pages" page. 284 */ 285 function statistics_top_pages() { 286 $sql = "SELECT COUNT(path) AS hits, path, title, AVG(timer) AS average_time, SUM(timer) AS total_time FROM {accesslog} GROUP BY path, title"; 287 $sql_cnt = "SELECT COUNT(DISTINCT(path)) FROM {accesslog}"; 288 289 $header = array( 290 array('data' => t('Hits'), 'field' => 'hits', 'sort' => 'desc'), 291 array('data' => t('Page'), 'field' => 'path'), 292 array('data' => t('Average page generation time'), 'field' => 'average_time'), 293 array('data' => t('Total page generation time'), 'field' => 'total_time') 294 ); 295 $sql .= tablesort_sql($header); 296 $result = pager_query($sql, 30, 0, $sql_cnt); 297 298 while ($page = db_fetch_object($result)) { 299 $rows[] = array($page->hits, _statistics_format_item($page->title, $page->path), t('%time ms', array('%time' => round($page->average_time))), format_interval(round($page->total_time / 1000))); 300 } 301 302 drupal_set_title(t('Top pages in the past %interval', array('%interval' => format_interval(variable_get('statistics_flush_accesslog_timer', 259200))))); 303 $output = theme('table', $header, $rows); 304 $output .= theme('pager', NULL, 30, 0); 305 return $output; 306 } 307 308 /** 309 * Menu callback; presents the "top visitors" page. 310 */ 311 function statistics_top_visitors() { 312 313 $header = array( 314 array('data' => t('Hits'), 'field' => 'hits', 'sort' => 'desc'), 315 array('data' => t('Visitor'), 'field' => 'u.name'), 316 array('data' => t('Total page generation time'), 'field' => 'total'), 317 array('data' => t('Operations')) 318 ); 319 320 $sql = "SELECT COUNT(a.uid) AS hits, a.uid, u.name, a.hostname, SUM(a.timer) AS total, ac.aid FROM {accesslog} a LEFT JOIN {access} ac ON ac.type = 'host' AND LOWER(a.hostname) LIKE (ac.mask) LEFT JOIN {users} u ON a.uid = u.uid GROUP BY a.hostname, a.uid, u.name, ac.aid". tablesort_sql($header); 321 $sql_cnt = "SELECT COUNT(DISTINCT(CONCAT(uid, hostname))) FROM {accesslog}"; 322 $result = pager_query($sql, 30, 0, $sql_cnt); 323 324 while ($account = db_fetch_object($result)) { 325 $qs = drupal_get_destination(); 326 $ban_link = $account->aid ? l(t('unban'), "admin/user/rules/delete/$account->aid", array(), $qs) : l(t('ban'), "admin/user/rules/add/$account->hostname/host", array(), $qs); 327 $rows[] = array($account->hits, ($account->uid ? theme('username', $account) : $account->hostname), format_interval(round($account->total / 1000)), $ban_link); 328 } 329 330 drupal_set_title(t('Top visitors in the past %interval', array('%interval' => format_interval(variable_get('statistics_flush_accesslog_timer', 259200))))); 331 $output = theme('table', $header, $rows); 332 $output .= theme('pager', NULL, 30, 0); 333 return $output; 334 } 335 336 /** 337 * Menu callback; presents the "referrer" page. 338 */ 339 function statistics_top_referrers() { 340 $query = "SELECT url, COUNT(url) AS hits, MAX(timestamp) AS last FROM {accesslog} WHERE url NOT LIKE '%%%s%%' AND url <> '' GROUP BY url"; 341 $query_cnt = "SELECT COUNT(DISTINCT(url)) FROM {accesslog} WHERE url <> '' AND url NOT LIKE '%%%s%%'"; 342 drupal_set_title(t('Top referrers in the past %interval', array('%interval' => format_interval(variable_get('statistics_flush_accesslog_timer', 259200))))); 343 344 $header = array( 345 array('data' => t('Hits'), 'field' => 'hits', 'sort' => 'desc'), 346 array('data' => t('Url'), 'field' => 'url'), 347 array('data' => t('Last visit'), 'field' => 'last'), 348 ); 349 350 $query .= tablesort_sql($header); 351 $result = pager_query($query, 30, 0, $query_cnt, $_SERVER['HTTP_HOST']); 352 353 while ($referrer = db_fetch_object($result)) { 354 $rows[] = array($referrer->hits, _statistics_link($referrer->url), t('@time ago', array('@time' => format_interval(time() - $referrer->last)))); 355 } 356 357 $output = theme('table', $header, $rows); 358 $output .= theme('pager', NULL, 30, 0); 359 return $output; 360 } 361 362 function statistics_access_logging_settings() { 363 // Access log settings: 364 $options = array('1' => t('Enabled'), '0' => t('Disabled')); 365 $form['access'] = array( 366 '#type' => 'fieldset', 367 '#title' => t('Access log settings')); 368 $form['access']['statistics_enable_access_log'] = array( 369 '#type' => 'radios', 370 '#title' => t('Enable access log'), 371 '#default_value' => variable_get('statistics_enable_access_log', 0), 372 '#options' => $options, 373 '#description' => t('Log each page access. Required for referrer statistics.')); 374 $period = drupal_map_assoc(array(3600, 10800, 21600, 32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200, 4838400, 9676800), 'format_interval'); 375 $form['access']['statistics_flush_accesslog_timer'] = array( 376 '#type' => 'select', 377 '#title' => t('Discard access logs older than'), 378 '#default_value' => variable_get('statistics_flush_accesslog_timer', 259200), 379 '#options' => $period, 380 '#description' => t('Older access log entries (including referrer statistics) will be automatically discarded. Requires crontab.')); 381 382 // count content views settings 383 $form['content'] = array( 384 '#type' => 'fieldset', 385 '#title' => t('Content viewing counter settings')); 386 $form['content']['statistics_count_content_views'] = array( 387 '#type' => 'radios', 388 '#title' => t('Count content views'), 389 '#default_value' => variable_get('statistics_count_content_views', 0), 390 '#options' => $options, 391 '#description' => t('Increment a counter each time content is viewed.')); 392 393 return system_settings_form($form); 394 } 395 396 /** 397 * Implementation of hook_cron(). 398 */ 399 function statistics_cron() { 400 $statistics_timestamp = variable_get('statistics_day_timestamp', ''); 401 402 if ((time() - $statistics_timestamp) >= 86400) { 403 /* reset day counts */ 404 db_query('UPDATE {node_counter} SET daycount = 0'); 405 variable_set('statistics_day_timestamp', time()); 406 } 407 408 /* clean expired access logs */ 409 db_query('DELETE FROM {accesslog} WHERE timestamp < %d', time() - variable_get('statistics_flush_accesslog_timer', 259200)); 410 } 411 412 /** 413 * Returns all time or today top or last viewed node(s). 414 * 415 * @param $dbfield 416 * one of 417 * - 'totalcount': top viewed content of all time. 418 * - 'daycount': top viewed content for today. 419 * - 'timestamp': last viewed node. 420 * 421 * @param $dbrows 422 * number of rows to be returned. 423 * 424 * @return 425 * A query result containing n.nid, n.title, u.uid, u.name of the selected node(s) 426 * or FALSE if the query could not be executed correctly. 427 */ 428 function statistics_title_list($dbfield, $dbrows) { 429 return db_query_range(db_rewrite_sql("SELECT n.nid, n.title, u.uid, u.name FROM {node} n INNER JOIN {node_counter} s ON n.nid = s.nid INNER JOIN {users} u ON n.uid = u.uid WHERE %s <> '0' AND n.status = 1 ORDER BY %s DESC"), 's.'. $dbfield, 's.'. $dbfield, 0, $dbrows); 430 } 431 432 433 /** 434 * Retrieves a node's "view statistics". 435 * 436 * @param $nid 437 * node ID 438 * 439 * @return 440 * An array with three entries: [0]=totalcount, [1]=daycount, [2]=timestamp 441 * - totalcount: count of the total number of times that node has been viewed. 442 * - daycount: count of the total number of times that node has been viewed "today". 443 * For the daycount to be reset, cron must be enabled. 444 * - timestamp: timestamp of when that node was last viewed. 445 */ 446 function statistics_get($nid) { 447 448 if ($nid > 0) { 449 /* retrieves an array with both totalcount and daycount */ 450 $statistics = db_fetch_array(db_query('SELECT totalcount, daycount, timestamp FROM {node_counter} WHERE nid = %d', $nid)); 451 } 452 453 return $statistics; 454 } 455 456 /** 457 * Implementation of hook_block(). 458 */ 459 function statistics_block($op = 'list', $delta = 0, $edit = array()) { 460 switch ($op) { 461 case 'list': 462 if (variable_get('statistics_count_content_views', 0)) { 463 $blocks[0]['info'] = t('Popular content'); 464 } 465 return $blocks; 466 467 case 'configure': 468 // Popular content block settings 469 $numbers = array('0' => t('Disabled')) + drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 40)); 470 $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.')); 471 $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.')); 472 $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.')); 473 return $form; 474 475 case 'save': 476 variable_set('statistics_block_top_day_num', $edit['statistics_block_top_day_num']); 477 variable_set('statistics_block_top_all_num', $edit['statistics_block_top_all_num']); 478 variable_set('statistics_block_top_last_num', $edit['statistics_block_top_last_num']); 479 break; 480 481 case 'view': 482 if (user_access('access content')) { 483 $content = array(); 484 485 $daytop = variable_get('statistics_block_top_day_num', 0); 486 if ($daytop && ($result = statistics_title_list('daycount', $daytop)) && db_num_rows($result)) { 487 $content[] = node_title_list($result, t("Today's:")); 488 } 489 490 $alltimetop = variable_get('statistics_block_top_all_num', 0); 491 if ($alltimetop && ($result = statistics_title_list('totalcount', $alltimetop)) && db_num_rows($result)) { 492 $content[] = node_title_list($result, t('All time:')); 493 } 494 495 $lasttop = variable_get('statistics_block_top_last_num', 0); 496 if ($lasttop && ($result = statistics_title_list('timestamp', $lasttop)) && db_num_rows($result)) { 497 $content[] = node_title_list($result, t('Last viewed:')); 498 } 499 500 if (count($content)) { 501 $block['content'] = implode('<br />', $content); 502 $block['subject'] = t('Popular content'); 503 return $block; 504 } 505 } 506 } 507 } 508 509 /** 510 * It is possible to adjust the width of columns generated by the 511 * statistics module. 512 */ 513 function _statistics_link($path, $width = 35) { 514 $title = drupal_get_path_alias($path); 515 $title = truncate_utf8($title, $width, FALSE, TRUE); 516 return l($title, $path); 517 } 518 519 function _statistics_format_item($title, $path) { 520 $path = ($path ? $path : '/'); 521 $output = ($title ? "$title<br />" : ''); 522 $output .= _statistics_link($path); 523 return $output; 524 } 525 526 /** 527 * Implementation of hook_nodeapi(). 528 */ 529 function statistics_nodeapi(&$node, $op, $arg = 0) { 530 switch ($op) { 531 case 'delete': 532 // clean up statistics table when node is deleted 533 db_query('DELETE FROM {node_counter} WHERE nid = %d', $node->nid); 534 } 535 } 536 537
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Fri Nov 30 16:20:15 2007 | par Balluche grâce à PHPXref 0.7 |
![]() |