Index: /trunk/admin.php
===================================================================
--- /trunk/admin.php	(revision 1726)
+++ /trunk/admin.php	(revision 1727)
@@ -83,5 +83,6 @@
   array(
     'U_SITE_MANAGER'=> $link_start.'site_manager',
-    'U_HISTORY'=> $link_start.'stats',
+    'U_HISTORY_STAT'=> $link_start.'stats',
+    'U_HISTORY_SEARCH'=> $link_start.'history',
     'U_FAQ'=> $link_start.'help',
     'U_SITES'=> $link_start.'remote_site',
Index: /trunk/admin/history.php
===================================================================
--- /trunk/admin/history.php	(revision 1727)
+++ /trunk/admin/history.php	(revision 1727)
@@ -0,0 +1,388 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date: 2006-11-29 05:18:11 +0100 (mer, 29 nov 2006) $
+// | last modifier : $Author: rvelices $
+// | revision      : $Revision: 1620 $
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify  |
+// | it under the terms of the GNU General Public License as published by  |
+// | the Free Software Foundation                                          |
+// |                                                                       |
+// | This program is distributed in the hope that it will be useful, but   |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
+// | General Public License for more details.                              |
+// |                                                                       |
+// | You should have received a copy of the GNU General Public License     |
+// | along with this program; if not, write to the Free Software           |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA.                                                                  |
+// +-----------------------------------------------------------------------+
+
+/**
+ * Display filtered history lines
+ */
+
+// echo '<pre>$_POST:
+// '; print_r($_POST); echo '</pre>';
+// echo '<pre>$_GET:
+// '; print_r($_GET); echo '</pre>';
+
+// +-----------------------------------------------------------------------+
+// |                              functions                                |
+// +-----------------------------------------------------------------------+
+
+// +-----------------------------------------------------------------------+
+// |                           initialization                              |
+// +-----------------------------------------------------------------------+
+
+if (!defined('PHPWG_ROOT_PATH'))
+{
+  die('Hacking attempt!');
+}
+
+include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+
+if (isset($_GET['start']) and is_numeric($_GET['start']))
+{
+  $page['start'] = $_GET['start'];
+}
+else
+{
+  $page['start'] = 0;
+}
+
+// +-----------------------------------------------------------------------+
+// | Check Access and exit when user status is not ok                      |
+// +-----------------------------------------------------------------------+
+
+check_status(ACCESS_ADMINISTRATOR);
+
+// +-----------------------------------------------------------------------+
+// | Build search criteria and redirect to results                         |
+// +-----------------------------------------------------------------------+
+
+$errors = array();
+$search = array();
+
+if (isset($_POST['submit']))
+{
+  // dates
+  if (!empty($_POST['start_year']))
+  {
+    $search['fields']['date-after'] = sprintf(
+      '%d-%02d-%02d',
+      $_POST['start_year'],
+      $_POST['start_month'],
+      $_POST['start_day']
+      );
+  }
+
+  if (!empty($_POST['end_year']))
+  {
+    $search['fields']['date-before'] = sprintf(
+      '%d-%02d-%02d',
+      $_POST['end_year'],
+      $_POST['end_month'],
+      $_POST['end_day']
+      );
+  }
+
+  // echo '<pre>'; print_r($search); echo '</pre>';
+  
+  if (!empty($search))
+  {
+    // register search rules in database, then they will be available on
+    // thumbnails page and picture page.
+    $query ='
+INSERT INTO '.SEARCH_TABLE.'
+  (rules)
+  VALUES
+  (\''.serialize($search).'\')
+;';
+    pwg_query($query);
+
+    $search_id = mysql_insert_id();
+    
+    redirect(
+      PHPWG_ROOT_PATH.'admin.php?page=history&search_id='.$search_id
+      );
+  }
+  else
+  {
+    array_push($errors, $lang['search_one_clause_at_least']);
+  }
+}
+
+// +-----------------------------------------------------------------------+
+// |                             template init                             |
+// +-----------------------------------------------------------------------+
+
+$template->set_filenames(array('history'=>'admin/history.tpl'));
+
+$base_url = PHPWG_ROOT_PATH.'admin.php?page=history';
+
+$template->assign_vars(
+  array(
+    'U_HELP' => PHPWG_ROOT_PATH.'popuphelp.php?page=history',
+
+    'F_ACTION' => PHPWG_ROOT_PATH.'admin.php?page=history'
+    )
+  );
+
+$template->assign_vars(
+  array(
+    'TODAY_DAY'   => date('d', time()),
+    'TODAY_MONTH' => date('m', time()),
+    'TODAY_YEAR'  => date('Y', time()),
+    )
+  );
+
+// +-----------------------------------------------------------------------+
+// |                             history lines                             |
+// +-----------------------------------------------------------------------+
+
+if (isset($_GET['search_id'])
+    and $page['search_id'] = (int)$_GET['search_id'])
+{
+  // what are the lines to display in reality ?
+  $query = '
+SELECT rules
+  FROM '.SEARCH_TABLE.'
+  WHERE id = '.$page['search_id'].'
+;';
+  list($serialized_rules) = mysql_fetch_row(pwg_query($query));
+
+  $page['search'] = unserialize($serialized_rules);
+
+  // echo '<pre>'; print_r($page['search']); echo '</pre>';
+  
+  $clauses = array();
+
+  if (isset($page['search']['fields']['date-after']))
+  {
+    array_push(
+      $clauses,
+      "date >= '".$page['search']['fields']['date-after']."'"
+      );
+  }
+
+  if (isset($page['search']['fields']['date-before']))
+  {
+    array_push(
+      $clauses,
+      "date <= '".$page['search']['fields']['date-before']."'"
+      );
+  }
+
+  $clauses = prepend_append_array_items($clauses, '(', ')');
+
+  $where_separator =
+    implode(
+      "\n    AND ",
+      $clauses
+      );
+  
+  $query = '
+SELECT COUNT(*)
+  FROM '.HISTORY_TABLE.'
+  WHERE '.$where_separator.'
+';
+
+  list($page['nb_lines']) = mysql_fetch_row(pwg_query($query));
+
+  $query = '
+SELECT date, time, user_id, IP, section, category_id, tag_ids, image_id
+  FROM '.HISTORY_TABLE.'
+  WHERE '.$where_separator.'
+  LIMIT '.$page['start'].', '.$conf['nb_logs_page'].'
+;';
+
+  $result = pwg_query($query);
+  $history_lines = array();
+  while ($row = mysql_fetch_array($result))
+  {
+    $user_ids[$row['user_id']] = 1;
+
+    if (isset($row['category_id']))
+    {
+      $category_ids[$row['category_id']] = 1;
+    }
+
+    if (isset($row['image_id']))
+    {
+      $image_ids[$row['image_id']] = 1;
+    }
+
+    array_push(
+      $history_lines,
+      $row
+      );
+  }
+
+  // prepare reference data (users, tags, categories...)
+  if (count($user_ids) > 0)
+  {
+    $query = '
+SELECT '.$conf['user_fields']['id'].' AS id
+     , '.$conf['user_fields']['username'].' AS username
+  FROM '.USERS_TABLE.'
+  WHERE id IN ('.implode(',', array_keys($user_ids)).')
+;';
+    $result = pwg_query($query);
+
+    $username_of = array();
+    while ($row = mysql_fetch_array($result))
+    {
+      $username_of[$row['id']] = $row['username'];
+    }
+  }
+
+  if (count($category_ids) > 0)
+  {
+    $query = '
+SELECT id, uppercats
+  FROM '.CATEGORIES_TABLE.'
+  WHERE id IN ('.implode(',', array_keys($category_ids)).')
+;';
+    $uppercats_of = simple_hash_from_query($query, 'id', 'uppercats');
+
+    $name_of_category = array();
+    
+    foreach ($uppercats_of as $category_id => $uppercats)
+    {
+      $name_of_category[$category_id] = get_cat_display_name_cache(
+        $uppercats
+        );
+    }
+  }
+
+  if (count($image_ids) > 0)
+  {
+    $query = '
+SELECT id, IF(name IS NULL, file, name) AS label
+  FROM '.IMAGES_TABLE.'
+  WHERE id IN ('.implode(',', array_keys($image_ids)).')
+;';
+    $label_of_image = simple_hash_from_query($query, 'id', 'label');
+  }
+  
+  $i = 0;
+
+  foreach ($history_lines as $line)
+  {
+    $template->assign_block_vars(
+      'detail',
+      array(
+        'DATE'      => $line['date'],
+        'TIME'      => $line['time'],
+        'USER'      => isset($username_of[$line['user_id']])
+          ? $username_of[$line['user_id']]
+          : $line['user_id']
+        ,
+        'IP'        => $line['IP'],
+        'IMAGE'     => isset($line['image_id'])
+          ? $label_of_image[$line['image_id']]
+          : $line['image_id'],
+        'SECTION'   => $line['section'],
+        'CATEGORY'  => isset($line['category_id'])
+          ? $name_of_category[$line['category_id']]
+          : '',
+        'TAG'       => $line['tag_ids'],
+        'T_CLASS'   => ($i++ % 2) ? 'row1' : 'row2',
+        )
+      );
+  }
+}
+
+// $groups_string = preg_replace(
+//     '/(\d+)/e',
+//     "\$groups['$1']",
+//     implode(
+//       ', ',
+//       $local_user['groups']
+//       )
+//     );
+
+// +-----------------------------------------------------------------------+
+// |                            navigation bar                             |
+// +-----------------------------------------------------------------------+
+
+if (isset($page['search_id']))
+{
+  $navbar = create_navigation_bar(
+    PHPWG_ROOT_PATH.'admin.php'.get_query_string_diff(array('start')),
+    $page['nb_lines'],
+    $page['start'],
+    $conf['nb_logs_page']
+    );
+
+  $template->assign_block_vars(
+    'navigation',
+    array(
+      'NAVBAR' => $navbar
+      )
+    );
+}
+
+// +-----------------------------------------------------------------------+
+// |                             filter form                               |
+// +-----------------------------------------------------------------------+
+
+$form = array();
+
+if (isset($page['search']))
+{
+  if (isset($page['search']['fields']['date-after']))
+  {
+    $tokens = explode('-', $page['search']['fields']['date-after']);
+    
+    $form['start_year']  = (int)$tokens[0];
+    $form['start_month'] = (int)$tokens[1];
+    $form['start_day']   = (int)$tokens[2];
+  }
+
+  if (isset($page['search']['fields']['date-before']))
+  {
+    $tokens = explode('-', $page['search']['fields']['date-before']);
+    
+     (int)$tokens[0];
+     (int)$tokens[1];
+     (int)$tokens[2];
+  }
+}
+else
+{
+  // by default, at page load, we want the selected date to be the current
+  // date
+  $form['start_year']  = $form['end_year']  = date('Y');
+  $form['start_month'] = $form['end_month'] = date('n');
+  $form['start_day']   = $form['end_day']   = date('j');
+}
+
+// start date
+get_day_list('start_day', @$form['start_day']);
+get_month_list('start_month', @$form['start_month']);
+// end date
+get_day_list('end_day', @$form['end_day']);
+get_month_list('end_month', @$form['end_month']);
+
+$template->assign_vars(
+  array(
+    'START_YEAR' => @$form['start_year'],
+    'END_YEAR'   => @$form['end_year'],
+    )
+  );
+  
+// +-----------------------------------------------------------------------+
+// |                           html code display                           |
+// +-----------------------------------------------------------------------+
+
+$template->assign_var_from_handle('ADMIN_CONTENT', 'history');
+?>
Index: unk/admin/images/daily_stats.img.php
===================================================================
--- /trunk/admin/images/daily_stats.img.php	(revision 1726)
+++ 	(revision )
@@ -1,126 +1,0 @@
-<?php
-// +-----------------------------------------------------------------------+
-// | PhpWebGallery - a PHP based picture gallery                           |
-// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
-// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
-// +-----------------------------------------------------------------------+
-// | branch        : BSF (Best So Far)
-// | file          : $RCSfile$
-// | last update   : $Date$
-// | last modifier : $Author$
-// | revision      : $Revision$
-// +-----------------------------------------------------------------------+
-// | This program is free software; you can redistribute it and/or modify  |
-// | it under the terms of the GNU General Public License as published by  |
-// | the Free Software Foundation                                          |
-// |                                                                       |
-// | This program is distributed in the hope that it will be useful, but   |
-// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
-// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
-// | General Public License for more details.                              |
-// |                                                                       |
-// | You should have received a copy of the GNU General Public License     |
-// | along with this program; if not, write to the Free Software           |
-// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
-// | USA.                                                                  |
-// +-----------------------------------------------------------------------+
-//----------------------------------------------------------- include
-define('PHPWG_ROOT_PATH','../../');
-define('IN_ADMIN', true);
-include_once( PHPWG_ROOT_PATH.'include/common.inc.php' );
-include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
-include_once( 'phpBarGraph.php' );
-
-// +-----------------------------------------------------------------------+
-// | Check Access and exit when user status is not ok                      |
-// +-----------------------------------------------------------------------+
-check_status(ACCESS_ADMINISTRATOR);
-
-//------------------------------------------------ variable definition
-$outputFormat = "png";
-$legend = $lang['stats_daily_graph_title'];
-$imageHeight = 256;
-$imageWidth = 512;
-$sql = '
-SELECT DISTINCT COUNT(*)
-     , HOUR(DATE_FORMAT(date, \'%H:%i:%s\'))
-  FROM '.HISTORY_TABLE.'
-  WHERE YEAR(date) = '.$_GET['year'].'
-    AND MONTH(date) = '.$_GET['month'].'
-    AND DAYOFMONTH(date) = '.$_GET['day'].'
-  GROUP BY DATE_FORMAT(date, \'%H\') DESC;';
-
-//------------------------------------------------ Image definition
-$image = ImageCreate($imageWidth, $imageHeight);
-//$image = ImageCreateTrueColor($imageWidth, $imageHeight);
-// Fill it with your favorite background color..
-$backgroundColor = ImageColorAllocate($image, 184, 184, 184);
-ImageFill($image, 0, 0, $backgroundColor);
-$white = ImageColorAllocate($image, 0, 0, 0);
-
-// Interlace the image..
-Imageinterlace($image, 1);
-
-// Create a new BarGraph..
-$myBarGraph = new PhpBarGraph;
-$myBarGraph->SetX(10);              // Set the starting x position
-$myBarGraph->SetY(10);              // Set the starting y position
-$myBarGraph->SetWidth($imageWidth-20);    // Set how wide the bargraph will be
-$myBarGraph->SetHeight($imageHeight-20);  // Set how tall the bargraph will be
-$myBarGraph->SetNumOfValueTicks(3); // Set this to zero if you don't want to show any. These are the vertical bars to help see the values.
-
-
-// You can try uncommenting these lines below for different looks.
-
-// $myBarGraph->SetShowLabels(false);  // The default is true. Setting this to false will cause phpBarGraph to not print the labels of each bar.
-$myBarGraph->SetShowValues(false);  // The default is true. Setting this to false will cause phpBarGraph to not print the values of each bar.
-// $myBarGraph->SetBarBorder(false);   // The default is true. Setting this to false will cause phpBarGraph to not print the border of each bar.
-// $myBarGraph->SetShowFade(false);    // The default is true. Setting this to false will cause phpBarGraph to not print each bar as a gradient.
-// $myBarGraph->SetShowOuterBox(false);   // The default is true. Setting this to false will cause phpBarGraph to not print the outside box.
-$myBarGraph->SetBarSpacing(5);     // The default is 10. This changes the space inbetween each bar.
-
-
-// Add Values to the bargraph..
-$result = pwg_query($sql)
-or die(mysql_errno().": ".mysql_error()."<BR>".$sql);
-
-$hours = array();
-for ($i = 0; $i <= 23; $i++)
-{
-  $hours[$i] = 0;
-}
-
-while ($r = mysql_fetch_row($result))
-{ 
-  $hours[$r[1]]= $r[0];
-}
-$o=0;
-while (list ($key,$value) = each($hours ))
-{
-  $myBarGraph->AddValue($key, $value);
-}
-
-//$myBarGraph->SetDebug(true);
-// Set the colors of the bargraph..
-$myBarGraph->SetStartBarColor("6666ff");  // This is the color on the top of every bar.
-$myBarGraph->SetEndBarColor("2222aa");    // This is the color on the bottom of every bar. This is not used when SetShowFade() is set to false.
-$myBarGraph->SetLineColor("000000");      // This is the color all the lines and text are printed out with.
-
-// Print the BarGraph to the image..
-$myBarGraph->DrawBarGraph($image);
-Imagestring($image, 2, 2, $imageHeight-14, $legend, $white);
-   
-//------------------------------------------------ Image output
-if ($outputFormat == "png")
-{
-  header("Content-type: image/png");
-  ImagePNG($image);
-}
-else if (in_array($outputFormat, array("jpg", "jpeg")))
-{
-  header("Content-type: image/jpeg");
-  Imagejpeg($image);
-}
-// Destroy the image.
-Imagedestroy($image);
-?> 
Index: unk/admin/images/global_stats.img.php
===================================================================
--- /trunk/admin/images/global_stats.img.php	(revision 1726)
+++ 	(revision )
@@ -1,126 +1,0 @@
-<?php
-// +-----------------------------------------------------------------------+
-// | PhpWebGallery - a PHP based picture gallery                           |
-// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
-// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
-// +-----------------------------------------------------------------------+
-// | branch        : BSF (Best So Far)
-// | file          : $RCSfile$
-// | last update   : $Date$
-// | last modifier : $Author$
-// | revision      : $Revision$
-// +-----------------------------------------------------------------------+
-// | This program is free software; you can redistribute it and/or modify  |
-// | it under the terms of the GNU General Public License as published by  |
-// | the Free Software Foundation                                          |
-// |                                                                       |
-// | This program is distributed in the hope that it will be useful, but   |
-// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
-// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
-// | General Public License for more details.                              |
-// |                                                                       |
-// | You should have received a copy of the GNU General Public License     |
-// | along with this program; if not, write to the Free Software           |
-// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
-// | USA.                                                                  |
-// +-----------------------------------------------------------------------+
-//----------------------------------------------------------- include
-define('PHPWG_ROOT_PATH','../../');
-define('IN_ADMIN', true);
-include_once( PHPWG_ROOT_PATH.'include/common.inc.php' );
-include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
-include_once( 'phpBarGraph.php' );
-
-// +-----------------------------------------------------------------------+
-// | Check Access and exit when user status is not ok                      |
-// +-----------------------------------------------------------------------+
-check_status(ACCESS_ADMINISTRATOR);
-
-//------------------------------------------------ variable definition
-$outputFormat = "png";
-$legend = $lang['stats_global_graph_title'];
-$imageHeight = 256;
-$imageWidth = 320;
-$sql = "SELECT DISTINCT COUNT(*), MONTH(date) 
-  FROM ".HISTORY_TABLE." 
-  WHERE (date > DATE_SUB(CURRENT_DATE(), INTERVAL 12 MONTH)) 
-  GROUP BY DATE_FORMAT(date,'%Y-%m') DESC;";
-
-//------------------------------------------------ Image definition
-$image = ImageCreate($imageWidth, $imageHeight);
-//$image = ImageCreateTrueColor($imageWidth, $imageHeight);
-// Fill it with your favorite background color..
-$backgroundColor = ImageColorAllocate($image, 184, 184, 184);
-ImageFill($image, 0, 0, $backgroundColor);
-$white = ImageColorAllocate($image, 0, 0, 0);
-
-// Interlace the image..
-Imageinterlace($image, 1);
-
-// Create a new BarGraph..
-$myBarGraph = new PhpBarGraph;
-$myBarGraph->SetX(10);              // Set the starting x position
-$myBarGraph->SetY(10);              // Set the starting y position
-$myBarGraph->SetWidth($imageWidth-20);    // Set how wide the bargraph will be
-$myBarGraph->SetHeight($imageHeight-20);  // Set how tall the bargraph will be
-$myBarGraph->SetNumOfValueTicks(3); // Set this to zero if you don't want to show any. These are the vertical bars to help see the values.
-
-
-// You can try uncommenting these lines below for different looks.
-
-// $myBarGraph->SetShowLabels(false);  // The default is true. Setting this to false will cause phpBarGraph to not print the labels of each bar.
- $myBarGraph->SetShowValues(false);  // The default is true. Setting this to false will cause phpBarGraph to not print the values of each bar.
-// $myBarGraph->SetBarBorder(false);   // The default is true. Setting this to false will cause phpBarGraph to not print the border of each bar.
-// $myBarGraph->SetShowFade(false);    // The default is true. Setting this to false will cause phpBarGraph to not print each bar as a gradient.
-// $myBarGraph->SetShowOuterBox(false);   // The default is true. Setting this to false will cause phpBarGraph to not print the outside box.
-$myBarGraph->SetBarSpacing(5);     // The default is 10. This changes the space inbetween each bar.
-
-
-// Add Values to the bargraph..
-$result = pwg_query($sql)
-or die(mysql_errno().": ".mysql_error()."<BR>".$sql);
-
-//$monthes =array_fill(1,12,0);
-$monthes =array();
-$date = getdate();
-$current_month = $date['mon'];
-for ($i=0;$i<12;$i++)
-{
-  $monthes[(($current_month-$i+11)%12)+1]=0;
-}
-
-while ($r = mysql_fetch_row($result))
-{ 
-  if (!$monthes[$r[1]]) $monthes[$r[1]]= $r[0];
-}
-$monthes = array_reverse($monthes,true);
-while (list ($key,$value) = each($monthes))
-{
-  $nls_key = substr($lang['month'][$key],0,3);
-  $myBarGraph->AddValue($nls_key, $value);
-}
-
-//$myBarGraph->SetDebug(true);
-// Set the colors of the bargraph..
-$myBarGraph->SetStartBarColor("6666ff");  // This is the color on the top of every bar.
-$myBarGraph->SetEndBarColor("2222aa");    // This is the color on the bottom of every bar. This is not used when SetShowFade() is set to false.
-$myBarGraph->SetLineColor("000000");      // This is the color all the lines and text are printed out with.
-
-// Print the BarGraph to the image..
-$myBarGraph->DrawBarGraph($image);
-Imagestring($image, 2, 2, $imageHeight-14, $legend, $white);
-   
-//------------------------------------------------ Image output
-if ($outputFormat == "png")
-{
-  header("Content-type: image/png");
-  ImagePNG($image);
-}
-else if (in_array($outputFormat, array("jpg", "jpeg")))
-{
-  header("Content-type: image/jpeg");
-  Imagejpeg($image);
-}
-// Destroy the image.
-Imagedestroy($image);
-?> 
Index: unk/admin/images/monthly_stats.img.php
===================================================================
--- /trunk/admin/images/monthly_stats.img.php	(revision 1726)
+++ 	(revision )
@@ -1,126 +1,0 @@
-<?php
-// +-----------------------------------------------------------------------+
-// | PhpWebGallery - a PHP based picture gallery                           |
-// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
-// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
-// +-----------------------------------------------------------------------+
-// | branch        : BSF (Best So Far)
-// | file          : $RCSfile$
-// | last update   : $Date$
-// | last modifier : $Author$
-// | revision      : $Revision$
-// +-----------------------------------------------------------------------+
-// | This program is free software; you can redistribute it and/or modify  |
-// | it under the terms of the GNU General Public License as published by  |
-// | the Free Software Foundation                                          |
-// |                                                                       |
-// | This program is distributed in the hope that it will be useful, but   |
-// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
-// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
-// | General Public License for more details.                              |
-// |                                                                       |
-// | You should have received a copy of the GNU General Public License     |
-// | along with this program; if not, write to the Free Software           |
-// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
-// | USA.                                                                  |
-// +-----------------------------------------------------------------------+
-//----------------------------------------------------------- include
-define('PHPWG_ROOT_PATH','../../');
-define('IN_ADMIN', true);
-include_once( PHPWG_ROOT_PATH.'include/common.inc.php' );
-include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
-include_once( 'phpBarGraph.php' );
-
-// +-----------------------------------------------------------------------+
-// | Check Access and exit when user status is not ok                      |
-// +-----------------------------------------------------------------------+
-check_status(ACCESS_ADMINISTRATOR);
-
-//------------------------------------------------ variable definition
-$outputFormat = "png";
-$legend = $lang['stats_monthly_graph_title'];
-$imageHeight = 256;
-$imageWidth = 512;
-$sql = '
-SELECT DISTINCT COUNT(*)
-     , DAYOFMONTH(date) 
-  FROM '.HISTORY_TABLE.'
-  WHERE YEAR(date) = '.$_GET['year'].'
-    AND MONTH(date) = '.$_GET['month'].'
-  GROUP BY DATE_FORMAT(date, \'%Y-%m-%d\') DESC
-;';
-
-//------------------------------------------------ Image definition
-$image = ImageCreate($imageWidth, $imageHeight);
-//$image = ImageCreateTrueColor($imageWidth, $imageHeight);
-// Fill it with your favorite background color..
-$backgroundColor = ImageColorAllocate($image, 184, 184, 184);
-ImageFill($image, 0, 0, $backgroundColor);
-$white = ImageColorAllocate($image, 0, 0, 0);
-
-// Interlace the image..
-Imageinterlace($image, 1);
-
-// Create a new BarGraph..
-$myBarGraph = new PhpBarGraph;
-$myBarGraph->SetX(10);              // Set the starting x position
-$myBarGraph->SetY(10);              // Set the starting y position
-$myBarGraph->SetWidth($imageWidth-20);    // Set how wide the bargraph will be
-$myBarGraph->SetHeight($imageHeight-20);  // Set how tall the bargraph will be
-$myBarGraph->SetNumOfValueTicks(3); // Set this to zero if you don't want to show any. These are the vertical bars to help see the values.
-
-
-// You can try uncommenting these lines below for different looks.
-
-// $myBarGraph->SetShowLabels(false);  // The default is true. Setting this to false will cause phpBarGraph to not print the labels of each bar.
-$myBarGraph->SetShowValues(false);  // The default is true. Setting this to false will cause phpBarGraph to not print the values of each bar.
-// $myBarGraph->SetBarBorder(false);   // The default is true. Setting this to false will cause phpBarGraph to not print the border of each bar.
-// $myBarGraph->SetShowFade(false);    // The default is true. Setting this to false will cause phpBarGraph to not print each bar as a gradient.
-// $myBarGraph->SetShowOuterBox(false);   // The default is true. Setting this to false will cause phpBarGraph to not print the outside box.
-$myBarGraph->SetBarSpacing(5);     // The default is 10. This changes the space inbetween each bar.
-
-
-// Add Values to the bargraph..
-$result = pwg_query($sql)
-or die(mysql_errno().": ".mysql_error()."<BR>".$sql);
-
-$days = array();
-for ($i = 1; $i <= 31; $i++)
-{
-  $days[$i] = 0;
-}
-
-while ($r = mysql_fetch_row($result))
-{ 
-  $days[$r[1]]= $r[0];
-}
-$o=0;
-while (list ($key,$value) = each($days ))
-{
-  $myBarGraph->AddValue($key, $value);
-}
-
-//$myBarGraph->SetDebug(true);
-// Set the colors of the bargraph..
-$myBarGraph->SetStartBarColor("6666ff");  // This is the color on the top of every bar.
-$myBarGraph->SetEndBarColor("2222aa");    // This is the color on the bottom of every bar. This is not used when SetShowFade() is set to false.
-$myBarGraph->SetLineColor("000000");      // This is the color all the lines and text are printed out with.
-
-// Print the BarGraph to the image..
-$myBarGraph->DrawBarGraph($image);
-Imagestring($image, 2, 2, $imageHeight-14, $legend, $white);
-   
-//------------------------------------------------ Image output
-if ($outputFormat == "png")
-{
-  header("Content-type: image/png");
-  ImagePNG($image);
-}
-else if (in_array($outputFormat, array("jpg", "jpeg")))
-{
-  header("Content-type: image/jpeg");
-  Imagejpeg($image);
-}
-// Destroy the image.
-Imagedestroy($image);
-?> 
Index: /trunk/admin/images/stats.img.php
===================================================================
--- /trunk/admin/images/stats.img.php	(revision 1727)
+++ /trunk/admin/images/stats.img.php	(revision 1727)
@@ -0,0 +1,241 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date: 2006-12-04 23:08:35 +0100 (lun, 04 déc 2006) $
+// | last modifier : $Author: rub $
+// | revision      : $Revision: 1635 $
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify  |
+// | it under the terms of the GNU General Public License as published by  |
+// | the Free Software Foundation                                          |
+// |                                                                       |
+// | This program is distributed in the hope that it will be useful, but   |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
+// | General Public License for more details.                              |
+// |                                                                       |
+// | You should have received a copy of the GNU General Public License     |
+// | along with this program; if not, write to the Free Software           |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA.                                                                  |
+// +-----------------------------------------------------------------------+
+//----------------------------------------------------------- include
+define('PHPWG_ROOT_PATH','../../');
+define('IN_ADMIN', true);
+include_once( PHPWG_ROOT_PATH.'include/common.inc.php' );
+include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+include_once( 'phpBarGraph.php' );
+
+// +-----------------------------------------------------------------------+
+// | Check Access and exit when user status is not ok                      |
+// +-----------------------------------------------------------------------+
+check_status(ACCESS_ADMINISTRATOR);
+
+//------------------------------------------------ variable definition
+$outputFormat = "png";
+$legend = $lang['stats_global_graph_title'];
+$imageHeight = 256;
+$imageWidth = 500;
+
+foreach (array('day', 'month', 'year') as $key)
+{
+  if (isset($_GET[$key]))
+  {
+    $page[$key] = (int)$_GET[$key];
+  }
+}
+
+if (isset($page['day']))
+{
+  if (!isset($page['month']))
+  {
+    die('[stats.img.php] month is missing in URL');
+  }
+}
+
+if (isset($page['month']))
+{
+  if (!isset($page['year']))
+  {
+    die('[stats.img.php] year is missing in URL');
+  }
+}
+
+$query = '
+SELECT
+  nb_pages AS y,';
+
+$min_x = null;
+$max_x = null;
+
+if (isset($page['day']))
+{
+  $query.= '
+  hour AS x
+  FROM '.HISTORY_SUMMARY_TABLE.'
+  WHERE year = '.$page['year'].'
+    AND month = '.$page['month'].'
+    AND day = '.$page['day'].'
+    AND hour IS NOT NULL
+  ORDER BY hour ASC
+';
+
+  $min_x = 0;
+  $max_x = 23;
+}
+elseif (isset($page['month']))
+{
+  $query.= '
+  day AS x
+  FROM '.HISTORY_SUMMARY_TABLE.'
+  WHERE year = '.$page['year'].'
+    AND month = '.$page['month'].'
+    AND day IS NOT NULL
+    AND hour IS NULL
+  ORDER BY day ASC
+';
+
+  $min_x = 1;
+  $max_x = 31;
+}
+elseif (isset($page['year']))
+{
+  $query.= '
+  month AS x
+  FROM '.HISTORY_SUMMARY_TABLE.'
+  WHERE year = '.$page['year'].'
+    AND month IS NOT NULL
+    AND day IS NULL
+  ORDER BY month ASC
+';
+
+  $min_x = 1;
+  $max_x = 12;
+}
+else
+{
+  $query.= '
+  year AS x
+  FROM '.HISTORY_SUMMARY_TABLE.'
+  WHERE year IS NOT NULL
+    AND month IS NULL
+  ORDER BY year ASC
+';
+}
+
+//------------------------------------------------ Image definition
+$image = ImageCreate($imageWidth, $imageHeight);
+
+// Fill it with your favorite background color..
+$backgroundColor = ImageColorAllocate($image, 184, 184, 184);
+ImageFill($image, 0, 0, $backgroundColor);
+$white = ImageColorAllocate($image, 0, 0, 0);
+
+// Interlace the image..
+Imageinterlace($image, 1);
+
+// Create a new BarGraph..
+$myBarGraph = new PhpBarGraph;
+
+// Set the starting x position
+$myBarGraph->SetX(10);
+
+// Set the starting y position
+$myBarGraph->SetY(10);
+
+// Set how wide the bargraph will be
+$myBarGraph->SetWidth($imageWidth-20);
+
+// Set how tall the bargraph will be
+$myBarGraph->SetHeight($imageHeight-20);
+
+// Set this to zero if you don't want to show any. These are the vertical
+// bars to help see the values.
+// $myBarGraph->SetNumOfValueTicks(3);
+
+
+// You can try uncommenting these lines below for different looks.
+//
+// The default is true. Setting this to false will cause phpBarGraph to not
+// print the labels of each bar.
+$myBarGraph->SetShowLabels(true);
+
+// The default is true. Setting this to false will cause phpBarGraph to not
+// print the values of each bar.
+$myBarGraph->SetShowValues(false);
+
+// The default is true. Setting this to false will cause phpBarGraph to not
+// print the border of each bar.
+$myBarGraph->SetBarBorder(true);
+
+// The default is true. Setting this to false will cause phpBarGraph to not
+// print each bar as a gradient.
+$myBarGraph->SetShowFade(true);
+
+// The default is true. Setting this to false will cause phpBarGraph to not
+// print the outside box.
+$myBarGraph->SetShowOuterBox(true);
+
+// The default is 10. This changes the space inbetween each bar.
+$myBarGraph->SetBarSpacing(5);
+
+
+// Add Values to the bargraph..
+$result = pwg_query($query);
+$datas = array();
+while ($row = mysql_fetch_array($result))
+{
+  $datas[$row['x']] = $row['y'];
+}
+
+if (!isset($min_x) and !isset($max_x))
+{
+  $min_x = min(array_keys($datas));
+  $max_x = max(array_keys($datas));
+}
+
+for ($i = $min_x; $i <= $max_x; $i++)
+{
+  if (!isset($datas[$i]))
+  {
+    $datas[$i] = 0;
+  }
+
+  $myBarGraph->AddValue($i, $datas[$i]);
+}
+
+// Set the colors of the bargraph..
+//
+// This is the color on the top of every bar.
+$myBarGraph->SetStartBarColor("6666ff");
+
+// This is the color on the bottom of every bar. This is not used when
+// SetShowFade() is set to false.
+$myBarGraph->SetEndBarColor("2222aa");
+
+// This is the color all the lines and text are printed out with.
+$myBarGraph->SetLineColor("000000");
+
+// Print the BarGraph to the image..
+$myBarGraph->DrawBarGraph($image);
+Imagestring($image, 2, 2, $imageHeight-14, $legend, $white);
+   
+//------------------------------------------------ Image output
+if ($outputFormat == "png")
+{
+  header("Content-type: image/png");
+  ImagePNG($image);
+}
+else if (in_array($outputFormat, array("jpg", "jpeg")))
+{
+  header("Content-type: image/jpeg");
+  Imagejpeg($image);
+}
+// Destroy the image.
+Imagedestroy($image);
+?> 
Index: /trunk/admin/stats.php
===================================================================
--- /trunk/admin/stats.php	(revision 1726)
+++ /trunk/admin/stats.php	(revision 1727)
@@ -25,7 +25,8 @@
 // | USA.                                                                  |
 // +-----------------------------------------------------------------------+
-if( !defined("PHPWG_ROOT_PATH") )
-{
-	die ("Hacking attempt!");
+
+if (!defined("PHPWG_ROOT_PATH"))
+{
+  die ("Hacking attempt!");
 }
 
@@ -33,285 +34,455 @@
 
 // +-----------------------------------------------------------------------+
+// | Functions                                                             |
+// +-----------------------------------------------------------------------+
+
+function get_summary($year = null, $month = null, $day = null)
+{
+  $query = '
+SELECT
+    year,
+    month,
+    day,
+    hour,
+    nb_pages
+  FROM '.HISTORY_SUMMARY_TABLE;
+  
+  if (isset($day))
+  {
+    $query.= '
+  WHERE year = '.$year.'
+    AND month = '.$month.'
+    AND day = '.$day.'
+    AND hour IS NOT NULL
+  ORDER BY
+    year ASC,
+    month ASC,
+    day ASC,
+    hour ASC
+;';
+  }
+  elseif (isset($month))
+  {
+    $query.= '
+  WHERE year = '.$year.'
+    AND month = '.$month.'
+    AND day IS NOT NULL
+    AND hour IS NULL
+  ORDER BY
+    year ASC,
+    month ASC,
+    day ASC
+;';
+  }
+  elseif (isset($year))
+  {
+    $query.= '
+  WHERE year = '.$year.'
+    AND month IS NOT NULL
+    AND day IS NULL
+  ORDER BY
+    year ASC,
+    month ASC
+;';   
+  }
+  else
+  {
+    $query.= '
+  WHERE year IS NOT NULL
+    AND month IS NULL
+  ORDER BY
+    year ASC
+;';   
+  }
+
+  $result = pwg_query($query);
+
+  $output = array();
+  while ($row = mysql_fetch_array($result))
+  {
+    array_push($output, $row);
+  }
+
+  return $output;
+}
+
+// +-----------------------------------------------------------------------+
 // | Check Access and exit when user status is not ok                      |
 // +-----------------------------------------------------------------------+
+
 check_status(ACCESS_ADMINISTRATOR);
 
-$url_img = PHPWG_ROOT_PATH.'admin/images/'; 
-$nls_value_title = $lang['w_month'];
-$group_clause = "DATE_FORMAT(date,'%Y-%m') DESC";
-$where_clause = "1";
-
-
-if (isset($_GET['day']) && isset($_GET['month']) && isset($_GET['year']) )
-{
-  $url_img .= 'daily_stats.img.php?year='.$_GET['year'].'&amp;month='.$_GET['month'].'&amp;day='.$_GET['day'];
-  $nls_value_title = $lang['w_day'];
-  $group_clause = "DATE_FORMAT(date,'%Y-%m-%d') ASC";
-  $where_clause = "(YEAR(date) = ".$_GET['year']." AND MONTH(date) = ".$_GET['month']." )";
-}
-elseif (isset($_GET['month']) && isset($_GET['year']) )
-{
-  $url_img .= 'monthly_stats.img.php?year='.$_GET['year'].'&amp;month='.$_GET['month'];
-  $nls_value_title = $lang['w_day'];
-  $group_clause = "DATE_FORMAT(date,'%Y-%m-%d') ASC";
-  $where_clause = "(YEAR(date) = ".$_GET['year']." AND MONTH(date) = ".$_GET['month']." )";
-}
-else 
-{
-  $url_img .= 'global_stats.img.php';
-}
-
-
-//----------------------------------------------------- template initialization
-if (isset($_GET['day']) && isset($_GET['month']) && isset($_GET['year']) )
-{
-  $date_of_day=$_GET['day'].' '.$lang['month'][$_GET['month']].' '.$_GET['year'];
-  $title_page=$lang['stats_day_title'].' : '.$date_of_day;
-  $url_back = PHPWG_ROOT_PATH."admin.php?page=stats";
-  $url_back = $url_back;
-  $title_details='<a href='.$url_back.'>'.$lang['stats_day_title'].'</a>';
-  $title_day = $date_of_day;
-}
-elseif ( isset($_GET['month']) && isset($_GET['year']) )
-{
-  $date_of_day=$lang['month'][$_GET['month']].' '.$_GET['year'];
-  $title_page=$lang['stats_month_title'].' : '.$date_of_day;
-  $url_back = PHPWG_ROOT_PATH."admin.php?page=stats";
-  $url_back = $url_back;
-  $title_details='<a href='.$url_back.'>'.$lang['stats_day_title'].'</a>';
-  $title_day=$lang['today'];
-}
-else
-{
-  $date_of_day='';
-  $title_page=$lang['stats_title'];
-  $title_details=$lang['stats_month_title'];
-  $title_day=$lang['today'];
-}
-
-
-$template->set_filenames( array('stats'=>'admin/stats.tpl') );
-
-$template->assign_vars(array(
-  'L_VALUE'=>$nls_value_title,
-  'L_PAGES_SEEN'=>$lang['stats_pages_seen'],
-  'L_VISITORS'=>$lang['visitors'],
-  'L_PICTURES'=>$lang['pictures'],
-  'L_STAT_TITLE'=>$lang['stats_title'],
-  'L_STAT_MONTH_TITLE'=>$lang['stats_month_title'],
-  'L_STAT_MONTHLY_ALT'=>$lang['stats_global_graph_title'],
-  'L_STAT_TITLE'=>$title_page,
-  'L_STAT_DETAIL_TITLE'=>$title_details,
-  'L_DATE_TITLE'=>$title_day,
-  'L_STAT_MONTHLY_ALT'=>$lang['stats_global_graph_title'],
-  'L_STAT_HOUR'=>$lang['stats_hour'],
-  'L_STAT_LOGIN'=>$lang['stats_login'],
-  'L_STAT_ADDR'=>$lang['stats_addr'],
-  'L_STAT_CATEGORY'=>$lang['stats_category'],
-  'L_STAT_FILE'=>$lang['stats_file'],
-  'L_STAT_PICTURE'=>$lang['stats_picture'],
-  
-  'IMG_REPORT'=>$url_img
-  ));
-
-//---------------------------------------------------------------- log  history
+// +-----------------------------------------------------------------------+
+// | Refresh summary from details                                          |
+// +-----------------------------------------------------------------------+
+
 $query = '
-SELECT DISTINCT COUNT(*) as p,
-       DAYOFMONTH(date) as d,
-       MONTH(date) as m,
-       YEAR(date) as y
-  FROM '.HISTORY_TABLE.' 
-  WHERE '.$where_clause.'
-  GROUP BY '.$group_clause.';';
-
-$result = pwg_query( $query );
-$i=0;
-while ( $row = mysql_fetch_array( $result ) )
-{
-  $where_clause="";
+SELECT
+    year,
+    month,
+    day,
+    hour,
+    max(id) AS max_id,
+    COUNT(*) AS nb_pages
+  FROM '.HISTORY_TABLE.'
+  WHERE summarized = \'false\'
+  GROUP BY
+    year ASC,
+    month ASC,
+    day ASC,
+    hour ASC
+;';
+$result = pwg_query($query);
+
+$need_update = array();
+
+$max_id = 0;
+$is_first = true;
+$first_time_key = null;
+
+while ($row = mysql_fetch_array($result))
+{
+  $time_keys = array(
+    sprintf(
+      '%4u',
+      $row['year']
+      ),
+    sprintf(
+      '%4u.%02u',
+      $row['year'], $row['month']
+      ),
+    sprintf(
+      '%4u.%02u.%02u',
+      $row['year'], $row['month'], $row['day']
+      ),
+    sprintf(
+      '%4u.%02u.%02u.%02u',
+      $row['year'], $row['month'], $row['day'], $row['hour']
+      ),
+    );
+
+  foreach ($time_keys as $time_key)
+  {
+    if (!isset($need_update[$time_key]))
+    {
+      $need_update[$time_key] = 0;
+    }
+    $need_update[$time_key] += $row['nb_pages'];
+  }
+
+  if ($row['max_id'] > $max_id)
+  {
+    $max_id = $row['max_id'];
+  }
+
+  if ($is_first)
+  {
+    $is_first = false;
+    $first_time_key = $time_keys[3];
+  }
+}
+
+// Only the oldest time_key might be already summarized, so we have to
+// update the 4 corresponding lines instead of simply inserting them.
+//
+// For example, if the oldest unsummarized is 2005.08.25.21, the 4 lines
+// that can be updated are:
+//
+// +---------------+----------+
+// | id            | nb_pages |
+// +---------------+----------+
+// | 2005          |   241109 |
+// | 2005.08       |    20133 |
+// | 2005.08.25    |      620 |
+// | 2005.08.25.21 |      151 |
+// +---------------+----------+
+
+$existing_time_keys = array();
+
+if (isset($first_time_key))
+{
+  list($year, $month, $day, $hour) = explode('.', $first_time_key);
+
+  $time_keys = array(
+    sprintf('%4u',                $year),
+    sprintf('%4u.%02u',           $year, $month),
+    sprintf('%4u.%02u.%02u',      $year, $month, $day),
+    sprintf('%4u.%02u.%02u.%02u', $year, $month, $day, $hour),
+    );
+  
+  $query = '
+SELECT
+    id,
+    nb_pages
+  FROM '.HISTORY_SUMMARY_TABLE.'
+  WHERE id IN (\''.implode("', '", $time_keys).'\')
+;';
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    $existing_time_keys[ $row['id'] ] = $row['nb_pages'];
+  }
+}
+
+$updates = array();
+$inserts = array();
+
+foreach (array_keys($need_update) as $time_key)
+{
+  $time_tokens = explode('.', $time_key);
+
+  if (isset($existing_time_keys[$time_key]))
+  {
+    array_push(
+      $updates,
+      array(
+        'id'       => $time_key,
+        'nb_pages' => $existing_time_keys[$time_key] + $need_update[$time_key],
+        )
+      );
+  }
+  else
+  {
+    array_push(
+      $inserts,
+      array(
+        'id'       => $time_key,
+        'year'     => $time_tokens[0],
+        'month'    => @$time_tokens[1],
+        'day'      => @$time_tokens[2],
+        'hour'     => @$time_tokens[3],
+        'nb_pages' => $need_update[$time_key],
+        )
+      );
+  }
+}
+
+if (count($updates) > 0)
+{
+  mass_updates(
+    HISTORY_SUMMARY_TABLE,
+    array(
+      'primary' => array('id'),
+      'update'  => array('nb_pages'),
+      ),
+    $updates
+    );
+}
+
+if (count($inserts) > 0)
+{
+  mass_inserts(
+    HISTORY_SUMMARY_TABLE,
+    array_keys($inserts[0]),
+    $inserts
+    );
+}
+
+if ($max_id != 0)
+{
+  $query = '
+UPDATE '.HISTORY_TABLE.'
+  SET summarized = \'true\'
+  WHERE summarized = \'false\'
+    AND id <= '.$max_id.'
+;';
+  pwg_query($query);
+}
+
+// +-----------------------------------------------------------------------+
+// | Page parameters check                                                 |
+// +-----------------------------------------------------------------------+
+
+foreach (array('day', 'month', 'year') as $key)
+{
+  if (isset($_GET[$key]))
+  {
+    $page[$key] = (int)$_GET[$key];
+  }
+}
+
+if (isset($page['day']))
+{
+  if (!isset($page['month']))
+  {
+    die('month is missing in URL');
+  }
+}
+
+if (isset($page['month']))
+{
+  if (!isset($page['year']))
+  {
+    die('year is missing in URL');
+  }
+}
+
+$url_img = PHPWG_ROOT_PATH.'admin/images/stats.img.php';
+
+if (isset($page['year']))
+{
+  $url_img.= '?year='.$page['year'];
+}
+
+if (isset($page['month']))
+{
+  $url_img.= '&amp;month='.$page['month'];
+}
+
+if (isset($page['day']))
+{
+  $url_img.= '&amp;day='.$page['day'];
+}
+
+$summary_lines = get_summary(
+  @$page['year'],
+  @$page['month'],
+  @$page['day']
+  );
+
+// +-----------------------------------------------------------------------+
+// | Display statistics header                                             |
+// +-----------------------------------------------------------------------+
+
+// page title creation
+$title_parts = array();
+
+$url = PHPWG_ROOT_PATH.'admin.php?page=stats';
+
+array_push(
+  $title_parts,
+  '<a href="'.$url.'">'.l10n('Overall').'</a>'
+  );
+
+$period_label = l10n('Year');
+
+if (isset($page['year']))
+{
+  $url.= '&amp;year='.$page['year'];
+
+  array_push(
+    $title_parts,
+    '<a href="'.$url.'">'.sprintf(l10n('Year %d'), $page['year']).'</a>'
+    );
+
+  $period_label = l10n('Month');
+}
+
+if (isset($page['month']))
+{
+  $url.= '&amp;month='.$page['month'];
+
+  array_push(
+    $title_parts,
+    '<a href="'.$url.'">'.$lang['month'][$page['month']].'</a>'
+    );
+
+  $period_label = l10n('Day');
+}
+
+if (isset($page['day']))
+{
+  $url.= '&amp;day='.$page['day'];
+
+  $time = mktime(12, 0, 0, $page['month'], $page['day'], $page['year']);
+  
+  $day_title = sprintf(
+    '%u (%s)',
+    $page['day'],
+    $lang['day'][date('w', $time)]
+    );
+  
+  array_push(
+    $title_parts,
+    '<a href="'.$url.'">'.$day_title.'</a>'
+    );
+
+  $period_label = l10n('Hour');
+}
+
+$template->set_filenames(array('stats'=>'admin/stats.tpl'));
+
+$template->assign_vars(
+  array(
+    'L_STAT_TITLE' => implode($conf['level_separator'], $title_parts),
+    'SRC_REPORT' => $url_img,
+    'PERIOD_LABEL' => $period_label,
+    )
+  );
+
+// +-----------------------------------------------------------------------+
+// | Display statistic rows                                                |
+// +-----------------------------------------------------------------------+
+
+$i = 1;
+
+foreach ($summary_lines as $line)
+{
+  // echo '<pre>'; print_r($line); echo '</pre>';
+
   $value = '';
-  if (isset($_GET['month']) && isset($_GET['year']) )
-  {
-    $where_clause = 'DAYOFMONTH(date) = '.$row['d'].'
-    AND MONTH(date) = '.$row['m'].'
-    AND YEAR(date) = '.$row['y'];
-    
-    $week_day =
-      $lang['day'][date('w', mktime(12,0,0,$row['m'],$row['d'],$row['y']))];
-
+  
+  if (isset($line['hour']))
+  {
+    $value.= $line['hour'].' '.l10n('hour');
+  }
+  else if (isset($line['day']))
+  {
     $url =
       PHPWG_ROOT_PATH.'admin.php'
       .'?page=stats'
-      .'&amp;year='.$row['y']
-      .'&amp;month='.$row['m']
-      .'&amp;day='.$row['d']
+      .'&amp;year='.$line['year']
+      .'&amp;month='.$line['month']
+      .'&amp;day='.$line['day']
       ;
 
+    $time = mktime(12, 0, 0, $line['month'], $line['day'], $line['year']);
+    
     $value = '<a href="'.$url.'">';
-    $value.= $row['d'].' ('.$week_day.')';
-    $value.= "</a>";
-  }
-  else
-  {
-    $current_month = $row['y']."-";
-    if ($row['m'] <10) {$current_month.='0';}
-    $current_month .= $row['m'];
-    
-    $where_clause = "DATE_FORMAT(date,'%Y-%m') = '".$current_month."'";
-
+    $value.= $line['day'].' ('.$lang['day'][date('w', $time)].')';
+    $value.= "</a>";    
+  }
+  else if (isset($line['month']))
+  {
     $url =
       PHPWG_ROOT_PATH.'admin.php'
       .'?page=stats'
-      .'&amp;year='.$row['y']
-      .'&amp;month='.$row['m']
+      .'&amp;year='.$line['year']
+      .'&amp;month='.$line['month']
       ;
     
     $value = '<a href="'.$url.'">';
-    $value.= $lang['month'][$row['m']].' '.$row['y'];
+    $value.= $lang['month'][$line['month']];
     $value.= "</a>";
   }
-  
-  // Number of pictures seen
-  $query = '
-SELECT COUNT(*) as p
-    FROM '.HISTORY_TABLE.' 
-    WHERE '.$where_clause.'
-    AND FILE = \'picture\'
-;';
-  $pictures = mysql_fetch_array(pwg_query( $query ));
-  
-  // Number of different visitors
-  $query = '
-SELECT COUNT(*) as p, login
-  FROM '.HISTORY_TABLE.' 
-  WHERE '.$where_clause.'
-  GROUP BY login, IP
-;';
-  $user_results = pwg_query( $query );
-  $nb_visitors = 0;
-  $auth_users = array();
-  while ( $user_array = mysql_fetch_array( $user_results ) )
-  {
-    if ($user_array['login'] == 'guest') 
-	  $nb_visitors += 1;
-	else
-	  array_push($auth_users, $user_array['login']);
-  }
-  $nb_visitors +=count(array_unique($auth_users));
-  $class = ($i % 2)? 'row1':'row2'; $i++;
-  
-  $template->assign_block_vars('statrow',array(
-      'VALUE'=>$value,
-	'PAGES'=>$row['p'],
-	'VISITORS'=>$nb_visitors,
-	'IMAGES'=>$pictures['p'],
-	
-	'T_CLASS'=>$class
-    ));
-}
-$nb_visitors = mysql_num_rows( $result );
-$days = array();
-$max_nb_visitors = 0;
-$max_pages_seen = 0;
-
-//----------------------------------------------------------- stats / jour
-
-if ( isset( $_GET['month'] ) && isset( $_GET['month'] ) && isset( $_GET['day'] ) )
-{  if ($_GET['day'] <10) {$current_day='0';
-  	$current_day.= $_GET['day'];}
-  else {$current_day = $_GET['day'];}
-  if ($_GET['month'] <10) {$current_month='0';
-  	$current_month.= $_GET['month'];}
-  else {$current_month = $_GET['month'];}
-  $current_year = $_GET['year'];
-}
-
-else
-{  $current_date = GetDate();
-  if ($current_date['mday'] <10) {$current_day='0';
-  	$current_day.= $current_date['mday'];}
-  else {$current_day = $current_date['mday'];}
-  if ($current_date['mon'] <10) {$current_month='0';
-  	$current_month.= $current_date['mon'];}
-  else {$current_month = $current_date['mon'];}
-  $current_year = $current_date['year'];  
-}
-
-// Set WHERE clause
-$where = ' WHERE DATE_FORMAT(date,\'%Y-%m-%d\') = \''.$current_year."-".$current_month."-".$current_day.'\'';
-  
-// Set LIMIT clause
-$limit = ' LIMIT ';
-$page['start'] = 0;
-if (isset($_GET['start']) and is_numeric($_GET['start'])) $page['start'] = abs($_GET['start']);
-$limit .= $page['start'];
-$limit .= ','.$conf['nb_logs_page'];
-
-$query = '
-SELECT DATE_FORMAT(date,\'%H:%i:%s\') AS hour,
-     login,
-     IP,
-     category,
-     file,
-     picture
-  FROM '.HISTORY_TABLE.
-  $where.'
-  ORDER BY date DESC'.
-  $limit.
-  ';';
-
-
-$result = pwg_query( $query );
-
-$i=0;
- 
-while ( $row = mysql_fetch_array( $result ) )
-{
-  $class = ($i % 2)? 'row1':'row2'; $i++;
-    $template->assign_block_vars('detail',array(
-    'HOUR'=>$row['hour'],
-    'LOGIN'=>$row['login'],
-    'IP'=>$row['IP'],
-    'CATEGORY'=>$row['category'],
-    'FILE'=>$row['file'],
-    'PICTURE'=>$row['picture'],
-    'T_CLASS'=>$class
-  ));
-  }
-
-
-// Get total number of logs
-$query = '
-    SELECT COUNT(date) as nb_logs
-     FROM '.HISTORY_TABLE.
-  $where.'
-    ;';
-
-  $result = pwg_query($query);
-  $row = mysql_fetch_array($result);
-  $page['nb_logs']=$row['nb_logs'];
-
-  //display nav bar
-$url = $_SERVER['PHP_SELF'].'?page=stats';
-$url.= isset($_GET['year']) ? '&amp;year='.$_GET['year'] : '';
-$url.= isset($_GET['month']) ? '&amp;month='.$_GET['month'] : '';
-$url.= isset($_GET['day']) ? '&amp;day='.$_GET['day'] : '';
-
-$page['navigation_bar'] =
-create_navigation_bar(
-  $url,
-  $page['nb_logs'],
-  $page['start'],
-  $conf['nb_logs_page']
-  );
-
-$template->assign_block_vars(
-  'navigation',
-  array(
-    'NAV_BAR' => $page['navigation_bar']
-    )
-  );
-
-//----------------------------------------------------------- sending html code
+  else
+  {
+    // at least the year is defined
+    $url =
+      PHPWG_ROOT_PATH.'admin.php'
+      .'?page=stats'
+      .'&amp;year='.$line['year']
+      ;
+    
+    $value = '<a href="'.$url.'">';
+    $value.= $line['year'];
+    $value.= "</a>";    
+  }
+  
+  $template->assign_block_vars(
+    'statrow',
+    array(
+      'VALUE' => $value,
+      'PAGES' => $line['nb_pages'],
+      
+      'T_CLASS' => ($i++ % 2) ? 'row1' : 'row2'
+      )
+    );
+}
+
+// +-----------------------------------------------------------------------+
+// | Sending html code                                                     |
+// +-----------------------------------------------------------------------+
+
 $template->assign_var_from_handle('ADMIN_CONTENT', 'stats');
 ?>
Index: /trunk/identification.php
===================================================================
--- /trunk/identification.php	(revision 1726)
+++ /trunk/identification.php	(revision 1727)
@@ -64,5 +64,4 @@
     }
     log_user($row['id'], $remember_me);
-    pwg_log_login( $username );
     redirect(empty($redirect_to) ? make_index_url() : $redirect_to);
   }
Index: /trunk/include/constants.php
===================================================================
--- /trunk/include/constants.php	(revision 1726)
+++ /trunk/include/constants.php	(revision 1727)
@@ -53,4 +53,5 @@
 define('GROUPS_TABLE', $prefixeTable.'groups');
 define('HISTORY_TABLE', $prefixeTable.'history');
+define('HISTORY_SUMMARY_TABLE', $prefixeTable.'history_summary');
 define('IMAGE_CATEGORY_TABLE', $prefixeTable.'image_category');
 define('IMAGES_TABLE', $prefixeTable.'images');
Index: /trunk/include/functions.inc.php
===================================================================
--- /trunk/include/functions.inc.php	(revision 1726)
+++ /trunk/include/functions.inc.php	(revision 1727)
@@ -412,53 +412,83 @@
 }
 
-function pwg_log( $file, $category, $picture = '' )
-{
-  global $conf, $user;
-
-  if ( is_admin() )
-  {
-    $doit=$conf['history_admin'];
-  }
-  elseif ( $user['is_the_guest'] )
-  {
-    $doit=$conf['history_guest'];
-  }
-  else
-  {
-    $doit = $conf['log'];
-  }
-
-  if ($doit)
-  {
-    $login = ($user['id'] == $conf['guest_id'])
-      ? 'guest' : addslashes($user['username']);
-    insert_into_history($login, $file, $category, $picture);
-  }
-}
-
-function pwg_log_login( $username )
-{
-  global $conf;
-  if ( $conf['login_history'] )
-  {
-    insert_into_history($username, 'login', '', '');
-  }
-}
-
-// inserts a row in the history table
-function insert_into_history( $login, $file, $category, $picture)
-{
+function pwg_log($image_id = null)
+{
+  global $conf, $user, $page;
+
+  if (!$conf['log'])
+  {
+    return false;
+  }
+
+  if (is_admin() and !$conf['history_admin'])
+  {
+    return false;
+  }
+
+  if ($user['is_the_guest'] and !$conf['history_guest'])
+  {
+    return false;
+  }
+
+  $tags_string = null;
+  if (isset($page['section']) and $page['section'] == 'tags')
+  {
+    $tag_ids = array();
+    foreach ($page['tags'] as $tag)
+    {
+      array_push($tag_ids, $tag['id']);
+    }
+
+    $tags_string = implode(',', $tag_ids);
+  }
+
+  // here we ask the database the current date and time, and we extract
+  // {year, month, day} from the current date. We could do this during the
+  // insert query with a CURDATE(), CURTIME(), DATE_FORMAT(CURDATE(), '%Y')
+  // ... but I (plg) think it would cost more than a double query and a PHP
+  // extraction.
+  $query = '
+SELECT CURDATE(), CURTIME()
+;';
+  list($curdate, $curtime) = mysql_fetch_row(pwg_query($query));
+
+  list($curyear, $curmonth, $curday) = explode('-', $curdate);
+  list($curhour) = explode(':', $curtime);
+  
   $query = '
 INSERT INTO '.HISTORY_TABLE.'
-  (date,login,IP,file,category,picture)
+  (
+    date,
+    time,
+    year,
+    month,
+    day,
+    hour,
+    user_id,
+    IP,
+    section,
+    category_id,
+    image_id,
+    tag_ids
+  )
   VALUES
-  (NOW(),
-  \''.$login.'\',
-  \''.$_SERVER['REMOTE_ADDR'].'\',
-  \''.addslashes($file).'\',
-  \''.addslashes(strip_tags($category)).'\',
-  \''.addslashes($picture).'\')
+  (
+    \''.$curdate.'\',
+    \''.$curtime.'\',
+    '.$curyear.',
+    '.$curmonth.',
+    '.$curday.',
+    '.$curhour.',
+    '.$user['id'].',
+    \''.$_SERVER['REMOTE_ADDR'].'\',
+    '.(isset($page['section']) ? "'".$page['section']."'" : 'NULL').',
+    '.(isset($page['category']) ? $page['category'] : 'NULL').',
+    '.(isset($image_id) ? $image_id : 'NULL').',
+    '.(isset($tags_string) ? "'".$tags_string."'" : 'NULL').'
+  )
 ;';
   pwg_query($query);
+
+  return true;
 }
 
@@ -841,5 +871,11 @@
 
   $template->assign_block_vars(
-    $blockname, array('SELECTED' => '', 'VALUE' => 0, 'OPTION' => '--'));
+    $blockname,
+    array(
+      'SELECTED' => '',
+      'VALUE' => 0,
+      'OPTION' => '--'
+      )
+    );
 
   for ($i = 1; $i <= 31; $i++)
@@ -851,7 +887,11 @@
     }
     $template->assign_block_vars(
-      $blockname, array('SELECTED' => $selected,
-                        'VALUE' => $i,
-                        'OPTION' => str_pad($i, 2, '0', STR_PAD_LEFT)));
+      $blockname,
+      array(
+        'SELECTED' => $selected,
+        'VALUE' => $i,
+        'OPTION' => str_pad($i, 2, '0', STR_PAD_LEFT)
+        )
+      );
   }
 }
@@ -868,7 +908,10 @@
 
   $template->assign_block_vars(
-    $blockname, array('SELECTED' => '',
-                      'VALUE' => 0,
-                      'OPTION' => '------------'));
+    $blockname,
+    array(
+      'SELECTED' => '',
+      'VALUE' => 0,
+      'OPTION' => '------------')
+    );
 
   for ($i = 1; $i <= 12; $i++)
@@ -880,7 +923,10 @@
     }
     $template->assign_block_vars(
-      $blockname, array('SELECTED' => $selected,
-                        'VALUE' => $i,
-                        'OPTION' => $lang['month'][$i]));
+      $blockname,
+      array(
+        'SELECTED' => $selected,
+        'VALUE' => $i,
+        'OPTION' => $lang['month'][$i])
+      );
   }
 }
