is there an version of graphstat for drupal 5.0 in planning?

If so, it would be nice to have some more graphs, like additional ones for special node types or user groups.

Comments

pnikosis’s picture

I agree... now that I'm upgrading I'll lose my graphs :/

brashquido’s picture

I'd settle for a version that works with Drupal 5, never mind the enhancements for now.

havoc’s picture

+1 for working 5.x version. features can wait.

dwees’s picture

Version 5 available, although I'm not the module maintainer.

For graphstat.module use:

// $Id: graphstat.module,v 1.6.2.5 2006/11/12 10:35:00 driesk Exp $
/**
 * Implementation of hook_perm().
 */
function graphstat_perm() {
  return array('access graphs');
}

/**
 * Implementation of hook_help().
 */
function graphstat_help($section = '') {
  $output = '';
  switch ($section) {
    case 'admin/modules#description':
      return t('Creates graphs based on data recorded by the statistics, node, user and comment modules.');
    case 'admin/logs/graphs':
    case 'admin/logs/graphs/daily':
      $output = '<p>'. t('Daily graphs are based on data recorded by the statistics module. They show average statistics for one particular day at a time. The available dates depend on your '.l('Discard access logs', 'admin/settings/statistics').' settings.') .'</p>';
      if (variable_get('configurable_timezones', 1)) {
        global $user;
        $output .= '<p>'. t('Dates and times shown in the graphs, correspond to your '.l('local timezone', 'user/'.$user->uid.'/edit').'.') .'</p>';
      }
      return $output;
    case 'admin/logs/graphs/history':
      return '<p>'. t('History graphs are based on data recorded by the node, user and comment modules. They show statistics from the day the first node, user or comment was created, until today. If comment module is disabled, or no nodes or comments exist, the graphs concerned will not be displayed.') .'</p>';
  }
}

/**
 * Implementation of hook_menu().
 */
