Bidder Files
src/Bidder.class.php
src/BidderUtils.class.php
src/KeyNames.class.php
src/MemUtils.class.php
src/bidderConfig.php
src/bidderFiles.php
src/index.php
src/sharedConfig.php
scripts/Aggregator.class.php
scripts/MinuteSaver.class.php
scripts/PlacementPpmCacher.class.php
scripts/RevenueCollector.class.php
scripts/WinsCollector.class.php
scripts/aggregator.php
scripts/minuteSaver.php
scripts/placementPpmCacher.php
scripts/revenueCollector.php
scripts/scriptsConfig.php
scripts/winsCollector.php
Bidder UI & Exchage simulation

bidder/src/Bidder.class.php

<?php
/*------------------------------------------------------------*/
class Bidder extends Mcontroller {
    
/*------------------------------------------------------------*/
    
private $Mmemcache;
    private 
$bidderUtils;
    private 
$memUtils;
    private 
$keyNames;
    
/*------------------------------*/
    
private $logger;
    
/*------------------------------*/
    // request and others()
    
private $bidRequest;
    private 
$bidRequestId;
    private 
$placementId;
    
/*------------------------------*/
    // request only
    
private $input;
    private 
$bidRequestKind;
    private 
$bidRequestName;
    private 
$w;
    private 
$h;
    private 
$geo;
    private 
$domain;
    
/*------------------------------------------------------------*/
    
private $campaigns;
    private 
$pacedCampaigns;
    private 
$campaign;
    private 
$controlPanel;
    
/*------------------------------*/
    // others() only 
    
private $bidId;
    private 
$bid;
    
/*------------------------------------------------------------*/
    
public function index() {
        
$startTime microtime(true);
        
$this->Mmemcache = new Mmemcache;
        
$this->keyNames = new KeyNames;
        
$logsDir "/var/www/vhosts/bidder.theora.com/logs/bidder";
        
$today date("Y-m-d");
        
$logFileName "bidder.$today.log";
        
$logFile "$logsDir/$logFileName";
        
$this->logger = new Logger($logFile);
        
$this->bidderUtils = new BidderUtils($logFile);
        
$this->memUtils = new MemUtils($logFile);
        
$this->campaigns $this->pacedCampaigns = array();

        
$bidId = @$_REQUEST['bidId'];
        if ( 
$bidId ) {
            
/*    $this->log("index: $bidId");    */
            
$this->others($bidId);
            return;
        }
        
$this->input file_get_contents("php://input");
        
$forceCampaignId = @$_REQUEST['forceCampaignId'];
        if ( 
$forceCampaignId ) {
            
$this->parseRequest();
            
$this->forceCampaignId($forceCampaignId);
            return;
        }
        
$filters $this->filters();

        foreach ( 
$filters as $func ) {
            if ( ! 
$this->$func() ) {
                
$this->noBid();
                
$this->logTime("noBid"$startTime1);
                return;
            }
        }
        
$this->bid();
        
$this->logTime("bid"$startTime4);
    }
    
/*------------------------------*/
    
private function logTime($label$startTime$r) {
        if ( 
rand(1100 1000) > $r 1000 )
                return;
        
$endTime microtime(true);
        
$secondsElapsed $endTime $startTime;
        
$millisecondsElapsed round($secondsElapsed 10002);
        
$this->log("$label$r/100: $millisecondsElapsed milliseconds");
    }
    
/*------------------------------------------------------------*/
    
private function others($bidId) {
        
$this->bidId $bidId;
        
$this->bid $this->memUtils->bid($bidId);
        if ( ! 
$this->bid ) {
            
$this->error("others:$bidId: bid not found");
            return;
        }
        
$bidRequestId $this->bidRequestId $this->bid['id'];
        
$this->bidRequest $this->memUtils->bidRequest($bidRequestId);
        if ( 
$this->bidRequest ) {
            
$this->exchangeId = @$this->bidRequest['exchangeId'];
            
$this->placementId $this->bidderUtils->placementId($this->bidRequest);
        } else {
            
$this->error("others:$bidId:$bidRequestId: bid request not found");
            return;
        }

        
$pathInfo $_REQUEST['PATH_INFO'];
        if ( 
strstr($pathInfo"win") )
            
$this->win($bidId);
        elseif ( 
strstr($pathInfo"view") )
            
$this->view($bidId);
        elseif ( 
strstr($pathInfo"click") )
            
$this->click($bidId);
        elseif ( 
strstr($pathInfo"cpa") )
            
$this->cpa($bidId);
        else
            
$this->error("pathInfo=$pathInfo not understood"100);
    }
    
/*------------------------------------------------------------*/
    
private function campaignId($bidId) {
        
$bid $this->memUtils->bid($bidId);
        if ( ! 
$bid ) {
            
$this->error("campaignId: $bidId: cannot find bid $bidId in memcache");
            return(
null);
        }
        
$bid0 = @$bid['seatbid'][0]['bid'];
        if ( ! 
$bid0 ) {
            
$this->error("campaignId: $bidId: cannot find bid0 in bid");
            return(
null);
        }
        
$campaignId = @$bid0['cid'];
        if ( ! 
$campaignId ) {
            
$this->error("campaignId: $bidId: cannot find cid in bid0");
            return(
null);
        }
        return(
$campaignId);
    }
    
/*------------------------------------------------------------*/
    
private function win($bidId) {
        
$cost = @$_REQUEST['cost'];
        if ( ! 
$cost ) {
            
$this->error("win: no cost (bidId: $bidId)");
            return;
        }
        
$realCost $cost/1000;
        
$memCost $this->memUtils->memDouble2int($realCost);
        
$campaignId $this->campaignId($bidId);
        if ( ! 
$campaignId ) {
            
$this->error("win: $bidId: no campaignId");
            return;
        }
        
$campaignName $this->bidderUtils->campaignName($campaignId);
        
$this->log("win: $campaignName:$bidId$realCost"10);

        
$mkey $this->keyNames->bidderCounter("wins""thisMinute");
        
$this->Mmemcache->increment($mkey300);
        
$mkey $this->keyNames->bidderCounter("cost""thisMinute");
        
$this->Mmemcache->incrementBy($mkey$memCost300);

        
$mkey $this->keyNames->campaignCounter("wins""thisMinute"$campaignId);
        
$this->Mmemcache->increment($mkey300);
        
$mkey $this->keyNames->campaignCounter("cost""thisMinute"$campaignId);
        
$this->Mmemcache->incrementBy($mkey$memCost300);

        
$mkey $this->keyNames->placementCounter("wins""thisMinute"$this->placementId);
        
$this->Mmemcache->increment($mkey300);
        
$mkey $this->keyNames->placementCounter("cost""thisMinute"$this->placementId);
        
$this->Mmemcache->incrementBy($mkey$memCost300);

        
$mkey $this->keyNames->exchangeCounter("wins""thisMinute"$this->exchangeId);
        
$this->Mmemcache->increment($mkey300);
        
$mkey $this->keyNames->exchangeCounter("cost""thisMinute"$this->exchangeId);
        
$this->Mmemcache->incrementBy($mkey$memCost300);

        
$this->qPlacement();

        
$winQname $this->keyNames->winQname();
        
$datetime date("Y-m-d H:i:s");
        
$date substr($datetime010);
        
$hour = (int)substr($datetime112);
        
$minute = (int)substr($datetime142);
        
$row = array(
            
'date' => $date,
            
'hour' => $hour,
            
'minute' => $minute,
            
'datetime' => $datetime,
            
'exchangeId' => $this->exchangeId,
            
'campaignId' => $campaignId,
            
'bidRequestId' => $this->bidRequestId,
            
'bidId' => $this->bidId,
            
'placementId' => $this->placementId,
            
'cost' => $realCost,
        );
        
$json json_encode($row);
        
$this->log("win: $json"1);
        
$this->Mmemcache->msgQadd($winQname$row);
    }
    
/*------------------------------------------------------------*/
    
private function qPlacement() {
        
$placementIdsQname $this->keyNames->placementIdsQname();
        
$this->log("qPlacement: ".$this->placementId1);
        
$this->Mmemcache->msgQadd($placementIdsQname$this->placementId);
    }
    
/*------------------------------------------------------------*/
    // viewrate for placements identifies fraud placements
    
private function view($bidId) {
        
$campaignId $this->campaignId($bidId);
        if ( ! 
$campaignId ) {
            
$this->error("view:$bidId: no campaignId");
            return;
        }
        
$this->log("view: $bidId"1);
        
$mkey $this->keyNames->bidderCounter("views""thisMinute");
        
$this->Mmemcache->increment($mkey300);

        
$mkey $this->keyNames->campaignCounter("views""thisMinute"$campaignId);
        
$this->Mmemcache->increment($mkey300);

        
$mkey $this->keyNames->placementCounter("views""thisMinute"$this->placementId);
        
$this->Mmemcache->increment($mkey300);

        
$mkey $this->keyNames->exchangeCounter("views""thisMinute"$this->exchangeId);
        
$this->Mmemcache->increment($mkey300);

        
$this->qPlacement();

        
header("Content-type: image/gif");
        
$onePixelPath "../images/onePixel.gif";
        
readfile($onePixelPath);
    }
    
/*------------------------------------------------------------*/
    
private function click($bidId) {
        
$campaignId $this->campaignId($bidId);
        if ( ! 
$campaignId ) {
            
$this->error("click:$bidId: no campaignId");
            return;
        }
        
$campaign $this->bidderUtils->campaign($campaignId);;
        
$campaignName = @$campaign['name'];
        
$this->log("click:$campaignName:$bidId"10);

        
$mkey $this->keyNames->bidderCounter("clicks""thisMinute");
        
$this->Mmemcache->increment($mkey300);

        
$mkey $this->keyNames->campaignCounter("clicks""thisMinute"$campaignId);
        
$this->Mmemcache->increment($mkey300);

        
$mkey $this->keyNames->placementCounter("clicks""thisMinute"$this->placementId);
        
$this->Mmemcache->increment($mkey300);

        
$mkey $this->keyNames->exchangeCounter("clicks""thisMinute"$this->exchangeId);
        
$this->Mmemcache->increment($mkey300);

        
$this->qPlacement();

        
// Sun May 3 15:38:34 IDT 2020
        // todo
        // (CPC campaigns only): call $this->revenue() with campaign cpc

        
$url $campaign['landingPage'];
        
header("Location: $url");
    }
    
/*------------------------------------------------------------*/
    
private function cpa($bidId) {
        
$cpa = @$_REQUEST['cpa'];
        if ( ! 
$cpa ) {
            
$this->error("cpa:$bidId: no cpa in url)");
            return;
        }
        
$this->revenue($bidId$cpa);
    }
    
/*------------------------------*/
    
private function revenue($bidId$revenue) {
        
$campaignId $this->campaignId($bidId);
        if ( ! 
$campaignId ) {
            
$this->error("revenue:$bidId: no campaignId");
            return;
        }
        
$memRevenue $this->memUtils->memDouble2int($revenue);

        
$campaignName $this->bidderUtils->campaignName($campaignId);
        
$this->log("revenue:$campaignName:$bidId$revenue"5);

        
$mkey $this->keyNames->bidderCounter("revenue""thisMinute");
        
$this->Mmemcache->incrementBy($mkey$memRevenue300);

        
$mkey $this->keyNames->campaignCounter("revenue""thisMinute"$campaignId);
        
$this->Mmemcache->incrementBy($mkey$memRevenue300);

        
$mkey $this->keyNames->placementCounter("revenue""thisMinute"$this->placementId);
        
$this->Mmemcache->incrementBy($mkey$memRevenue300);
        
$this->log("revenue: incrementing $mkey by $memRevenue"9);

        
$mkey $this->keyNames->exchangeCounter("revenue""thisMinute"$this->exchangeId);
        
$this->Mmemcache->incrementBy($mkey$memRevenue300);

        
$this->qPlacement();

        
$revenueQname $this->keyNames->revenueQname();
        
$datetime date("Y-m-d H:i:s");
        
$date substr($datetime010);
        
$hour = (int)substr($datetime112);
        
$minute = (int)substr($datetime142);
        
$row = array(
            
'date' => $date,
            
'hour' => $hour,
            
'minute' => $minute,
            
'datetime' => $datetime,
            
'exchangeId' => $this->exchangeId,
            
'campaignId' => $campaignId,
            
'bidRequestId' => $this->bidRequestId,
            
'bidId' => $this->bidId,
            
'placementId' => $this->placementId,
            
'revenue' => $revenue,
        );
        
$json json_encode($row);
        
$this->log("revenue: $json"1);
        
$this->Mmemcache->msgQadd($revenueQname$row);
    }
    
/*------------------------------------------------------------*/
    
private function noBid() {
    
$this->log("noBid"0.1);
        
http_response_code(204);
    }
    
/*------------------------------------------------------------*/
    
private function filters() {
        
// countRequest keeps counts for placements and exchanges
        // even if the bidder is off or unthrottled.
        // so parseRequest comes first, then countRequest,
        // only then onOff & throttle
        // throttle needs countRequest
        // (is this ok for performance?)
        // otherwise, split count filters to just count the requests
        // and only after throttle parse the request, and count placement & exchange
        // loosing count from those when bidder is off/un-throttled
        
$filters = array(
            
'parseRequest',
            
'countRequest',
            
'onOff',
            
'throttle',
            
'bidderBlack',
            
'bidderPacer',
            
'match',
            
'campaignsPacer',
            
'setPrices',
            
'selectCampaign',
        );
        return(
$filters);
    }
    
/*------------------------------------------------------------*/
    
private function bidderBlack() {
        return( ! 
$this->campaignBlack(0$this->domain));
    }
    
/*------------------------------------------------------------*/
    
private function parseRequest() {
        
$this->bidRequest json_decode($this->inputtrue);
        
$this->bidRequest['exchangeVhost'] = $this->bidderUtils->exchangeVhost();
        
$this->exchangeId $this->bidRequest['exchangeId'] = $this->bidderUtils->exchangeId();

        
$this->bidRequestKind $this->bidderUtils->bidRequestKind($this->bidRequest);
        
$this->bidRequestName $this->bidderUtils->bidRequestName($this->bidRequest);
        
$site = @$this->bidRequest['site'];
        
$app = @$this->bidRequest['app'];
        
$domain $app ? @$app['domain'] : @$site['domain'];
        
$this->domain strtolower($domain);
        
$video = @$this->bidRequest['video'];
        
$banner = @$this->bidRequest['imp'][0]['banner'];

        
$this->bidRequestId = @$this->bidRequest['id'];
        if ( ! 
$this->bidRequestId ) {
            
$this->error("no id request"100);
            return(
false);
        }
        
$this->= @$banner['w'];
        
$this->= @$banner['h'];
        
$code3 = @$this->bidRequest['device']['geo']['country'];
        
$this->geo $this->bidderUtils->geo322($code3);
        
// this also filters out all requerst with no banner object, like video
        
if ( ! $this->|| ! $this->|| ! $this->geo ) {
            
$this->error("no w h or geo in request"100);
            
$printr print_r($this->bidRequesttrue);
            
$this->error($printr100);
            return(
false);
        }
        
$placementId $this->placementId $this->bidderUtils->placementId($this->bidRequest);
        
$this->log("parseRequest:placementId: $placementId"2);

        
$mkey $this->keyNames->lastRequestId();
        
$this->Mmemcache->set($mkey$this->bidRequestId300);
        
$mkey $this->keyNames->bidRequest($this->bidRequestId);
        
$this->Mmemcache->set($mkey$this->bidRequest300);

        return(
true);
    }
    
/*------------------------------------------------------------*/
    
private function countRequest() {
        
$mkey $this->keyNames->bidderCounter("bidRequests""thisMinute");
        
$this->Mmemcache->increment($mkey300);
        
$mkey $this->keyNames->placementCounter("bidRequests""thisMinute"$this->placementId);
        
$this->Mmemcache->increment($mkey300);
        
$mkey $this->keyNames->exchangeCounter("bidRequests""thisMinute"$this->exchangeId);
        
$this->Mmemcache->increment($mkey300);
        
$this->log("countRequest"0.4);
        return(
true);
    }
    
/*------------------------------------------------------------*/
    
private function onOff() {
        
$this->controlPanel $this->bidderUtils->controlPanel();
        
$this->log("onOff"0.2);
        return(@
$this->controlPanel['onOff']);
    }
    
/*------------------------------------------------------------*/
    // todo: maxQps should be better controlled
    
private function throttle() {
        
$maxQps 5;
        
$mkey $this->keyNames->bidderCounter("bidRequests""thisMinute");
        
$cnt $this->Mmemcache->rawGet($mkey);
        
$elapsed date("s");
        if ( 
$elapsed == ) {
            
// first second of the minute
            
return($cnt $maxQps);
        }
        
$qps $cnt $elapsed ;
        
$isOK $qps $maxQps;
        if ( ! 
$isOK )
            
$this->log("throttle: tossing traffic over $maxQps QPS"3);
        return(
$isOK);
    }
    
/*------------------------------------------------------------*/
    
private function bidderHourPacer($hourlyBudget) {
        
$secondsSoFar time() % 3600 ;
        if ( ! 
$secondsSoFar ) {
            
$this->log("bidderHourPacer: 1st second of the hour");
            return(
true);
        }
        
$mkey $this->keyNames->bidderCounter("cost""thisHour");
        
$spentSoFar $this->Mmemcache->rawGet($mkey);
        if ( ! 
$spentSoFar ) {
            
$this->log("bidderHourPacer: nothing yet spent thisHour"10);
            return(
true);
        }
        
        
$hourPart $secondsSoFar 3600 ;
        
$budgetSoFar $hourlyBudget $hourPart;
        
$ok $spentSoFar $budgetSoFar;
        
$this->log("bidderHourPacer: $spentSoFar/$budgetSoFar"1);
        return(
$ok);
    }
    
/*------------------------------*/
    
private function bidderPacer() {
        
$dailyBudget $this->bidderUtils->dailyBudget();
        
$secondsSoFar time() % 86400 ;
        if ( ! 
$secondsSoFar ) {
            
$this->log("bidderPacer: 1st second of the day");
            return(
true);
        }
        
$mkey $this->keyNames->bidderCounter("cost""today");
        
$spentSoFar $this->Mmemcache->rawGet($mkey);
        if ( ! 
$spentSoFar ) {
            
$this->log("bidderPacer: nothing yet spent today");
            return(
true);
        }
        
        
$dayPart $secondsSoFar 86400 ;
        
$budgetSoFar $dailyBudget $dayPart;
        
$ok $spentSoFar $budgetSoFar;
        
$this->log("bidderPacer: $spentSoFar/$budgetSoFar"1);
        if ( ! 
$ok )
            return(
false);
        
$hourPacerOK $this->bidderHourPacer($dailyBudget/24);
        return(
$hourPacerOK);
    }
    
/*------------------------------------------------------------*/
    
private function match() {
        
$campaigns $this->bidderUtils->onCampaigns();
        if ( ! 
$campaigns ) {
            
$this->log("No active campaigns"100);
            return(
false);
        }
        foreach ( 
$campaigns as $campaign )
            if ( 
$this->campaignMatches($campaign) )
                
$this->campaigns[] = $campaign;
        
$this->log("match"0.1);
        if ( 
$this->campaigns )
            return(
true);
        else
            return(
false);
    }
    
/*------------------------------------------------------------*/
    // campaignBlack() is true if its blacklisted for $domain
    // campaignWhite() is true if the $domain is ok for this campaign
    /*------------------------------*/
    
private function campaignWhite($campaignId$domain) {
        
$whiteListsDomains $this->bidderUtils->whiteListsDomains($campaignId);
        if ( ! 
$whiteListsDomains )
            return(
true);
        if ( 
in_array($this->domain$whiteListsDomains) ) {
            return(
true);
        }
        
$this->log("campaignWhite: $campaignId$domain"100);
        return(
false);
    }
    
/*------------------------------*/
    
private function campaignBlack($campaignId$domain) {
        
$blackListsDomains $this->bidderUtils->blackListsDomains($campaignId);
        if ( ! 
$blackListsDomains )
            return(
false);
        if ( 
in_array($this->domain$blackListsDomains) ) {
            
$this->log("campaignBlack: $campaignId$domain"100);
            return(
true);
        }
        return(
false);
    }
    
/*------------------------------------------------------------*/
    
private function campaignMatches($campaign) {
        
$kind $this->bidRequestKind;
        
$w $this->w;
        
$h $this->h;
        
$geo $this->geo;
        
$cw $campaign['w'];
        
$ch $campaign['h'];
        
$cgeo $campaign['geo'];
        
$ckind $campaign['kind'];

        
$basics $kind == $ckind && $w == $cw && $h == $ch && $geo == $cgeo ;
        if ( ! 
$basics )
            return(
false);

        if ( 
$campaign['hours'] ) {
            
$campaignHours $campaign['hours'];
            
$thisHour date("G");
            if ( ! 
strstr(",$campaignHours,"",$thisHour,") )
                return(
false);
        }
        
// Sat Aug  1 17:08:29 IDT 2020
        // todo?
        // there are no fields appName & siteName at this time
        /*    if ( @$campaign['appName'] || @$campaign['siteName'] ) {    */
            /*    $name = $this->bidRequestName ;    */
            /*    $ok = $name &&    */
                /*    ( $name == @$campaign['appName']    */
                    /*    || $name == @$campaign['siteName'] );    */
            /*    if ( ! $ok )    */
                /*    return(false);    */
        /*    }    */
        // there are no fields appName & siteName at this time


        
if ( $this->campaignBlack($campaign['id'], $this->domain) )
            return(
false);
        if ( ! 
$this->campaignWhite($campaign['id'], $this->domain) )
            return(
false);
        return(
true);
    }
    
/*------------------------------------------------------------*/
    
private function campaignHourPacer($campaign$hourlyBudget) {
        
$campaignId $campaign['id'];
        
$secondsSoFar time() % 3600 ;
        if ( ! 
$secondsSoFar ) {
            
$this->log("campaignHourPacer:$campaignId: 1st second of the hour");
            return(
true);
        }
        
$mkey $this->keyNames->campaignCounter("cost""thisHour"$campaignId);
        
$spentSoFar $this->Mmemcache->rawGet($mkey);
        if ( ! 
$spentSoFar ) {
            
$this->log("campaignHourPacer:$campaignId: nothing yet spent thisHour"10);
            return(
true);
        }
        
        
$hourPart $secondsSoFar 3600 ;
        
$budgetSoFar $hourlyBudget $hourPart;
        
$ok $spentSoFar $budgetSoFar;
        
$this->log("campaignHourPacer:$campaignId$spentSoFar/$budgetSoFar"4);
        return(
$ok);
    }
    
/*------------------------------*/
    
private function campaignPacer($campaign) {
        
$dailyBudget $campaign['dailyBudget'];
        
$campaignId $campaign['id'];

        
$secondsSoFar time() % 86400 ;
        if ( ! 
$secondsSoFar ) {
            
$this->log("campaignPacer:$campaignId: 1st second of the day");
            return(
true);
        }
        
$mkey $this->keyNames->campaignCounter("cost""today"$campaignId);
        
$spentSoFar $this->Mmemcache->rawGet($mkey);
        if ( ! 
$spentSoFar ) {
            
$this->log("campaignPacer:$campaignId: nothing yet spent today");
            return(
true);
        }
        
        
$dayPart $secondsSoFar 86400 ;
        
$budgetSoFar $dailyBudget $dayPart;
        
$ok $spentSoFar $budgetSoFar;
        
$this->log("campaignPacer:$campaignId$spentSoFar/$budgetSoFar"4);
        if ( ! 
$ok )
            return(
false);
        
$hourPacerOK $this->campaignHourPacer($campaign$dailyBudget/24);
        return(
$hourPacerOK);
    }
    
/*------------------------------*/
    
private function campaignsPacer() {
        
$this->log("campaignsPacer"0.5);
        foreach ( 
$this->campaigns as $campaign ) {
            if ( 
$this->campaignPacer($campaign) )
                
$this->pacedCampaigns[] = $campaign;
        }
        if ( 
$this->pacedCampaigns )
            return(
true);
        else
            return(
false);
    }
    
/*------------------------------------------------------------*/
    
private function selectCampaign() {
        
$price 0;
        
$selected = array();
        foreach ( 
$this->pacedCampaigns as $key => $campaign ) {
            
$bidPrice $campaign['bidPrice'];
            if ( 
$bidPrice $price ) {
                
$selected = array($campaign,);
                
$price $bidPrice;
            } elseif ( 
$price == $bidPrice )
                
$selected[] = $campaign;
        }
        
$cnt count($selected);
        if ( ! 
$cnt ) {
            
$this->log("selectCampaign: none selected"100);
            return(
false);
        }
        if ( 
$cnt == ) {
            
$this->campaign $campaign;
        } else {
            
$this->campaign $selected[rand(0$cnt-1)];
        }
        
$campaignName $this->campaign['name'];
        
$this->log("selectCampaign: $campaignName"10);
        return(
true);
    }
    
/*------------------------------------------------------------*/
    
private function setPrices() {
        
$placementId $this->placementId;
        
$placementPpm $this->memUtils->placementPPM($placementId);
        foreach ( 
$this->pacedCampaigns as $key => $campaign ) {
            if ( 
$placementPpm === null ) {
                
$this->pacedCampaigns[$key]['bidPrice'] = $campaign['baseBid'];
            } else {
                if ( 
$placementPpm )
                    return(
false); // this placemnt is bad, deny it altogether.
                
$maxBid $campaign['maxBid'];
                
$desiredProfitMargin $campaign['desiredProfitMargin'];
                
$plBidPrice $placementPpm / ( $desiredProfitMargin 100 ) ;
                
$bidPrice $plBidPrice $maxBid $maxBid $plBidPrice ;
                
$this->pacedCampaigns[$key]['bidPrice'] = $bidPrice;
                
$this->log("setPrices: setting $bidPrice for $placementId"10);
            }
        }
        return(
true);
    }
    
/*------------------------------------------------------------*/
    
private function forceCampaignId($campaignId) {
        
$this->bidRequestId = @$this->bidRequest['id'];
        
$this->campaign $this->bidderUtils->campaign($campaignId);
        
$this->bid();
    }
    
/*------------------------------------------------------------*/
    /*------------------------------------------------------------*/
    
private function bid() {
        
$this->bidId $bidId $this->newBidId();
        
// Thu Jul 30 22:10:54 IDT 2020
        // too late if adm returns with an error!
        
$adm $this->adm();
        
$winServer WIN_SERVER;
        
$nurl "http://$winServer/win?bidId=$bidId&cost=".'${AUCTION_PRICE}';
        
$bannerUrl $this->bannerUrl();
        
$iurl $bannerUrl;
        
$price $this->campaign['bidPrice'];
        
$cid $this->campaign['id'];
        
$bid = array(
            
'id' => $this->bidRequestId,
            
'bidid' => $bidId,
            
'seatbid' => array(
                array(
                    
'seat' => "theora.com",
                    
'bid' => array(
                        
'id' => $bidId,
                        
'adid' => 1,
                        
'price' => $price,
                        
'nurl' => $nurl,
                        
'adm' => $adm,
                        
'adomain' => array('theora.com',),
                        
'cat' => array("IAB1",),
                        
'attr' => array(6,),
                        
'impid' => 1,
                        
'iurl' => $iurl,
                        
'cid' => $cid,
                        
// Sun Aug  2 04:15:17 IDT 2020
                        // with forceCampaignId, this->w,h are not set
                        
'w' => $this->campaign['w'],
                        
'h' => $this->campaign['h'],
                    ),
                ),
            ),
        );

        
$mkey $this->keyNames->bidderCounter("bids""thisMinute");
        
$this->Mmemcache->increment($mkey300);

        
$mkey $this->keyNames->campaignCounter("bids""thisMinute"$cid);
        
$this->Mmemcache->increment($mkey300);

        
$mkey $this->keyNames->placementCounter("bids""thisMinute"$this->placementId);
        
$this->Mmemcache->increment($mkey300);

        
$mkey $this->keyNames->exchangeCounter("bids""thisMinute"$this->exchangeId);
        
$this->Mmemcache->increment($mkey300);

        
$json json_encode($bid);
        
$bid['campaign'] = $this->campaign;
        
$mkey $this->keyNames->bid($bidId);
        
$this->Mmemcache->set($mkey$bid300);
        
$mkey $this->keyNames->lastBidId();
        
$this->Mmemcache->set($mkey$bidId300);
        
$mkey $this->keyNames->lastCampaignBidId($cid);
        
$this->Mmemcache->set($mkey$bidId300);
        
$bidRequestId $this->bidRequestId;
        
$campaignName $this->campaign['name'];
        
$this->log("Bidding: $bidRequestId --> $bidId - $price - $campaignName"1);
        echo 
$json;
    }
    
/*------------------------------------------------------------*/
    
private function bannerUrl() {
        
$bannerServer BANNER_SERVER;
        
$banner $this->campaign['banner'];
        
$bannerUrl "http://$bannerServer/banners/$banner";
        return(
$bannerUrl);
    }
    
/*------------------------------------------------------------*/
    
private function adm() {
        
$bidId $this->bidId;
        
$viewServer VIEW_SERVER;
        
$viewUrl "http://$viewServer/view?bidId=$bidId";
        
$viewPixel "<img width=\"1\" height=\"1\" src=\"$viewUrl\" style=\"display:none;\" />";
        
$clickServer CLICK_SERVER;
        
$clickUrl "http://$clickServer/click?bidId=$bidId";

        if ( 
$this->campaign['adm'] ) {
            
$inner $this->campaign['adm'];
            
$inner str_replace("{$CLICK_URL}"$clickUrl$inner);
        } elseif ( 
$this->campaign['banner'] ) {
            
$bannerServer BANNER_SERVER;
            
$bannerUrl $this->bannerUrl();
            
$inner "<a href=\"$clickUrl\"><img src=\"$bannerUrl\" /></a>";
        } else {
            
$campaignId $this->campaign['id'];
            
$campaignName $this->campaign['name'];
            
$this->error("No banner nor adm in campaign:  $campaignId:$campaignName");
            return(
null);
        }
        
$adm "$viewPixel$inner";
        return(
$adm);
    }
    
/*------------------------------------------------------------*/
    
private function newBidId() {
        
$microtime microtime(true);
        
$rand rand(10009999);
        
$bidId sprintf("%.6lf-$rand"$microtime);
        return(
$bidId);
    }
    
/*------------------------------------------------------------*/
    /*------------------------------------------------------------*/
    
private function error($msg$r 100) {
        
$this->log("ERROR: $msg"$r);
        
error_log($msg);
    }
    
/*------------------------------------------------------------*/
    
private function log($msg$r 100) {
        if ( 
rand(1100 1000) > $r 1000 )
                return;
        if ( 
$r == 100 )
                
$str $msg;
        else
                
$str "$r/100: $msg";
        
$this->logger->log($str);
    }
    
/*------------------------------------------------------------*/
}
Running Time: 17.245 milliseconds


© Ohad Aloni 2020