You are here

ad_report.module in Advertisement 5.2

Provides comprehensive charts and reports about advertising statistics.

Copyright (c) 2007-2008. Jeremy Andrews <jeremy@tag1consulting.com>.

File

report/ad_report.module
View source
<?php

/**
 * @file
 * Provides comprehensive charts and reports about advertising statistics.
 *
 * Copyright (c) 2007-2008.
 *   Jeremy Andrews <jeremy@tag1consulting.com>.
 */

/**
 * Implementation of hook_menu().
 */
function ad_report_menu($may_cache) {
  $items = array();
  if ($may_cache) {
    $items[] = array(
      'path' => 'admin/content/ad/report',
      'title' => t('Reports'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'ad_report_admin',
      ),
      'type' => MENU_LOCAL_TASK,
      'weight' => 1,
    );
    $items[] = array(
      'path' => 'admin/content/ad/report/display',
      'callback' => 'ad_report_admin_display',
      'type' => MENU_CALLBACK,
    );
  }
  else {
    if (arg(0) == 'node' && is_numeric(arg(1)) && ad_permission(arg(1), 'access statistics')) {
      $node = node_load(arg(1));
      if ($node->adtype) {
        $start = (int) arg(3);
        $end = (int) arg(4);
        $items[] = array(
          'path' => "node/{$node->nid}/report",
          'title' => t('Reports'),
          'callback' => 'ad_report_bargraph',
          'callback arguments' => array(
            $node,
            "node/{$node->nid}/report",
            'node',
            $start,
            $end,
          ),
          'type' => MENU_LOCAL_TASK,
          'access' => ad_permission($node->nid, 'generate reports'),
        );
      }
    }
    else {
      if (arg(0) == 'ad_report' && is_numeric(arg(1)) && is_numeric(arg(4)) && is_numeric(arg(5))) {
        if (arg(3) == 'node') {
          $access = ad_permission(arg(1), 'generate reports');
        }
        else {
          $access = user_access('generate administrative reports');
        }
        $id = arg(1);
        $type = arg(3);
        $start = (int) arg(4);
        $start_date = _ad_report_get_date_from_path($start);
        $end = (int) arg(5);
        $end_date = _ad_report_get_date_from_path($end);
        $items[] = array(
          'path' => "ad_report/{$id}/bargraph/{$type}/{$start}/{$end}",
          'title' => 'Bar graph',
          'callback' => 'ad_report_generate_bargraph',
          'callback arguments' => array(
            $id,
            $type,
            $start_date,
            $end_date,
          ),
          'type' => MENU_CALLBACK,
          'access' => $access,
        );
      }
      else {
        if (arg(0) == 'ad_report' && is_numeric(arg(3) && is_numeric(arg(4)))) {
        }
      }
    }
    $start = strtotime($_SESSION['ad_report_start']);
    $end = strtotime($_SESSION['ad_report_end']);
    $group = $_SESSION['ad_report_group'];
    if ($start && $end && is_array($group)) {
      $items[] = array(
        'path' => 'admin/content/ad/report/csv',
        'callback' => 'ad_report_admin_ad_table',
        'callback arguments' => array(
          $start,
          $end,
          $group,
          TRUE,
        ),
        'type' => MENU_CALLBACK,
      );
    }
  }
  return $items;
}

/**
 * Drupal hook_perm implementation.
 */
function ad_report_perm() {
  return array(
    t('generate administrative reports'),
  );
}

/**
 * Ad module hook_adapi.
 */
function ad_report_adapi($op, $node = NULL) {
  switch ($op) {
    case 'permissions':
      return array(
        'generate reports' => TRUE,
      );
  }
}

/**
 *
 */
function ad_report_admin() {
  $form = array();
  $start = $_SESSION['ad_report_start'] ? strtotime($_SESSION['ad_report_start']) : _ad_report_first_day_of_month();
  $end = $_SESSION['ad_report_end'] ? strtotime($_SESSION['ad_report_end']) : _ad_report_last_day_of_month();
  $group = $_SESSION['ad_report_group'] ? $_SESSION['ad_report_group'] : array(
    'all',
  );
  $form['dates'] = array(
    '#type' => 'fieldset',
    '#title' => t('Report dates'),
    '#prefix' => '<div class="container-inline">',
    '#suffix' => '</div>',
  );
  $form['dates']['start'] = array(
    '#type' => 'textfield',
    '#title' => t('Start'),
    '#size' => 24,
    '#maxlength' => 64,
    '#default_value' => _ad_report_format_date_human($start),
    // display pop up calendar if jstools jscalendar module enabled
    '#attributes' => array(
      'class' => 'jscalendar',
    ),
    '#jscalendar_ifFormat' => '%Y-%m-%d %H:%M',
    '#jscalendar_timeFormat' => '24',
  );
  $form['dates']['space1'] = array(
    '#value' => '&nbsp;&nbsp;',
  );
  $form['dates']['end'] = array(
    '#type' => 'textfield',
    '#title' => t('End'),
    '#size' => 24,
    '#maxlength' => 64,
    '#default_value' => _ad_report_format_date_human($end),
    // display pop up calendar if jstools jscalendar module enabled
    '#attributes' => array(
      'class' => 'jscalendar',
    ),
    '#jscalendar_ifFormat' => '%Y-%m-%d %H:%M',
  );
  $form['dates']['space2'] = array(
    '#value' => '&nbsp;&nbsp;&nbsp;',
  );

  // groups
  $groups = ad_groups_list();
  $form['groups'] = array(
    '#type' => 'fieldset',
    '#title' => t('Groups'),
  );
  $options = array();
  $options['all'] = t('- All -');
  $options = $options + $groups;
  $form['groups']['group'] = array(
    '#type' => 'select',
    '#title' => t('Ad groups'),
    '#options' => $options,
    '#multiple' => TRUE,
    '#required' => TRUE,
    '#default_value' => $group,
  );

  // submit
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Generate report'),
  );
  $form['reset'] = array(
    '#type' => 'submit',
    '#value' => t('Reset report'),
  );
  return $form;
}

/**
 * Sanity check the date range.
 */
function ad_report_admin_validate($form_id, $form_values) {
  if ($_POST['op'] == t('Reset report')) {
    unset($_SESSION['ad_report_start']);
    unset($_SESSION['ad_report_end']);
    unset($_SESSION['ad_report_group']);
  }
  else {
    $start = strtotime($form_values['start']);
    $end = strtotime($form_values['end']);
    if (!$start) {
      form_set_error('start', t('You must enter a valid start date.'));
    }
    else {
      if ($start >= time() - 3600) {
        form_set_error('start', t('The report must start at least one hour before the current time.'));
      }
      else {
        if ($start >= $end) {
          form_set_error('start', t('The report must start before it ends.'));
        }
      }
    }
    if (!$end) {
      form_set_error('end', t('You must enter a valid end date.'));
    }
  }
}

/**
 * Redirect to a path to generate the requested report.
 */
function ad_report_admin_submit($form_id, $form_values) {
  if ($_POST['op'] == t('Generate report')) {
    $start = date('YmdHi', strtotime($form_values['start']));
    $end = date('YmdHi', strtotime($form_values['end']));
    $group = $form_values['group'];
    $_SESSION['ad_report_start'] = $start;
    $_SESSION['ad_report_end'] = $end;
    $_SESSION['ad_report_group'] = $group;
    drupal_goto('admin/content/ad/report/display');
  }
}

/**
 * Display the administrative report.
 */
function ad_report_admin_display() {
  $start = $_SESSION['ad_report_start'];
  $end = $_SESSION['ad_report_end'];
  $group = $_SESSION['ad_report_group'];
  $output = '<div class="image"><img src="' . url("ad_report/0/bargraph/admin/{$start}/{$end}") . '" /></div>';
  $output .= ad_report_admin_ad_table(strtotime($start), strtotime($end), $group);
  $output .= '<div>' . l(t('Modify report'), 'admin/content/ad/report') . '</div>';
  return $output;
}

/**
 *
 */
