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 |
