Mercurial > defr > drupal > ad
comparison channel/ad_channel.inc @ 7:6aeff3329e01 ad
maj module ad 2.1rc1
author | piotre |
---|---|
date | Mon, 20 Jul 2009 13:54:40 +0000 |
parents | e5584a19768b |
children |
comparison
equal
deleted
inserted
replaced
6:b7653861e0b4 | 7:6aeff3329e01 |
---|---|
12 * Filter advertisements not in an appropriate channel, from cache. | 12 * Filter advertisements not in an appropriate channel, from cache. |
13 */ | 13 */ |
14 function ad_channel_cache_filter($ads) { | 14 function ad_channel_cache_filter($ads) { |
15 _debug_echo("ad_channel_cache: adserve_cache_filter"); | 15 _debug_echo("ad_channel_cache: adserve_cache_filter"); |
16 | 16 |
17 // get channel array from cache | |
17 $channels = adserve_cache('get_cache', 'channel'); | 18 $channels = adserve_cache('get_cache', 'channel'); |
18 $valid = array(); | 19 // 0 = only display advertisements not assigned to any channel if no matching |
19 $nochannel = array(); | 20 // ads in selected channel; 1 = always display advertisements not assigned to |
20 $nochannel_weight = array(); | 21 // any channel; 2 = never display advertisements not assigned to any channel |
21 $matched_channel = array(); | 22 $nochannel_display = $channels['display']; |
23 $valid_ads = array(); | |
24 $nochannel_fallback_ads = array(); | |
25 $nochannel_percent = array(); | |
26 // determine which channels each advertisement is assigned to | |
22 foreach ($ads as $aid) { | 27 foreach ($ads as $aid) { |
23 _debug_echo("ad_channel_cache: checking aid($aid)"); | 28 _debug_echo("ad_channel_cache: checking aid($aid)"); |
24 if (is_array($channels['ads']) && isset($channels['ads'][$aid]) && | 29 if (is_array($channels['ads']) && isset($channels['ads'][$aid]) && |
25 is_array($channels['ads'][$aid])) { | 30 is_array($channels['ads'][$aid])) { |
26 foreach ($channels['ads'][$aid] as $chid) { | 31 foreach ($channels['ads'][$aid] as $chid) { |
27 $channel = $channels['channels'][$chid]; | 32 $channel = $channels['channels'][$chid]; |
28 $display = $channel->display; | 33 $display_by_url = $channel->display; |
29 $urls = unserialize($channel->urls); | 34 $urls = unserialize($channel->urls); |
30 $frontpage = adserve_variable('site_frontpage') ? adserve_variable('site_frontpage') : 'node'; | 35 $frontpage = adserve_variable('site_frontpage') ? adserve_variable('site_frontpage') : 'node'; |
31 $regexp = '/^('. preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/', '/(^|\|)\\\\<front\\\\>($|\|)/'), array('|', '.*', '\1'. preg_quote($frontpage, '/') .'\2'), preg_quote($urls, '/')) .')$/'; | 36 $regexp = '/^('. preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/', '/(^|\|)\\\\<front\\\\>($|\|)/'), array('|', '.*', '\1'. preg_quote($frontpage, '/') .'\2'), preg_quote($urls, '/')) .')$/'; |
32 $match = preg_match($regexp, adserve_variable('url')); | 37 $match = preg_match($regexp, adserve_variable('url')); |
33 _debug_echo("ad_channel_cache: checking aid($aid) against channel($chid) path(". adserve_variable('url') .") regexp($regexp) match($match)"); | 38 _debug_echo("ad_channel_cache: checking aid($aid) against channel($chid) path(". adserve_variable('url') .") regexp($regexp) match($match) display[$display_by_url]"); |
34 if ($display == 0) { // display on all except listed urls | 39 // display ad on all except matching urls |
40 if ($display_by_url == 0) { | |
35 if (empty($urls) || !$match) { | 41 if (empty($urls) || !$match) { |
36 _debug_echo("ad_channel_cache: aid($aid) is valid"); | 42 _debug_echo("ad_channel_cache: aid($aid) is valid"); |
37 $valid[] = $aid; | 43 $valid_ads[$chid][] = $aid; |
38 if ($display == 1) { | 44 if ($nochannel_display == 1) { |
39 $nochannel_weight[$chid] = $channel->no_channel_weight; | 45 $nochannel_percent[$chid] = $channel->no_channel_percent; |
40 } | 46 _debug_echo("ad_channel_cache: channel($chid) no_channel_percent($nochannel_percent[$chid])"); |
41 $matched_channel[$aid] = $chid; | 47 } |
42 _debug_echo("ad_channel_cache: channel($channel->chid) no_channel_weight(". $nochannel_weight[$chid] .')'); | 48 else { |
49 _debug_echo("ad_channel_cache: channel($chid)"); | |
50 } | |
43 break; | 51 break; |
44 } | 52 } |
45 } | 53 } |
46 else { // display only on listed urls | 54 // display ad on matching urls |
55 else { | |
47 if (!empty($urls) && $match) { | 56 if (!empty($urls) && $match) { |
48 _debug_echo("ad_channel_cache: aid($aid) is valid"); | 57 _debug_echo("ad_channel_cache: aid($aid) is valid"); |
49 $valid[] = $aid; | 58 $valid_ads[$chid][] = $aid; |
50 if ($display == 1) { | 59 if ($nochannel_display == 1) { |
51 $nochannel_weight[$chid] = $channel->no_channel_weight; | 60 $nochannel_percent[$chid] = $channel->no_channel_percent; |
52 } | 61 _debug_echo("ad_channel_cache: channel($chid) no_channel_percent($nochannel_percent[$chid])"); |
53 $matched_channel[$aid] = $chid; | 62 } |
63 else { | |
64 _debug_echo("ad_channel_cache: channel($chid)"); | |
65 } | |
54 break; | 66 break; |
55 } | 67 } |
56 } | 68 } |
69 // no match so we didn't hit a break, ad is not valid | |
57 _debug_echo("ad_channel_cache: aid($aid) is not valid"); | 70 _debug_echo("ad_channel_cache: aid($aid) is not valid"); |
58 } | 71 } |
59 } | 72 } |
60 else { | 73 else { |
61 // no channel information for ad, it's valid | 74 // no channel information for ad |
62 $display = $channels['display']; | 75 _debug_echo("ad_channel_cache: aid($aid) has no channel info, nochannel_display($nochannel_display)"); |
63 _debug_echo("ad_channel_cache: aid($aid) has no channel info [$display]"); | 76 switch ($nochannel_display) { |
64 switch ($display) { | |
65 case 0: | 77 case 0: |
66 $nochannel[] = $aid; | 78 $nochannel_fallback_ads[] = $aid; |
67 _debug_echo("ad_channel_cache: aid($aid) is valid if no valid ads found in current channel"); | 79 _debug_echo("ad_channel_cache: non-channel aid($aid) is valid if no valid ads are assigned to current channel"); |
68 break; | 80 break; |
69 case 1: | 81 case 1: |
70 $valid[] = $aid; | 82 $valid_ads[0][] = $aid; |
71 _debug_echo("ad_channel_cache: aid($aid) is valid"); | 83 _debug_echo("ad_channel_cache: non-channel aid($aid) is valid"); |
72 break; | 84 break; |
73 case 2: | 85 case 2: |
74 _debug_echo("ad_channel_cache: aid($aid) is not valid"); | 86 _debug_echo("ad_channel_cache: aid($aid) is not valid"); |
75 break; | 87 break; |
76 } | 88 } |
77 } | 89 } |
78 } | 90 } |
79 | 91 |
80 // Apply weights, applicable for advertisements that are not assigned to any | 92 // Apply frequencies, applicable to all channels |
81 // channel. | 93 if (!empty($valid_ads) && !empty($nochannel_percent)) { |
82 if (!empty($valid) && !empty($nochannel_weight)) { | 94 $frequencies = array(); |
83 $weights = array(); | 95 foreach (array_keys($valid_ads) as $chid) { |
84 foreach ($valid as $aid) { | 96 if ($chid) { |
85 if (isset($matched_channel[$aid])) { | 97 if (isset($nochannel_percent[$chid]) && $nochannel_percent[$chid]) { |
86 $chid = $matched_channel[$aid]; | 98 $frequencies[$chid] = $nochannel_percent[$chid]; |
87 if (isset($nochannel_weight[$chid])) { | 99 _debug_echo("ad_channel_cache: channel $chid has a non-channel ad frequency of ". $nochannel_percent[$chid]."%"); |
88 $weights[$aid] = $nochannel_weight[$chid]; | |
89 _debug_echo("ad_channel_cache: ad $aid in channel $chid with weight ". $nochannel_weight[$chid]); | |
90 } | 100 } |
91 else { | 101 else { |
92 // by default, ads are assigned a weight of 100% | 102 // by default, channels return 'non-channel ads' with a frequency |
93 $weights[$aid] = 100; | 103 // of 10% |
94 _debug_echo("ad_channel_cache: ad $aid in channel $chid with default weight of 100"); | 104 $frequencies[$chid] = 10; |
105 _debug_echo("ad_channel_cache: channel $chid assigned a default non-channel ad frequency of 10%"); | |
95 } | 106 } |
96 } | 107 } |
97 else { | 108 else { |
98 // by default, ads are assigned a weight of 100% | 109 // frequency for non-channel ads is not meaningful |
99 $weights[$aid] = 100; | 110 } |
100 _debug_echo("ad_channel_cache: ad $aid in no channel with default weight of 100"); | 111 } |
101 } | 112 if (!empty($frequencies)) { |
102 } | 113 $balanced_channels = array(); |
103 if (!empty($weights)) { | 114 $num_channels = sizeof($valid_ads); |
104 $gcd = ad_channel_probability_gcd($weights); | 115 |
105 $display = array(); | 116 foreach (array_keys($valid_ads) as $chid) { |
106 _debug_echo("ad_channel_cache: adjusting channel weights, gcd ($gcd)"); | 117 if (isset($frequencies[$chid])) { |
107 foreach ($valid as $aid) { | 118 // for a given channel, ensure the proper ratio to non-channel ads |
108 $weight = $weights[$aid] / $gcd; | 119 if ($frequencies[$chid] <= 50) { // increase occurrences of $chid |
109 for ($i = 1; $i <= $weight; $i++) { | 120 $balanced_channels[] = 0; |
110 $display[] = $aid; | 121 $frequency = round(100 / $frequencies[$chid]) - 1; |
111 } | 122 _debug_echo("ad_channel_cache: adjusting ratio of channel($chid) to $frequency:1 relative non-channel ads"); |
112 } | 123 for ($i = 1; $i <= $frequency; $i++) { |
113 $valid = $display; | 124 $balanced_channels[] = $chid; |
114 } | 125 } |
115 } | 126 } |
116 else if (empty($valid) && !empty($nochannel)) { | 127 else { // add $chid and additional non-channel ads |
128 $balanced_channels[] = $chid; | |
129 $frequency = round(100 / (100 - $frequencies[$chid])) - 1; | |
130 _debug_echo("ad_channel_cache: adjusting ratio of channel($chid) to 1:$frequency relative non-channel ads"); | |
131 for ($i = 1; $i <= $frequency; $i++) { | |
132 $balanced_channels[] = 0; | |
133 } | |
134 } | |
135 } | |
136 } | |
137 _debug_echo('ad_channel_cache: channel 0 contains all non-channel ads'); | |
138 if (adserve_variable('debug') >= 2) { | |
139 foreach ($balanced_channels as $key => $chid) { | |
140 _debug_echo("ad_channel_cache: channel $chid => index $key"); | |
141 } | |
142 } | |
143 } | |
144 $random_channel = _select_channel_id($balanced_channels); | |
145 } | |
146 else if (!empty($valid_ads)) { | |
147 foreach ($valid_ads as $chid => $ads) { | |
148 $chids[$chid] = $chid; | |
149 } | |
150 shuffle($chids); | |
151 $random_channel = array_pop($chids); | |
152 } | |
153 else if (empty($valid_ads) && !empty($nochannel_fallback_ads)) { | |
117 _debug_echo("ad_channel_cache: using ads with no channel info"); | 154 _debug_echo("ad_channel_cache: using ads with no channel info"); |
118 $valid = $nochannel; | 155 $valid_ads[0] = $nochannel_fallback_ads; |
156 $random_channel = 0; | |
119 } | 157 } |
120 | 158 |
121 $premiere = adserve_cache('get_cache', 'premiere'); | 159 $premiere = adserve_cache('get_cache', 'premiere'); |
122 $premieres = array(); | |
123 if (is_array($premiere)) { | 160 if (is_array($premiere)) { |
124 foreach ($valid as $aid) { | 161 $premieres = array(); |
125 if (in_array($aid, $premiere)) { | 162 foreach (array_keys($valid_ads) as $chid) { |
126 _debug_echo("ad_channel_cache: aid($aid) is premiere advertisement"); | 163 foreach ($valid_ads[$chid] as $aid) { |
127 $premieres[$aid] = $aid; | 164 if (in_array($aid, $premiere)) { |
128 } | 165 _debug_echo("ad_channel_cache: aid($aid) is premiere advertisement"); |
129 else { | 166 $premieres[$aid] = $aid; |
130 _debug_echo("ad_channel_cache: aid($aid) is not a premiere advertisement"); | 167 } |
168 else { | |
169 _debug_echo("ad_channel_cache: aid($aid) is not a premiere advertisement"); | |
170 } | |
131 } | 171 } |
132 } | 172 } |
133 if (!empty($premieres)) { | 173 if (!empty($premieres)) { |
134 _debug_echo("ad_channel_cache: returning premiere advertisements"); | 174 _debug_echo("ad_channel_cache: returning premiere advertisements"); |
135 return $premieres; | 175 return $premieres; |
136 } | 176 } |
137 } | 177 } |
138 _debug_echo("ad_channel_cache: returning non-premiere advertisements"); | 178 _debug_echo("ad_channel_cache: returning non-premiere advertisements from randomly selected channel $random_channel"); |
139 return $valid; | 179 |
180 if (isset($valid_ads[$random_channel])) { | |
181 return ad_channel_enforce_inventory_level($random_channel, $valid_ads[$random_channel]); | |
182 } | |
140 } | 183 } |
141 | 184 |
142 /** | 185 /** |
143 * Returns the greatest common divisor of an array of integers. | 186 * Randomly select a valid channel id from an array channel ids |
144 */ | 187 * @param array, valid array. |
145 function ad_channel_probability_gcd($integers) { | 188 */ |
146 $gcd = array_shift($integers); | 189 function _select_channel_id($choices) { |
147 | 190 $selected = 0; |
148 while (!empty($integers)) { | 191 if (is_array($choices)) { |
149 $gcd = _ad_channel_probability_gcd($gcd, array_shift($integers)); | 192 $available = sizeof($choices); |
150 } | 193 _debug_echo("ad_channel_cache: randomly selecting from $available indexes."); |
151 return $gcd; | 194 $selected = $available > 1 ? $choices[mt_rand(0, $available - 1)] : $choices[0]; |
195 _debug_echo("ad_channel_cache: randomly selected channel $selected."); | |
196 } | |
197 | |
198 return $selected; | |
152 } | 199 } |
153 | 200 |
154 /** | 201 /* |
155 * Helper function to calculate the greatest common divisor using the Euclidean | 202 * Augment the selected channel with 'remnant' ads to ensure that any specified |
156 * algorithm (http://en.wikipedia.org/wiki/Euclidean_algorithm). | 203 * inventory level is honored |
157 */ | 204 * @param int, channel id |
158 function _ad_channel_probability_gcd($a, $b) { | 205 * @param array, valid array. |
159 if ($b == 0) { | 206 */ |
160 return $a; | 207 function ad_channel_enforce_inventory_level($chid, $ads) { |
208 if ($chid > 0) { | |
209 $channels = adserve_cache('get_cache', 'channel'); | |
210 $channel = $channels['channels'][$chid]; | |
211 $level = $channel->inventory; | |
212 $num_ads = count($ads); | |
213 if ($num_ads < $level) { | |
214 _debug_echo("ad_channel_enforce_inventory_level: channel($chid) has $num_ads and needs $level"); | |
215 $remnants = array_values(adserve_cache('get_cache', 'remnant')); | |
216 $available = count($remnants); | |
217 if ($available > 0) { | |
218 _debug_echo("ad_channel_enforce_inventory_level: randomly selecting from $available remnants."); | |
219 while (count($ads) < $level) { | |
220 shuffle($remnants); | |
221 $selected = array_pop($remnants); | |
222 _debug_echo("ad_channel_enforce_inventory_level: selected $selected."); | |
223 $ads[] = $selected; | |
224 } | |
225 } | |
226 else { | |
227 _debug_echo("ad_channel_enforce_inventory_level: no remnants to choose from."); | |
228 } | |
229 } | |
230 else { | |
231 _debug_echo("ad_channel_enforce_inventory_level: channel($chid) no inventory level assigned"); | |
232 } | |
161 } | 233 } |
162 else { | 234 else { |
163 return _ad_channel_probability_gcd($b, $a % $b); | 235 _debug_echo("ad_channel_enforce_inventory_level: not needed for channel($chid)"); |
164 } | 236 } |
237 return $ads; | |
165 } | 238 } |
239 |