pierre@1: . pierre@1: */ pierre@1: pierre@1: /** pierre@1: * Filter advertisements not in an appropriate channel, from cache. pierre@1: */ pierre@1: function ad_channel_cache_filter($ads) { pierre@1: _debug_echo("ad_channel_cache: adserve_cache_filter"); pierre@1: piotre@7: // get channel array from cache pierre@1: $channels = adserve_cache('get_cache', 'channel'); piotre@7: // 0 = only display advertisements not assigned to any channel if no matching piotre@7: // ads in selected channel; 1 = always display advertisements not assigned to piotre@7: // any channel; 2 = never display advertisements not assigned to any channel piotre@7: $nochannel_display = $channels['display']; piotre@7: $valid_ads = array(); piotre@7: $nochannel_fallback_ads = array(); piotre@7: $nochannel_percent = array(); piotre@7: // determine which channels each advertisement is assigned to pierre@1: foreach ($ads as $aid) { pierre@1: _debug_echo("ad_channel_cache: checking aid($aid)"); pierre@1: if (is_array($channels['ads']) && isset($channels['ads'][$aid]) && pierre@1: is_array($channels['ads'][$aid])) { pierre@1: foreach ($channels['ads'][$aid] as $chid) { pierre@1: $channel = $channels['channels'][$chid]; piotre@7: $display_by_url = $channel->display; pierre@1: $urls = unserialize($channel->urls); pierre@1: $frontpage = adserve_variable('site_frontpage') ? adserve_variable('site_frontpage') : 'node'; pierre@1: $regexp = '/^('. preg_replace(array('/(\r\n?|\n)/', '/\\\\\*/', '/(^|\|)\\\\($|\|)/'), array('|', '.*', '\1'. preg_quote($frontpage, '/') .'\2'), preg_quote($urls, '/')) .')$/'; pierre@1: $match = preg_match($regexp, adserve_variable('url')); piotre@7: _debug_echo("ad_channel_cache: checking aid($aid) against channel($chid) path(". adserve_variable('url') .") regexp($regexp) match($match) display[$display_by_url]"); piotre@7: // display ad on all except matching urls piotre@7: if ($display_by_url == 0) { pierre@1: if (empty($urls) || !$match) { pierre@1: _debug_echo("ad_channel_cache: aid($aid) is valid"); piotre@7: $valid_ads[$chid][] = $aid; piotre@7: if ($nochannel_display == 1) { piotre@7: $nochannel_percent[$chid] = $channel->no_channel_percent; piotre@7: _debug_echo("ad_channel_cache: channel($chid) no_channel_percent($nochannel_percent[$chid])"); sly@2: } piotre@7: else { piotre@7: _debug_echo("ad_channel_cache: channel($chid)"); piotre@7: } pierre@1: break; pierre@1: } pierre@1: } piotre@7: // display ad on matching urls piotre@7: else { pierre@1: if (!empty($urls) && $match) { pierre@1: _debug_echo("ad_channel_cache: aid($aid) is valid"); piotre@7: $valid_ads[$chid][] = $aid; piotre@7: if ($nochannel_display == 1) { piotre@7: $nochannel_percent[$chid] = $channel->no_channel_percent; piotre@7: _debug_echo("ad_channel_cache: channel($chid) no_channel_percent($nochannel_percent[$chid])"); sly@2: } piotre@7: else { piotre@7: _debug_echo("ad_channel_cache: channel($chid)"); piotre@7: } pierre@1: break; pierre@1: } pierre@1: } piotre@7: // no match so we didn't hit a break, ad is not valid pierre@1: _debug_echo("ad_channel_cache: aid($aid) is not valid"); pierre@1: } pierre@1: } pierre@1: else { piotre@7: // no channel information for ad piotre@7: _debug_echo("ad_channel_cache: aid($aid) has no channel info, nochannel_display($nochannel_display)"); piotre@7: switch ($nochannel_display) { pierre@1: case 0: piotre@7: $nochannel_fallback_ads[] = $aid; piotre@7: _debug_echo("ad_channel_cache: non-channel aid($aid) is valid if no valid ads are assigned to current channel"); pierre@1: break; pierre@1: case 1: piotre@7: $valid_ads[0][] = $aid; piotre@7: _debug_echo("ad_channel_cache: non-channel aid($aid) is valid"); pierre@1: break; pierre@1: case 2: pierre@1: _debug_echo("ad_channel_cache: aid($aid) is not valid"); pierre@1: break; pierre@1: } pierre@1: } pierre@1: } pierre@1: piotre@7: // Apply frequencies, applicable to all channels piotre@7: if (!empty($valid_ads) && !empty($nochannel_percent)) { piotre@7: $frequencies = array(); piotre@7: foreach (array_keys($valid_ads) as $chid) { piotre@7: if ($chid) { piotre@7: if (isset($nochannel_percent[$chid]) && $nochannel_percent[$chid]) { piotre@7: $frequencies[$chid] = $nochannel_percent[$chid]; piotre@7: _debug_echo("ad_channel_cache: channel $chid has a non-channel ad frequency of ". $nochannel_percent[$chid]."%"); sly@2: } sly@2: else { piotre@7: // by default, channels return 'non-channel ads' with a frequency piotre@7: // of 10% piotre@7: $frequencies[$chid] = 10; piotre@7: _debug_echo("ad_channel_cache: channel $chid assigned a default non-channel ad frequency of 10%"); sly@2: } sly@2: } sly@2: else { piotre@7: // frequency for non-channel ads is not meaningful sly@2: } sly@2: } piotre@7: if (!empty($frequencies)) { piotre@7: $balanced_channels = array(); piotre@7: $num_channels = sizeof($valid_ads); piotre@7: piotre@7: foreach (array_keys($valid_ads) as $chid) { piotre@7: if (isset($frequencies[$chid])) { piotre@7: // for a given channel, ensure the proper ratio to non-channel ads piotre@7: if ($frequencies[$chid] <= 50) { // increase occurrences of $chid piotre@7: $balanced_channels[] = 0; piotre@7: $frequency = round(100 / $frequencies[$chid]) - 1; piotre@7: _debug_echo("ad_channel_cache: adjusting ratio of channel($chid) to $frequency:1 relative non-channel ads"); piotre@7: for ($i = 1; $i <= $frequency; $i++) { piotre@7: $balanced_channels[] = $chid; piotre@7: } piotre@7: } piotre@7: else { // add $chid and additional non-channel ads piotre@7: $balanced_channels[] = $chid; piotre@7: $frequency = round(100 / (100 - $frequencies[$chid])) - 1; piotre@7: _debug_echo("ad_channel_cache: adjusting ratio of channel($chid) to 1:$frequency relative non-channel ads"); piotre@7: for ($i = 1; $i <= $frequency; $i++) { piotre@7: $balanced_channels[] = 0; piotre@7: } piotre@7: } sly@2: } sly@2: } piotre@7: _debug_echo('ad_channel_cache: channel 0 contains all non-channel ads'); piotre@7: if (adserve_variable('debug') >= 2) { piotre@7: foreach ($balanced_channels as $key => $chid) { piotre@7: _debug_echo("ad_channel_cache: channel $chid => index $key"); piotre@7: } piotre@7: } sly@2: } piotre@7: $random_channel = _select_channel_id($balanced_channels); sly@2: } piotre@7: else if (!empty($valid_ads)) { piotre@7: foreach ($valid_ads as $chid => $ads) { piotre@7: $chids[$chid] = $chid; piotre@7: } piotre@7: shuffle($chids); piotre@7: $random_channel = array_pop($chids); piotre@7: } piotre@7: else if (empty($valid_ads) && !empty($nochannel_fallback_ads)) { pierre@1: _debug_echo("ad_channel_cache: using ads with no channel info"); piotre@7: $valid_ads[0] = $nochannel_fallback_ads; piotre@7: $random_channel = 0; pierre@1: } pierre@1: pierre@1: $premiere = adserve_cache('get_cache', 'premiere'); pierre@1: if (is_array($premiere)) { piotre@7: $premieres = array(); piotre@7: foreach (array_keys($valid_ads) as $chid) { piotre@7: foreach ($valid_ads[$chid] as $aid) { piotre@7: if (in_array($aid, $premiere)) { piotre@7: _debug_echo("ad_channel_cache: aid($aid) is premiere advertisement"); piotre@7: $premieres[$aid] = $aid; piotre@7: } piotre@7: else { piotre@7: _debug_echo("ad_channel_cache: aid($aid) is not a premiere advertisement"); piotre@7: } pierre@1: } pierre@1: } pierre@1: if (!empty($premieres)) { pierre@1: _debug_echo("ad_channel_cache: returning premiere advertisements"); pierre@1: return $premieres; pierre@1: } pierre@1: } piotre@7: _debug_echo("ad_channel_cache: returning non-premiere advertisements from randomly selected channel $random_channel"); piotre@7: piotre@7: if (isset($valid_ads[$random_channel])) { piotre@7: return ad_channel_enforce_inventory_level($random_channel, $valid_ads[$random_channel]); piotre@7: } pierre@1: } sly@2: sly@2: /** piotre@7: * Randomly select a valid channel id from an array channel ids piotre@7: * @param array, valid array. sly@2: */ piotre@7: function _select_channel_id($choices) { piotre@7: $selected = 0; piotre@7: if (is_array($choices)) { piotre@7: $available = sizeof($choices); piotre@7: _debug_echo("ad_channel_cache: randomly selecting from $available indexes."); piotre@7: $selected = $available > 1 ? $choices[mt_rand(0, $available - 1)] : $choices[0]; piotre@7: _debug_echo("ad_channel_cache: randomly selected channel $selected."); piotre@7: } sly@2: piotre@7: return $selected; sly@2: } sly@2: piotre@7: /* piotre@7: * Augment the selected channel with 'remnant' ads to ensure that any specified piotre@7: * inventory level is honored piotre@7: * @param int, channel id piotre@7: * @param array, valid array. sly@2: */ piotre@7: function ad_channel_enforce_inventory_level($chid, $ads) { piotre@7: if ($chid > 0) { piotre@7: $channels = adserve_cache('get_cache', 'channel'); piotre@7: $channel = $channels['channels'][$chid]; piotre@7: $level = $channel->inventory; piotre@7: $num_ads = count($ads); piotre@7: if ($num_ads < $level) { piotre@7: _debug_echo("ad_channel_enforce_inventory_level: channel($chid) has $num_ads and needs $level"); piotre@7: $remnants = array_values(adserve_cache('get_cache', 'remnant')); piotre@7: $available = count($remnants); piotre@7: if ($available > 0) { piotre@7: _debug_echo("ad_channel_enforce_inventory_level: randomly selecting from $available remnants."); piotre@7: while (count($ads) < $level) { piotre@7: shuffle($remnants); piotre@7: $selected = array_pop($remnants); piotre@7: _debug_echo("ad_channel_enforce_inventory_level: selected $selected."); piotre@7: $ads[] = $selected; piotre@7: } piotre@7: } piotre@7: else { piotre@7: _debug_echo("ad_channel_enforce_inventory_level: no remnants to choose from."); piotre@7: } piotre@7: } piotre@7: else { piotre@7: _debug_echo("ad_channel_enforce_inventory_level: channel($chid) no inventory level assigned"); piotre@7: } sly@2: } sly@2: else { piotre@7: _debug_echo("ad_channel_enforce_inventory_level: not needed for channel($chid)"); sly@2: } piotre@7: return $ads; sly@2: } piotre@7: