diff adserve.inc @ 1:948362c2a207 ad

update advertisement
author pierre
date Thu, 02 Apr 2009 15:28:21 +0000
parents d8a3998dac8e
children e5584a19768b
line wrap: on
line diff
--- a/adserve.inc	Fri Feb 20 14:04:09 2009 +0000
+++ b/adserve.inc	Thu Apr 02 15:28:21 2009 +0000
@@ -1,5 +1,5 @@
 <?php
-// $Id: adserve.inc,v 1.1.2.31.2.8 2009/02/17 19:22:45 jeremy Exp $
+// $Id: adserve.inc,v 1.1.2.31.2.8.2.6 2009/03/27 17:26:02 jeremy Exp $
 
 /**
  * @file
@@ -28,265 +28,28 @@
 function adserve_ad($options = array()) {
   static $displayed_count = 0;
 
-  // If no $options are passed in, assume we're using JavaScript.
+  // if no $options are passed in, assume we're using JavaScript
   if (!empty($options)) {
     adserve_variable('variable_load', $options);
   }
   else {
     adserve_variable('variable_load');
   }
+
+  // include Drupal's settings.php
   adserve_bootstrap(0);
 
+  // if debug enabled, dump current state
   adserve_debug();
 
+  // start with 'error' set to false
   adserve_variable('error', FALSE);
-  $output = NULL;
-  if (adserve_variable('adcache') != 'none') {
-    /**
-     * Ad caches are defined through external modules.  Ad caches are composed
-     * of a module 'ad_cache_TYPE.module' and an include file
-     * 'ad_cache_TYPE.inc' that live in the 'cache/TYPE' subdirectory where
-     * 'TYPE' is replaced with the type of cache.  For example, the included
-     * file cache lives in 'cache/file'.
-     *
-     * The ad_cache_TYPE.inc file must have a function named ad_cache_TYPE()
-     * which is used to display ads.  It can optionally include a function
-     * titled ad_cache_TYPE_variables used to extract any necessary
-     * variables from the global $_GET array (this can also be used to override
-     * values that would normally be set from $_GET).  Any functions used
-     * by this code without bootstrapping Drupal should also be in this file.
-     *
-     * The ad_cache_TYPE.module file should define the drupal _help() hook
-     * so the module can be enabled.  It should also define the _adcacheapi()
-     * hook allowing for configuration and processing.  Any functions used by
-     * this code after bootstrapping Drupal should also be in this module.
-     *
-     * Refer to cache/file/* for an implementation example.
-     */
-    $function = 'ad_cache_'. adserve_variable('adcache');
-    $output = adserve_invoke_file($function);
 
-  }
+  // invoke cache function (file already included in adserve_variable)
+  $ids = adserve_cache('get_ad_ids');
 
