comparison adcache.inc @ 1:948362c2a207 ad

update advertisement
author pierre
date Thu, 02 Apr 2009 15:28:21 +0000
parents
children e5584a19768b
comparison
equal deleted inserted replaced
0:d8a3998dac8e 1:948362c2a207
1 <?php
2
3 /**
4 * Wrapper for calling adserve_cache functions.
5 */
6 function adserve_cache() {
7 static $functions = array();
8 $args = func_get_args();
9 $function = array_shift($args);
10
11 _debug_echo("adserve_cache function($function)");
12
13 if (!isset($functions[$function])) {
14 $cache = adserve_variable('adcache');
15 $test = "ad_cache_{$cache}_$function";
16 if (!function_exists($test)) {
17 _debug_echo("Cache function '$test' does not exist.\n");
18 $test = "adserve_cache_$function";
19 }
20 $functions[$function] = $test;
21 }
22
23 if (function_exists($functions[$function])) {
24 _debug_memory();
25 _debug_echo("Invoking cache function '". $functions[$function] ."'.");
26 return call_user_func_array($functions[$function], $args);
27 }
28 else {
29 _debug_echo("Cache function '". $functions[$function] ."' does not exist.\n");
30 }
31 return array();
32 }
33
34 /**
35 * Invoke adserve cache hook, including files as necessary.
36 */
37 function adserve_invoke_hook() {
38 static $hooks = array();
39 $args = func_get_args();
40 $hook = array_shift($args);
41 $action = array_shift($args);
42
43 _debug_echo("adserve_invoke_hook hook($hook) action($action)");
44
45 if (!isset($hooks[$hook])) {
46 $hooks[$hook] = adserve_cache('hook', $hook);
47 if (is_array($hooks[$hook]) && !empty($hooks[$hook]) &&
48 is_array($hooks[$hook]['file'])) {
49 // Include all necessary files.
50 foreach ($hooks[$hook]['file'] as $files) {
51 if (is_array($files)) {
52 foreach ($files as $file) {
53 $include_file = adserve_variable('root_dir') .'/'. $file;
54 if (file_exists($include_file) && is_file($include_file)) {
55 _debug_echo("Including file: '$include_file'.");
56 include_once($include_file);
57 }
58 else {
59 _debug_echo("Failed to include file: '$include_file'.");
60 }
61 }
62 }
63 }
64 }
65 }
66
67 $return = array();
68 if (is_array($hooks[$hook]) && !empty($hooks[$hook]) &&
69 is_array($hooks[$hook]['function'])) {
70 foreach ($hooks[$hook]['function'] as $weight => $functions) {
71 foreach ($functions as $function) {
72 if (function_exists($function)) {
73 _debug_echo("Invoking '$function'.");
74 $return[] = call_user_func_array($function, $args);
75 }
76 else {
77 _debug_echo("Function '$function' does not exist.\n");
78 }
79 }
80 }
81 }
82 else {
83 $function = "adserve_hook_$hook";
84 if (function_exists($function)) {
85 _debug_echo("Invoking '$function'.");
86 $return[] = call_user_func_array($function, $args);
87 }
88 else {
89 _debug_echo("Function '$function' does not exist.\n");
90 }
91 }
92
93 switch ($action) {
94 case 'intersect':
95 if (sizeof($return) == 1) {
96 return $return[0];
97 }
98 else {
99 return call_user_func_array('array_intersect', $return);
100 }
101
102 case 'merge':
103 if (sizeof($return) == 1) {
104 return $return[0];
105 }
106 else {
107 $merge = array();
108 foreach ($return as $array) {
109 $merge += $array;
110 }
111 return $merge;
112 }
113
114 case 'first':
115 foreach ($return as $item) {
116 if (is_array($item) && !empty($item)) {
117 return $item;
118 }
119 }
120 return array();
121
122 case 'append':
123 $append = '';
124 foreach ($return as $item) {
125 if (!is_array($item)) {
126 $append .= $item;
127 }
128 }
129 return $append;
130
131 default:
132 case 'raw':
133 default:
134 return $return;
135 }
136 }
137
138 /** Cache functions **/
139
140 /**
141 * Default initialization function, fully bootstraps Drupal to gain access to
142 * the database.
143 */
144 function adserve_cache_open() {
145 adserve_bootstrap();
146 }
147
148 /**
149 * Build and return the cache.
150 * TODO: It's expensive to build the cache each time we serve an ad, this should
151 * be cached in the database, not in a static.
152 */
153 function adserve_cache_get_cache($data = NULL) {
154 static $cache = NULL;
155 // if we don't the the cache yet, build it
156 if (is_null($cache)) {
157 $cache = module_invoke_all('ad_build_cache');
158 }
159
160 if ($data) {
161 if (isset($cache[$data])) {
162 return $cache[$data];
163 }
164 else {
165 return NULL;
166 }
167 }
168 return $cache;
169 }
170
171 /**
172 * Invoke the appropraite hook.
173 */
174 function adserve_cache_hook($hook) {
175 static $cache = NULL;
176 // if we don't have the cache yet, build it
177 if (is_null($cache)) {
178 $external = adserve_cache('get_cache');
179 $cache = adserve_cache('build_hooks', $external);
180 }
181
182 // return hook definition, if exists
183 if (is_array($cache) && isset($cache["hook_$hook"]) && is_array($cache["hook_$hook"])) {
184 _debug_echo("Invoking hook '$hook'.");
185 return $cache["hook_$hook"];
186 }
187 _debug_echo("Did not find hook '$hook'.");
188 }
189
190 /**
191 * Helper function to build hook tree.
192 */
193 function adserve_cache_build_hooks($cache) {
194 $return = array();
195 if (is_array($cache)) {
196 foreach ($cache as $module => $hooks) {
197 // supported cache hooks
198 foreach (array('hook_init', 'hook_filter', 'hook_weight', 'hook_select',
199 'hook_init_text', 'hook_exit_text',
200 'hook_increment_extra') as $hook) {
201 if (isset($hooks[$hook]) && is_array($hooks[$hook])) {
202 $weight = isset($hooks[$hook]['weight']) ? (int)$hooks[$hook]['weight'] : 0;
203 $return[$hook]['file'][$weight][] = $hooks[$hook]['file'];
204 $return[$hook]['function'][$weight][] = $hooks[$hook]['function'];
205 }
206 }
207 }
208 }
209 return $return;
210 }
211
212 /**
213 * Default function for retrieving list of ids.
214 */
215 function adserve_cache_id($type, $id) {
216 switch ($type) {
217 case 'nids':
218 $result = db_query("SELECT aid FROM {ads} WHERE adstatus = 'active' AND aid IN(%d)", $id);
219 break;
220 case 'tids':
221 $result = db_query("SELECT a.aid FROM {ads} a INNER JOIN {term_node} n ON a.aid = n.nid WHERE a.adstatus = 'active' AND n.tid IN(%d)", $id);
222 break;
223 case 'default':
224 $result = db_query("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");
225 break;
226 default:
227 _debug_echo("Unsupported type '$type'.");
228 }
229
230 $ids = array();
231 if (isset($result)) {
232 while ($ad = db_fetch_object($result)) {
233 $ids[$ad->aid] = $ad->aid;
234 }
235 }
236 return $ids;
237 }
238
239 /**
240 * Support filter hooks.
241 */
242 function adserve_hook_filter($ids, $hostid) {
243 return $ids;
244 }
245
246 /**
247 * Support weight hooks.
248 */
249 function adserve_hook_weight($ids, $hostid) {
250 return $ids;
251 }
252
253 /**
254 * Load and display an advertisement directly from the database.
255 */
256 function adserve_cache_display_ad($id) {
257 static $modules = array();
258
259 $ad = node_load($id);
260 if (!isset($modules[$ad->adtype])) {
261 $modules[$ad->adtype] = db_result(db_query("SELECT filename FROM {system} WHERE name = '%s'", "ad_$ad->adtype"));
262 }
263 _debug_echo("Ad type '$ad->adtype', loading module '". $modules[$ad->adtype] ."'");
264 return module_invoke("ad_$ad->adtype", 'display_ad', $ad);
265 }
266
267 /**
268 * Validate aids.
269 */
270 function adserve_cache_validate($aids, $displayed, $hostid) {
271 $valid = array();
272 foreach ($aids as $aid) {
273 if (!in_array($aid, $displayed)) {
274 $valid[] = $aid;
275 }
276 }
277 return $valid;
278 }
279
280 /**
281 * Increment action directly in the database.
282 */
283 function adserve_cache_increment($action, $aid) {
284 $hostid = adserve_variable('hostid');
285 _debug_echo("adserve_increment action($action) aid($aid) hostid($hostid)");
286
287 // be sure that drupal is bootstrapped
288 adserve_bootstrap();
289
290 // allow add-on modules to implement their own statistics granularity
291 $extra = adserve_invoke_hook('increment_extra', 'merge', $action, $aid);
292 if (is_array($extra)) {
293 $extra = implode('|,|', $extra);
294 }
295 adserve_variable('extra', $extra);
296 _debug_echo("adserve_increment extra($extra)");
297
298 // update statistics
299 db_query("UPDATE {ad_statistics} SET count = count + 1 WHERE aid = %d AND action = '%s' AND date = %d AND adgroup = '%s' AND extra = '%s' AND hostid = '%s'", $aid, $action, date('YmdH'), adserve_variable('group'), $extra, $hostid);
300 // if column doesn't already exist, add it
301 if (!db_affected_rows()) {
302 db_query("INSERT INTO {ad_statistics} (aid, date, action, adgroup, extra, hostid, count) VALUES(%d, %d, '%s', '%s', '%s', '%s', 1)", $aid, date('YmdH'), $action, adserve_variable('group'), $extra, $hostid);
303 if (!db_affected_rows()) {
304 // we lost a race to add it, increment it
305 db_query("UPDATE {ad_statistics} SET count = count + 1 WHERE aid = %d AND action = '%s' AND date = %d AND adgroup = '%s' AND extra = '%s' AND hostid = '%s'", $aid, $action, date('YmdH'), adserve_variable('group'), $extra, $hostid);
306 }
307 }
308
309 if ($action == 'view') {
310 $ad = db_fetch_object(db_query('SELECT maxviews, activated FROM {ads} WHERE aid = %d', $aid));
311 // See if we need to perform additional queries.
312 if ($ad->maxviews) {
313 $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)));
314 if ($views >= $ad->maxviews) {
315 db_query("UPDATE {ads} SET adstatus = 'expired', autoexpire = 0, autoexpired = %d, expired = %d WHERE aid = %d", time(), time(), $aid);
316 ad_statistics_increment('autoexpired', $aid);
317 ad_statistics_increment('expired', $aid);
318 }
319 }
320 }
321 }
322
323 /**
324 * Randomly select advertisements.
325 * @param array, valid ad ids.
326 * @param integer, how many advertisements to select
327 * @param string, the hostid
328 */
329 function adserve_hook_select($ids, $quantity = 1, $hostid = '') {
330 $select = 0;
331 $selected = array();
332 if (is_array($ids)) {
333 $ads = $ids;
334 foreach ($ids as $key => $value) {
335 $available = sizeof($ads);
336 $select++;
337 _debug_echo("Randomly selecting ad $select of $quantity.");
338 $id = 0;
339 if ($id == 0) {
340 $id = $available > 1 ? $ads[mt_rand(0, $available - 1)] : $ads[0];
341 _debug_echo("Randomly selected ID: $id.");
342 $selected[] = $id;
343 // strip away advertisments that have already been selected
344 $ads = adserve_cache('validate', $ads, array($id), $hostid);
345 }
346 if (($quantity == $select) || !count($ads)) {
347 // we have selected the right number of advertisements
348 break;
349 }
350 }
351 }
352 if ($select < $quantity) {
353 _debug_echo('No more advertisements available.');
354 }
355 return $selected;
356 }
357 /**
358 * Default wrapper function for displaying advertisements. This generally
359 * is not replaced by ad caches modules.
360 */
361 function adserve_cache_get_ad_ids() {
362 static $displayed_count = 0;
363 _debug_echo('Entering default adserve_display.');
364
365 // open the cache
366 adserve_cache('open');
367
368 $hostid = adserve_variable('hostid') ? adserve_variable('hostid') : 'none';
369 _debug_echo("Hostid: '$hostid'.");
370
371 // invoke hook_init
372 $init = adserve_invoke_hook('init', 'first', $hostid);
373
374 // start with list of advertisements provided externally
375 if (is_array($init) && !empty($init)) {
376 _debug_echo('Initialized externally.');
377 $quantity = $init['quantity'];
378 $id = $init['id'];
379 $aids = explode(',', $id);
380 $type = $init['type'];
381 }
382 else {
383 // build list of ad ids to choose from
384 $quantity = adserve_variable('quantity');
385 // use list for specific host
386 if ($ids = adserve_cache('id', 'host', NULL, $hostid)) {
387 $id = implode(',', $ids);
388 $type = 'host';
389 }
390 // use list of node ids
391 else if ($id = adserve_variable('nids')) {
392 $type = 'nids';
393 adserve_variable('group', "n$id");
394 }
395 // use list of group ids
396 else if ($id = adserve_variable('tids')) {
397 $type = 'tids';
398 adserve_variable('group', "t$id");
399 }
400 // use list without group ids
401 else {
402 $id = 0;
403 $type = 'default';
404 adserve_variable('group', "$id");
405 }
406 _debug_echo("Searching $type: $id");
407 $aids = adserve_cache('id', $type, $id, $hostid);
408 }
409
410 // prepare to select advertisements
411 $number_of_ads = sizeof($aids);
412 _debug_echo("Total ads: '$number_of_ads'.");
413
414 $displayed = adserve_variable("$type-displayed");
415 if (!is_array($displayed)) {
416 $displayed = array();
417 }
418 _debug_echo('Already displayed: '. sizeof($displayed));
419
420 // validate available advertisements
421 $aids = adserve_cache('validate', $aids, $displayed, $hostid);
422 $number_of_ads = sizeof($aids);
423 _debug_echo("Validated ads: '$number_of_ads'.");
424
425 // filter advertisements
426 $aids = adserve_invoke_hook('filter', 'intersect', $aids, $hostid);
427 $number_of_ads = sizeof($aids);
428 _debug_echo("Filtered ads: '$number_of_ads'.");
429
430
431 // apply weight to advertisements
432 $aids = adserve_invoke_hook('weight', 'first', $aids, $hostid);
433 $number_of_ads = sizeof($aids);
434 _debug_echo("Weighted ads: '$number_of_ads'.");
435
436 // select advertisements
437 $aids = adserve_invoke_hook('select', 'first', $aids, $quantity, $hostid);
438 $number_of_ads = sizeof($aids);
439 _debug_echo("Selected ads: '$number_of_ads'.");
440
441 // track which advertisements have been "displayed"
442 adserve_variable("$type-displayed", array_merge($aids, $displayed));
443
444 return $aids;
445 }
446
447 /**
448 * Default function for displaying advertisements. This is not generally
449 * replaced by ad cache modules.
450 */
451 function adserve_cache_display($ids) {
452 $output = '';
453 $ads = 0;
454 foreach ($ids as $id) {
455 $ad = adserve_cache('display_ad', $id);
456 _debug_echo('ad: '. htmlentities($ad));
457 // if displaying multiple ads, separate each with a div
458 if ($output) {
459 $group = adserve_variable('group');
460 $output .= "<div class=\"advertisement-space\" id=\"space-$group-$ads\"></div>";
461 }
462 // display advertisement
463 $output .= $ad;
464 // increment counters
465 if (adserve_variable('ad_display') == 'raw') {
466 $output .= ad_display_image($ad);
467 }
468 else {
469 adserve_cache('increment', 'view', $id);
470 }
471 $ads++;
472 }
473
474 if (empty($ids)) {
475 adserve_variable('error', TRUE);
476 $output = 'No active ads were found in '. adserve_variable('group');
477 adserve_cache('increment', 'count', NULL);
478 }
479
480 // close/update cache, if necessary
481 adserve_cache('close');
482
483 // update the dynamic portion of the output
484 $params = array();
485 $group = adserve_variable('group');
486 $replace = "/$group";
487 if ($hostid = adserve_variable('hostid')) {
488 $params[] = "hostid=$hostid";
489 }
490 if ($url = htmlentities(adserve_variable('url'))) {
491 $params[] = "url=$url";
492 }
493 if ($extra = adserve_variable('extra')) {
494 $params[] = "extra=$extra";
495 }
496 if (!empty($params)) {
497 $replace .= '?'. implode('&', $params);
498 }
499 $output = preg_replace('&/@HOSTID___&', $replace, $output);
500
501 // there was an error, hide the output in comments
502 if (adserve_variable('error')) {
503 $output = "<!-- $output -->";
504 }
505
506 // allow custom text to be displayed before and after advertisement
507 $init_text = adserve_invoke_hook('init_text', 'append');
508 $exit_text = adserve_invoke_hook('exit_text', 'append');
509 $output = $init_text . $output . $exit_text;
510
511 _debug_memory();
512
513 // TODO: turn all of these into hooks
514 switch (adserve_variable('ad_display')) {
515 case 'javascript':
516 default:
517 $output = str_replace(array("\r", "\n", "<", ">", "&"),
518 array('\r', '\n', '\x3c', '\x3e', '\x26'),
519 addslashes($output));
520 if (!adserve_variable('debug')) {
521 // Tell the web browser not to cache this script so the ad refreshes
522 // each time the page is viewed.
523 // Expires in the past:
524 header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
525 // Last load:
526 header('Last-Modified: '. gmdate('D, d M Y H:i:s') .' GMT');
527 // HTTP 1.1:
528 header('Cache-Control: no-store, no-cache, must-revalidate');
529 header('Cache-Control: post-check=0, pre-check=0', false);
530 // HTTP 1.0:
531 header('Pragma: no-cache');
532 // Output is a JavaScript:
533 header('Content-Type: application/x-javascript; charset=utf-8');
534 }
535 print "document.write('$output');";
536 exit(0);
537 case 'iframe':
538 case 'jquery':
539 if (!adserve_variable('debug')) {
540 // Tell the web browser not to cache this frame so the ad refreshes
541 // each time the page is viewed.
542
543 // Expires in the past:
544 header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
545 // Last load:
546 header('Last-Modified: '. gmdate('D, d M Y H:i:s') .' GMT');
547 // HTTP 1.1:
548 header('Cache-Control: no-store, no-cache, must-revalidate');
549 header('Cache-Control: post-check=0, pre-check=0', false);
550 // HTTP 1.0:
551 header('Pragma: no-cache');
552 }
553 else {
554 _debug_echo('Output: '. htmlentities($output));
555 }
556 print "$output";
557 exit(0);
558 case 'raw':
559 _debug_echo('Output: '. htmlentities($output));
560 chdir(adserve_variable('ad_dir'));
561 return $output;
562
563 }
564
565 _debug_echo('Output: '. htmlentities($output));
566 return $output;
567 }
568