@@ -1078,4 +1124,44 @@
 
 /**
+ * Prepends and appends a string at each value of the given array.
+ *
+ * @param array
+ * @param string prefix to each array values
+ * @param string suffix to each array values
+ */
+function prepend_append_array_items($array, $prepend_str, $append_str)
+{
+  array_walk(
+    $array,
+    create_function('&$s', '$s = "'.$prepend_str.'".$s."'.$append_str.'";')
+    );
+
+  return $array;
+}
+
+/**
+ * creates an hashed based on a query, this function is a very common
+ * pattern used here. Among the selected columns fetched, choose one to be
+ * the key, another one to be the value.
+ *
+ * @param string $query
+ * @param string $keyname
+ * @param string $valuename
+ * @return array
+ */
+function simple_hash_from_query($query, $keyname, $valuename)
+{
+  $array = array();
+
+  $result = pwg_query($query);
+  while ($row = mysql_fetch_array($result))
+  {
+    $array[ $row[$keyname] ] = $row[$valuename];
+  }
+
+  return $array;
+}
+
+/**
  * Return basename of the current script
  * Lower case convertion is applied on return value
Index: /trunk/include/functions_search.inc.php
===================================================================
--- /trunk/include/functions_search.inc.php	(revision 1726)
+++ /trunk/include/functions_search.inc.php	(revision 1727)
@@ -26,21 +26,4 @@
 // +-----------------------------------------------------------------------+
 
-
-/**
- * Prepends and appends a string at each value of the given array.
- *
- * @param array
- * @param string prefix to each array values
- * @param string suffix to each array values
- */
-function prepend_append_array_items($array, $prepend_str, $append_str)
-{
-  array_walk(
-    $array,
-    create_function('&$s', '$s = "'.$prepend_str.'".$s."'.$append_str.'";')
-    );
-
-  return $array;
-}
 
 /**
Index: /trunk/index.php
===================================================================
--- /trunk/index.php	(revision 1726)
+++ /trunk/index.php	(revision 1727)
@@ -302,5 +302,5 @@
 }
 //------------------------------------------------------------ log informations
-pwg_log('category', $page['title']);
+pwg_log();
 
 include(PHPWG_ROOT_PATH.'include/page_header.php');
Index: /trunk/install/db/42-database.php
===================================================================
--- /trunk/install/db/42-database.php	(revision 1727)
+++ /trunk/install/db/42-database.php	(revision 1727)
@@ -0,0 +1,88 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2005 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | branch        : BSF (Best So Far)
+// | file          : $RCSfile$
+// | last update   : $Date: 2005-09-21 00:04:57 +0200 (mer, 21 sep 2005) $
+// | last modifier : $Author: plg $
+// | revision      : $Revision: 870 $
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify  |
+// | it under the terms of the GNU General Public License as published by  |
+// | the Free Software Foundation                                          |
+// |                                                                       |
+// | This program is distributed in the hope that it will be useful, but   |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
+// | General Public License for more details.                              |
+// |                                                                       |
+// | You should have received a copy of the GNU General Public License     |
+// | along with this program; if not, write to the Free Software           |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA.                                                                  |
+// +-----------------------------------------------------------------------+
+
+if (!defined('PHPWG_ROOT_PATH'))
+{
+  die('Hacking attempt!');
+}
+
+$upgrade_description = 'History table new model and new table history_summary';
+
+include_once(PHPWG_ROOT_PATH.'include/constants.php');
+
+// +-----------------------------------------------------------------------+
+// |                            Upgrade content                            |
+// +-----------------------------------------------------------------------+
+
+echo "Recreate table ".HISTORY_TABLE."\n";
+
+$query = 'DROP TABLE '.HISTORY_TABLE.';';
+pwg_query($query);
+
+$query = "
+CREATE TABLE `".HISTORY_TABLE."` (
+  `id` int(10) unsigned NOT NULL auto_increment,
+  `date` date NOT NULL default '0000-00-00',
+  `time` time NOT NULL default '00:00:00',
+  `year` smallint(4) NOT NULL default '0',
+  `month` tinyint(2) NOT NULL default '0',
+  `day` tinyint(2) NOT NULL default '0',
+  `hour` tinyint(2) NOT NULL default '0',
+  `user_id` smallint(5) NOT NULL default '0',
+  `IP` varchar(15) NOT NULL default '',
+  `section` enum('categories','tags','search','list','favorites','most_visited','best_rated','recent_pics','recent_cats') default NULL,
+  `category_id` smallint(5) default NULL,
+  `tag_ids` varchar(50) default NULL,
+  `image_id` mediumint(8) default NULL,
+  `summarized` enum('true','false') default 'false',
+  PRIMARY KEY  (`id`),
+  KEY `history_i1` (`summarized`)
+) TYPE=MyISAM
+;";
+pwg_query($query);
+
+echo "Create table ".HISTORY_SUMMARY_TABLE."\n";
+$query = "
+CREATE TABLE `".HISTORY_SUMMARY_TABLE."` (
+  `id` varchar(13) NOT NULL default '',
+  `year` smallint(4) NOT NULL default '0',
+  `month` tinyint(2) default NULL,
+  `day` tinyint(2) default NULL,
+  `hour` tinyint(2) default NULL,
+  `nb_pages` int(11) default NULL,
+  PRIMARY KEY  (`id`)
+) TYPE=MyISAM
+;";
+pwg_query($query);
+
+echo
+"\n"
+.'"'.$upgrade_description.'"'.' ended'
+."\n"
+;
+
+?>
Index: /trunk/install/phpwebgallery_structure.sql
===================================================================
--- /trunk/install/phpwebgallery_structure.sql	(revision 1726)
+++ /trunk/install/phpwebgallery_structure.sql	(revision 1727)
@@ -1,3 +1,3 @@
-1-- MySQL dump 9.11
+-- MySQL dump 9.11
 --
 -- Host: localhost    Database: pwg-bsf
@@ -113,11 +113,35 @@
 DROP TABLE IF EXISTS `phpwebgallery_history`;
 CREATE TABLE `phpwebgallery_history` (
-  `date` datetime NOT NULL default '0000-00-00 00:00:00',
-  `login` varchar(15) default NULL,
-  `IP` varchar(50) NOT NULL default '',
-  `category` varchar(150) default NULL,
-  `file` varchar(50) default NULL,
-  `picture` varchar(150) default NULL,
-  KEY `history_i1` (`date`)
+  `id` int(10) unsigned NOT NULL auto_increment,
+  `date` date NOT NULL default '0000-00-00',
+  `time` time NOT NULL default '00:00:00',
+  `year` smallint(4) NOT NULL default '0',
+  `month` tinyint(2) NOT NULL default '0',
+  `day` tinyint(2) NOT NULL default '0',
+  `hour` tinyint(2) NOT NULL default '0',
+  `user_id` smallint(5) NOT NULL default '0',
+  `IP` varchar(15) NOT NULL default '',
+  `section` enum('categories','tags','search','list','favorites','most_visited','best_rated','recent_pics','recent_cats') default NULL,
+  `category_id` smallint(5) default NULL,
+  `tag_ids` varchar(50) default NULL,
+  `image_id` mediumint(8) default NULL,
+  `summarized` enum('true','false') default 'false',
+  PRIMARY KEY  (`id`),
+  KEY `history_i1` (`summarized`)
+) TYPE=MyISAM;
+
+--
+-- Table structure for table `phpwebgallery_history_summary`
+--
+
+DROP TABLE IF EXISTS `phpwebgallery_history_summary`;
+CREATE TABLE `phpwebgallery_history_summary` (
+  `id` varchar(13) NOT NULL default '',
+  `year` smallint(4) NOT NULL default '0',
+  `month` tinyint(2) default NULL,
+  `day` tinyint(2) default NULL,
+  `hour` tinyint(2) default NULL,
+  `nb_pages` int(11) default NULL,
+  PRIMARY KEY  (`id`)
 ) TYPE=MyISAM;
 
@@ -299,7 +323,7 @@
   `cat_id` smallint(5) unsigned NOT NULL default '0',
   `max_date_last` datetime default NULL,
-  `count_images` mediumint(8) unsigned default 0,
-  `count_categories` mediumint(8) unsigned default 0,
-  PRIMARY KEY  (`user_id`, `cat_id`)
+  `count_images` mediumint(8) unsigned default '0',
+  `count_categories` mediumint(8) unsigned default '0',
+  PRIMARY KEY  (`user_id`,`cat_id`)
 ) TYPE=MyISAM;
 
@@ -396,22 +420,22 @@
 ) TYPE=MyISAM;
 
--- 
+--
 -- Table structure for table `phpwebgallery_ws_access`
--- 
-
-DROP TABLE IF EXISTS phpwebgallery_ws_access;
-CREATE TABLE phpwebgallery_ws_access (
-  id smallint(5) unsigned NOT NULL auto_increment,
-  name varchar(32) NOT NULL default '',
-  access varchar(255) default NULL,
+--
+
+DROP TABLE IF EXISTS `phpwebgallery_ws_access`;
+CREATE TABLE `phpwebgallery_ws_access` (
+  `id` smallint(5) unsigned NOT NULL auto_increment,
+  `name` varchar(32) NOT NULL default '',
+  `access` varchar(255) default NULL,
   `start` datetime default NULL,
   `end` datetime default NULL,
-  request varchar(255) default NULL,
-  high enum('true','false') NOT NULL default 'true',
-  normal enum('true','false') NOT NULL default 'true',
+  `request` varchar(255) default NULL,
+  `high` enum('true','false') NOT NULL default 'true',
+  `normal` enum('true','false') NOT NULL default 'true',
   `limit` smallint(5) unsigned default NULL,
   `comment` varchar(255) default NULL,
-  PRIMARY KEY  (id),
-  UNIQUE KEY name (name)
-) ENGINE=MyISAM COMMENT='Access for Web Services';
-        
+  PRIMARY KEY  (`id`),
+  UNIQUE KEY `name` (`name`)
+) TYPE=MyISAM COMMENT='Access for Web Services';
+
Index: /trunk/picture.php
===================================================================
--- /trunk/picture.php	(revision 1726)
+++ /trunk/picture.php	(revision 1727)
@@ -790,5 +790,5 @@
 }
 //------------------------------------------------------------ log informations
-pwg_log('picture', $page['title'], $picture['current']['file']);
+pwg_log($picture['current']['id']);
 
 include(PHPWG_ROOT_PATH.'include/page_header.php');
Index: /trunk/search.php
===================================================================
--- /trunk/search.php	(revision 1726)
+++ /trunk/search.php	(revision 1727)
@@ -235,5 +235,4 @@
 }
 //------------------------------------------------------------ log informations
-pwg_log( 'search', $title );
 include(PHPWG_ROOT_PATH.'include/page_header.php');
 $template->parse('search');
Index: /trunk/template/yoga/admin.tpl
===================================================================
--- /trunk/template/yoga/admin.tpl	(revision 1726)
+++ /trunk/template/yoga/admin.tpl	(revision 1727)
@@ -16,5 +16,13 @@
         <li><a href="{U_FAQ}">{lang:instructions}</a></li>
         <li><a href="{U_SITE_MANAGER}">{lang:Site manager}</a></li>
-        <li><a href="{U_HISTORY}">{lang:history}</a></li>
+
+        <li>
+          {lang:history}
+          <ul>
+            <li><a href="{U_HISTORY_STAT}">{lang:Statistics}</a></li>
+            <li><a href="{U_HISTORY_SEARCH}">{lang:Search}</a></li>
+          </ul>
+        </li>
+
         <li><a href="{U_CAT_UPDATE}">{lang:update}</a></li>
       </ul>
Index: /trunk/template/yoga/admin/element_set_global.tpl
===================================================================
--- /trunk/template/yoga/admin/element_set_global.tpl	(revision 1726)
+++ /trunk/template/yoga/admin/element_set_global.tpl	(revision 1727)
@@ -160,4 +160,6 @@
     <li><label><input type="radio" name="caddie_action" value="add_selected" /> {lang:Add selected elements to caddie}</label></li>
     <!-- END not_in_caddie -->
+
+    <li><label><input type="radio" name="caddie_action" value="export" /> {lang:Export data}</label></li>
   
   </ul>
Index: /trunk/template/yoga/admin/history.tpl
===================================================================
--- /trunk/template/yoga/admin/history.tpl	(revision 1727)
+++ /trunk/template/yoga/admin/history.tpl	(revision 1727)
@@ -0,0 +1,93 @@
+<div class="titrePage">
+  <ul class="categoryActions">
+    <li>
+      <a
+        href="{U_HELP}"
+        onclick="popuphelp(this.href); return false;"
+        title="{lang:Help}"
+      >
+        <img src="{themeconf:icon_dir}/help.png" class="button" alt="(?)">
+      </a>
+    </li>
+  </ul>
+  <h2>{lang:History}</h2>
+</div>
+
+<form class="filter" method="post" name="filter" action="{F_ACTION}">
+<fieldset>
+  <legend>{lang:Filter}</legend>
+  <ul>
+    <li><label>{lang:search_date_from}</label></li>
+    <li>
+      <select name="start_day">
+        <!-- BEGIN start_day -->
+        <option {start_day.SELECTED} value="{start_day.VALUE}">{start_day.OPTION}</option>
+        <!-- END start_day -->
+      </select>
+      <select name="start_month">
+        <!-- BEGIN start_month -->
+        <option {start_month.SELECTED} value="{start_month.VALUE}">{start_month.OPTION}</option>
+        <!-- END start_month -->
+      </select>
+      <input name="start_year" value="{START_YEAR}" type="text" size="4" maxlength="4" >
+    </li>
+  </ul>
+  <ul>
+    <li><label>{lang:search_date_to}</label></li>
+    <li>
+      <select name="end_day">
+        <!-- BEGIN end_day -->
+        <option {end_day.SELECTED} value="{end_day.VALUE}">{end_day.OPTION}</option>
+        <!-- END end_day -->
+      </select>
+      <select name="end_month">
+        <!-- BEGIN end_month -->
+        <option {end_month.SELECTED} value="{end_month.VALUE}">{end_month.OPTION}</option>
+        <!-- END end_month -->
+      </select>
+      <input name="end_year" value="{END_YEAR}" type="text" size="4" maxlength="4" >
+    </li>
+  </ul>
+
+  <input type="submit" name="submit" value="{lang:submit}" {TAG_INPUT_ENABLED}/>
+</fieldset>
+</form>
+
+<h3>{L_DATE_TITLE}</h3>
+
+<!-- BEGIN navigation -->
+<div class="admin">
+{navigation.NAVBAR}
+</div>
+<!-- END navigation -->
+
+<table class="table2" id="detailedStats">
+  <tr class="throw">
+    <th>{lang:date}</th>
+    <th>{lang:time}</th>
+    <th>{lang:user}</th>
+    <th>{lang:IP}</th>
+    <th>{lang:image}</th>
+    <th>{lang:section}</th>
+    <th>{lang:category}</th>
+    <th>{lang:tags}</th>
+  </tr>
+<!-- BEGIN detail -->
+  <tr class="{detail.T_CLASS}">
+    <td class="hour">{detail.DATE}</td>
+    <td class="hour">{detail.TIME}</td>
+    <td>{detail.USER}</td>
+    <td>{detail.IP}</td>
+    <td>{detail.IMAGE}</td>
+    <td>{detail.SECTION}</td>
+    <td>{detail.CATEGORY}</td>
+    <td>{detail.TAGS}</td>
+  </tr>
+<!-- END detail -->
+</table>
+
+<!-- BEGIN navigation -->
+<div class="admin">
+{navigation.NAVBAR}
+</div>
+<!-- END navigation -->
Index: /trunk/template/yoga/admin/stats.tpl
===================================================================
--- /trunk/template/yoga/admin/stats.tpl	(revision 1726)
+++ /trunk/template/yoga/admin/stats.tpl	(revision 1727)
@@ -3,13 +3,11 @@
 
 <h3>{L_STAT_TITLE}</h3>
-<img class="image" src="{IMG_REPORT}" alt="{L_STAT_MONTHLY_ALT}" />
 
-<h3>{L_STAT_DETAIL_TITLE}</h3>
+<img class="image" src="{SRC_REPORT}" alt="{lang:history chart}" />
+
 <table class="table2" id="dailyStats">
   <tr class="throw">
-    <th>{L_VALUE}</th>
-    <th>{L_PAGES_SEEN}</th>
-    <th>{L_VISITORS}</th>
-    <th>{L_PICTURES}</th>
+    <th>{PERIOD_LABEL}</th>
+    <th>{lang:Pages seen}</th>
   </tr>
 <!-- BEGIN statrow -->
@@ -17,35 +15,5 @@
     <td>{statrow.VALUE}</td>
     <td class="number">{statrow.PAGES}</td>
-    <td class="number">{statrow.VISITORS}</td>
-    <td class="number">{statrow.IMAGES}</td>
   </tr>
 <!-- END statrow -->
 </table>
-
-<h3>{L_DATE_TITLE}</h3>
-<table class="table2" id="detailedStats">
-  <tr class="throw">
-    <th>{L_STAT_HOUR}</th>
-    <th>{L_STAT_LOGIN}</th>
-    <th>{L_STAT_ADDR}</th>
-    <th>{L_STAT_CATEGORY}</th>
-    <th>{L_STAT_FILE}</th>
-    <th>{L_STAT_PICTURE}</th> 
-  </tr>
-<!-- BEGIN detail -->
-  <tr class="{detail.T_CLASS}">
-    <td class="hour">{detail.HOUR}</td>
-    <td>{detail.LOGIN}</td>
-    <td>{detail.IP}</td>
-    <td>{detail.CATEGORY}</td>
-    <td>{detail.FILE}</td>
-    <td>{detail.PICTURE}</td>
-  </tr>
-<!-- END detail -->
-</table>
-
-<!-- BEGIN navigation -->
-<div class="admin">
-{navigation.NAV_BAR}
-</div>
-<!-- END navigation -->
Index: /trunk/tools/fill_history.pl
===================================================================
--- /trunk/tools/fill_history.pl	(revision 1727)
+++ /trunk/tools/fill_history.pl	(revision 1727)
@@ -0,0 +1,336 @@
+#!/usr/bin/perl
+
+use warnings;
+use strict;
+use Getopt::Long;
+use DBI;
+use File::Basename;
+use Time::Local;
+use List::Util qw/shuffle min/;
+
+my %opt;
+GetOptions(
+    \%opt,
+    qw/dbname=s dbuser=s dbpass=s prefix=s
+       total=i start_date=s end_date=s
+       help/
+   );
+
+if (defined($opt{help}))
+{
+  print <<FIN;
+
+Fill the user comments table of PhpWebGallery.
+
+Usage: pwg_fill_comments.pl --dbname=<database_name>
+                            --dbuser=<username>
+                            --dbpass=<password>
+                            --tagfile=<tags filename>
+                            [--prefix=<tables prefix>]
+                            [--help]
+
+--dbname, --dbuser and --dbpass are connexion parameters.
+
+--tagfile
+
+--prefix : determines the prefix for your table names.
+
+--help : show this help
+
+FIN
+
+  exit(0);
+}
+
+my $usage = "\n\n".basename($0)." --help for help\n\n";
+
+foreach my $option (qw/dbname dbuser dbpass start_date end_date/) {
+  if (not exists $opt{$option}) {
+    die 'Error: '.$option.' is a mandatory option', $usage;
+  }
+}
+
+$opt{prefix} = 'phpwebgallery_' if (not defined $opt{prefix});
+my $dbh = DBI->connect(
+    'DBI:mysql:'.$opt{dbname},
+    $opt{dbuser},
+    $opt{dbpass}
+);
+
+my $query;
+my $sth;
+
+
+# retrieve all available users
+$query = '
+SELECT id
+  FROM '.$opt{prefix}.'users
+';
+my @user_ids = keys %{ $dbh->selectall_hashref($query, 'id') };
+
+# set a list of IP addresses for each users
+my %user_IPs = ();
+foreach my $user_id (@user_ids) {
+    for (1 .. 1 + int rand 5) {
+        push(
+            @{ $user_IPs{$user_id} },
+            join(
+                '.',
+                map {1 + int rand 255} 1..4
+            )
+        );
+    }
+}
+
+# use Data::Dumper; print Dumper(\%user_IPs); exit();
+
+# start and end dates
+my ($year,$month,$day,$hour,$min,$sec)
+     = ($opt{start_date} =~ m/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/);
+my $start_unixtime = timelocal(0,0,0,$day,$month-1,$year);
+
+($year,$month,$day,$hour,$min,$sec)
+     = ($opt{end_date} =~ m/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/);
+my $end_unixtime = timelocal(0,0,0,$day,$month-1,$year);
+
+# "tags from image" and "images from tag"
+$query = '
+SELECT image_id, tag_id
+  FROM '.$opt{prefix}.'image_tag
+';
+my %image_tags = ();
+my %tag_images = ();
+my %related_tag_of = ();
+my @tags = ();
+$sth = $dbh->prepare($query);
+$sth->execute();
+while (my $row = $sth->fetchrow_hashref()) {
+    push(
+        @{$image_tags{$row->{image_id}}},
+        $row->{tag_id}
+    );
+
+    push(
+        @{$tag_images{$row->{tag_id}}},
+        $row->{image_id}
+    );
+
+    push (
+        @tags,
+        $row->{tag_id}
+    );
+}
+
+# foreach my $tag_id (keys %tag_images) {
+#     printf(
+#         "tag %5u: %5u images\n",
+#         $tag_id,
+#         scalar @{$tag_images{$tag_id}}
+#     );
+# }
+# exit();
+
+# use Data::Dumper; print Dumper(\%tag_images); exit();
+
+# categories from image_id
+$query = '
+SELECT image_id, category_id
+  FROM '.$opt{prefix}.'image_category
+';
+my %image_categories = ();
+my %category_images =();
+my %categories = ();
+$sth = $dbh->prepare($query);
+$sth->execute();
+while (my $row = $sth->fetchrow_hashref()) {
+    push(
+        @{$image_categories{$row->{image_id}}},
+        $row->{category_id}
+    );
+
+    push(
+        @{$category_images{$row->{category_id}}},
+        $row->{image_id}
+    );
+
+    $categories{ $row->{category_id} }++;
+}
+
+my @images = keys %image_categories;
+my @categories = keys %categories;
+
+# use Data::Dumper;
+# print Dumper(\%image_categories);
+
+my @sections = (
+    'categories',
+#     'tags',
+#     'search',
+#     'list',
+#     'favorites',
+#     'most_visited',
+#     'best_rated',
+#     'recent_pics',
+#     'recent_cats',
+);
+
+my @inserts = ();
+
+USER : foreach my $user_id (@user_ids) {
+    print 'user_id: ', $user_id, "\n";
+
+    my $current_unixtime = $start_unixtime;
+    my @IPs = @{ $user_IPs{$user_id} };
+
+    VISIT : foreach my $visit_num (1..100_000) {
+        print 'visit: ', $visit_num, "\n";
+        my @temp_inserts = ();
+        my $IP = (@IPs)[int rand @IPs];
+        my $current_page = 0;
+        my $visit_size = 10 + int rand 90;
+        $current_unixtime+= 86_400 + int rand(86_400 * 30);
+
+        my $section = $sections[int rand scalar @sections];
+        # print 'section: ', $section, "\n";
+
+        push(
+            @temp_inserts,
+            {
+                section => $section,
+            }
+        );
+
+        if ($section eq 'categories') {
+            CATEGORY : foreach my $category_id (
+                (shuffle @categories)[1..int rand scalar @categories]
+            ) {
+                # print 'category: ', $category_id, "\n";
+                push(
+                    @temp_inserts,
+                    {
+                        category_id => $category_id,
+                    }
+                );
+
+                my @images = @{$category_images{$category_id}};
+                IMAGE : foreach my $image_id (
+                    (shuffle @images)[1..min(10, scalar @images)]
+                ) {
+                    push(
+                        @temp_inserts,
+                        {
+                            category_id => $category_id,
+                            image_id => $image_id,
+                        }
+                    );
+                }
+            }
+        }
+
+        if ($section eq 'tags') {
+            # TODO
+        }
+
+        # transfert @temp_inserts to @inserts
+        print 'temp_insert size: ', scalar @temp_inserts, "\n";
+        foreach my $temp_insert (@temp_inserts) {
+            $current_unixtime+= 5 + int rand 25;
+            next VISIT if ++$current_page == $visit_size;
+            last VISIT if $current_unixtime >= $end_unixtime;
+
+            my $date = unixtime_to_mysqldate($current_unixtime);
+            my $time = unixtime_to_mysqltime($current_unixtime);
+
+            my ($year, $month, $day) = split '-', $date;
+            my ($hour) = split ':', $time;
+
+            $temp_insert->{date} = $date;
+            $temp_insert->{time} = $time;
+            $temp_insert->{year} = $year;
+            $temp_insert->{month} = $month;
+            $temp_insert->{day} = $day;
+            $temp_insert->{hour} = $hour;
+            $temp_insert->{IP} = $IP;
+            $temp_insert->{section} = $section;
+            $temp_insert->{user_id} = $user_id;
+
+            push(@inserts, $temp_insert);
+        }
+    }
+}
+
+@inserts = sort {
+    $a->{date} cmp $b->{date}
+    or $a->{time} cmp $b->{time}
+} @inserts;
+
+if (scalar @inserts) {
+    my @columns =
+        qw/
+              date time year month day hour
+              user_id IP
+              section category_id image_id
+          /;
+
+    my $question_marks_string = '(';
+    $question_marks_string.= join(
+        ',',
+        map {'?'} @columns
+    );
+    $question_marks_string.= ')';
+
+    my $query = '
+INSERT INTO '.$opt{prefix}.'history
+  ('.join(', ', @columns).')
+  VALUES
+';
+    $query.= join(
+        ',',
+        map {$question_marks_string} (1 .. scalar @inserts)
+    );
+    $query.= '
+';
+
+    # print $query, "\n";
+
+    my @values = ();
+
+    foreach my $insert (@inserts) {
+        push(
+            @values,
+            map {
+                $insert->{$_}
+            } @columns
+        );
+    }
+
+    $sth = $dbh->prepare($query);
+    $sth->execute(@values)
+        or die 'cannot execute insert query';
+}
+
+sub unixtime_to_mysqldate {
+    my ($unixtime) = @_;
+
+    ($sec,$min,$hour,$day,$month,$year) = localtime($unixtime);
+
+    return sprintf(
+        '%d-%02d-%02d',
+        $year+1900,
+        $month+1,
+        $day,
+    );
+}
+
+sub unixtime_to_mysqltime {
+    my ($unixtime) = @_;
+
+    ($sec,$min,$hour,$day,$month,$year) = localtime($unixtime);
+
+    return sprintf(
+        '%d:%d:%d',
+        $hour,
+        $min,
+        $sec
+    );
+}