-  // If there's no output, we assume either there's no cache enabled, or the
-  // cache failed.
-  // TODO: Log failures with the watchdog.
-  if ($output == NULL) {
-    if (adserve_variable('debug')) {
-      echo "No cache enabled.<br />\n";
-    }
-
-    adserve_bootstrap();
-
-    if (adserve_variable('nids')) {
-      $id = adserve_variable('nids');
-      $type = 'nids';
-      adserve_variable('group', "n$id");
-
-      // Retrieve all active advertisements from the provided nid list.
-      $sql = "SELECT aid FROM {ads} WHERE adstatus = 'active' AND aid IN (%s)";
-      $result = db_query($sql, $id);
-
-      if (adserve_variable('debug')) {
-        echo "Searching for ad from nid list: $id.<br />\n";
-        echo "Query: \"$sql;\"<br />\n";
-      }
-    }
-    else if (adserve_variable('tids')) {
-      $id = adserve_variable('tids');
-      $type = 'tids';
-      adserve_variable('group', "t$id");
-
-      // Retrieve all active advertisements from the provided tid list.
-      $sql = "SELECT a.aid FROM {ads} a INNER JOIN {term_node} n ON a.aid = n.nid WHERE a.adstatus = 'active' AND n.tid IN (%s)";
-      $result = db_query($sql, $id);
-
-      if (adserve_variable('debug')) {
-        echo "Searching for ad from tid list: $id.<br />\n";
-        echo "Query: \"$sql;\"<br />\n";
-      }
-    }
-    else {
-      $id = 0;
-      $type = 'default';
-      adserve_variable('group', "$id");
-
-      // Randomly determine which ad to display from those that do not have
-      // any tid assigned to them.
-      $sql = "SELECT a.aid FROM {ads} a LEFT JOIN {term_node} n ON a.aid = n.nid WHERE a.adstatus = 'active' AND n.tid IS NULL";
-      $result = db_query($sql);
-
-      if (adserve_variable('debug')) {
-        echo "Searching for ads with no tids.<br />\n";
-        echo "Query: \"$sql;\"<br />\n";
-      }
-    }
-
-    // Build list of all available ads to choose from.
-    $available = array();
-    while ($ad = db_fetch_object($result)) {
-      $available[$ad->aid] = $ad->aid;
-    }
-    if (adserve_variable('debug')) {
-      echo 'Available ads: ';
-      if (sizeof($ads)) {
-        echo implode(', ', $available) ."<br />";
-      }
-      else {
-        echo 'none<br />';
-      }
-    }
-
-    // Randomly select from available advertisements.
-    $selected = adserve_select_ad($available, adserve_variable('quantity'));
-
-    $output = '';
-    $ads = 0;
-    $details = array();
-    $ids = array();
-    // Include appropriate module for displaying selected ad.
-    foreach ($selected as $aid) {
-      $ids[$aid] = $aid;
-      $ads++;
-      $detail = $details[$aid] = node_load($aid);
-      if (!isset($modules[$detail->adtype])) {
-        $modules[$detail->adtype] = db_result(db_query("SELECT filename FROM {system} WHERE name = '%s'", 'ad_'. $detail->adtype));
-      }
-      if (adserve_variable('debug')) {
-        echo 'ad: <pre>';
-        print_r($detail);
-        echo '</pre>';
-        echo "Loading module '". $modules[$detail->adtype] ."'.<br />\n";
-      }
-      include_once $modules[$detail->adtype];
-
-      if ($output) {
-        // Add a div between ads that themers can use to arrange ads when
-        // displaying more than one at a time.
-        $displayed_count++;
-        $output .= "<div class=\"advertisement-space\" id=\"space-$id-$displayed_count\"></div>";
-      }
-      $output .= module_invoke("ad_$detail->adtype", 'display_ad', $detail);
-
-      // Update the ad's impressions counter.
-      if (adserve_variable('ad_display') == 'raw') {
-        $output .= ad_display_image($detail);
-      }
-      else {
-        adserve_increment($detail);
-      }
-    }
-    adserve_variable("$type-ids", $ids);
-    if (empty($ads)) {
-      adserve_variable('error', TRUE);
-      $output = 'No active ads were found in the '. (empty($nids) ? 'tids' : 'nids') ." '$id'.";
-      adserve_increment(NULL, 'count');
-    }
-    if (adserve_variable('debug')) {
-      echo "Ads displayed: $ads<br />";
-    }
-  }
-
-  $hostid = adserve_variable('hostid');
-  $group = adserve_variable('group');
-  $replace = "/$group";
-  if (!empty($hostid)) {
-    $replace .= "/$hostid";
-  }
-  if ($url = htmlentities(adserve_variable('url'))) {
-    $replace .= "?u=$url";
-  }
-
-  $output = preg_replace('&/@HOSTID___&', $replace, $output);
-  if (adserve_variable('error')) {
-    $output = "<!-- $output -->";
-  }
-
-  /**
-   * Modules can add custom code to be displayed before or after ads are
-   * displayed.  For example, you many want to add a tagline, "Powered by
-   * Drupal".  To do so, define 'adserve_exit_text' within your module's
-   * adapi hook.
-   *
-   * Code sample for adserve_exit_text example:
-   *
-   *   sample_adapi($op, $ad) {
-   *     case 'adserve_exit_text':
-   *       return array(
-   *         'sample' => array(
-   *           'text' => t('Powered by Drupal'),
-   *         )
-   *       );
-   *   }
-   *
-   * As another example use case, you could also use the _init_text and
-   * _exit_text hooks to wrap all advertisements in a custom div.
-   */
-  $init = TRUE;
-  foreach (array('adserve_init_text', 'adserve_exit_text') as $hook) {
-    $result = adserve_invoke_hook($hook);
-    if (is_array($result)) {
-      $append = '';
-      foreach ($result as $text) {
-        if ($text['text']) {
-          $append .= $text['text'];
-        }
-      }
-      if ($init) {
-        $output = $append . $output;
-      }
-      else {
-        $output .= $append;
-      }
-    }
-    $init = FALSE;
-  }
-
-  switch (adserve_variable('ad_display')) {
-    case 'iframe':
-    case 'jquery':
-      if (!adserve_variable('debug')) {
-        // Tell the web browser not to cache this frame so the ad refreshes
-        // each time the page is viewed.
-
-        // Expires in the past:
-        header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
-        // Last load:
-        header('Last-Modified: '. gmdate('D, d M Y H:i:s') .' GMT');
-        // HTTP 1.1:
-        header('Cache-Control: no-store, no-cache, must-revalidate');
-        header('Cache-Control: post-check=0, pre-check=0', FALSE);
-        // HTTP 1.0:
-        header('Pragma: no-cache');
-      }
-      print "$output";
-      exit(0);
-    case 'javascript':
-    default:
-      $output = str_replace(array("\r", "\n", "<", ">", "&"),
-                            array('\r', '\n', '\x3c', '\x3e', '\x26'),
-                            addslashes($output));
-      if (!adserve_variable('debug')) {
-        // Tell the web browser not to cache this script so the ad refreshes
-        // each time the page is viewed.
-        // Expires in the past:
-        header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
-        // Last load:
-        header('Last-Modified: '. gmdate('D, d M Y H:i:s') .' GMT');
-        // HTTP 1.1:
-        header('Cache-Control: no-store, no-cache, must-revalidate');
-        header('Cache-Control: post-check=0, pre-check=0', FALSE);
-        // HTTP 1.0:
-        header('Pragma: no-cache');
-        // Output is a JavaScript:
-        header('Content-Type: application/x-javascript; charset=utf-8');
-      }
-      print "document.write('$output');";
-      exit(0);
-    case 'raw':
-      chdir(adserve_variable('ad_dir'));
-      return $output;
-  }
+  // display the advertisement(s)
+  adserve_cache('display', $ids);
 }
 
 /**
@@ -296,6 +59,11 @@
   global $conf;
   static $variables = NULL, $overridden = NULL, $cache_loaded = array();
 
+  // Declare variables if not already declared.
+  if ($variables === NULL) {
+    $variables = new stdClass();
+  }
+
   // Update the value, if set.
   if (isset($value)) {
     $variables->$variable = $value;
@@ -330,6 +98,9 @@
     $variables->hostid = isset($values['k']) ? preg_replace('/[^0-9a-f]/', '', $values['k']) : '';
     // Click url
     $variables->url = isset($values['u']) ? $values['u'] : '';
+    if (!$variables->url) {
+      $variables->url = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
+    }
     // Quantity is an integer.
     $variables->quantity = isset($values['q']) ? (int)$values['q'] : 0;
     // Ad ID is an integer.
@@ -423,170 +194,52 @@
   return $output;
 }
 
-/**
- * Invoke adserve hooks, defined in adapi with adserve_HOOK.
+/*
+ * When debugging, strip away distracting header errors.  Dump all other errors.
  */