function graphstat_menu($may_cache) {
  drupal_add_css(drupal_get_path('module', 'graphstat').'/graphstat.css');
  $items = array();
  if ($may_cache) {
    $access = user_access('access graphs');
    $items[] = array('path' => 'admin/logs/graphs', 'title' => t('Graphs'),
                     'callback' => 'graphstat_graphs', 'access' => $access,
                     'weight' => 10);
    $items[] = array('path' => 'admin/logs/graphs/daily', 'title' => t('Daily graphs'),
                     'callback' => 'graphstat_graphs',
                     'access' => $access,
                     'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10);
    $items[] = array('path' => 'admin/logs/graphs/history', 'title' => t('History graphs'),
                     'callback' => 'graphstat_graphs_history',
                     'access' => $access,
                     'type' => MENU_LOCAL_TASK, 'weight' => -9);
  }
  return $items;
}

/**
 * Menu callback. Generates daily graphs page.
 */
function graphstat_graphs() {
  if (!module_exists('statistics')) {
    return '<p>'. t('Statistics module should be enabled in order to view these graphs.') .'</p>';
  }
    $path = drupal_get_path('module', 'graphstat');
    $edit = $_POST['edit'];
    global $user;
    if (variable_get('configurable_timezones', 1) && $user->uid && strlen($user->timezone)) {
      $timezone = $user->timezone;
    }
    else {
      $timezone = variable_get('date_default_timezone', 0);
    }
    // get oldest record and current date
    $min = db_result(db_query('SELECT MIN(timestamp) FROM {accesslog}'));
    $now = time();
    // figure out which local dates correspond with these timestamps - can be different between timezones
    $min_date = format_date($min, 'custom', 'm/d/Y');
    $now_date = format_date($now, 'custom', 'm/d/Y');
    // figure out the (UNIX Epoch) timestamp that corresponds to when the first day began locally
    // figure out the (UNIX Epoch) timestamp that corresponds to when today ends locally
    $min_date_frag = explode('/', $min_date);
    $now_date_frag = explode('/', $now_date);
    $gm_timestamp_min = gmmktime(0, 0, 0, $min_date_frag[0], $min_date_frag[1], $min_date_frag[2]);
    $gm_timestamp_now = gmmktime(23, 59, 59, $now_date_frag[0], $now_date_frag[1], $now_date_frag[2]);
    if ($timezone > 0) {
      $local_timestamp_min = $gm_timestamp_min - $timezone;
      $local_timestamp_now = $gm_timestamp_now - $timezone;
    }
    elseif ($timezone < 0) {
      $local_timestamp_min = $gm_timestamp_min + abs($timezone);
      $local_timestamp_now = $gm_timestamp_now + abs($timezone);
    }
    else {
      $local_timestamp_min = $gm_timestamp_min;
      $local_timestamp_now = $gm_timestamp_now;
    }
		
    $output = drupal_get_form('graphstat_date_pick', $local_timestamp_min, $local_timestamp_now);

    if ($_POST['op'] == t('Show') && isset($_POST['stat_date'])) {
      $start = $_POST['stat_date'];
      $stop = $start + 86400;
      while ($start < $stop) {
        $int = $start + 7200;
        // use this line if you want standard errors
        // $stats = db_fetch_object(db_query('SELECT AVG(timer) AS avg, (STDDEV(timer) / SQRT(COUNT(timer))) AS se FROM {accesslog} WHERE timestamp > %d AND timestamp <= %d', $start, $int));

        // use this line if you want standard deviations
        $stats = db_fetch_object(db_query('SELECT AVG(timer) AS avg, STDDEV(timer) AS se FROM {accesslog} WHERE timestamp > %d AND timestamp <= %d', $start, $int));

        $avg[] = $stats->avg ? round($stats->avg, 0) : 0;
        $se[] = $stats->se ? round($stats->se, 0) : 0;
        $start = $start + 7200;
      }
      $avg = implode(',', $avg);
      $se = implode(',', $se);
      $output .= '<div class="graph-container">';
      $output .= '<div class="graph-image">';
      $output .= theme('image', $path.'/render.php?h='.$avg.'&s='.$se.'&x='.t('Time (h)').'&y='.t('Page generation (ms)'), t('Average page generation time'), t('Average page generation time'), NULL, FALSE);
      $output .= '</div>';
      $output .= '<div class="graph-legend">';
      $output .= t('Average page generation time in milliseconds.');
      $output .= '<br />';
      $output .= t('Error bars indicate standard deviations.');
      $output .= '</div></div>';

      $start = $_POST['stat_date'];
      while ($start < $stop) {
        $int = $start + 7200;
        $stats = db_fetch_object(db_query('SELECT COUNT(aid) AS count FROM {accesslog} WHERE timestamp > %d AND timestamp <= %d', $start, $int));
        $count[] = $stats->count ? $stats->count : 0;
        $start = $start + 7200;
      }
      $count = implode(',', $count);
      $output .= '<div class="graph-container">';
      $output .= '<div class="graph-image">';
      $output .= theme('image', $path.'/render.php?h='.$count.'&x='.t('Time (h)').'&y='.t('Pages served'), t('Total number of pages served'), t('Total number of pages served'), NULL, FALSE);
      $output .= '</div>';
      $output .= '<div class="graph-legend">';
      $output .= t('Total number of pages served.');
      $output .= '</div></div>';

      $start = $_POST['stat_date'];
      while ($start < $stop) {
        $int = $start + 7200;
        $stats = db_fetch_object(db_query('SELECT COUNT(DISTINCT(path)) AS count FROM {accesslog} WHERE timestamp > %d AND timestamp <= %d', $start, $int));
        $pages[] = $stats->count ? $stats->count : 0;
        $start = $start + 7200;
      }
      $pages = implode(',', $pages);
      $output .= '<div class="graph-container">';
      $output .= '<div class="graph-image">';
      $output .= theme('image', $path.'/render.php?h='.$pages.'&x='.t('Time (h)').'&y='.t('Unique pages'), t('Number of unique pages served'), t('Number of unique pages served'), NULL, FALSE);
      $output .= '</div>';
      $output .= '<div class="graph-legend">';
      $output .= t('Number of unique pages served.');
      $output .= '</div></div>';

      $start = $_POST['stat_date'];
      while ($start < $stop) {
        $int = $start + 7200;
        $stats = db_fetch_object(db_query('SELECT COUNT(DISTINCT(hostname)) AS count FROM {accesslog} WHERE timestamp > %d AND timestamp <= %d', $start, $int));
        $visitors[] = $stats->count ? $stats->count : 0;
        $start = $start + 7200;
      }
      $visitors = implode(',', $visitors);
      $output .= '<div class="graph-container">';
      $output .= '<div class="graph-image">';
      $output .= theme('image', $path.'/render.php?h='.$visitors.'&x='.t('Time (h)').'&y='.t('Unique visitors'), t('Unique visitors'), t('Unique visitors'), NULL, FALSE);
      $output .= '</div>';
      $output .= '<div class="graph-legend">';
      $output .= t('Unique visitors.');
      $output .= '</div></div>';
    }
  return $output;
}

function graphstat_date_pick($local_timestamp_min, $local_timestamp_now) {
	// build the select form with all dates
	$select[0] = t('Select a date');
	while ($local_timestamp_min < $local_timestamp_now) {
		$date = format_date($local_timestamp_min, 'custom', 'm/d/Y');
		$select[$local_timestamp_min] = $date;
		$local_timestamp_min = $local_timestamp_min + 86400;
	}
	$form['stat_date'] = array('#type' => 'select', '#default_value' => $select[0], '#options' => $select);
	$form['submit'] = array('#type' => 'submit', '#value' => t('Show'));
	$form['#redirect'] = FALSE;
	
	return $form;
}

function graphstat_date_pick_submit() {
}

/**
 * Menu callback. Generates history graphs page.
 */
function graphstat_graphs_history() {
  $path = drupal_get_path('module', 'graphstat');
  $min['node'] = db_result(db_query('SELECT MIN(created) FROM {node}'));
  $min['users'] = db_result(db_query('SELECT MIN(created) FROM {users} WHERE uid != 0'));
  if (module_exists('comment')) {
    $min['comments'] = db_result(db_query('SELECT MIN(timestamp) FROM {comments}'));
  }
  $now = time();
  foreach ($min as $key => $value) {
    if ($min[$key]) {
      $int = round(($now - $value) / 11, 0);
      $time = $min[$key];
      for ($i = 0; $i < 12; $i++) {
        $id = drupal_substr($key, 0, 1).'id';
        $data[$key][$time] = db_result(db_query('SELECT COUNT(%s) FROM {'. $key .'} WHERE %s <= %d AND %s != 0', $id, $key == 'comments' ? 'timestamp' : 'created', $time, $id));
        $time = $time + $int;
      }
      $points[$key] = implode(',', $data[$key]);
      $x_labels[$key][] = format_date($min[$key], 'custom', 'm/d/Y');
      $x_labels[$key][] = format_date(round(($min[$key] + (($now - $min[$key]) * 0.33)), 0), 'custom', 'm/d/Y');
      $x_labels[$key][] = format_date(round(($min[$key] + (($now - $min[$key]) * 0.66)), 0), 'custom', 'm/d/Y');
      $x_labels[$key][] = format_date($now, 'custom', 'm/d/Y');
      $x_labels[$key] = implode(',', $x_labels[$key]);
    }
    else {
      $data[$key] = FALSE;
    }
  }
  if ($data['node']) {
    $output .= '<div class="graph-container">';
    $output .= '<div class="graph-image">';
    $output .= theme('image', $path.'/render.php?l='.$points['node'].'&xl='.$x_labels['node'].'&x='.t('Date').'&y='.t('Number of nodes'), t('Number of nodes'), t('Number of nodes'), NULL, FALSE);
    $output .= '</div>';
    $output .= '<div class="graph-legend">';
    $output .= t('Number of nodes.');
    $output .= '</div></div>';
  }
  if ($data['users']) {
    $output .= '<div class="graph-container">';
    $output .= '<div class="graph-image">';
    $output .= theme('image', $path.'/render.php?l='.$points['users'].'&xl='.$x_labels['users'].'&x='.t('Date').'&y='.t('Number of users'), t('Number of users'), t('Number of users'), NULL, FALSE);
    $output .= '</div>';
    $output .= '<div class="graph-legend">';
    $output .= t('Number of users.');
    $output .= '</div></div>';
  }
  if ($data['comments']) {
    $output .= '<div class="graph-container">';
    $output .= '<div class="graph-image">';
    $output .= theme('image', $path.'/render.php?l='.$points['comments'].'&xl='.$x_labels['comments'].'&x='.t('Date').'&y='.t('Number of comments'), t('Number of comments'), t('Number of comments'), NULL, FALSE);
    $output .= '</div>';
    $output .= '<div class="graph-legend">';
    $output .= t('Number of comments.');
    $output .= '</div></div>';
  }
  return $output;
}

Create a new file called graphstat.info and put this inside it:

; $Id$
name = Graphstat
description = Creates graphical summaries of site statistics.
dwees’s picture

Oops. Delete the first <?php from the first file.

brashquido’s picture

Thanks dwees :)

jacauc’s picture

Can someone commit a final release of this please.
The above solution works kinda, but when running update.php, I get messages about:

warning: Cannot modify header information - headers already sent by (output started at /home/dieinte1/public_html/sites/all/modules/graphstat/graphstat.module:255) in /home/dieinte1/public_html/includes/common.inc on line 141.

Once this is sorted, things should be lekker

bloomaniac’s picture

Works good for me too.
Please create a 5.x release.

binford2k’s picture

To avoid the "output already started" error, remove the extraneous whitespace from the file you created. (before and after the php tags)

beginner’s picture

profix898’s picture

Status: Active » Fixed
bloomaniac’s picture

Status: Fixed » Active

looks good,
I think a 'real' release would be good.

profix898’s picture

Status: Active » Fixed

Now there is a 5.x-1.0 release :)
I thought to collect feedback on the module first before creating a release ...

Anonymous’s picture

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for two weeks with no activity.