/** * @todo Fix this test to not rely on apd:override_function * */ function test_adSelect2() { $this->sendMessage('test_adSelect2'); require_once MAX_PATH . '/lib/max/Delivery/common.php'; require MAX_PATH . '/lib/max/Delivery/tests/data/test_adSelectZone.php'; // set up a small test data set $context = array(); $test_ads = $aLinked_ads; $test_ads['ads'][4][1122] = $test_ads['ads'][5][1022]; $test_ads['ads'][4][1124] = $test_ads['ads'][5][1024]; $test_ads['ads'][5] = array(); $test_ads['ads'][5][1022] = $test_ads['ads'][4][1122]; $test_ads['ads'][5][1024] = $test_ads['ads'][4][1124]; $test_ads['ads'][4][1122]['ad_id'] = '1122'; $test_ads['ads'][4][1124]['ad_id'] = '1124'; // case 1: cp5, 2 ads both 0.7 $ads_copy = $test_ads; $ads_copy['ads'][5][1022]['priority'] = 0.7; $ads_copy['ads'][5][1024]['priority'] = 0.7; $GLOBALS['test_MAX_cacheGetAd_val'] = $ads_copy['ads'][5]; // this should pick the first one $GLOBALS['rand_val'] = 0.49; $return = _adSelect($ads_copy, $context, $source, $richMedia, false, 'ads', 5); $this->assertTrue(array_key_exists($return['ad_id'], $ads_copy['ads'][5])); $this->assertTrue($ads_copy['priority_used']['ads'][5] >= 1); // case 2: cp5, 2 ads both 0.7 $prev_return = $return; $ads_copy = $test_ads; $ads_copy['ads'][5][1022]['priority'] = 0.7; $ads_copy['ads'][5][1024]['priority'] = 0.7; // this should pick the second one $GLOBALS['rand_val'] = 0.51; $return = _adSelect($ads_copy, $context, $source, $richMedia, false, 'ads', 5); $this->assertTrue(array_key_exists($return['ad_id'], $ads_copy['ads'][5])); $this->assertNotEqual($return['ad_id'], $prev_return['ad_id']); // case 3: cp5, 2 ads both 0.4, cp4, 2 ads both 0.3 $ads_copy = $test_ads; $ads_copy['ads'][5][1022]['priority'] = 0.4; $ads_copy['ads'][5][1024]['priority'] = 0.4; $ads_copy['ads'][4][1122]['priority'] = 0.3; $ads_copy['ads'][4][1124]['priority'] = 0.3; // this should not pick a cp5 ad $GLOBALS['rand_val'] = 0.8100000000000001; $return = _adSelect($ads_copy, $context, $source, $richMedia, false, 'ads', 5); $this->assertNull($return); // this should choose the first ad $GLOBALS['rand_val'] = 0.49; $GLOBALS['test_MAX_cacheGetAd_val'] = $ads_copy['ads'][4]; $return = _adSelect($ads_copy, $context, $source, $richMedia, false, 'ads', 4); $this->assertTrue(array_key_exists($return['ad_id'], $ads_copy['ads'][4])); $this->assertEqual($ads_copy['priority_used']['ads'][5], 0.8); $this->assertEqual($ads_copy['priority_used']['ads'][4], 0.6); // case 4: cp5, 2 ads both 0.4, cp4, 2 ads both 0.3 $ads_copy = $test_ads; $prev_return = $return; $ads_copy['ads'][5][1022]['priority'] = 0.4; $ads_copy['ads'][5][1024]['priority'] = 0.4; $ads_copy['ads'][4][1122]['priority'] = 0.3; $ads_copy['ads'][4][1124]['priority'] = 0.3; // this should not pick a cp5 ad $GLOBALS['rand_val'] = 0.8100000000000001; $return = _adSelect($ads_copy, $context, $source, $richMedia, false, 'ads', 5); $this->assertNull($return); // this should choose the second ad $GLOBALS['rand_val'] = 0.51; $GLOBALS['test_MAX_cacheGetAd_val'] = $ads_copy['ads'][4]; $return = _adSelect($ads_copy, $context, $source, $richMedia, false, 'ads', 4); $this->assertTrue(array_key_exists($return['ad_id'], $ads_copy['ads'][4])); $this->assertEqual($ads_copy['priority_used']['ads'][5], 0.8); $this->assertEqual($ads_copy['priority_used']['ads'][4], 0.6); // make sure it's not the same ad $this->assertNotEqual($return['ad_id'], $prev_return['ad_id']); // case 5: cp5, 2 ads both 0.2, cp4, 2 ads both 0.2 $ads_copy = $test_ads; $prev_return = $return; $ads_copy['ads'][5][1022]['priority'] = 0.2; $ads_copy['ads'][5][1024]['priority'] = 0.2; $ads_copy['ads'][4][1122]['priority'] = 0.2; $ads_copy['ads'][4][1124]['priority'] = 0.2; // this will not pick from cp5 or cp4 $GLOBALS['rand_val'] = 0.41; $return = _adSelect($ads_copy, $context, $source, $richMedia, false, 'ads', 5); $this->assertNull($return); $GLOBALS['rand_val'] = 0.67; $return = _adSelect($ads_copy, $context, $source, $richMedia, false, 'ads', 4); $this->assertNull($return); $this->assertEqual($ads_copy['priority_used']['ads'][5], 0.4); $this->assertEqual($ads_copy['priority_used']['ads'][4], 0.4); // case 6: cp5, 2 ads both 0.5, cp4, 2 ads both 0.2 // one of the cp5 ads will be filtered out $ads_copy = $test_ads; $ads_copy['ads'][5][1022]['priority'] = 0.5; $ads_copy['ads'][5][1024]['priority'] = 0.5; $ads_copy['ads'][4][1122]['priority'] = 0.2; $ads_copy['ads'][4][1124]['priority'] = 0.2; $context = array(array('!=' => 'bannerid:1024')); // this will not pick from cp5 due to the ad exclusion $GLOBALS['rand_val'] = 0.51; $return = _adSelect($ads_copy, $context, $source, $richMedia, false, 'ads', 5); $this->assertNull($return); $GLOBALS['rand_val'] = 0.79; $return = _adSelect($ads_copy, $context, $source, $richMedia, false, 'ads', 4); $this->assertNotNull($return); $this->assertEqual($ads_copy['priority_used']['ads'][5], 0.5); $this->assertEqual($ads_copy['priority_used']['ads'][4], 0.4); // case 7: all ads get filtered out $ads_copy = $test_ads; unset($ads_copy['ads'][5][1022]); $ads_copy['ads'][5][1024]['priority'] = 0.5; $context = array(array('!=' => 'bannerid:1024')); // just expect null response $GLOBALS['rand_val'] = 0.51; $return = _adSelect($ads_copy, $context, $source, $richMedia, false, 'ads', 5); $this->assertNull($return); $this->assertTrue(!isset($ads_copy['priority_used']['ads'][5])); $context = ""; // case 8: priority_used limit reached $ads_copy = $test_ads; $ads_copy['priority_used']['ads'][9] = 0.5; $ads_copy['priority_used']['ads'][8] = 0.3; $ads_copy['priority_used']['ads'][6] = 0.3; // this will return -1, since we've already used the entire priority space $GLOBALS['rand_val'] = 0.51; $return = _adSelect($ads_copy, $context, $source, $richMedia, false, 'ads', 5); $this->assertEqual($return, $GLOBALS['OX_adSelect_SkipOtherPriorityLevels']); $this->assertTrue(!isset($ads_copy['priority_used']['ads'][5])); // case 9: cp5, 2 ads both 0.5, cp4, 2 ads both 0.2 // one of the cp5 ads will be filtered out $ads_copy = $test_ads; $ads_copy['ads'][5][1022]['priority'] = 0; $ads_copy['ads'][5][1024]['priority'] = 0; // this will not pick from cp5 due to the ad exclusion $GLOBALS['rand_val'] = 0.51; $return = _adSelect($ads_copy, $context, $source, $richMedia, false, 'ads', 5); $this->assertNull($return); $this->assertEqual($ads_copy['priority_used']['ads'][5], 0); // case 10: cp5, 2 ads both 0.7, cp4, 2 ads both 0.2 // cp5 ad will win, but confirm that the cp4 ads will be filtered $ads_copy = $test_ads; $ads_copy['ads'][5][1022]['priority'] = 0.7; $ads_copy['ads'][5][1024]['priority'] = 0.7; $ads_copy['ads'][4][1122]['priority'] = 0.2; $ads_copy['ads'][4][1124]['priority'] = 0.2; $context = array(array('!=' => 'bannerid:1124')); $GLOBALS['_MAX']['considered_ads'] = array(); // this will not pick from cp5 due to the ad exclusion $GLOBALS['rand_val'] = 0.51; $GLOBALS['test_MAX_cacheGetAd_val'] = $ads_copy['ads'][5]; $return = _adSelectCommon($ads_copy, $context, $source, $richMedia); $this->assertNotNull($return); $ads_ret =& $GLOBALS['_MAX']['considered_ads'][0]; $this->assertEqual($ads_ret['priority_used']['ads'][5], (double) 1.4); $this->assertFalse(isset($ads_ret['ads'][4][1124])); $this->assertTrue(isset($ads_ret['ads'][4][1122])); // case 11: cp5, 2 ads both 0.7, ecpm enabled $GLOBALS['_MAX']['CONF']['delivery']['ecpmSelectionRate'] = 1; $ads_copy = $test_ads; $ads_copy['ads'][6] = $ads_copy['ads'][5]; $ads_copy['ads'][6][1022]['priority'] = 0.7; $ads_copy['ads'][6][1022]['ecpm_enabled'] = 1; $ads_copy['ads'][6][1022]['ecpm'] = 2.0; $ads_copy['ads'][6][1024]['priority'] = 0.7; $ads_copy['ads'][6][1024]['ecpm_enabled'] = 1; $ads_copy['ads'][6][1024]['ecpm'] = 0.5; $GLOBALS['test_MAX_cacheGetAd_val'] = $ads_copy['ads'][6]; $context = ''; // after ecpm optimization, the priorities should be // [1022] = 0.7 => 0.7 // [1024] = 0.7 => 0.3 // // this should pick the first one $GLOBALS['rand_val'] = 0.49; $return = _adSelect($ads_copy, $context, $source, $richMedia, false, 'ads', 6); $this->assertTrue(array_key_exists($return['ad_id'], $ads_copy['ads'][6])); $this->assertEqual($return['ad_id'], 1022); $this->assertTrue($ads_copy['priority_used']['ads'][6] >= 1); $ads_copy = $test_ads; $ads_copy['ads'][6] = $ads_copy['ads'][5]; $ads_copy['ads'][6][1022]['priority'] = 0.7; $ads_copy['ads'][6][1022]['ecpm_enabled'] = 1; $ads_copy['ads'][6][1022]['ecpm'] = 2.0; $ads_copy['ads'][6][1024]['priority'] = 0.7; $ads_copy['ads'][6][1024]['ecpm_enabled'] = 1; $ads_copy['ads'][6][1024]['ecpm'] = 0.5; $GLOBALS['test_MAX_cacheGetAd_val'] = $ads_copy['ads'][6]; // this should pick the second one $GLOBALS['rand_val'] = 0.71; $return = _adSelect($ads_copy, $context, $source, $richMedia, false, 'ads', 6); $this->assertTrue(array_key_exists($return['ad_id'], $ads_copy['ads'][6])); $this->assertEqual($return['ad_id'], 1024); $this->assertTrue($ads_copy['priority_used']['ads'][6] >= 1); // case 12: cp5, 2 ads both 0.7, ecpm enabled $GLOBALS['_MAX']['CONF']['delivery']['ecpmSelectionRate'] = 1; $ads_copy = $test_ads; $ads_copy['ads'][6] = $ads_copy['ads'][5]; $ads_copy['ads'][6][1122] = $ads_copy['ads'][5][1022]; $ads_copy['ads'][6][1124] = $ads_copy['ads'][5][1024]; $ads_copy['ads'][6][1222] = $ads_copy['ads'][5][1222]; $ads_copy['ads'][6][1022]['priority'] = 0.2; $ads_copy['ads'][6][1022]['ecpm_enabled'] = 1; $ads_copy['ads'][6][1022]['ecpm'] = 2.0; $ads_copy['ads'][6][1024]['priority'] = 0.5; $ads_copy['ads'][6][1024]['ecpm_enabled'] = 1; $ads_copy['ads'][6][1024]['ecpm'] = 0.5; $ads_copy['ads'][6][1122]['ad_id'] = 1122; $ads_copy['ads'][6][1122]['priority'] = 0.7; $ads_copy['ads'][6][1122]['ecpm_enabled'] = 1; $ads_copy['ads'][6][1122]['ecpm'] = 2.0; $ads_copy['ads'][6][1124]['ad_id'] = 1124; $ads_copy['ads'][6][1124]['priority'] = 0.7; $ads_copy['ads'][6][1124]['ecpm_enabled'] = 1; $ads_copy['ads'][6][1124]['ecpm'] = 0.5; $ads_copy['ads'][6][1222]['ad_id'] = 1222; $ads_copy['ads'][6][1222]['priority'] = 0.7; $ads_copy['ads'][6][1222]['ecpm_enabled'] = 1; $ads_copy['ads'][6][1222]['ecpm'] = 0.4; $GLOBALS['test_MAX_cacheGetAd_val'] = $ads_copy['ads'][6]; // this should result in the following // [1022] = 0.2 // [1024] = 0.5 * (1-(0.2+0.7)) / (0.5+0.7) = 0.0417 // [1122] = 0.7 // [1124] = 0.7 * (1-(0.2+0.7)) / (0.5+0.7) = 0.0583 // [1222] = 0.0 // this should pick 1024 $GLOBALS['rand_val'] = 0.22; $return = _adSelect($ads_copy, $context, $source, $richMedia, false, 'ads', 6); $this->assertTrue(array_key_exists($return['ad_id'], $ads_copy['ads'][6])); $this->assertEqual($return['ad_id'], 1024); $this->assertTrue($ads_copy['priority_used']['ads'][6] >= 1); $this->assertEqual($ads_copy['ads'][6][1022]['priority'], 0.2); //unchanged $this->assertNotEqual($ads_copy['ads'][6][1024]['priority'], 0.5); //scaled $this->assertEqual($ads_copy['ads'][6][1222]['priority'], 0); //zeroed $this->assertEqual($ads_copy['ads'][6][1022]['priority'] + $ads_copy['ads'][6][1024]['priority'] + $ads_copy['ads'][6][1122]['priority'] + $ads_copy['ads'][6][1124]['priority'], 1); $ads_copy = $test_ads; $ads_copy['eAds'][-2] = $ads_copy['ads'][5]; $ads_copy['eAds'][-2][1022]['priority'] = 0.2; $ads_copy['eAds'][-2][1022]['ecpm_enabled'] = 1; $ads_copy['eAds'][-2][1022]['ecpm'] = 2.0; $ads_copy['eAds'][-2][1024]['priority'] = 0.1; $ads_copy['eAds'][-2][1024]['ecpm_enabled'] = 1; $ads_copy['eAds'][-2][1024]['ecpm'] = 2.0; $GLOBALS['test_MAX_cacheGetAd_val'] = $ads_copy['eAds'][-2]; // this should pick the second one $GLOBALS['rand_val'] = 0.51; $return = _adSelect($ads_copy, $context, $source, $richMedia, false, 'eAds', -2); $this->assertTrue(array_key_exists($return['ad_id'], $ads_copy['eAds'][-2])); $this->assertEqual($return['ad_id'], 1024); $ads_copy = $test_ads; $ads_copy['eAds'][-2] = $ads_copy['ads'][5]; $ads_copy['eAds'][-2][1022]['priority'] = 0.7; $ads_copy['eAds'][-2][1022]['ecpm_enabled'] = 1; $ads_copy['eAds'][-2][1022]['ecpm'] = 1.0; $ads_copy['eAds'][-2][1024]['priority'] = 0.1; $ads_copy['eAds'][-2][1024]['ecpm_enabled'] = 1; $ads_copy['eAds'][-2][1024]['ecpm'] = 2.0; $GLOBALS['test_MAX_cacheGetAd_val'] = $ads_copy['eAds'][-2]; // this should pick the second one $GLOBALS['rand_val'] = 0.01; $return = _adSelect($ads_copy, $context, $source, $richMedia, false, 'eAds', -2); $this->assertTrue(array_key_exists($return['ad_id'], $ads_copy['eAds'][-2])); $this->assertEqual($return['ad_id'], 1024); // case 13: cp6, 4 ads 2 0.7, 2 0.9, ecpm enabled $GLOBALS['_MAX']['CONF']['delivery']['ecpmSelectionRate'] = 0.001; $GLOBALS['_MAX']['CONF']['delivery']['enableControlOnPureCPM'] = 0; $ads_copy = $test_ads; $ads_copy['ads'][6] = $ads_copy['ads'][5]; $ads_copy['ads'][6][1122] = $ads_copy['ads'][5][1022]; $ads_copy['ads'][6][1124] = $ads_copy['ads'][5][1024]; $ads_copy['ads'][6][1122]['ad_id'] = 1122; $ads_copy['ads'][6][1124]['ad_id'] = 1124; $ads_copy['ads'][6][1022]['priority'] = 0.7; $ads_copy['ads'][6][1022]['ecpm_enabled'] = 1; $ads_copy['ads'][6][1022]['ecpm'] = 2.0; $ads_copy['ads'][6][1022]['revenue_type'] = 1; $ads_copy['ads'][6][1024]['priority'] = 0.9; $ads_copy['ads'][6][1024]['ecpm_enabled'] = 1; $ads_copy['ads'][6][1024]['ecpm'] = 0.5; $ads_copy['ads'][6][1024]['revenue_type'] = 1; $ads_copy['ads'][6][1122]['priority'] = 0.7; $ads_copy['ads'][6][1122]['ecpm_enabled'] = 1; $ads_copy['ads'][6][1122]['ecpm'] = 2.0; $ads_copy['ads'][6][1122]['revenue_type'] = 1; $ads_copy['ads'][6][1124]['priority'] = 0.9; $ads_copy['ads'][6][1124]['ecpm_enabled'] = 1; $ads_copy['ads'][6][1124]['ecpm'] = 0.5; $ads_copy['ads'][6][1124]['revenue_type'] = 1; $GLOBALS['test_MAX_cacheGetAd_val'] = $ads_copy['ads'][6]; $context = ''; // if control were enabled, 1124 would be picked. // this should pick the 1122 after ecpm optimization $GLOBALS['rand_val'] = 0.99; $return = _adSelect($ads_copy, $context, $source, $richMedia, false, 'ads', 6); $this->assertTrue(array_key_exists($return['ad_id'], $ads_copy['ads'][6])); $this->assertEqual($return['ad_id'], 1122); $this->assertTrue($ads_copy['priority_used']['ads'][6] >= 1); $this->assertEqual(_controlTrafficEnabled($ads_copy['ads'][6]), false); $GLOBALS['_MAX']['CONF']['delivery']['enableControlOnPureCPM'] = 1; $this->assertEqual(_controlTrafficEnabled($ads_copy['ads'][6]), true); $ads_copy['ads'][6][1124]['revenue_type'] = 0; $this->assertEqual(_controlTrafficEnabled($ads_copy['ads'][6]), true); }
function _adSelect(&$aLinkedAdInfos, $context, $source, $richMedia, $companion, $adArrayVar = 'ads', $cp = null) { if (!is_array($aLinkedAdInfos)) { return; } if (!is_null($cp) && isset($aLinkedAdInfos[$adArrayVar][$cp])) { $aAds =& $aLinkedAdInfos[$adArrayVar][$cp]; } elseif (is_null($cp) && isset($aLinkedAdInfos[$adArrayVar])) { $aAds =& $aLinkedAdInfos[$adArrayVar]; } else { $aAds = array(); } if (count($aAds) == 0) { return; } $aContext = _adSelectBuildContextArray($aAds, $adArrayVar, $context, $companion); _adSelectDiscardNonMatchingAds($aAds, $aContext, $source, $richMedia); if (count($aAds) == 0) { return; } global $n; mt_srand(floor((isset($n) && strlen($n) > 5 ? hexdec($n[0] . $n[2] . $n[3] . $n[4] . $n[5]) : 1000000) * (double) microtime())); $conf = $GLOBALS['_MAX']['CONF']; if ($adArrayVar == 'eAds') { if (!empty($conf['delivery']['ecpmSelectionRate'])) { $selection_rate = floatval($conf['delivery']['ecpmSelectionRate']); if (!_controlTrafficEnabled($aAds) || mt_rand(0, $GLOBALS['_MAX']['MAX_RAND']) / $GLOBALS['_MAX']['MAX_RAND'] <= $selection_rate) { $max_ecpm = 0; $top_ecpms = array(); foreach ($aAds as $key => $ad) { if ($ad['ecpm'] < $max_ecpm) { continue; } elseif ($ad['ecpm'] > $max_ecpm) { $top_ecpms = array(); $max_ecpm = $ad['ecpm']; } $top_ecpms[$key] = 1; } if ($max_ecpm <= 0) { $GLOBALS['_MAX']['ECPM_CONTROL'] = 1; $total_priority = _setPriorityFromWeights($aAds); } else { $GLOBALS['_MAX']['ECPM_SELECTION'] = 1; $total_priority = count($top_ecpms); foreach ($aAds as $key => $ad) { if (!empty($top_ecpms[$key])) { $aAds[$key]['priority'] = 1 / $total_priority; } else { $aAds[$key]['priority'] = 0; } } } } else { $GLOBALS['_MAX']['ECPM_CONTROL'] = 1; $total_priority = _setPriorityFromWeights($aAds); } } } else { if (isset($cp)) { $used_priority = 0; for ($i = 10; $i > $cp; $i--) { if (isset($aLinkedAdInfos['priority_used'][$adArrayVar][$i])) { $used_priority += $aLinkedAdInfos['priority_used'][$adArrayVar][$i]; } } if ($used_priority >= 1) { return $GLOBALS['OX_adSelect_SkipOtherPriorityLevels']; } $remaining_priority = 1 - $used_priority; $total_priority_orig = 0; foreach ($aAds as $ad) { $total_priority_orig += $ad['priority'] * $ad['priority_factor']; } $aLinkedAdInfos['priority_used'][$adArrayVar][$i] = $total_priority_orig; if ($total_priority_orig <= 0) { return; } if ($total_priority_orig > $remaining_priority || $companion) { $scaling_denom = $total_priority_orig; if ($cp >= PRI_ECPM_FROM && $cp <= PRI_ECPM_TO && !empty($conf['delivery']['ecpmSelectionRate'])) { $selection_rate = floatval($conf['delivery']['ecpmSelectionRate']); if (!_controlTrafficEnabled($aAds) || mt_rand(0, $GLOBALS['_MAX']['MAX_RAND']) / $GLOBALS['_MAX']['MAX_RAND'] <= $selection_rate) { $GLOBALS['_MAX']['ECPM_SELECTION'] = 1; foreach ($aAds as $key => $ad) { $ecpms[] = $ad['ecpm']; $adids[] = $key; } array_multisort($ecpms, SORT_DESC, $adids); $p_avail = $remaining_priority; $ad_count = count($aAds); $i = 0; while ($i < $ad_count) { $l = $i; while ($l < $ad_count - 1 && $ecpms[$l + 1] == $ecpms[$i]) { $l++; } $p_needed = 0; for ($a_idx = $i; $a_idx <= $l; $a_idx++) { $id = $adids[$a_idx]; $p_needed += $aAds[$id]['priority'] * $aAds[$id]['priority_factor']; } if ($p_needed > $p_avail) { $scale = $p_avail / $p_needed; for ($a_idx = $i; $a_idx <= $l; $a_idx++) { $id = $adids[$a_idx]; $aAds[$id]['priority'] = $aAds[$id]['priority'] * $scale; } $p_avail = 0; for ($a_idx = $l + 1; $a_idx < $ad_count; $a_idx++) { $id = $adids[$a_idx]; $aAds[$id]['priority'] = 0; } break; } else { $p_avail -= $p_needed; $i = $l + 1; } } $scaling_denom = $remaining_priority; } else { $GLOBALS['_MAX']['ECPM_CONTROL'] = 1; } } $scaling_factor = 1 / $scaling_denom; } else { $scaling_factor = 1 / $remaining_priority; } $total_priority = 0; foreach ($aAds as $key => $ad) { $newPriority = $ad['priority'] * $ad['priority_factor'] * $scaling_factor; $aAds[$key]['priority'] = $newPriority; $total_priority += $newPriority; } } else { $total_priority = _setPriorityFromWeights($aAds); } } global $n; mt_srand(floor((isset($n) && strlen($n) > 5 ? hexdec($n[0] . $n[2] . $n[3] . $n[4] . $n[5]) : 1000000) * (double) microtime())); $conf = $GLOBALS['_MAX']['CONF']; $random_num = mt_rand(0, $GLOBALS['_MAX']['MAX_RAND']) / $GLOBALS['_MAX']['MAX_RAND']; if ($random_num > $total_priority) { return; } $low = 0; $high = 0; foreach ($aAds as $aLinkedAd) { if (!empty($aLinkedAd['priority'])) { $low = $high; $high += $aLinkedAd['priority']; if ($high > $random_num && $low <= $random_num) { $ad = MAX_cacheGetAd($aLinkedAd['ad_id']); $ad['tracker_status'] = !empty($aLinkedAd['tracker_status']) ? $aLinkedAd['tracker_status'] : null; if ($ad['width'] == $ad['height'] && $ad['width'] == -1) { $ad['width'] = $aLinkedAd['width']; $ad['height'] = $aLinkedAd['height']; } return $ad; } } } return; }
/** * This function takes a group of ads, and selects the ad to show * * @param array $aLinkedAds The array of possible ads for this search criteria * @param array $context The context of this ad selection * - used for companion positioning * - and excluding banner/campaigns from this ad-call * @param string $source The "source" parameter passed into the adcall * @param boolean $richMedia Does this invocation method allow for serving 3rd party/html ads * @param boolean $companion Should ad selection only return companion ads? * @param string $adArrayVar The collection of ads in $aLinkedAds to select the ad from * @param integer $cp * * @return array|void The ad-array for the selected ad or void if no ad selected */ function _adSelect(&$aLinkedAdInfos, $context, $source, $richMedia, $companion, $adArrayVar = 'ads', $cp = null) { // If there are no linked ads, we can return if (!is_array($aLinkedAdInfos)) { return; } if (!is_null($cp) && isset($aLinkedAdInfos[$adArrayVar][$cp])) { $aAds =& $aLinkedAdInfos[$adArrayVar][$cp]; } elseif (is_null($cp) && isset($aLinkedAdInfos[$adArrayVar])) { $aAds =& $aLinkedAdInfos[$adArrayVar]; } else { $aAds = array(); } // If there are no linked ads of the specified type, we can return if (count($aAds) == 0) { return; } // Build preconditions $aContext = _adSelectBuildContextArray($aAds, $adArrayVar, $context, $companion); // New delivery algorithm: discard all invalid ads before iterating over them // $aAds passed by ref here _adSelectDiscardNonMatchingAds($aAds, $aContext, $source, $richMedia); // If there are no linked ads of the specified type, we can return if (count($aAds) == 0) { return; } // Seed the random number generator global $n; mt_srand(floor((isset($n) && strlen($n) > 5 ? hexdec($n[0] . $n[2] . $n[3] . $n[4] . $n[5]) : 1000000) * (double) microtime())); $conf = $GLOBALS['_MAX']['CONF']; if ($adArrayVar == 'eAds') { if (!empty($conf['delivery']['ecpmSelectionRate'])) { // we should still allow there to be some portion of control // responses in order to avoid starving out any ad $selection_rate = floatval($conf['delivery']['ecpmSelectionRate']); if (!_controlTrafficEnabled($aAds) || mt_rand(0, $GLOBALS['_MAX']['MAX_RAND']) / $GLOBALS['_MAX']['MAX_RAND'] <= $selection_rate) { // Find the highest value eCPM ad(s) an naively select // from that set. $max_ecpm = 0; $top_ecpms = array(); // build an eCPM sorted index for the ads foreach ($aAds as $key => $ad) { if ($ad['ecpm'] < $max_ecpm) { continue; } elseif ($ad['ecpm'] > $max_ecpm) { $top_ecpms = array(); $max_ecpm = $ad['ecpm']; } $top_ecpms[$key] = 1; } // fallback to weighted prioritization if ecpm weighting zeros out if ($max_ecpm <= 0) { $GLOBALS['_MAX']['ECPM_CONTROL'] = 1; $total_priority = _setPriorityFromWeights($aAds); } else { // zero out the priority for all except ads with the // highest eCPM value $GLOBALS['_MAX']['ECPM_SELECTION'] = 1; $total_priority = count($top_ecpms); foreach ($aAds as $key => $ad) { if (!empty($top_ecpms[$key])) { $aAds[$key]['priority'] = 1 / $total_priority; } else { $aAds[$key]['priority'] = 0; } } } } else { $GLOBALS['_MAX']['ECPM_CONTROL'] = 1; $total_priority = _setPriorityFromWeights($aAds); } } } else { if (isset($cp)) { // How much of the priority space have we already covered? $used_priority = 0; for ($i = 10; $i > $cp; $i--) { if (isset($aLinkedAdInfos['priority_used'][$adArrayVar][$i])) { $used_priority += $aLinkedAdInfos['priority_used'][$adArrayVar][$i]; } } // sanity check, in case there is no space left. if ($used_priority >= 1) { return $GLOBALS['OX_adSelect_SkipOtherPriorityLevels']; } $remaining_priority = 1 - $used_priority; // Calculate the sum of all priority values $total_priority_orig = 0; foreach ($aAds as $ad) { $total_priority_orig += $ad['priority'] * $ad['priority_factor']; } $aLinkedAdInfos['priority_used'][$adArrayVar][$i] = $total_priority_orig; // If there are no active ads, we can return if ($total_priority_orig <= 0) { return; } // In this case, the sum of priorities is greater than the ratio // we have remaining, so just scale to fill the remaining space. if ($total_priority_orig > $remaining_priority || $companion) { $scaling_denom = $total_priority_orig; // In this case, the space has been oversold, so eCPM optimization // is allowed to be applied. The approach is to give priority to // higher eCPM, but not to rescale priorities, unless there is a tie // for a position at the edge of the dropoff. if ($cp >= PRI_ECPM_FROM && $cp <= PRI_ECPM_TO && !empty($conf['delivery']['ecpmSelectionRate'])) { // we should still allow there to be some portion of control // responses in order to avoid starving out any ad $selection_rate = floatval($conf['delivery']['ecpmSelectionRate']); if (!_controlTrafficEnabled($aAds) || mt_rand(0, $GLOBALS['_MAX']['MAX_RAND']) / $GLOBALS['_MAX']['MAX_RAND'] <= $selection_rate) { // set flag to indicate this request has applied ecpm optimization $GLOBALS['_MAX']['ECPM_SELECTION'] = 1; // build an eCPM sorted index for the ads foreach ($aAds as $key => $ad) { $ecpms[] = $ad['ecpm']; $adids[] = $key; } array_multisort($ecpms, SORT_DESC, $adids); $p_avail = $remaining_priority; $ad_count = count($aAds); $i = 0; while ($i < $ad_count) { // find the range of consecutive ads with equal eCPMs $l = $i; while ($l < $ad_count - 1 && $ecpms[$l + 1] == $ecpms[$i]) { $l++; } // how much priority space does this range of equal eCPM ads require? $p_needed = 0; for ($a_idx = $i; $a_idx <= $l; $a_idx++) { $id = $adids[$a_idx]; $p_needed += $aAds[$id]['priority'] * $aAds[$id]['priority_factor']; } // if this range needs more priority space than is left, we'll scale // these and zero out all ads with lower eCPM values if ($p_needed > $p_avail) { $scale = $p_avail / $p_needed; for ($a_idx = $i; $a_idx <= $l; $a_idx++) { $id = $adids[$a_idx]; $aAds[$id]['priority'] = $aAds[$id]['priority'] * $scale; } $p_avail = 0; // zero out remaining ads priorities for ($a_idx = $l + 1; $a_idx < $ad_count; $a_idx++) { $id = $adids[$a_idx]; $aAds[$id]['priority'] = 0; } break; } else { $p_avail -= $p_needed; $i = $l + 1; } } $scaling_denom = $remaining_priority; } else { // set flag to indicate this request was eligible for ecpm optimization, // but did not apply it in order to serve a control result set $GLOBALS['_MAX']['ECPM_CONTROL'] = 1; } } // scaling_denom is either remaining_priority or total_priority_orig, both of which // have been guarded against being 0, so there's no risk of div by 0 here $scaling_factor = 1 / $scaling_denom; } else { // in this case, we don't need to use the whole of the remaining // space, but we scale to the remaining size, which leaves room to // select a lower level, since $total_priority_orig / $remaining_priority < 1 $scaling_factor = 1 / $remaining_priority; } // recalculate the priorities (in place??), using the scaling factor. $total_priority = 0; foreach ($aAds as $key => $ad) { $newPriority = $ad['priority'] * $ad['priority_factor'] * $scaling_factor; $aAds[$key]['priority'] = $newPriority; $total_priority += $newPriority; } } else { // Rescale priorities by weights $total_priority = _setPriorityFromWeights($aAds); } } // Seed the random number generator global $n; mt_srand(floor((isset($n) && strlen($n) > 5 ? hexdec($n[0] . $n[2] . $n[3] . $n[4] . $n[5]) : 1000000) * (double) microtime())); $conf = $GLOBALS['_MAX']['CONF']; // Pick a float random number between 0 and 1, inclusive. $random_num = mt_rand(0, $GLOBALS['_MAX']['MAX_RAND']) / $GLOBALS['_MAX']['MAX_RAND']; ###START_STRIP_DELIVERY // testing support if (function_exists('test_mt_rand')) { $random_num = test_mt_rand(0, $GLOBALS['_MAX']['MAX_RAND']) / $GLOBALS['_MAX']['MAX_RAND']; } ###END_STRIP_DELIVERY // Is it higher than the sum of all the priority values? if ($random_num > $total_priority) { // No suitable ad found, proceed as usual return; } // Perform selection of an ad, based on the random number $low = 0; $high = 0; foreach ($aAds as $aLinkedAd) { if (!empty($aLinkedAd['priority'])) { $low = $high; $high += $aLinkedAd['priority']; if ($high > $random_num && $low <= $random_num) { ###START_STRIP_DELIVERY // testing support if (function_exists('test_MAX_cacheGetAd')) { return test_MAX_cacheGetAd($aLinkedAd['ad_id']); } ###END_STRIP_DELIVERY $ad = MAX_cacheGetAd($aLinkedAd['ad_id']); // Carry over for conversion tracking $ad['tracker_status'] = !empty($aLinkedAd['tracker_status']) ? $aLinkedAd['tracker_status'] : null; // Carry over for ad dimensions for market ads if ($ad['width'] == $ad['height'] && $ad['width'] == -1) { $ad['width'] = $aLinkedAd['width']; $ad['height'] = $aLinkedAd['height']; } return $ad; } } } return; }