function ad_report_admin_ad_table($start, $end, $group, $csv = FALSE) {

  // prepare dates
  $start = _ad_report_format_date_db($start);
  $end = _ad_report_format_date_db($end);

  // prepare groups
  $groups = ad_groups_list();
  $all = FALSE;
  $none = FALSE;
  if (is_array($group)) {
    if (in_array('all', $group)) {
      $all = TRUE;
    }
    if (!$all) {
      if (sizeof($group) == sizeof($groups)) {
        $all = TRUE;
      }
    }
    if (in_array('0', $group)) {
      unset($group[0]);
      $none = TRUE;
    }
  }
  if ($all) {
    $result = db_query('SELECT DISTINCT(aid) FROM {ad_statistics} WHERE date >= %d AND date <= %d', $start, $end);
  }
  else {
    if ($none) {
      if (sizeof($group)) {
        $result = db_query("SELECT DISTINCT(a.aid) FROM {ad_statistics} a LEFT JOIN {term_node} t ON a.aid = t.tid WHERE (t.tid IN (%s) OR ISNULL(t.tid)) AND action = 'view' AND a.date >= %d AND a.date <= %d", implode(',', $group), $start, $end);
      }
      else {
        $result = db_query("SELECT DISTINCT(a.aid) FROM {ad_statistics} a LEFT JOIN {term_node} t ON a.aid = t.tid WHERE ISNULL(t.tid) AND action = 'view' AND a.date >= %d AND a.date <= %d", $start, $end);
      }
    }
    else {
      $result = db_query("SELECT DISTINCT(a.aid) FROM {ad_statistics} a LEFT JOIN {term_node} t ON a.aid = t.tid WHERE t.tid IN (%s) AND action = 'view' AND a.date >= %d AND a.date <= %d", implode(',', $group), $start, $end);
    }
  }
  $ads = array();
  while ($ad = db_fetch_object($result)) {
    if ($ad->aid) {
      $ads[$ad->aid] = $ad->aid;
    }
  }
  if ($csv) {
    header('Content-type: application/octet-stream');
    header("Content-Disposition: attachment; filename=report-{$start}-{$end}.csv");
    echo "ad id, title, first view, last view, clicks, views, click-thru\n";
  }
  else {
    $output = '<div class="describe">' . t('There !count matching your parameters.', array(
      '!count' => format_plural(sizeof($ads), 'was 1 active ad', 'were @count active ads'),
    )) . '</div>';
    $headers = array(
      t('Advertisement'),
      t('Active dates'),
      t('Views'),
      t('Clicks'),
      t('Click-thru'),
    );

    // get counts for each ad
    $rows = array();
  }
  $total_views = $total_clicks = 0;
  foreach ($ads as $aid) {
    $ad = node_load($aid);
    if ($ad->aid) {
      $views = (int) db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'view' AND date >= %d AND date <= %d", $aid, $start, $end));
      $first = _ad_report_get_date_from_path((int) db_result(db_query("SELECT MIN(date) FROM {ad_statistics} WHERE aid = %d AND action = 'view' AND date >= %d AND date <= %d", $aid, $start, $end)));
      $first = format_date($first, 'small');
      $last = _ad_report_get_date_from_path((int) db_result(db_query("SELECT MAX(date) FROM {ad_statistics} WHERE aid = %d AND action = 'view' AND date >= %d AND date <= %d", $aid, $start, $end)));
      $last = format_date($last, 'small');
      $clicks = (int) db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'click' AND date >= %d AND date <= %d", $aid, $start, $end));
      if ($views) {
        $clickthru = number_format($clicks / $views, 2) . '%';
      }
      else {
        $clickthru = '0%';
      }
      if ($views || $clicks) {
        if ($csv) {
          echo "{$ad->nid}, {$ad->title}, {$first}, {$last}, {$views}, {$clicks}, {$clickthru}\n";
        }
        else {
          $row = array();
          $row[] = l($ad->title, "node/{$ad->nid}");
          $row[] = "first view: {$first}<br />last view: {$last}";
          $row[] = number_format($views);
          $row[] = number_format($clicks);
          $row[] = $clickthru;
          $rows[] = $row;
          $total_views += $views;
          $total_clicks += $clicks;
        }
      }
    }
  }
  if ($csv) {
    return 0;
  }
  if ($total_views || $total_clicks) {
    $row = array();
    $row[] = '<strong>' . t('Total') . '</strong>';
    $row[] = '';
    $row[] = '<strong>' . number_format($total_views) . '</strong>';
    $row[] = '<strong>' . number_format($total_clicks) . '</strong>';
    if ($total_views) {
      $row[] = '<strong>' . number_format($total_clicks / $total_views, 2) . '%' . '</strong>';
    }
    else {
      $row[] = '<strong>' . '0%' . '</strong>';
    }
    $rows[] = $row;
  }
  $output = theme('table', $headers, $rows);
  $output .= l(t('Download CSV'), 'admin/content/ad/report/csv');
  return $output;
}