-function adserve_invoke_hook($hook, $a1 = NULL, $a2 = NULL) {
-  if (adserve_variable('adcache') != 'none') {
-    $cache = adserve_variable('adcache');
-    _debug_echo("Invoking adserve hook '$hook' in $cache cache.");
-    // Get information from cache.
-    return adserve_invoke_file("ad_cache_{$cache}_$hook", $a1, $a2);
+function _debug_error_handler($errno, $errstr, $errfile = NULL, $errline = 0, $errcontext = NULL) {
+  if (!preg_match('/Cannot modify header information/', $errstr) &&
+      !preg_match('/Cannot send session cache limiter/', $errstr)) {
+    echo "PHP: errno($errno): $errstr ";
+    if ($errfile && $errline) {
+      echo "; Line $errline in [$errfile]";
+    }
+    echo "<br />\n";
+    if (!empty($errcontext) && adserve_variable('debug') >= 5) {
+      echo 'Error context:<pre>';
+      print_r($errcontext);
+      echo '</pre>';
+    }
   }
-  else {
-    _debug_echo("Invoking adserve hook '$hook'.");
-    // Get information from Drupal variable table.
-    $actions = variable_get($hook, '');
-    $return = array();
-    if (!empty($actions)) {
-      $actions = unserialize($actions);
-      foreach ($actions as $name => $action) {
-        if ($action['function']) {
-          $function = $action['function'];
-          if (!function_exists($function)) {
-            if ($action['path']) {
-              _debug_echo("Including file '". $action['path'] ."'.");
-              include_once($action['path']);
-            }
-          }
-          if (function_exists($function)) {
-            _debug_echo("Invoking function '$function'.");
-            $return[] = $function($a1, $a2);
-          }
-          else if (adserve_variable('debug')) {
-            echo "Function '$function' does not exist.<br />\n";
-          }
-        }
-        else {
-          $return[] = $action;
-        }
-      }
-    }
-    return $return;
-  }
-  // Retreive hook definition from cache if using, or from variable_get
-  // return hook action.
 }
 
+/**
+ * Dump debug message to screen; set custom error handler.
+ */
 function _debug_echo($text) {
+  static $error_handler = FALSE;
+  static $time = 0;
+
   if (adserve_variable('debug')) {
+    if ($time < time()) {
+      $time = time();
+      echo '--> Time mark: '. date('H:i:s', $time) ."<br />\n";
+      _debug_memory();
+    }
+    if (!$error_handler) {
+      set_error_handler('_debug_error_handler');
+      $error_handler = TRUE;
+    }
     echo "$text<br />\n";
   }
 }
 
-/**
- * Remove one or more ids from array.
- * TODO: Optimize.  Perhaps something like array_flip, unset, array_flip.
- * @param $ids An array of ID's, ie array(5, 8, 9, 11).
- * @param $remove An ID or an array of ID's to be removed from $ids.
- */
-function adserve_select_reindex($ids, $remove) {
-  $new = array();
-  // Walk through array of IDs and decide what to keep.
-  foreach ($ids as $id) {
-    // If $remove is an array, walk through array to decide fate of ID.
-    if (is_array($remove)) {
-      $keep = TRUE;
-      foreach ($remove as $rem) {
-        // Loop until we find one that matches or reach end of array.
-        if ($id == $rem) {
-          $keep = FALSE;
-          break;
-        }
-      }
-      if ($keep) {
-        $new[] = $id;
-      }
-    }
-    else {
-      if ($id != $remove) {
-        $new[] = $id;
-      }
-    }
+function _debug_memory() {
+  $memory = '';
+  if (adserve_variable('debug') && function_exists('memory_get_usage')) {
+    $memory = number_format(round(memory_get_usage() / 1024, 3), 3);
+    echo "Memory usage: $memory K<br />\n";
   }
-  return $new;
-}
-
-/**
- * Disabled: will be re-implemented with new adserve hooks introduced for
- * geotargeting.
-function adserve_invoke_weight($ads, $quantity = 1, $invalid = array()) {
-  $parent = adserve_variable('ad_dir') .'/weight';
-  if (is_dir($parent) && $handle = opendir($parent)) {
-    while ($dir = readdir($handle)) {
-      if (is_dir("$parent/$dir") && !in_array($dir, array('.', '..', 'CVS'))) {
-        $include = "$parent/$dir/ad_weight_$dir.inc";
-        if (file_exists($include)) {
-          require_once($include);
-          $function = "ad_weight_{$dir}_select_ad";
-          if (function_exists($function)) {
-            $return = $function($ads, $quantity, $invalid);
-            // First come, first serve.  We found an ad_weight function that
-            // returned something, so we'll take it.
-            if ($return) {
-              return $return;
-            }
-          }
-        }
-      }
-    }
-  }
-}
- */
-
-/**
- * Simple default function to randomly select an ad.  Provides a hook to allow
- * the definition of external display methods.
- * @param An array of valid ad IDs, ie array(5, 8, 9, 11).
- * @param Optional, how many unique ads to select.
- * @param Optional, an array of invalid IDs.
- */
-function adserve_select_ad($ads, $quantity = 1, $invalid = array()) {
-  //adserve_invoke_weight($ads, $quantity, $invalid);
-
-  $ids = array();
-  $id = 0;
-  $total = sizeof($ads);
-  _debug_echo("Selecting $quantity ad(s) from $total total ad(s).");
-  if (is_array($ads)) {
-    $ads = adserve_select_reindex($ads, $invalid);
-    $total = sizeof($ads);
-    for ($i = 0; $i < $quantity; $i++) {
-      _debug_echo('Randomly selecting ad: '. ($i + 1) ." of $quantity.");
-      $id = 0;
-      // Randomly select a unique banner to display.  We subtract 1 as arrays
-      // start at 0.
-      $return = adserve_invoke_hook('adserve_select', $ads, $invalid);
-      if (is_array($return) && !empty($return)) {
-        foreach ($return as $id) {
-          // First come first serve.
-          if ((int)$id) break;
-        }
-      }
-      if ($id >= 0 && sizeof($ads)) {
-        if ($id == 0) {
-          _debug_echo("Default ID selection in adserve.inc.");
-          $id = $total > 1 ? $ads[mt_rand(0, $total - 1)] : $ads[0];
-          _debug_echo("Randomly selected ID: $id.");
-        }
-        if ($id > 0) {
-          $ids[] = $id;
-        }
-      }
-      else {
-        // There are no more valid advertisements left to display.
-        break;
-      }
-      $invalid[] = $id;
-      $ads = adserve_select_reindex($ads, $id);
-      $total = sizeof($ads);
-      // We're out of ads to display.
-      if ($total <= 0) {
-        break;
-      }
-    }
-  }
-  return $ids;
 }
 
 /**
@@ -629,65 +282,10 @@
     $bootstrap = DRUPAL_BOOTSTRAP_FULL;
   }
 
-  if (adserve_variable('debug')) {
-    echo "Drupal bootstrap '". $bootstrap ."'.<br />\n";
-  }
+  echo _debug_echo("Drupal bootstrap '$bootstrap'.");
 
   drupal_bootstrap($bootstrap);
-}
-
-/**
- * Increment ad counters.  Increment in cache if enabled.
- */
-function adserve_increment($ad, $action = 'view') {
-  $cache = adserve_variable('adcache');
-  if (adserve_variable('debug')) {
-    echo "adserve_increment action($action) cache($cache)<br />\n";
-  }
-  if (is_object($ad) && isset($ad->aid)) {
-    $aid = $ad->aid;
-  }
-  else {
-    $aid = 0;
-  }
-  if ($cache != 'none') {
-    $rc = adserve_invoke_file("ad_cache_{$cache}_increment", $action, $aid);
-    if ($rc) return;
-  }
-  adserve_bootstrap();
-  // Update impressions statistics.
-  db_query("UPDATE {ad_statistics} SET count = count + 1 WHERE aid = %d AND action = '%s' AND date = %d AND adgroup = '%s' AND hostid = '%s'", $aid, $action, date('YmdH'), adserve_variable('group'), adserve_variable('hostid'));
-  // If column doesn't already exist, we need to add it.
-  if (!db_affected_rows()) {
-    db_query("INSERT INTO {ad_statistics} (aid, date, action, adgroup, hostid, count) VALUES(%d, %d, '%s', '%s', '%s', 1)", $aid, date('YmdH'), $action, adserve_variable('hostid'), adserve_variable('hostid'));
-    // If another process already added this row our INSERT will fail, if
-    // so we still need to increment it so we don't loose an impression.
-    if (!db_affected_rows()) {
-      db_query("UPDATE {ad_statistics} SET count = count + 1 WHERE aid = %d AND action = '%s' AND date = %d AND adgroup = '%s' AND hostid = '%s'", $aid, $action, date('YmdH'), adserve_variable('group'), adserve_variable('hostid'));
-    }
-  }
-
-  if ($action == 'view') {
-    // See if we need to perform additional queries.
-    if (isset($ad->maxviews) && $ad->maxviews > 0) {
-      $views = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'view' AND date >= %d", $aid, date('YmdH', $ad->activated)));
-      if ($views >= $ad->maxviews) {
-        db_query("UPDATE {ads} SET adstatus = 'expired', autoexpire = 0, autoexpired = %d, expired = %d WHERE aid = %d", time(), time(), $aid);
-        ad_statistics_increment($aid, 'autoexpired');
-        ad_statistics_increment($aid, 'expired');
-      }
-    }
-  }
-  // TODO: Do we need to do this here?  Can it happen when a new click is
-  // registered?
-  if (isset($ad->maxclicks) && $ad->maxclicks > 0) {
-    $clicks = (int)db_result(db_query("SELECT SUM(count) FROM {ad_statistics} WHERE aid = %d AND action = 'click' AND date >= %d", $aid, date('YmdH', $ad->activated)));
-    if ($clicks >= $ad->maxclicks) {
-      db_query("UPDATE {ads} SET adstatus = 'expired', autoexpire = 0, autoexpired = %d, expired = %d WHERE aid = %d", time(), time(), $aid);
-      ad_statistics_increment($aid, 'autoexpired');
-      ad_statistics_increment($aid, 'expired');
-    }
-  }
+  echo _debug_echo("Drupal bootstrap complete.");
 }
 
 /**
@@ -698,12 +296,12 @@
     echo "Root drupal directory detected as '". adserve_variable('root_dir') ."'.<br />\n<br />\n";
 
     $ad_dir = adserve_variable('ad_dir');
-    $files = array("$ad_dir/serve.php", "$ad_dir/ad.module");
-    if (adserve_variable('debug') > 2) {
+    $files = array("$ad_dir/serve.php", "$ad_dir/adserve.inc", "$ad_dir/adcache.inc", "$ad_dir/ad.module");
+    if (adserve_variable('debug') >= 2) {
       $files = array_merge($files, array("$ad_dir/ad.install"));
     }
-    if (adserve_variable('debug') > 3) {
-      $files = array_merge($files, array("$ad_dir/image/ad_image.module", "$ad_dir/image/ad_image.install", "$ad_dir/text/ad_text.module", "$ad_dir/text/ad_text.install", "$ad_dir/embed/ad_embed.module", "$ad_dir/report/ad_report.module", "$ad_dir/notify/ad_notify.module", "$ad_dir/notify/ad_notify.install"));
+    if (adserve_variable('debug') >= 3) {
+      $files = array_merge($files, array("$ad_dir/image/ad_image.module", "$ad_dir/image/ad_image.install", "$ad_dir/text/ad_text.module", "$ad_dir/text/ad_text.install", "$ad_dir/embed/ad_embed.module", "$ad_dir/report/ad_report.module", "$ad_dir/notify/ad_notify.module", "$ad_dir/notify/ad_notify.install", "$ad_dir/cache/file/ad_cache_file.inc", "$ad_dir/cache/file/ad_cache_file.module", "$ad_dir/permission/ad_permission.module", "$ad_dir/weight/probability/ad_weight_probability.module", "$ad_dir/weight/probability/ad_weight_probability.inc"));
     }
     foreach ($files as $file) {
       if (!file_exists($file)) {