/** * A method to activate/deactivate campaigns, based on the date and/or the inventory * requirements (impressions, clicks and/or conversions). Also sends email reports * for any campaigns that are activated/deactivated, as well as sending email reports * for any campaigns that are likely to expire in the near future. * * @param Date $oDate The current date/time. * @return string Report on the campaigns activated/deactivated. */ function manageCampaigns($oDate) { $aConf = $GLOBALS['_MAX']['CONF']; $oServiceLocator =& OA_ServiceLocator::instance(); $oEmail =& $oServiceLocator->get('OA_Email'); if ($oEmail === false) { $oEmail = new OA_Email(); $oServiceLocator->register('OA_Email', $oEmail); } $report = "\n"; // Select all campaigns in the system, where: // The campaign is ACTIVE and: // - The end date stored for the campaign is not null; or // - The campaign has a lifetime impression, click or conversion // target set. // // That is: // - It is possible for the active campaign to be automatically // stopped, as it has a valid end date. (No limitations are // applied to those campaigns tested, as the ME may not have // run for a while, and if so, even campaigns with an end date // of many, many weeks ago should be tested to ensure they are // [belatedly] halted.) // - It is possible for the active campaign to be automatically // stopped, as it has at leaast one lifetime target that could // have been reached. // // The campaign is INACTIVE and: // - The start date stored for the campaign is not null; and // - The weight is greater than zero; and // - The end date stored for the campaign is either null, or is // greater than "today" less one day. // // That is: // - It is possible for the inactive campaign to be automatically // started, as it has a valid start date. (No limitations are // applied to those campaigns tested, as the ME may not have run // for a while, and if so, even campaigns with an activation date // of many, many weeks ago should be tested to ensure they are // [belatedy] enabled.) // - The campaign is not in a permanently inactive state, as a // result of the weight being less then one, which means that // it cannot be activated. // - The test to start the campaign is unlikely to fail on account // of the end date. $prefix = $this->getTablePrefix(); $oNowDate = new Date($oDate); $oNowDate->toUTC(); $query = "\n SELECT\n cl.clientid AS advertiser_id,\n cl.account_id AS advertiser_account_id,\n cl.agencyid AS agency_id,\n cl.contact AS contact,\n cl.email AS email,\n cl.reportdeactivate AS send_activate_deactivate_email,\n ca.campaignid AS campaign_id,\n ca.campaignname AS campaign_name,\n ca.views AS targetimpressions,\n ca.clicks AS targetclicks,\n ca.conversions AS targetconversions,\n ca.status AS status,\n ca.activate_time AS start,\n ca.expire_time AS end\n FROM\n {$prefix}campaigns AS ca,\n {$prefix}clients AS cl\n WHERE\n ca.clientid = cl.clientid\n AND\n ((\n ca.status = " . $this->oDbh->quote(OA_ENTITY_STATUS_RUNNING, 'integer') . " AND\n (\n ca.expire_time IS NOT NULL\n OR\n (\n ca.views > 0\n OR\n ca.clicks > 0\n OR\n ca.conversions > 0\n )\n )\n ) OR (\n ca.status = " . $this->oDbh->quote(OA_ENTITY_STATUS_AWAITING, 'integer') . " AND\n (\n ca.activate_time <= " . $this->oDbh->quote($oNowDate->getDate(DATE_FORMAT_ISO), 'timestamp') . "\n AND\n (\n ca.weight > 0\n OR\n ca.priority > 0\n )\n AND\n (\n ca.expire_time >= " . $this->oDbh->quote($oNowDate->getDate(DATE_FORMAT_ISO), 'timestamp') . "\n OR\n ca.expire_time IS NULL\n )\n )\n ))\n ORDER BY\n advertiser_id"; OA::debug('- Requesting campaigns to test for activation/deactivation', PEAR_LOG_DEBUG); $rsResult = $this->oDbh->query($query); if (PEAR::isError($rsResult)) { return MAX::raiseError($rsResult, MAX_ERROR_DBFAILURE, PEAR_ERROR_DIE); } OA::debug('- Found ' . $rsResult->numRows() . ' campaigns to test for activation/deactivation', PEAR_LOG_DEBUG); while ($aCampaign = $rsResult->fetchRow()) { if ($aCampaign['status'] == OA_ENTITY_STATUS_RUNNING) { // The campaign is currently running, look at the campaign $disableReason = 0; $canExpireSoon = false; if ($aCampaign['targetimpressions'] > 0 || $aCampaign['targetclicks'] > 0 || $aCampaign['targetconversions'] > 0) { OA::debug(' - Selecting impressions, clicks and conversions for this running campaign ID = ' . $aCampaign['campaign_id'], PEAR_LOG_DEBUG); // The campaign has an impression, click and/or conversion target, // so get the sum total statistics for the campaign $query = "\n SELECT\n SUM(dia.impressions) AS impressions,\n SUM(dia.clicks) AS clicks,\n SUM(dia.conversions) AS conversions\n FROM\n " . $this->oDbh->quoteIdentifier($aConf['table']['prefix'] . $aConf['table']['data_intermediate_ad'], true) . " AS dia,\n " . $this->oDbh->quoteIdentifier($aConf['table']['prefix'] . $aConf['table']['banners'], true) . " AS b\n WHERE\n dia.ad_id = b.bannerid\n AND b.campaignid = {$aCampaign['campaign_id']}"; $rsResultInner = $this->oDbh->query($query); $valuesRow = $rsResultInner->fetchRow(); if (isset($valuesRow['impressions']) || !is_null($valuesRow['clicks']) || !is_null($valuesRow['conversions'])) { // There were impressions, clicks and/or conversions for this // campaign, so find out if campaign targets have been passed if (!isset($valuesRow['impressions'])) { // No impressions $valuesRow['impressions'] = 0; } if (!isset($valuesRow['clicks'])) { // No clicks $valuesRow['clicks'] = 0; } if (!isset($valuesRow['conversions'])) { // No conversions $valuesRow['conversions'] = 0; } if ($aCampaign['targetimpressions'] > 0) { if ($aCampaign['targetimpressions'] <= $valuesRow['impressions']) { // The campaign has an impressions target, and this has been // passed, so update and disable the campaign $disableReason |= OX_CAMPAIGN_DISABLED_IMPRESSIONS; } } if ($aCampaign['targetclicks'] > 0) { if ($aCampaign['targetclicks'] <= $valuesRow['clicks']) { // The campaign has a click target, and this has been // passed, so update and disable the campaign $disableReason |= OX_CAMPAIGN_DISABLED_CLICKS; } } if ($aCampaign['targetconversions'] > 0) { if ($aCampaign['targetconversions'] <= $valuesRow['conversions']) { // The campaign has a target limitation, and this has been // passed, so update and disable the campaign $disableReason |= OX_CAMPAIGN_DISABLED_CONVERSIONS; } } if ($disableReason) { // One of the campaign targets was exceeded, so disable $message = ' - Exceeded a campaign quota: Deactivating campaign ID ' . "{$aCampaign['campaign_id']}: {$aCampaign['campaign_name']}"; OA::debug($message, PEAR_LOG_INFO); $report .= $message . "\n"; $doCampaigns = OA_Dal::factoryDO('campaigns'); $doCampaigns->campaignid = $aCampaign['campaign_id']; $doCampaigns->find(); $doCampaigns->fetch(); $doCampaigns->status = OA_ENTITY_STATUS_EXPIRED; $result = $doCampaigns->update(); if ($result == false) { return MAX::raiseError($rows, MAX_ERROR_DBFAILURE, PEAR_ERROR_DIE); } phpAds_userlogSetUser(phpAds_userMaintenance); phpAds_userlogAdd(phpAds_actionDeactiveCampaign, $aCampaign['campaign_id']); } else { // The campaign didn't have a diable reason, // it *might* possibly be diabled "soon"... $canExpireSoon = true; } } } // Does the campaign need to be disabled due to the date? if (!empty($aCampaign['end'])) { // The campaign has a valid end date, stored in in UTC $oEndDate = new Date($aCampaign['end']); $oEndDate->setTZByID('UTC'); if ($oDate->after($oEndDate)) { // The end date has been passed; disable the campaign $disableReason |= OX_CAMPAIGN_DISABLED_DATE; $message = " - Passed campaign end time of '" . $oEndDate->getDate() . " UTC" . "': Deactivating campaign ID {$aCampaign['campaign_id']}: {$aCampaign['campaign_name']}"; OA::debug($message, PEAR_LOG_INFO); $report .= $message . "\n"; $doCampaigns = OA_Dal::factoryDO('campaigns'); $doCampaigns->campaignid = $aCampaign['campaign_id']; $doCampaigns->find(); $doCampaigns->fetch(); $doCampaigns->status = OA_ENTITY_STATUS_EXPIRED; $result = $doCampaigns->update(); if ($result == false) { return MAX::raiseError($rows, MAX_ERROR_DBFAILURE, PEAR_ERROR_DIE); } phpAds_userlogSetUser(phpAds_userMaintenance); phpAds_userlogAdd(phpAds_actionDeactiveCampaign, $aCampaign['campaign_id']); } else { // The campaign wasn't disabled based on the end // date, to it *might* possibly be disabled "soon"... $canExpireSoon = true; } } if ($disableReason) { // The campaign was disabled, so send the appropriate // message to the campaign's contact $query = "\n SELECT\n bannerid AS advertisement_id,\n description AS description,\n alt AS alt,\n url AS url\n FROM\n " . $this->oDbh->quoteIdentifier($aConf['table']['prefix'] . $aConf['table']['banners'], true) . "\n WHERE\n campaignid = {$aCampaign['campaign_id']}"; OA::debug(" - Getting the advertisements for campaign ID {$aCampaign['campaign_id']}", PEAR_LOG_DEBUG); $rsResultAdvertisement = $this->oDbh->query($query); if (PEAR::isError($rsResultAdvertisement)) { return MAX::raiseError($rsResultAdvertisement, MAX_ERROR_DBFAILURE, PEAR_ERROR_DIE); } while ($advertisementRow = $rsResultAdvertisement->fetchRow()) { $advertisements[$advertisementRow['advertisement_id']] = array($advertisementRow['description'], $advertisementRow['alt'], $advertisementRow['url']); } if ($aCampaign['send_activate_deactivate_email'] == 't') { OA::debug(" - Sending campaign deactivated email ", PEAR_LOG_DEBUG); $oEmail->sendCampaignActivatedDeactivatedEmail($aCampaign['campaign_id'], $disableReason); // Also send campaignDeliveryEmail for the campaign we just deactivated. $doClients = OA_Dal::staticGetDO('clients', $aCampaign['advertiser_id']); $aAdvertiser = $doClients->toArray(); OA::debug(" - Sending campaign delivery email ", PEAR_LOG_DEBUG); $oStart = new Date($aAdvertiser['reportlastdate']); $oEnd = new Date($oDate); // Set end date to tomorrow so we get stats for today. $oEnd->addSpan(new Date_Span('1-0-0-0')); $oEmail->sendCampaignDeliveryEmail($aAdvertiser, $oStart, $oEnd, $aCampaign['campaign_id']); } } else { if ($canExpireSoon) { // The campaign has NOT been deactivated - test to see if it will // be deactivated "soon", and send email(s) warning of this as required OA::debug(" - Sending campaign 'soon deactivated' email ", PEAR_LOG_DEBUG); $oEmail->sendCampaignImpendingExpiryEmail($oDate, $aCampaign['campaign_id']); } } } elseif (!empty($aCampaign['start'])) { // The campaign is awaiting activation and has a valid start date, stored in UTC $oStartDate = new Date($aCampaign['start']); $oStartDate->setTZByID('UTC'); // Find out if there are any impression, click or conversion targets for // the campaign (i.e. if the target values are > 0) $remainingImpressions = 0; $remainingClicks = 0; $remainingConversions = 0; if ($aCampaign['targetimpressions'] > 0 || $aCampaign['targetclicks'] > 0 || $aCampaign['targetconversions'] > 0) { OA::debug(" - The campaign ID " . $aCampaign['campaign_id'] . " has an impression, click and/or conversion target, requesting impressions so far", PEAR_LOG_DEBUG); $query = "\n SELECT\n SUM(dia.impressions) AS impressions,\n SUM(dia.clicks) AS clicks,\n SUM(dia.conversions) AS conversions\n FROM\n " . $this->oDbh->quoteIdentifier($aConf['table']['prefix'] . $aConf['table']['data_intermediate_ad'], true) . " AS dia,\n " . $this->oDbh->quoteIdentifier($aConf['table']['prefix'] . $aConf['table']['banners'], true) . " AS b\n WHERE\n dia.ad_id = b.bannerid\n AND b.campaignid = {$aCampaign['campaign_id']}"; $rsResultInner = $this->oDbh->query($query); $valuesRow = $rsResultInner->fetchRow(); // Set the remaining impressions, clicks and conversions for the campaign $remainingImpressions = $aCampaign['targetimpressions'] - $valuesRow['impressions']; $remainingClicks = $aCampaign['targetclicks'] - $valuesRow['clicks']; $remainingConversions = $aCampaign['targetconversions'] - $valuesRow['conversions']; } // In order for the campaign to be activated, need to test: // 1) That there is no impression target (<= 0), or, if there is an impression target (> 0), // then there must be remaining impressions to deliver (> 0); and // 2) That there is no click target (<= 0), or, if there is a click target (> 0), // then there must be remaining clicks to deliver (> 0); and // 3) That there is no conversion target (<= 0), or, if there is a conversion target (> 0), // then there must be remaining conversions to deliver (> 0) if (($aCampaign['targetimpressions'] <= 0 || $aCampaign['targetimpressions'] > 0 && $remainingImpressions > 0) && ($aCampaign['targetclicks'] <= 0 || $aCampaign['targetclicks'] > 0 && $remainingClicks > 0) && ($aCampaign['targetconversions'] <= 0 || $aCampaign['targetconversions'] > 0 && $remainingConversions > 0)) { $message = "- Passed campaign start time of '" . $oStartDate->getDate() . " UTC" . "': Activating campaign ID {$aCampaign['campaign_id']}: {$aCampaign['campaign_name']}"; OA::debug($message, PEAR_LOG_INFO); $report .= $message . "\n"; $doCampaigns = OA_Dal::factoryDO('campaigns'); $doCampaigns->campaignid = $aCampaign['campaign_id']; $doCampaigns->find(); $doCampaigns->fetch(); $doCampaigns->status = OA_ENTITY_STATUS_RUNNING; $result = $doCampaigns->update(); if ($result == false) { return MAX::raiseError($rows, MAX_ERROR_DBFAILURE, PEAR_ERROR_DIE); } phpAds_userlogSetUser(phpAds_userMaintenance); phpAds_userlogAdd(phpAds_actionActiveCampaign, $aCampaign['campaign_id']); if ($aCampaign['send_activate_deactivate_email'] == 't') { OA::debug(" - Sending activation email for campaign ID " . $aCampaign['campaign_id'], PEAR_LOG_DEBUG); $oEmail->sendCampaignActivatedDeactivatedEmail($aCampaign['campaign_id']); } } } } }
function calc_timezone($newdate) { global $pref; if (!$pref['datetime'] || !$this->TimeZone) { $newdate = preg_replace('/UT$/', 'UTC', $newdate); $newdate = date("D, j M Y G:i O", strtotime($newdate)); return $newdate; } require_once 'Date.php'; // convert to ISO 8601 format if (preg_match('/(\\d+) ([a-z]+) (\\d\\d\\d?\\d?) (\\d\\d:\\d\\d:\\d\\d) ((\\+|-)\\d\\d\\d\\d|[a-z]+)/i', $newdate, $m)) { if (strlen($m[1]) == 1) { $m[1] = "0{$m['1']}"; } // If a 2 digit date is given then we need to make an assumption // about the actual year. If year >= 80 we can safely assume that // it's a 20th Century date e.g. 89 becomes 1989. Otherwise lets make it // a 21st Century date, e.g. 08 becomes 2008 if (strlen($m[3]) == 2) { $m[3] = $m[3] >= 80 ? "19{$m['3']}" : "20{$m['3']}"; } // format month name with uppercase firt char e.g Sep $m[2] = ucfirst(strtolower($m[2])); // Convert Timezone ID to GMT offset if (!is_numeric($m[5])) { // convert UT > UTC if ($m[5] == 'UT') { $m[5] = 'UTC'; } $dt = new Date_TimeZone($m[5]); $m[5] = $dt->getRawOffset(); if ($m[5] == 0) { $m[5] = 'Z'; } else { $m[5] = $m[5] / 36000; settype($m[5], 'string'); $m[5] = preg_replace('/(-|\\+)/', '${1}0', $m[5]); } } $newdate = "{$m['3']}{$this->months[$m[2]]}{$m['1']}T{$m['4']}{$m['5']}"; // Do timezone conversion $date = new Date($newdate); $date->convertTZbyID($this->TimeZone); $newdate = $date->getDate(); $newdate = date("D, j M Y G:i O", strtotime($newdate)); } elseif (preg_match('/(\\d+) ([a-z]+) (\\d\\d\\d\\d) (\\d\\d:\\d\\d:\\d\\d) (\\w+)/i', $newdate, $m)) { if (strlen($m[1]) == 1) { $m[1] = "0{$m['1']}"; } // If a 2 digit date is given then we need to make an assumption // about the actual year. If year >= 80 we can safely assume that // it's a 20th Century date e.g. 89 becomes 1989. Otherwise lets make it // a 21st Century date, e.g. 08 becomes 2008 if (strlen($m[3]) == 2) { $m[3] = $m[3] >= 80 ? "19{$m['3']}" : "20{$m['3']}"; } // format month name with uppercase firt char e.g Sep $m[2] = ucfirst(strtolower($m[2])); $newdate = "{$m['3']}{$this->months[$m[2]]}{$m['1']}"; // Convert date from timezone ID, rather than +0900 or -1100 format, format in GMT, MST, etc $date = new Date($newdate); $date->setTZByID($m[5]); $newdate = $date->getDate(); $newdate = date("D, j M Y G:i O", strtotime($newdate)); } else { $newdate = date("D, j M Y G:i O", strtotime($newdate)); } return $newdate; }
function _convertDate($date, $tz, $end) { if (empty($date) || $date == '0000-00-00') { return null; } $oDate = new Date($date); $oDate->setTZByID($tz); if ($end) { $oDate->setHour(23); $oDate->setMinute(59); $oDate->setSecond(59); } $oDate->toUTC(); return $oDate->getDate(DATE_FORMAT_ISO); }
function convertTimeZone($date, $localTimeZone, $convertToTimeZone) { global $timezones; $date = date("Y-m-d H:i:s", strtotime($date)); $dateArray = array("year" => '', "mon" => '', "mday" => '', "hours" => '', "minutes" => '', "seconds" => '', "timezone" => '', "month" => '', "weekday" => '', "shortMon" => ''); if ($localTimeZone == $convertToTimeZone) { $dateArray = getDate(strtotime($date)); $dateArray['timezone'] = date("T", strtotime($date)); $dateArray['shortMon'] = date("M", strtotime($date)); if ($dateArray['mon'] < 10) { $dateArray['mon'] = "0" . $dateArray['mon']; } if ($dateArray['mday'] < 10) { $dateArray['mday'] = "0" . $dateArray['mday']; } if ($dateArray['hours'] < 10) { $dateArray['hours'] = "0" . $dateArray['hours']; } if ($dateArray['minutes'] < 10) { $dateArray['minutes'] = "0" . $dateArray['minutes']; } if ($dateArray['seconds'] < 10) { $dateArray['seconds'] = "0" . $dateArray['seconds']; } return $dateArray; } if (!array_key_exists($convertToTimeZone, $timezones)) { $dateArray = getDate(strtotime($date)); $dateArray['timezone'] = date("T", strtotime($date)); $dateArray['shortMon'] = date("M", strtotime($date)); if ($dateArray['mon'] < 10) { $dateArray['mon'] = "0" . $dateArray['mon']; } if ($dateArray['mday'] < 10) { $dateArray['mday'] = "0" . $dateArray['mday']; } if ($dateArray['hours'] < 10) { $dateArray['hours'] = "0" . $dateArray['hours']; } if ($dateArray['minutes'] < 10) { $dateArray['minutes'] = "0" . $dateArray['minutes']; } if ($dateArray['seconds'] < 10) { $dateArray['seconds'] = "0" . $dateArray['seconds']; } return $dateArray; } $tmpDate = new Date($date); $tmpDate->setTZByID($localTimeZone); $tmpDate->convertTZByID($convertToTimeZone); $date = $tmpDate->format("%Y-%m-%d %H:%M:%S"); $timezone = $tmpDate->format("%Z"); $shortMon = $tmpDate->format("%b"); $dateArray = getDate(strtotime($date)); $dateArray['timezone'] = $timezone; $dateArray['shortMon'] = $shortMon; if ($dateArray['mon'] < 10) { $dateArray['mon'] = "0" . $dateArray['mon']; } if ($dateArray['mday'] < 10) { $dateArray['mday'] = "0" . $dateArray['mday']; } if ($dateArray['hours'] < 10) { $dateArray['hours'] = "0" . $dateArray['hours']; } if ($dateArray['minutes'] < 10) { $dateArray['minutes'] = "0" . $dateArray['minutes']; } if ($dateArray['seconds'] < 10) { $dateArray['seconds'] = "0" . $dateArray['seconds']; } return $dateArray; }