/**
 * Returns a timestamp for the first hour of the first day of the month.
 */
function _ad_report_first_day_of_month($time = NULL) {
  if ($time === NULL) {
    $time = time();
  }
  return strtotime(date('Ym010000', $time));
}

/**
 * Returns a timestamp for the last hour of the last day of the month.
 */
function _ad_report_last_day_of_month($time = NULL) {
  if ($time === NULL) {
    $time = time();
  }
  $month = date('m', $time);
  $year = date('Y', $time);
  $day = date('d', mktime(0, 0, 0, $month + 1, 0, $year));
  return strtotime("{$year}{$month}{$day}2359");
}

/**
 * Page to display ad with bargraph.
 */
function ad_report_bargraph($data, $url, $type = 'node', $start = 0, $end = 0) {
  if ($type == 'node') {
    drupal_set_title($data->title);
  }
  $start_date = _ad_report_get_date_from_path($start);
  $end_date = _ad_report_get_date_from_path($end);
  $output = drupal_get_form('ad_report_range_form', $type, $url, $start_date, $end_date);
  if ($start && $end) {
    switch ($type) {
      case 'node':
        $ad = db_fetch_object(db_query('SELECT aid, redirect, adtype FROM {ads} WHERE aid = %d', $data->nid));
        if ($ad->aid) {
          $output .= '<img src="' . url("ad_report/{$data->nid}/bargraph/node/{$start}/{$end}") . '" />';
          $output .= theme('box', '', module_invoke("ad_{$data->adtype}", 'display_ad', $ad));
          $output .= ad_report_group_table($data->nid, $type, $start, $end);
        }
        $output .= module_invoke('ad', 'click_history', $data->nid);
        break;
      default:
        $output = '<img src="' . url("ad_report/{$data->uid}/bargraph/{$granularity}/{$type}") . '" />';
        break;
    }
  }
  return $output;
}

/**
 * Return a form for selecting a date range for generating a report.
 */
function ad_report_range_form($type, $url = NULL, $start = NULL, $end = NULL) {
  $form = array();
  $start = $start ? $start : _ad_report_first_day_of_month();
  $end = $end ? $end : _ad_report_last_day_of_month();
  $form['report'] = array(
    '#type' => 'fieldset',
    '#title' => t('Report dates'),
    '#prefix' => '<div class="container-inline">',
    '#suffix' => '</div>',
  );
  $form['report']['type'] = array(
    '#value' => $type,
    '#type' => 'hidden',
  );
  $form['report']['url'] = array(
    '#value' => $url,
    '#type' => 'hidden',
  );
  $form['report']['start'] = array(
    '#type' => 'textfield',
    '#title' => t('Start'),
    '#size' => 24,
    '#maxlength' => 64,
    '#default_value' => _ad_report_format_date_human($start),
    // display pop up calendar if jstools jscalendar module enabled
    '#attributes' => array(
      'class' => 'jscalendar',
    ),
    '#jscalendar_ifFormat' => '%Y-%m-%d %H:%M',
    '#jscalendar_timeFormat' => '24',
  );
  $form['report']['space1'] = array(
    '#value' => '&nbsp;&nbsp;',
  );
  $form['report']['end'] = array(
    '#type' => 'textfield',
    '#title' => t('End'),
    '#size' => 24,
    '#maxlength' => 64,
    '#default_value' => _ad_report_format_date_human($end),
    // display pop up calendar if jstools jscalendar module enabled
    '#attributes' => array(
      'class' => 'jscalendar',
    ),
    '#jscalendar_ifFormat' => '%Y-%m-%d %H:%M',
  );
  $form['report']['space2'] = array(
    '#value' => '&nbsp;&nbsp;&nbsp;',
  );
  $form['report']['generate'] = array(
    '#type' => 'submit',
    '#value' => t('Generate report'),
  );
  return $form;
}

/**
 * Validate the form range.
 */
function ad_report_range_form_validate($form_id, $form_values) {
  $start = strtotime($form_values['start']);
  $end = strtotime($form_values['end']);
  if (!$start) {
    form_set_error('start', t('You must enter a valid start date.'));
  }
  else {
    if ($start >= time() - 3600) {
      form_set_error('start', t('The report must start at least one hour before the current time.'));
    }
    else {
      if ($start >= $end) {
        form_set_error('start', t('The report must start before it ends.'));
      }
    }
  }
  if (!$end) {
    form_set_error('end', t('You must enter a valid end date.'));
  }
}

/**
 * Redirect to URL for displaying report.
 */
function ad_report_range_form_submit($form_id, $form_values) {
  $start = date('YmdHi', strtotime($form_values['start']));
  $end = date('YmdHi', strtotime($form_values['end']));
  drupal_goto($form_values['url'] . "/{$start}/{$end}");
}

/**
 * Helper function to extract date from URL.
 */
function _ad_report_get_date_from_path($path) {
  if ($path) {
    $year = substr($path, 0, 4);
    $month = substr($path, 4, 2);
    $day = substr($path, 6, 2);
    $hour = substr($path, 8, 2);
    if (strlen($path) == 12) {
      $minute = substr($path, 10, 2);
    }
    else {
      $minute = 0;
    }
    $date = strtotime("{$month}/{$day}/{$year} {$hour}:{$minute}");
    if ($date > 0) {
      return $date;
    }
    drupal_set_message(t('Invalid date specified in range.'), 'error');
  }
}

/**
 * Helper function to format date.
 */
function _ad_report_format_date_human($date) {
  return date('Y-m-d H:i', $date);
}

/**
 * Helper function to format date.
 */
function _ad_report_format_date_db($date) {
  return date('YmdH', $date);
}

/**
 * Display table with per-group statistics.
 */
function ad_report_group_table($id, $type, $start, $end) {
  $start_date = _ad_report_format_date_db(_ad_report_get_date_from_path($start));
  $end_date = _ad_report_format_date_db(_ad_report_get_date_from_path($end));

  // TODO: Support other types than nodes
  $result = db_query('SELECT DISTINCT(adgroup) FROM {ad_statistics} WHERE aid = %d AND date >= %d AND date <= %d', $id, $start_date, $end_date);

  // extract all groups that this advertisement has been displayed in
  while ($group = db_fetch_object($result)) {
    if ($group->adgroup) {
      $first = substr($group->adgroup, 0, 1);
      if ($first == 't') {
        $tids = $tids = explode(',', substr($group->adgroup, 1, strlen($group->adgroup)));
        foreach ($tids as $tid) {
          if ($tid) {
            $adgroups[$tid][] = $group->adgroup;
          }
        }
      }
      else {

        // handle this type of "group"
        $adgroups['other'][] = $group->adgroup;
      }
    }
    else {
      $adgroups[0][] = $group->adgroup;
    }
  }
  $headers = array(
    t('Group'),
    t('Active dates'),
    t('Views'),
    t('Clicks'),
    t('Click-thru'),
  );

  // get counts for each group
  $groups = ad_groups_list();
  $rows = array();
  $total_views = $total_clicks = 0;
  foreach ($groups as $tid => $group) {
    $views = $clicks = 0;
    if (is_array($adgroups[$tid])) {
      foreach ($adgroups[$tid] as $adgroup) {
        $views += (int) db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND adgroup = '%s' AND action = 'view' AND date >= %d AND date <= %d", $id, $adgroup, $start_date, $end_date));
        $clicks += (int) db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND adgroup = '%s' AND action = 'click' AND date >= %d AND date <= %d", $id, $adgroup, $start_date, $end_date));
      }
    }
    if ($views || $clicks) {
      $begin = (int) db_result(db_query("SELECT MIN(date) FROM {ad_statistics} WHERE (adgroup LIKE '%%t%s' OR adgroup LIKE '%%,%s') AND action = 'view' AND date >= %d AND date <= %d", $tid, $tid, $start_date, $end_date));
      if ($begin) {
        $begin = format_date(_ad_report_get_date_from_path($begin), 'small');
        $finish = (int) db_result(db_query("SELECT MAX(date) FROM {ad_statistics} WHERE (adgroup LIKE '%%t%s' OR adgroup LIKE '%%,%s') AND action = 'view' AND date >= %d AND date <= %d", $tid, $tid, $start_date, $end_date));
        if ($finish) {
          $finish = format_date(_ad_report_get_date_from_path($finish), 'small');
        }
      }
      if ($begin && $finish) {
        $row = array();
        $row[] = $group;
        $row[] = "first view: {$begin}<br />last view: {$finish}";
        $row[] = number_format($views);
        $row[] = number_format($clicks);
        if ($views) {
          $row[] = number_format($clicks / $views, 2) . '%';
        }
        else {
          $row[] = '0%';
        }
        $rows[] = $row;
        $total_views += $views;
        $total_clicks += $clicks;
      }
    }
  }
  if ($total_views || $total_clicks) {
    $row = array();
    $row[] = '<strong>' . t('Total') . '</strong>';
    $row[] = '';
    $row[] = '<strong>' . number_format($total_views) . '</strong>';
    $row[] = '<strong>' . number_format($total_clicks) . '</strong>';
    if ($total_views) {
      $row[] = '<strong>' . number_format($total_clicks / $total_views, 2) . '%' . '</strong>';
    }
    else {
      $row[] = '<strong>' . '0%' . '</strong>';
    }
    $rows[] = $row;
  }
  return theme('table', $headers, $rows);
}

/**
 * Page that utilizes gd to generate a bargraph.
 */
function ad_report_generate_bargraph($id, $type, $start, $end) {
  header("Content-type: image/png");

  // be sure we've been passed in valid parameters
  $elapse = $end - $start;
  if ($elapse <= 0 || $start <= 0 || $end <= 0) {
    return NULL;
  }
  $increments = (int) ($elapse / 3600);

  // image size
  $image_width = 700;
  $image_height = 360;

  // graph size
  $graph_width = 600;
  $graph_height = 250;
  $graph_x_offset = 8;
  $graph_y_offset = 8;
  $graph_y = 8;

  // calculate slices to extract from database
  $width = $graph_width / $increments;
  $number = $increments;
  $factor = 1;
  if ($width < 1) {
    $factor = 1 / $width;
  }
  $number = $number / $factor;
  $width = $width * $factor;
  $slice = $elapse / $number;

  // retrieve views and clicks from the database
  $views = array();
  $clicks = array();
  $max_views = 0;
  $max_clicks = 0;
  $key = 0;
  for ($i = $start; $i < $end; $i += $slice) {
    $start_date = _ad_report_format_date_db($i);
    $end_date = _ad_report_format_date_db($i + $slice);
    switch ($type) {
      case 'node':
        $views[] = (int) db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'view' AND date >= %d AND date <= %d", $id, $start_date, $end_date));
        $clicks[] = (int) db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'click' AND date >= %d AND date <= %d", $id, $start_date, $end_date));
        break;
      case 'user':
        $views[] = (int) db_result(db_query("SELECT SUM(a.count) FROM {ad_statistics} a LEFT JOIN {node} n ON a.aid = n.nid WHERE n.uid = %d AND n.type = 'ad' AND a.action = 'view' AND a.date >= %d AND a.date <= %d", $id, $start_date, $end_date));
        $clicks[] = (int) db_result(db_query("SELECT SUM(a.count) FROM {ad_statistics} a LEFT JOIN {node} n ON a.aid = n.nid WHERE n.uid = %d AND n.type = 'ad' AND a.action = 'click' AND a.date >= %d AND a.date <= %d", $id, $start_date, $end_date));
        break;
      case 'admin':
        $group = $_SESSION['ad_report_group'];
        $all = FALSE;
        $none = FALSE;
        if (is_array($group)) {
          if (in_array('all', $group)) {
            $all = TRUE;
          }
          if (!$all) {
            $groups = ad_groups_list();
            if (sizeof($group) == sizeof($groups)) {
              $all = TRUE;
            }
          }
          if (in_array('0', $group)) {
            unset($group[0]);
            $none = TRUE;
          }
        }
        if ($all) {
          $views[] = (int) db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE action = 'view' AND date >= %d AND date <= %d", $start_date, $end_date));
          $clicks[] = (int) db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE action = 'click' AND date >= %d AND date <= %d", $start_date, $end_date));
        }
        else {
          if ($none) {
            if (sizeof($group)) {
              $views[] = (int) db_result(db_query("SELECT SUM(count) FROM {ad_statistics} a LEFT JOIN {term_node} t ON a.aid = t.tid WHERE (t.tid IN (%s) OR ISNULL(t.tid)) AND action = 'view' AND date >= %d AND date <= %d", implode(',', $group), $start_date, $end_date));
              $clicks[] = (int) db_result(db_query("SELECT SUM(count) FROM {ad_statistics} a LEFT JOIN {term_node} t ON a.aid = t.tid WHERE (t.tid IN (%s) OR ISNULL(t.tid)) AND action = 'click' AND date >= %d AND date <= %d", implode(',', $group), $start_date, $end_date));
            }
            else {
              $views[] = (int) db_result(db_query("SELECT SUM(count) FROM {ad_statistics} a LEFT JOIN {term_node} t ON a.aid = t.tid WHERE ISNULL(t.tid) AND action = 'view' AND date >= %d AND date <= %d", $start_date, $end_date));
              $clicks[] = (int) db_result(db_query("SELECT SUM(count) FROM {ad_statistics} a LEFT JOIN {term_node} t ON a.aid = t.tid WHERE ISNULL(t.tid) AND action = 'click' AND date >= %d AND date <= %d", $start_date, $end_date));
            }
          }
          else {
            $views[] = (int) db_result(db_query("SELECT SUM(count) FROM {ad_statistics} a LEFT JOIN {term_node} t ON a.aid = t.tid WHERE tid IN (%s) AND action = 'view' AND date >= %d AND date <= %d", implode(',', $group), $start_date, $end_date));
            $clicks[] = (int) db_result(db_query("SELECT SUM(count) FROM {ad_statistics} a LEFT JOIN {term_node} t ON a.aid = t.tid WHERE t.tid IN (%s) AND action = 'click' AND date >= %d AND date <= %d", implode(',', $group), $start_date, $end_date));
          }
        }
        break;
      default:
        $function = "ad_report_views_{$type}";
        if (function_exists("{$function}")) {
          $views[] = $function($id, $day_start, $day_end);
        }
        $function = "ad_report_clicks_{$type}";
        if (function_exists("{$function}")) {
          $clicks[] = $function($id, $day_start, $day_end);
        }
        break;
    }
    $max_views = $views[$key] > $max_views ? $views[$key] : $max_views;
    $max_clicks = $clicks[$key] > $max_clicks ? $clicks[$key] : $max_clicks;
    $key++;
  }

  // create graph
  $graph = imagecreate($image_width, $image_height);

  // configure colors to use in chart
  $color = array(
    'white' => imagecolorallocate($graph, 255, 255, 255),
    'black' => imagecolorallocate($graph, 0, 0, 0),
    'grey' => imagecolorallocate($graph, 192, 192, 192),
    'blue' => imagecolorallocate($graph, 0, 0, 255),
    'orange' => imagecolorallocate($graph, 220, 210, 60),
    'red' => imagecolorallocate($graph, 255, 0, 0),
  );

  // determine how big the spacers should be
  $max = $max_views > $max_clicks ? $max_views : $max_clicks;
  $y_map = ceil($max / $graph_y / $graph_y) * $graph_y;
  $y_total = $y_map * $graph_y;
  if ($y_total) {

    // plot views and clicks on graph
    foreach ($views as $key => $value) {
      $view_height = $graph_height / $y_total * $value;
      if ($view_height) {
        imagefilledrectangle($graph, $graph_x_offset + $key * $width, $graph_y_offset + $graph_height - $view_height, $graph_x_offset + ($key + 1) * $width - 1, $graph_y_offset + $graph_height - 1, $color['blue']);
      }
      $click_height = $graph_height / $y_total * $clicks[$key];
      if ($click_height) {
        imagefilledrectangle($graph, $graph_x_offset + $key * $width, $graph_y_offset + $graph_height - $click_height, $graph_x_offset + ($key + 1) * $width - 1, $graph_y_offset + $graph_height - 1, $color['red']);
      }
    }
  }

  // add scale to y
  if ($y_map) {
    $graph_y_width = $graph_height / $graph_y;
    for ($i = 1; $i <= $graph_y; $i++) {
      $text = number_format($i * $y_map);
      $len = strlen($text);
      $x_offset = $graph_width + 14;
      $y_pos = $graph_height - $i * $graph_y_width;

      //imagestring($graph, 1, $x_offset, $graph_y_offset + $y_pos - 3, $text, $color['black']);
      imagestring($graph, 2, $x_offset, $graph_y_offset + $y_pos - 7, $text, $color['black']);
    }
  }

  // add scale to x
  $graph_x = _ad_report_select_x($number, 8, 0);
  $offset = $elapse / $graph_x;
  $graph_x_width = $graph_width / $graph_x;
  $x_offset = $graph_x_width / 2;
  for ($i = 1; $i <= $graph_x; $i++) {
    $text = date('M d, Y H', $start + $offset * $i - $offset / 2);
    $len = strlen($text);
    $x_pos = $graph_x_offset - $x_offset + $i * $graph_x_width - 7;
    $y_pos = $graph_height + $graph_y_offset + $len * 6 + 3;
    imagestringup($graph, 2, $x_pos, $y_pos, $text, $color['black']);

    //$x_pos = $graph_x_offset - $x_offset + $i * $graph_x_width - 4;

    //$y_pos = $graph_height + $graph_y_offset + ($len * 5) + 3;

    //imagestringup($graph, 1, $x_pos, $y_pos, $text, $color['black']);
  }

  // draw a grid
  $style = array(
    $color['grey'],
    IMG_COLOR_TRANSPARENT,
    IMG_COLOR_TRANSPARENT,
  );
  imagesetstyle($graph, $style);
  for ($i = 1; $i <= $graph_x; $i++) {
    imageline($graph, $graph_x_offset + $i * $graph_x_width - $graph_x_width / 2, $graph_y_offset, $graph_x_offset + $i * $graph_x_width - $graph_x_width / 2, $graph_y_offset + $graph_height - 1, IMG_COLOR_STYLED);
  }
  for ($i = 1; $i < $graph_y; $i++) {
    imageline($graph, $graph_x_offset, $graph_y_offset + $i * $graph_y_width, $graph_x_offset + $graph_width, $graph_y_offset + $i * $graph_y_width, IMG_COLOR_STYLED);
  }

  // left, right, top, and bottom borders, respectively
  imageline($graph, $graph_x_offset, $graph_y_offset, $graph_x_offset, $graph_y_offset + $graph_height, $color['grey']);
  imageline($graph, $graph_x_offset + $graph_width - 1, $graph_y_offset, $graph_x_offset + $graph_width - 1, $graph_y_offset + $graph_height, $color['grey']);
  imageline($graph, $graph_x_offset, $graph_y_offset, $graph_x_offset + $graph_width - 1, $graph_y_offset, $color['grey']);
  imageline($graph, $graph_x_offset, $graph_y_offset + $graph_height, $graph_x_offset + $graph_width - 1, $graph_y_offset + $graph_height, $color['grey']);

  // display the graph
  imagepng($graph);
  imagedestroy($graph);
}

/**
 * Figure out how many x columns to display.
 * TODO: Find a better algorithm than this slop.
 */
function _ad_report_select_x($number, $divisor, $diff) {
  if ($divisor < 2) {
    return $number;
  }
  $divisor = $divisor + $diff;
  if ($divisor == 0) {
    $divisor = $divisor + $diff;
  }
  $result = (int) ($number / $divisor);
  if ($result < 8) {
    $diff -= 1;
    if ($diff) {
      return _ad_report_select_x($number, $divisor, $diff);
    }
  }
  else {
    if ($result > 12) {
      $diff += 1;
      if ($diff) {
        return _ad_report_select_x($number, $divisor, $diff);
      }
    }
  }
  return $result;
}

Functions

Namesort descending Description
ad_report_adapi Ad module hook_adapi.
ad_report_admin
ad_report_admin_ad_table
ad_report_admin_display Display the administrative report.
ad_report_admin_submit Redirect to a path to generate the requested report.
ad_report_admin_validate Sanity check the date range.
ad_report_bargraph Page to display ad with bargraph.
ad_report_generate_bargraph Page that utilizes gd to generate a bargraph.
ad_report_group_table Display table with per-group statistics.
ad_report_menu Implementation of hook_menu().
ad_report_perm Drupal hook_perm implementation.
ad_report_range_form Return a form for selecting a date range for generating a report.
ad_report_range_form_submit Redirect to URL for displaying report.
ad_report_range_form_validate Validate the form range.
_ad_report_first_day_of_month Returns a timestamp for the first hour of the first day of the month.
_ad_report_format_date_db Helper function to format date.
_ad_report_format_date_human Helper function to format date.
_ad_report_get_date_from_path Helper function to extract date from URL.
_ad_report_last_day_of_month Returns a timestamp for the last hour of the last day of the month.
_ad_report_select_x Figure out how many x columns to display. TODO: Find a better algorithm than this slop.