commit 9e06e9652dd7af5c3fc52926dc0327376db85463 Author: jaybe Date: Wed Mar 5 04:53:12 2025 +0000 Upload files to "/" diff --git a/KMDB.php b/KMDB.php new file mode 100644 index 0000000..b418877 --- /dev/null +++ b/KMDB.php @@ -0,0 +1,915 @@ +db = \Config\Database::connect('kakao'); + $this->zenith = \Config\Database::connect(); + // $this->db_query("SET FOREIGN_KEY_CHECKS = 0;"); + } + + public function update_token($data) + { + + $update_sql = ''; + $access_token = ''; + $refresh_token = ''; + if (isset($data['access_token'])) { + $access_token = $data['access_token']; + $update_sql .= "access_token = '{$access_token}', "; + } + if (isset($data['refresh_token'])) { + $refresh_token = $data['refresh_token']; + $update_sql .= "refresh_token = '{$refresh_token}', "; + } + $sql = "INSERT INTO api_info (uid, access_token, refresh_token, expires_time, update_time) + VALUES (0, '{$access_token}', '{$refresh_token}', DATE_ADD(NOW(), INTERVAL {$data['expires_in']} SECOND), NOW()) + ON DUPLICATE KEY + UPDATE {$update_sql}expires_time = DATE_ADD(NOW(), INTERVAL {$data['expires_in']} SECOND), update_time = NOW();"; + $result = $this->db_query($sql); + } + + public function get_token() + { + $sql = "SELECT access_token, refresh_token, expires_time FROM api_info WHERE uid = 0"; + $result = $this->db_query($sql) or die($this->db->error); + $row = $result->getRowArray(); + + return $row; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + public function getAdAccounts($config = 'ON', $is_update = 1, $order = false) + { + $sql = "SELECT * FROM mm_ad_account WHERE 1"; + + if (!is_null($is_update)) + $sql .= " AND is_update = {$is_update}"; + if (!is_null($config)) + $sql .= " AND config = '{$config}'"; + if ($order) $sql .= " " . $order; + $result = $this->db_query($sql); + + return $result; + } + + public function updateAdAccount($row) + { + foreach ($row as $k => $v) $row[$k] = !is_array($v) ? $this->db->escape($v) : $v; + if (is_array($row['ownerCompany'])) { + $ownerCompany = $this->db->escape($row['ownerCompany']['name'] . "(" . $row['ownerCompany']['businessRegistrationNumber'] . ")"); + } + if (is_array($row['advertiser'])) { + $advertiser = $this->db->escape($row['advertiser']['name'] . "(" . $row['advertiser']['businessRegistrationNumber'] . ")"); + } + $sql = "INSERT INTO mm_ad_account (id, name, memberType, config, ownerCompany, advertiser, type, isAdminStop, isOutOfBalance, statusDescription, create_time) + VALUES ({$row['id']}, {$row['name']}, {$row['memberType']}, {$row['config']}, {$ownerCompany}, {$advertiser}, {$row['type']}, {$row['isAdminStop']}, {$row['isOutOfBalance']}, {$row['statusDescription']}, NOW()) + ON DUPLICATE KEY + UPDATE name={$row['name']}, memberType={$row['memberType']}, config={$row['config']}, ownerCompany={$ownerCompany}, advertiser={$advertiser}, type={$row['type']}, isAdminStop={$row['isAdminStop']}, isOutOfBalance={$row['isOutOfBalance']}, statusDescription={$row['statusDescription']}, update_time=NOW();"; + $result = $this->db_query($sql) or die($sql . ' : ' . $this->db->error); + return $result; + } + + public function updateAdAccounts($data) + { //광고계정 목록 저장 + + foreach ($data as $row) { + if ($row['id']) $this->updateAdAccount($row); + } + } + + public function getCampaigns($config = ['ON']) + { + $sql = "SELECT A.* FROM mm_campaign AS A LEFT JOIN mm_ad_account AS B ON A.ad_account_id = B.id WHERE B.is_update = 1"; + if (!is_null($config)) + $sql .= " AND A.config IN ('" . implode("','", $config) . "')"; + $result = $this->db_query($sql); + + return $result; + } + + public function + getAutoLimitBudgetCampaign($data) + { + $sql = "SELECT A.id AS id, A.name AS name, A.config AS config, IF(F.campaign_id,true,false) AS already, A.autoBudget AS autoBudget, SUM( D.cost ) AS cost, SUM(E.db_count) AS unique_total, A.dailyBudgetAmount AS dailyBudgetAmount + FROM mm_campaign A + LEFT JOIN mm_adgroup B ON A.id = B.campaign_id + LEFT JOIN mm_creative C ON B.id = C.adgroup_id + LEFT JOIN mm_creative_report_basic D ON C.id = D.id + LEFT JOIN mm_db_count E ON C.id = E.creative_id AND E.date = D.date + LEFT JOIN mm_campaign_autobudget F ON A.id = F.campaign_id AND D.date = F.date + WHERE A.config = 'ON' AND A.autoBudget = 'ON' AND A.name LIKE '%@%' AND D.date = '{$data['date']}' + GROUP BY A.id"; + $result = $this->db_query($sql); + + return $result; + } + + + public function setAutoLimitBudgetCampaign($data) + { + $sql = "INSERT INTO mm_campaign_autobudget(campaign_id, date, set_db, valid_db, set_budget, reg_date) VALUES('{$data['id']}', '{$data['date']}', '{$data['set_db']}', '{$data['valid_db']}', '{$data['budget']}', NOW()) "; + $result = $this->db_query($sql, true); + } + + public function getCampaignById($id) + { + if (is_null($id)) return NULL; + $sql = "SELECT * FROM mm_campaign WHERE id = {$id}"; + $result = $this->db_query($sql); + $row = $result->getRowArray(); + return $row; + } + + public function updateCampaign($row) + { + $data = [ + 'ad_account_id' => $row['adAccountId'], + 'id' => $row['id'], + 'name' => $row['name'], + 'type' => $row['campaignTypeGoal']['campaignType']??null, + 'goal' => $row['campaignTypeGoal']['goal']??null, + 'config' => $row['config'], + 'objectiveType' => $row['objective']['type']??null, + 'objectiveDetailType' => $row['objective']['detailType']??null, + 'objectiveValue' => $row['objective']['value']??null, + 'dailyBudgetAmount' => $row['dailyBudgetAmount'], + 'statusDescription' => $row['statusDescription'], + 'trackId' => $row['trackId'], + ]; + $builder = $this->db->table('mm_campaign'); + $builder->setData($data); + $updateTime = ['update_time' => new RawSql('NOW()')]; + $builder->updateFields($updateTime, true); + $result = $builder->upsert(); + return $result; + } + + public function setCampaignOnOff($campaignId, $config) + { + $sql = "UPDATE mm_campaign SET config = '{$config}' WHERE id = {$campaignId}"; + $result = $this->db_query($sql) or die($sql . ' : ' . $this->db->error); + return $result; + } + + public function setCampaignDailyBudgetAmount($id, $budget) + { + if ($budget == '') $budget = NULL; + $sql = "UPDATE mm_campaign SET dailyBudgetAmount = '{$budget}' WHERE id = {$id}"; + $result = $this->db_query($sql) or die($sql . ' : ' . $this->db->error); + return $result; + } + + public function setCampaign($data) + { + foreach ($data as $key => $val) $q[] = "{$key} = '{$val}'"; + $query = implode(",", $q); + $sql = "UPDATE mm_campaign SET {$query} WHERE id = {$data['id']}"; + $result = $this->db_query($sql); + return $result; + } + + public function updateCampaigns($data) + { //캠페인 목록 저장 + + foreach ($data as $account_id => $account) { + foreach ($account as $row) { + $row['account_id'] = $account_id; + if ($row['id']) $this->updateCampaign($row); + } + } + } + + public function getAdGroups($config = null, $orderby = "") + { + $sql = "SELECT A.*, B.dailyBudgetAmount AS campaign_dailyBudgetAmount, B.ad_account_id, C.name AS account_name + FROM mm_adgroup AS A + LEFT JOIN mm_campaign AS B + ON A.campaign_id = B.id + LEFT JOIN mm_ad_account AS C + ON B.ad_account_id = C.id + WHERE C.is_update = 1"; + if (!is_null($config)) + $sql .= " AND A.config IN ('" . implode("','", $config) . "')"; + if ($orderby) $sql .= " " . $orderby; + $result = $this->db_query($sql); + + return $result; + } + + public function getAdAccountIdByAdGroupId($id) + { + if (is_null($id)) return NULL; + $sql = "SELECT C.ad_account_id FROM mm_adgroup AS B + LEFT JOIN mm_campaign AS C + ON B.campaign_id = C.id + LEFT JOIN mm_ad_account AS D + ON C.ad_account_id = D.id + WHERE B.id = {$id}"; + $result = $this->db_query($sql); + $row = $result->getRowArray(); + $ad_account_id = $row['ad_account_id']; + return $ad_account_id; + } + + public function updateAdGroup($row) + { + $data = [ + 'campaign_id' => $row['campaign_id'], + 'id' => $row['id'], + 'name' => $row['name'], + 'type' => $row['type'] ?? null, + 'config' => $row['config'], + 'allAvailableDeviceType' => $row['allAvailableDeviceType'], + 'allAvailablePlacement' => $row['allAvailablePlacement'], + 'pricingType' => $row['pricingType'], + 'pacing' => $row['pacing'] ?? null, + 'adult' => $row['adult'], + 'bidStrategy' => $row['bidStrategy'], + 'totalBudget' => $row['totalBudget'] ?? null, + 'dailyBudgetAmount' => $row['dailyBudgetAmount'] ?? null, + 'bidAmount' => $row['bidAmount'], + 'useMaxAutoBidAmount' => $row['useMaxAutoBidAmount'] ?? null, + 'autoMaxBidAmount' => $row['autoMaxBidAmount'] ?? null, + 'isDailyBudgetAmountOver' => $row['isDailyBudgetAmountOver'], + 'creativeOptimization' => $row['creativeOptimization'], + 'isValidPeriod' => $row['isValidPeriod'], + 'deviceTypes' => implode(',', $row['deviceTypes']??[]), + 'placements' => implode(',', $row['placements']??[]), + 'statusDescription' => $row['statusDescription'] ?? null + ]; + $builder = $this->db->table('mm_adgroup'); + $builder->setData($data); + $updateTime = ['update_time' => new RawSql('NOW()')]; + $builder->updateFields($updateTime, true); + $result = $builder->upsert(); + + return $result; + } + + public function setAdGroupOnOff($adgroupId, $config) + { + $sql = "UPDATE mm_adgroup SET config = '{$config}' WHERE id = {$adgroupId}"; + $result = $this->db_query($sql) or die($sql . ' : ' . $this->db->error); + return $result; + } + + + public function setAdGroupDailyBudgetAmount($id, $budget) + { + $sql = "UPDATE mm_adgroup SET dailyBudgetAmount = '{$budget}' WHERE id = {$id}"; + $result = $this->db_query($sql) or die($sql . ' : ' . $this->db->error); + return $result; + } + + public function setAdGroupBidAmount($adgroupId, $bidAmount) + { + $sql = "UPDATE mm_adgroup SET bidAmount = {$bidAmount} WHERE id = {$adgroupId}"; + $result = $this->db_query($sql) or die($sql . ' : ' . $this->db->error); + return $result; + } + + public function setAdGroup($data) + { + foreach ($data as $key => $val) $q[] = "{$key} = '{$val}'"; + $query = implode(",", $q); + $sql = "UPDATE mm_adgroup SET {$query} WHERE id = {$data['id']}"; + $result = $this->db_query($sql); + return $result; + } + + public function updateAdGroups($data) + { //광고그룹 목록 저장 + if(isset($data) && count($data)) { + foreach ($data as $campaign_id => $campaign) { + foreach ($campaign as $row) { + $row['campaign_id'] = $campaign_id; + if (isset($row['id'])) $this->updateAdGroup($row); + else print_r($row); + } + } + } + } + + + public function getAutoLimitBidAmountAdGroup($data) + { + $sql = "SELECT A.ad_account_id, + B.id AS id, + B.name AS name, + B.bidStrategy, + C.name AS ad_name, + A.goal, + A.config AS campaign_config, + B.config AS config, + B.aiConfig, + SUM(E.db_count) AS unique_total, + B.bidAmount, + SUM(D.cost) AS cost, + SUM(E.margin) AS margin, + IF(SUM(D.sales)>0, ROUND(SUM(E.margin)/SUM(D.sales)*100,0),0) AS margin_ratio, + IF(F.adgroup_id AND level = 1,true,false) AS already_1, + IF(F.adgroup_id AND level = 2,true,false) AS already_2, + IF(F.adgroup_id AND level = 3,true,false) AS already_3, + IF(F.adgroup_id AND level = 4,true,false) AS already_4 + FROM mm_adgroup B + LEFT JOIN mm_campaign A ON A.id = B.campaign_id + LEFT JOIN mm_creative C ON B.id = C.adgroup_id + LEFT JOIN mm_creative_report_basic D ON C.id = D.id + LEFT JOIN mm_db_count E ON C.id = E.creative_id AND E.date = D.date + LEFT JOIN (SELECT H.* + FROM (SELECT adgroup_id, MAX( reg_date ) reg_date FROM mm_adgroup_autobidamount GROUP BY adgroup_id) G + JOIN mm_adgroup_autobidamount H ON H.adgroup_id = G.adgroup_id AND H.reg_date = G.reg_date ) F + ON B.id = F.adgroup_id AND E.date = F.date + WHERE B.aiConfig = 'ON' AND D.date = '{$data['date']}' AND A.goal IN ('CONVERSION', 'VISITING') + GROUP BY B.id "; + $result = $this->db_query($sql, true); + return $result; + } + + public function setAutoLimitBidAmountAdGroup($data) + { + $sql = "INSERT INTO mm_adgroup_autobidamount(adgroup_id, date, level, msg, reg_date) VALUES('{$data['id']}', '{$data['date']}', '{$data['level']}', '{$data['msg']}', NOW()) "; + echo $sql . PHP_EOL; + $result = $this->db_query($sql, true); + return $result; + } + + public function getCreatives($config = ['ON']) + { + $sql = "SELECT A.*, C.ad_account_id FROM mm_creative AS A + LEFT JOIN mm_adgroup AS B + ON A.adgroup_id = B.id + LEFT JOIN mm_campaign AS C + ON B.campaign_id = C.id + LEFT JOIN mm_ad_account AS D + ON C.ad_account_id = D.id + WHERE D.is_update = 1"; + if (!is_null($config)) + $sql .= " AND A.config IN ('" . implode("','", $config) . "')"; + $result = $this->db_query($sql); + + return $result; + } + + public function getAdAccountIdByCreativeId($id) + { + if (is_null($id)) return NULL; + $sql = "SELECT C.ad_account_id FROM mm_creative AS A + LEFT JOIN mm_adgroup AS B + ON A.adgroup_id = B.id + LEFT JOIN mm_campaign AS C + ON B.campaign_id = C.id + LEFT JOIN mm_ad_account AS D + ON C.ad_account_id = D.id + WHERE (A.id = {$id} OR A.creativeId = {$id})"; + $result = $this->db_query($sql); + $row = $result->getRowArray(); + $ad_account_id = $row['ad_account_id']; + return $ad_account_id; + } + + + public function updateCreative($row) + { + $data = [ + 'adgroup_id' => $row['adgroup_id'], + 'id' => $row['id'], + 'creativeId' => $row['creativeId'], + 'name' => $row['name'], + 'altText' => $row['altText'], + 'type' => $row['type'], + 'landingType' => $row['landingInfo']['landingType']??null, + 'hasExpandable' => $row['hasExpandable'], + 'bizFormId' => $row['landingInfo']['bizFormId']??null, + 'format' => $row['format'], + 'bidAmount' => $row['bidAmount'], + 'landingUrl' => $row['landingUrl'], + 'frequencyCap' => $row['frequencyCap'], + 'frequencyCapType' => $row['frequencyCapType'], + 'config' => $row['config'], + 'imageUrl' => $row['image']['url']??null, + 'reviewStatus' => $row['reviewStatus'], + 'creativeStatus' => $row['creativeStatus'], + 'statusDescription' => $row['statusDescription'], + ]; + $builder = $this->db->table('mm_creative'); + $builder->setData($data); + $updateTime = ['update_time' => new RawSql('NOW()')]; + $builder->updateFields($updateTime, true); + $result = $builder->upsert(); + return $result; + } + + public function setCreativeOnOff($creativeId, $config) + { + $sql = "UPDATE mm_creative SET config = '{$config}' WHERE id = {$creativeId}"; + $result = $this->db_query($sql) or die($sql . ' : ' . $this->db->error); + return $result; + } + + public function insertCreativeAutoOnOff($creative, $set) { + $sql = "INSERT INTO mm_creative_autoonoff(creative_id, date, type, msg, reg_date) VALUES({$creative['id']}, NOW(), '{$creative['aitype']}', '{$set}', NOW());"; + $result = $this->db_query($sql) or die($sql . ' : ' . $this->db->error); + return $result; + } + + + public function getAutoCreativeOnOff($type) { + $sql = "SELECT maa.name AS account_name, maa.config AS account_config, mcm.name AS campaign_name, mcm.config AS campaign_config, ma.config AS adgroup_config, mc.id AS id, mc.name AS creative_name, mc.config AS creative_config, mcrb.date, mdc.db_price, mdc.db_count, mdc.margin, mcrb.cost, mcrb.sales, ROUND(mdc.margin/mcrb.sales*100,2) AS margin_ratio, (CASE WHEN mdc.db_count = 0 AND mdc.db_price <= mcrb.cost THEN '1' WHEN mdc.db_count >= 1 AND mdc.margin/mcrb.sales*100 <= 0 THEN '2' END) AS aitype + FROM mm_creative AS mc + LEFT JOIN mm_creative_report_basic AS mcrb ON mc.id = mcrb.id + LEFT JOIN mm_db_count AS mdc ON mc.id = mdc.creative_id + LEFT JOIN mm_adgroup AS ma ON ma.id = mc.adgroup_id + LEFT JOIN mm_campaign AS mcm ON mcm.id = ma.campaign_id + LEFT JOIN mm_ad_account AS maa ON maa.id = mcm.ad_account_id + WHERE mcrb.date = mdc.date AND mdc.date = DATE(NOW()) AND mdc.margin != 0 AND ma.config = 'ON' AND mcm.config = 'ON' AND maa.config = 'ON' AND mc.config = '".strtoupper($type)."' AND mc.aiConfig = 'ON' + GROUP BY mc.id"; + $result = $this->db_query($sql) or die($sql . ' : ' . $this->db->error); + return $result; + } + + + public function setCreative($data) + { + foreach ($data as $key => $val) $q[] = "{$key} = '{$val}'"; + $query = implode(",", $q); + $sql = "UPDATE mm_creative SET {$query} WHERE id = {$data['id']}"; + $result = $this->db_query($sql); + return $result; + } + + public function updateCreatives($data) + { //소재 목록 저장 + if (is_array($data) && count($data) > 0) { + foreach ($data as $adgroup_id => $adgroup) { + foreach ($adgroup as $row) { + $row['adgroup_id'] = $adgroup_id; + if (isset($row['id'])) $this->updateCreative($row); + } + } + } + } + + public function getInitCreatives() { + $sql = "SELECT mcrb.date AS report_date, mcrb.update_time AS report_update_time, maa.name AS account_name, mc2.id AS campaign_id, mc2.name AS campaign_name, mc2.type AS campaign_type, ma.id AS adgroup_id, ma.name AS adgroup_name, mc.id AS creative_id, mc.name AS creative_name, mc.create_time AS creative_create_time + FROM mm_creative_report_basic AS mcrb + LEFT JOIN mm_creative AS mc ON mc.id = mcrb.id + LEFT JOIN mm_adgroup AS ma ON ma.id = mc.adgroup_id + LEFT JOIN mm_campaign AS mc2 ON mc2.id = ma.campaign_id + LEFT JOIN mm_ad_account AS maa ON maa.id = mc2.ad_account_id + WHERE maa.is_update = 1 AND mc2.type IN ('TALK_BIZ_BOARD', 'DISPLAY') AND mc.config = 'ON' AND maa.config = 'ON' AND mc2.config = 'ON' AND DATE(mc.create_time) = DATE(NOW())"; + $result = $this->db_query($sql); + + return $result; + } + + public function getCreativeReportBasic($query = "") + { + $sql = "SELECT D.id AS ad_account_id, B.id AS adgroup_id, creative.creativeId AS creative_id, report.id, report.date, report.imp, report.imp, report.click, report.cost, creative.name, creative.landingUrl + FROM mm_creative_report_basic AS report + LEFT JOIN mm_creative AS creative + ON report.id = creative.id + LEFT JOIN mm_adgroup AS B + ON creative.adgroup_id = B.id + LEFT JOIN mm_campaign AS C + ON B.campaign_id = C.id + LEFT JOIN mm_ad_account AS D + ON C.ad_account_id = D.id + WHERE D.is_update = 1 {$query}"; + $result = $this->db_query($sql); + + return $result; + } + + public function updateCreativeReportBasic($row) + { + if((!isset($row['hour']) || !isset($row['date'])) || (!$row['hour'] || !$row['date'])) return null; + $data = [ + 'id' => $row['creative_id'], + 'date' => $row['date'], + 'hour' => $row['hour'], + 'imp' => $row['imp'], + 'click' => $row['click'], + 'ctr' => $row['ctr'], + 'cost' => $row['cost'], + ]; + $builder = $this->db->table('mm_creative_report_basic'); + $builder->setData($data); + $updateTime = ['update_time' => new RawSql('NOW()')]; + $builder->updateFields($updateTime, true); + $result = $builder->upsert(); + /* + foreach ($row as $k => $v) $row[$k] = !is_array($v) ? $this->db->escape($v) : $v; + if($row['imp'] == 0 && $row['click'] == 0 && $row['cost'] == 0 && $row['ctr'] == 0) return; + $sql = "INSERT INTO mm_creative_report_basic (id, date, hour, imp, click, ctr, cost, create_time) + VALUES ({$row['creative_id']}, {$row['date']}, IF({$row['hour']} <> '', {$row['hour']}, IF(DATE(NOW()) = {$row['date']}, HOUR(NOW()), 23)), {$row['imp']}, {$row['click']}, {$row['ctr']}, {$row['cost']}, NOW()) + ON DUPLICATE KEY + UPDATE date={$row['date']}, imp={$row['imp']}, click={$row['click']}, ctr={$row['ctr']}, cost={$row['cost']}, update_time=NOW();"; + // echo $sql.'
'; + $result = $this->db_query($sql) or die($sql . ' : ' . $this->db->error); + */ + return $result; + } + + public function updateCreativesReportBasic($data) + { //소재 목록 저장 + if ($data) { + foreach ($data as $creative_id => $creative) { + foreach ($creative as $row) { + $row['creative_id'] = $creative_id; + if ($row['imp'] >= 0) $this->updateCreativeReportBasic($row); + } + } + } + } + + public function getLeads($data) + { + if (!$data['event_seq']) return null; + $sql = "SELECT event_seq, site, date(from_unixtime(reg_timestamp)) AS date, HOUR(from_unixtime(reg_timestamp)) AS hour, count(event_seq) AS db_count + FROM `zenith`.`event_leads` + WHERE `reg_timestamp` >= unix_timestamp('{$data['date']}') + AND `status` = 1 AND `is_deleted` = 0 + AND `event_seq` = {$data['event_seq']} AND `site` = '{$data['site']}' AND DATE_FORMAT(`reg_date`, '%Y-%m-%d') = '{$data['date']}' + GROUP BY `event_seq`, `site`, HOUR(from_unixtime(reg_timestamp))"; + // echo $sql.PHP_EOL; + $result = $this->zenith->query($sql); + return $result; + } + + public function allAiOn($data) { + $sql = "UPDATE mm_campaign SET autoBudget = 'ON' WHERE id = {$data['campaign_id']} AND autoBudget = 'OFF'"; + $result = $this->db_query($sql); + $sql = "UPDATE mm_adgroup SET aiConfig = 'ON', aiConfig2 = 'ON' WHERE id = {$data['adgroup_id']} AND aiConfig = 'OFF' AND aiConfig2 = 'OFF'"; + $result = $this->db_query($sql); + } + + public function getAdLeads($date) + { + $sql = "SELECT report.id, CONCAT('{',GROUP_CONCAT('\"',report.`hour`,'\":',report.cost),'}') AS cost_data, creative.name, creative.landingUrl + FROM mm_creative_report_basic AS report + LEFT JOIN mm_creative AS creative + ON report.id = creative.id + LEFT JOIN mm_adgroup AS B + ON creative.adgroup_id = B.id + LEFT JOIN mm_campaign AS C + ON B.campaign_id = C.id + LEFT JOIN mm_ad_account AS D + ON C.ad_account_id = D.id + WHERE D.is_update = 1 AND report.date = '{$date}' GROUP BY report.id"; + $result = $this->db_query($sql); + + return $result; + } + + public function updateReport($data) + { + $row = $data; + foreach($row['data'] as $v) { + if ($row['creative_id']) { + $data = [ + 'id' => $row['creative_id'], + 'date' => $row['date'], + 'hour' => $v['hour'], + 'media' => $row['media'], + 'period' => $row['period_ad'], + 'event_seq' => $row['event_seq'], + 'site' => $row['site'], + 'db_price' => $row['db_price'], + 'db_count' => $v['count'], + 'margin' => $v['margin'], + 'sales' => $v['sales'], + ]; + $builder = $this->db->table('mm_creative_report_basic'); + $builder->setData($data); + $updateTime = ['update_time' => new RawSql('NOW()')]; + $builder->updateFields($updateTime, true); + // d($builder->getCompiledUpsert()); + $builder->upsert(); + /* + $sql = "UPDATE `z_moment`.`mm_creative_report_basic` + SET `media` = '{$row['media']}', `period` = '{$row['period_ad']}', `event_seq` = '{$row['event_seq']}', `site` = '{$row['site']}', `db_price` = '{$row['db_price']}', `db_count` = '{$v['count']}', `margin` = '{$v['margin']}', `sales` = '{$v['sales']}', `update_time` = NOW() + WHERE `id` = '{$row['creative_id']}' AND `date` = '{$row['date']}' AND `hour` = '{$v['hour']}'"; + $this->db_query($sql, true); + */ + } + } + } + + public function getDbPrice($data) + { + if (!$data['creative_id'] || !$data['date']) return NULL; + $sql = "SELECT id, date, db_price FROM `z_moment`.`mm_creative_report_basic` WHERE `id` = '{$data['creative_id']}' AND `date` = '{$data['date']}' GROUP BY date ORDER BY hour DESC LIMIT 1;"; + $result = $this->db_query($sql); + if (!$result) return null; + return $result->getResultArray(); + } + + public function insertToLeads($row) + { + $data = [ + 'event_seq' => $row['event_seq'], + 'site' => $row['site'], + 'name' => $row['name'], + 'phone' => new RawSql("enc_data('{$row['phone']}')"), + 'gender' => $row['gender'], + 'age' => $row['age'], + 'addr' => $row['addr'], + 'email' => $row['email'], + 'agree' => 'Y', + 'add1' => $row['add1'], + 'add2' => $row['add2'], + 'add3' => $row['add3'], + 'add4' => $row['add4'], + 'add5' => $row['add5'], + 'is_encryption' => 1, + 'lead_id' => $row['lead_id'], + 'reg_date' => date('Y-m-d H:i:s', $row['reg_timestamp']), + 'reg_timestamp' => $row['reg_timestamp'] + ]; + $builder = $this->zenith->table('event_leads'); + $builder->set($data); + $result = $builder->insert(); + // dd($builder->getCompiledInsert()); + if ($result) { + $builder = $this->db->table('mm_bizform_user_response'); + $builder->set('send_time', new RawSql('NOW()')); + $builder->where(['encUserId'=>$row['encUserId'], 'bizFormId'=>$row['bizFormId']]); + $builder->update(); + } + } + + public function getBizformQuestion($bizformId, $itemId) + { + $sql = "SELECT bizform_id, id, title FROM mm_bizform_items WHERE bizform_id = '{$bizformId}' AND id = '{$itemId}'"; + $result = $this->db_query($sql); + if (!$result->getNumRows()) return null; + $data = $result->getRowArray(); + return $data; + } + + public function getBizformUserResponse() + { + $sql = "SELECT ur.*, mc.code, mc.name, mc.id + FROM mm_creative AS mc + JOIN mm_bizform_user_response AS ur ON mc.id = ur.creative_id + WHERE ur.send_time IS NULL + ORDER BY ur.create_time ASC"; + $result = $this->db_query($sql); + + return $result; + } + + public function getBizformUpdateList() + { + $sql = "SELECT ei.creative_id, ei.bizform_apikey, mc.id, mc.bizFormId, mcp.name, ma.name, mc.name + FROM `zenith`.event_information AS ei + LEFT JOIN `z_moment`.mm_creative AS mc ON ei.creative_id = mc.creativeId + LEFT JOIN `z_moment`.mm_adgroup AS ma ON ma.id = mc.adgroup_id + LEFT JOIN `z_moment`.mm_campaign AS mcp ON mcp.id = ma.campaign_id + LEFT JOIN `z_moment`.mm_ad_account AS maa ON mcp.ad_account_id = maa.id + WHERE ei.creative_id <> '' AND ei.bizform_apikey <> '' AND ei.is_stop = 0 + AND mc.config = 'ON' AND maa.config = 'ON' AND maa.is_update = 1"; + $result = $this->db_query($sql); + if (!$result->getNumRows()) return NULL; + $data = []; + foreach ($result->getResultArray() as $row) { + $data[] = [ + 'id' => $row['id'], + 'bizFormId' => $row['bizFormId'], + 'bizFormApiKey' => $row['bizform_apikey'] + ]; + } + return $data; + } + + public function updateBizform($data) + { + $row = $data['data']; + if(empty($row) || !$row['id']) return; + $data = [ + 'id' => $row['id'], + 'title' => $row['title'], + 'imgUrl' => $row['imgUrl'], + 'startAt' => $row['startAt'], + 'startTimeAt' => $row['startTimeAt'], + 'endAt' => $row['endAt'], + 'endTimeAt' => $row['endTimeAt'], + 'applyType' => $row['applyType'], + 'privacyScopeUse' => $row['privacyScopeUse'], + 'flowType' => $row['flowType'], + 'completeType' => $row['completeType'], + 'status' => $row['status'], + 'runningStatus' => $row['runningStatus'], + 'editingPhase' => $row['editingPhase'], + 'channelUsed' => $row['channelUsed'], + 'channelProfileId' => $row['channelProfileId'], + 'prizeAnnouncedDateAt' => $row['prizeAnnouncedDateAt'], + 'prizeAnnouncedTimeAt' => $row['prizeAnnouncedTimeAt'], + 'partnerCsPhone' => $row['partnerCsPhone'], + 'partnerCsUrl' => $row['partnerCsUrl'], + 'reportEnable' => $row['reportEnable'], + 'createdAt' => $row['createdAt'], + 'abortedAt' => $row['abortedAt'], + 'finishUv' => $row['finishUv'], + ]; + $sql = "INSERT INTO mm_bizform(`id`, `title`, `imgUrl`, `startAt`, `startTimeAt`, `endAt`, `endTimeAt`, `applyType`, `privacyScopeUse`, `flowType`, `completeType`, `status`, `runningStatus`, `editingPhase`, `channelUsed`, `channelProfileId`, `prizeAnnouncedDateAt`, `prizeAnnouncedTimeAt`, `partnerCsPhone`, `partnerCsUrl`, `reportEnable`, `createdAt`, `abortedAt`, `finishUv`, `create_time`) + VALUES(:id:, :title:, :imgUrl:, :startAt:, :startTimeAt:, :endAt:, :endTimeAt:, :applyType:, :privacyScopeUse:, :flowType:, :completeType:, :status:, :runningStatus:, :editingPhase:, :channelUsed:, :channelProfileId:, :prizeAnnouncedDateAt:, :prizeAnnouncedTimeAt:, :partnerCsPhone:, :partnerCsUrl:, :reportEnable:, :createdAt:, :abortedAt:, :finishUv:, NOW()) + ON DUPLICATE KEY + UPDATE `id` = :id:, `title` = :title:, `imgUrl` = :imgUrl:, `startAt` = :startAt:, `startTimeAt` = :startTimeAt:, `endAt` = :endAt:, `endTimeAt` = :endTimeAt:, `applyType` = :applyType:, `privacyScopeUse` = :privacyScopeUse:, `flowType` = :flowType:, `completeType` = :completeType:, `status` = :status:, `runningStatus` = :runningStatus:, `editingPhase` = :editingPhase:, `channelUsed` = :channelUsed:, `channelProfileId` = :channelProfileId:, `prizeAnnouncedDateAt` = :prizeAnnouncedDateAt:, `prizeAnnouncedTimeAt` = :prizeAnnouncedTimeAt:, `partnerCsPhone` = :partnerCsPhone:, `partnerCsUrl` = :partnerCsUrl:, `reportEnable` = :reportEnable:, `createdAt` = :createdAt:, `abortedAt` = :abortedAt:, `finishUv` = :finishUv:, `update_time` = NOW()"; + + $result = $this->db->query($sql, $data); + if ($result) { + $this->updateBizFormItems($row['id'], $row['bizformItems']); + } + } + + public function updateBizFormItems($bizformId, $lists) + { + if(@count($lists) <= 0) return; + foreach ($lists as $row) { + if(!$row['id']) continue; + $data = [ + 'id' => $row['id'], + 'bizform_id' => $bizformId, + 'ordinal' => $row['ordinal'], + 'title' => $row['title'], + 'contents' => $row['contents'], + 'required' => $row['required'], + 'type' => $row['type'], + 'replyType' => $row['replyType'], + 'layoutType' => $row['layoutType'], + 'multiple' => $row['multiple'], + 'multipleLimitMin' => $row['multipleLimitMin'], + 'multipleLimitMax' => $row['multipleLimitMax'], + 'stepGroupId' => $row['stepGroupId'], + 'stepOrder' => $row['stepOrder'], + 'step' => $row['step'], + 'bizformOptions' => $row['bizformOptions'] + ]; + $builder = $this->db->table('mm_bizform_items'); + $builder->setData($data); + $updateTime = ['update_time' => new RawSql('NOW()')]; + $builder->updateFields($updateTime, true); + $builder->upsert(); + /* + $sql = "INSERT INTO mm_bizform_items(`id`, `bizform_id`, `ordinal`, `title`, `contents`, `required`, `type`, `replyType`, `layoutType`, `multiple`, `multipleLimitMin`, `multipleLimitMax`, `stepGroupId`, `stepOrder`, `step`, `bizformOptions`, `create_time`) + VALUES('{$row['id']}', '{$bizformId}', '{$row['ordinal']}', '{$row['title']}', '{$row['contents']}', '{$row['required']}', '{$row['type']}', '{$row['replyType']}', '{$row['layoutType']}', '{$row['multiple']}', '{$row['multipleLimitMin']}', '{$row['multipleLimitMax']}', '{$row['stepGroupId']}', '{$row['stepOrder']}', '{$row['step']}', '{$row['bizformOptions']}', NOW()) + ON DUPLICATE KEY + UPDATE `id` = '{$row['id']}', `bizform_id` = '{$bizformId}', `ordinal` = '{$row['ordinal']}', `title` = '{$row['title']}', `contents` = '{$row['contents']}', `required` = '{$row['required']}', `type` = '{$row['type']}', `replyType` = '{$row['replyType']}', `layoutType` = '{$row['layoutType']}', `multiple` = '{$row['multiple']}', `multipleLimitMin` = '{$row['multipleLimitMin']}', `multipleLimitMax` = '{$row['multipleLimitMax']}', `stepGroupId` = '{$row['stepGroupId']}', `stepOrder` = '{$row['stepOrder']}', `step` = '{$row['step']}', `bizformOptions` = '{$row['bizformOptions']}', `update_time` = NOW()"; + $this->db_query($sql, true); + */ + } + } + + public function updateBizFormUserResponse($creative_id, $bizformId, $list=[]) + { + foreach ($list as $row) { + $data = [ + 'bizFormId' => $bizformId, + 'creative_id' => $creative_id, + 'seq' => $row['seq'], + 'encUserId' => $row['encUserId'], + 'applyOrUpdate' => $row['applyOrUpdate'], + 'submitAt' => $row['submitAt'], + 'nickname' => $row['nickname'], + 'email' => $row['email'], + 'phoneNumber' => $row['phoneNumber'], + 'responses' => $row['response'] + ]; + $builder = $this->db->table('mm_bizform_user_response'); + $builder->setData($data); + $updateTime = ['update_time' => new RawSql('IF(seq<>VALUES(seq) OR applyOrUpdate<>VALUES(applyOrUpdate) OR submitAt<>VALUES(submitAt) OR nickname<>VALUES(nickname) OR email<>VALUES(email) OR phoneNumber<>VALUES(phoneNumber) OR responses<>VALUES(responses), NOW(), NULL)')]; + $builder->updateFields($updateTime, true); + $result = $builder->upsert(); + + /* + foreach ($row as $k => $v) $row[$k] = @$this->db->escape($v); + if(!$row['seq']) continue; + $sql = "INSERT INTO mm_bizform_user_response(`bizFormId`, `creative_id`, `seq`, `encUserId`, `applyOrUpdate`, `submitAt`, `nickname`, `email`, `phoneNumber`, `responses`, `create_time`) + VALUES({$bizformId}, {$creative_id}, {$row['seq']}, {$row['encUserId']}, {$row['applyOrUpdate']}, {$row['submitAt']}, {$row['nickname']}, {$row['email']}, {$row['phoneNumber']}, {$row['response']}, NOW()) + ON DUPLICATE KEY UPDATE + `update_time`= IF(seq<>VALUES(seq) OR applyOrUpdate<>VALUES(applyOrUpdate) OR submitAt<>VALUES(submitAt) OR nickname<>VALUES(nickname) OR email<>VALUES(email) OR phoneNumber<>VALUES(phoneNumber) OR responses<>VALUES(responses), NOW(), NULL), + `seq`={$row['seq']},`applyOrUpdate`={$row['applyOrUpdate']},`submitAt`={$row['submitAt']},`nickname`={$row['nickname']},`email`={$row['email']},`phoneNumber`={$row['phoneNumber']},`responses`={$row['response']}"; + + $this->db_query($sql, true); + */ + } + } + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + public function db_query($sql, $error = false) + { + if (!$sql) return false; + $result = null; + $this->sltDB = $this->db; + + $this->sltDB->query("BEGIN"); + if ($error) + $result = $this->sltDB->query($sql) or die($this->sltDB->error); + else + $result = $this->sltDB->query($sql); + if ($result) { + // $this->tracking($sql); + } + $this->sltDB->query("COMMIT"); + return $result; + } + + public function tracking($sql) + { + global $member; + $action = strtoupper(substr($sql, 0, 6)); + $allow = ['INSERT', 'UPDATE']; + $sql = preg_replace("/\r\n|\t+|\s+/", " ", $sql); + $table = preg_replace("/{$action}.+(mm_[_a-z]+)\s.+/i", "$1", $sql); + $result = ['action' => $action, 'table' => $table, 'query' => $this->db->escape($sql)]; + if (in_array($table, ['fb_optimization', 'fb_optimization_history', 'fb_optimization_onoff_history'])) return; + // echo '
'.print_r($result,1).'
'; + if (in_array($action, $allow) && $member['mb_id']) { + switch ($action) { + case "INSERT": + preg_match_all("/^.+\(([a-z,\s\_]*[^\)]+)\).+\(([a-z,\s\_]*[^\)]+)\).+/", $sql, $matches); + if (@count($matches[1]) > 0) { + $m['fields'] = array_map('trim', explode(",", $matches[1][0])); + $m['values'] = array_map('trim', explode(",", $matches[2][0])); + $combine = array_combine($m['fields'], $m['values']); + if (($key = array_search("NOW(", $combine)) !== false) unset($combine[$key]); + $result['data'] = array_map(function ($v) { + return trim($v, "'"); + }, $combine); + } + break; + case "UPDATE": + $m['where'] = preg_replace("/.+WHERE (.+[^;]+);?$/i", "$1", $sql); + $set = preg_replace("/.+SET\s(.+)WHERE.+/i", "$1", $sql); + $set = array_map('trim', explode(",", $set)); + foreach ($set as $k => $v) { + if (!preg_match('/\=/', $v)) { + $set[$k - 1] .= ',' . $v; + unset($set[$k]); + } + } + foreach ($set as $row) { + list($m['fields'][], $m['values'][]) = array_map('trim', explode("=", $row)); + } + list($m['fields'][], $m['values'][]) = array_map('trim', explode("=", $m['where'])); + $combine = array_combine($m['fields'], $m['values']); + if (($key = array_search("NOW()", $combine)) !== false) unset($combine[$key]); + $result['data'] = array_map(function ($v) { + return trim($v, "'"); + }, $combine); + break; + case "DELETE": + case "SELECT": + default: + break; + } + $sql = "INSERT INTO tracking_logs SET "; + $sql .= "action = '{$result['action']}', table_name = '{$result['table']}', query = '{$result['query']}', mb_id = '{$member['mb_id']}', reg_time = NOW()"; + foreach ($result['data'] as $field => $v) { + @$this->db->query("ALTER TABLE `tracking_logs` ADD `{$field}` VARCHAR(255) NULL DEFAULT NULL AFTER `query`;"); + $sql .= ", {$field} = '{$v}'"; + } + $this->db->query($sql) or die($this->db->error); + } + //echo '
'.PHP_EOL; + } + + public function getMemo($p) + { + $sql = "SELECT * FROM mm_memo WHERE id = '{$p['id']}' AND type = '{$p['type']}' ORDER BY datetime DESC"; + $result = $this->db_query($sql); + if ($result->getNumRow()) { + foreach ($result->getResultArray() as $row) { + $sql = "SELECT mb_name FROM g5_member WHERE mb_id = '{$row['mb_id']}'"; + $mb = $this->zenith->query($sql)->getResult(); + $row['mb_name'] = $mb['mb_name']; + $memo[] = $row; + } + } + return $memo; + } + + public function addMemo($data) + { + $data['memo'] = $this->db->escape($data['memo']); + $sql = "INSERT INTO mm_memo (`id`, `type`, `memo`, `mb_id`, `datetime`) VALUES({$data['id']}, '{$data['type']}', '{$data['memo']}', '{$data['mb_id']}', NOW())"; + if ($this->db_query($sql)) + return $data['id']; + } + + public function escape($val) + { + return $this->db->escape($val); + } +} diff --git a/MomentAPI.php b/MomentAPI.php new file mode 100644 index 0000000..15d0316 --- /dev/null +++ b/MomentAPI.php @@ -0,0 +1,1689 @@ +db = new KMDB(); + try { + include __DIR__."/config.php"; + $this->app_id = $config['app_id']; + $this->app_key = $config['app_key']; + $this->client_secret = $config['client_secret']; + $this->redirect_uri = $config['redirect_uri']; + + $token = $this->db->get_token(); + if (!empty($token['access_token'])) { + $this->access_token = $token['access_token']; + $this->refresh_token = $token['refresh_token']; + if (time() >= strtotime($token['expires_time'] . ' -2 hours')) $this->refresh_token(); + } else { + if (empty($_GET['code'])) + $this->get_code(); + } + $this->slack = new SlackChat(); + } catch (Exception $ex) { + echo $ex->getMessage(); + return false; + } + } + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + public function oauth() + { + if (!empty($_GET['code'])) { + var_dump($_GET['code']); + $this->koauth($_GET['code']); + } + } + private function get_code() + { + $redirect_code_uri = urlencode($this->redirect_uri); + $param = "?client_id={$this->app_key}&redirect_uri={$redirect_code_uri}&response_type=code"; + $response = $this->curl($this->oauth_url . '/authorize' . $param, NULL, NULL); + var_dump($response); + } + + private function koauth($code = '') + { + $data = array( + 'grant_type' => 'authorization_code', + 'client_id' => $this->app_key, + 'redirect_uri' => $this->redirect_uri, + 'code' => $_GET['code'], //get_code() 에서 받은 code 값 + 'client_secret' => $this->client_secret + ); + $data = http_build_query($data); + $response = $this->curl($this->oauth_url . '/token', NULL, $data, 'POST'); + if (isset($response['access_token'])) { + $this->db->update_token($response); + echo date('[H:i:s]') . '토큰 생성 완료' . PHP_EOL; + ob_flush(); + flush(); + usleep(1); + } + } + + public function refresh_token() + { + $data = array( + 'grant_type' => 'refresh_token', + 'client_id' => $this->app_key, + 'refresh_token' => $this->refresh_token + //'client_secret' => $this->client_secret + ); + $data = http_build_query($data); + $response = $this->curl($this->oauth_url . '/token', NULL, $data, 'POST'); + if (isset($response['access_token']) || isset($response['refresh_token'])) { + $this->db->update_token($response); + echo date('[H:i:s]') . '토큰 업데이트 완료' . PHP_EOL; + ob_flush(); + flush(); + usleep(1); + } + } + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /* 1. 광고계정 */ + + private function getAdAccountList() + { //1.1 광고계정 리스트 조회 + $request = 'adAccounts/pages'; + $param = array('config' => 'ON,OFF,DEL', 'page' => 0, 'size' => 2000); //enum{ON, OFF, DEL} + $result = $this->getCall($request, $param); + return $result; //[id] => 41250 [name] => 강남조은눈안과 [memberType] => MASTER [config] => ON + } + + private function getAdAccount($adAccountId = '') + { //1.2. 광고계정 조회 + $request = "adAccounts/{$adAccountId}"; + $this->ad_account_id = $adAccountId; + $result = $this->getCall($request); + return $result; //Array ( [id] => 41250 [name] => 강남조은눈안과 [ownerCompany] => Array ( [businessRegistrationNumber] => 220-88-36643 [name] => 주식회사 케어랩스 ) [advertiser] => Array ( [businessRegistrationNumber] => 104-90-96978 [name] => 강남조은눈안과 ) [type] => BUSINESS [config] => ON [isAdminStop] => [isOutOfBalance] => [statusDescription] => 운영중 ) + } + + public function updateAdAccounts() + { //전체 광고계정 업데이트 + try { + $adAccountList = $this->getAdAccountList(); + $i = 0; + $step = 1; + $total = count($adAccountList['content']); + CLI::write("[".date("Y-m-d H:i:s")."]"."{$total}개의 광고계정 수신을 시작합니다.", "light_red"); + foreach ($adAccountList['content'] as $row) { + CLI::showProgress($step++, $total); + if($row['config'] == 'DEL') continue; + $data[$i] = $this->getAdAccount($row['id']); + $data[$i]['memberType'] = $row['memberType']; + $i++; + } + $this->db->updateAdAccounts($data); + $msgs = [ + 'channel' => $this->slackChannel, + 'text' => "[".date("Y-m-d H:i:s")."][" . getenv('MY_SERVER_NAME') . "][카카오][광고계정] 수신 완료", + ]; + $this->slack->sendMessage($msgs); + return $data; + } catch (Exception $ex) { + $msgs = [ + 'channel' => $this->slackChannel, + 'text' => "[".date("Y-m-d H:i:s")."][" . getenv('MY_SERVER_NAME') . "][카카오][광고계정] 수신 오류 : " . $ex->getMessage(), + ]; + $this->slack->sendMessage($msgs); + } + } + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /* 2. 캠페인 */ + + private function getCampaigns($adAccountId) + { //2.1. 캠페인 리스트 조회 + $request = 'campaigns'; + $this->ad_account_id = $adAccountId; + $param = array('config' => 'ON,OFF,DEL'); + $result = $this->getCall($request, $param); + return $result; //Array ( [id] => 17550 [name] => ★썸네일피드 [type] => DISPLAY [userConfig] => ON ) + } + + private function getCampaign($campaignId, $adAccountId = '') + { //2.2. 캠페인 조회 + $request = "campaigns/{$campaignId}"; + if ($adAccountId) $this->ad_account_id = $adAccountId; + $result = $this->getCall($request, '', '', 'GET', true); + return $result; //Array ( [id] => 17550 [name] => ★썸네일피드 [adPurposeType] => INCREASE_WEB_VISITING [dailyBudgetAmount] => [config] => ON [isDailyBudgetAmountOver] => [statusDescription] => 운영중 ) + } + + public function setCampaignOnOff($campaignId, $config = 'ON', $adAccountId = '') + { //2.3. 캠페인 ON/OFF 수정 + $request = 'campaigns/onOff'; + $data = [ + 'id' => $campaignId, + 'config' => $config + ]; + $campaign = $this->db->getCampaignById($campaignId); + if ($campaign['ad_account_id']) $this->ad_account_id = $campaign['ad_account_id']; + $result = $this->getCall($request, NULL, $data, 'PUT'); + if ($result['http_code'] == 200) + $this->db->setCampaignOnOff($campaignId, $config); + return $result; + } + + private function setCampaignDailyBudgetAmount($campaignId = '', $dailyBudgetAmount = null) + { //2.4. 캠페인 일예산 수정 + $request = 'campaigns/dailyBudgetAmount'; + $data = array('id' => $campaignId, 'dailyBudgetAmount' => $dailyBudgetAmount); + $campaign = $this->db->getCampaignById($campaignId); + if ($campaign['ad_account_id']) $this->ad_account_id = $campaign['ad_account_id']; + $result = $this->getCall($request, NULL, $data, 'PUT', true); + return $result; + } + + public function setCampaign($param = [], $adAccountId = '') + { //2. 캠페인 수정하기 + $request = 'campaigns'; + if (!isset($param['id']) || !$param['id']) + return $this->fail("캠페인 아이디를 지정해주십시오."); + if ($adAccountId) + $this->ad_account_id = $adAccountId; + else { + $campaign = $this->db->getCampaignById($param['id']); + if ($campaign['ad_account_id']) $this->ad_account_id = $campaign['ad_account_id']; + } + $data = $this->getCampaign($param['id'], $this->ad_account_id); + if (isset($data['trackId'])) + $param['trackId'] = $data['trackId']; + if (isset($data['dailyBudgetAmount'])) + $param['dailyBudgetAmount'] = $data['dailyBudgetAmount']; + $result = $this->getCall($request, NULL, $param, 'PUT'); + if ($result['id'] == $param['id']) + $this->db->setCampaign($param); + return $result; + } + + public function updateCampaigns() + { //전체 캠페인 업데이트 + try { + $accounts = $this->db->getAdAccounts(); + $total = $accounts->getNumRows(); + CLI::write("[".date("Y-m-d H:i:s")."]"."{$total}개 계정의 캠페인 수신을 시작합니다.", "light_red"); + foreach ($accounts->getResultArray() as $account) { + $campaignList = $this->getCampaigns($account['id']); + if (isset($campaignList['content']) && count($campaignList['content']) > 0) { + $step = 1; + $total = count($campaignList['content']); + $i = 0; + CLI::write("[".date("Y-m-d H:i:s")."]"."{$account['name']} 계정의 캠페인 수신을 시작합니다.", "light_red"); + foreach ($campaignList['content'] as $row) { + CLI::showProgress($step++, $total); + if ($row['id'] && $row['config'] != 'DEL') { + $campaign = $this->getCampaign($row['id']); + $data[$account['id']][$i] = $campaign; + if (isset($campaign['extras']) && $campaign['extras']['detailCode'] == '31001') { + $delete = ['id' => $row['id'], 'config' => 'DEL']; + $this->db->setCampaign($delete); + continue; + //echo "{$account['id']} - 캠페인({$row['id']}) : 삭제" . PHP_EOL; + } + if(isset($row['type'])) $data[$account['id']][$i]['type'] = $row['type']; + $i++; + } else if ($row['config'] == 'DEL') { + $delete = ['id' => $row['id'], 'config' => 'DEL']; + $this->db->setCampaign($delete); + continue; + //echo "{$account['id']} - 캠페인({$row['id']}) : 삭제" . PHP_EOL; + } + } + } + } + // echo '
'.print_r($data,1).'
'; + $this->db->updateCampaigns($data); + $msgs = [ + 'channel' => $this->slackChannel, + 'text' => "[".date("Y-m-d H:i:s")."][" . getenv('MY_SERVER_NAME') . "][카카오][캠페인] 수신 완료", + ]; + $this->slack->sendMessage($msgs); + return $data; + } catch (Exception $ex) { + $msgs = [ + 'channel' => $this->slackChannel, + 'text' => "[".date("Y-m-d H:i:s")."][" . getenv('MY_SERVER_NAME') . "][카카오][캠페인] 수신 오류 : " . $ex->getMessage(), + ]; + $this->slack->sendMessage($msgs); + } + } + + public function getCampaignStatusBudget($campaignId) + { + $request = "campaigns/{$campaignId}"; + $campaign = $this->db->getCampaignById($campaignId); + if ($campaign['ad_account_id']) $this->ad_account_id = $campaign['ad_account_id']; + $result = $this->getCall($request, '', '', 'GET', true); + $data = [ + 'id' => $result['id'], + 'status' => $result['config'], + 'budget' => $result['dailyBudgetAmount'] + ]; + return $data; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /* 3. 광고그룹 */ + + public function getAdGroups($campaignId = '', $adAccountId = '') + { //3.1. 광고그룹 리스트 조회 + $request = 'adGroups'; + $param = array('campaignId' => $campaignId, 'config' => 'ON,OFF,DEL'); + if ($adAccountId) $this->ad_account_id = $adAccountId; + $result = $this->getCall($request, $param, '', 'GET', false); + return $result; //Array ( [id] => 35443 [name] => 3514 [type] => DISPLAY [userConfig] => ON ) + } + + public function getAdGroup($adGroupId, $adAccountId = '') + { //3.2. 광고그룹 조회 + $request = "adGroups/{$adGroupId}"; + if ($adAccountId) $this->ad_account_id = $adAccountId; + $result = $this->getCall($request, '', '', 'GET', false); + // echo '
'.print_r($result,1).'
'; exit; + return $result; //Array ( [id] => 35443 [name] => 3514 [pricingType] => CPC [pacing] => QUICK [bidStrategy] => MANUAL [dailyBudgetAmount] => 100000 [bidAmount] => 200 [config] => ON [isDailyBudgetAmountOver] => [isValidPeriod] => 1 [statusDescription] => 운영중 ) + } + + + public function setAdGroupOnOff($adGroupId = '', $config = 'ON', $adAccountId = '') + { //3.3. 광고그룹 ON/OFF 수정 + $request = 'adGroups/onOff'; + $data = array('id' => $adGroupId, 'config' => $config); + $adAccountId = $this->db->getAdAccountIdByAdGroupId($adGroupId); + if ($adAccountId) $this->ad_account_id = $adAccountId; + $result = $this->getCall($request, NULL, $data, 'PUT'); + if ($result['http_code'] == 200) + $this->db->setAdGroupOnOff($adGroupId, $config); + return $result; + } + + public function setAdGroup($param = [], $adAccountId = '') + { //3. 광고그룹 수정하기 + $request = 'adGroups'; + if (!isset($param['id']) || !$param['id']) + return $this->fail("광고그룹 아이디를 지정해주십시오."); + if ($adAccountId) + $this->ad_account_id = $adAccountId; + else { + $adAccountId = $this->db->getAdAccountIdByAdGroupId($param['id']); + if ($adAccountId) $this->ad_account_id = $adAccountId; + } + $adGroup = $this->getAdGroup($param['id'], $this->ad_account_id); + // echo '
'.print_r($adGroup,1).'
'; + if (empty($adGroup['deviceTypes']) && $adGroup['allAvailableDeviceType']) $deviceTypes = ['ANDROID', 'IOS', 'PC']; + else $deviceTypes = $adGroup['deviceTypes']; + $ag = [ + 'campaign' => $adGroup['campaign'], 'placements' => $adGroup['placements'], 'allAvailableDeviceType' => $adGroup['allAvailableDeviceType'], 'allAvailablePlacement' => $adGroup['allAvailablePlacement'], 'deviceTypes' => $deviceTypes, 'targeting' => $adGroup['targeting'], 'adult' => $adGroup['adult'], 'dailyBudgetAmount' => $adGroup['dailyBudgetAmount'], 'bidStrategy' => $adGroup['bidStrategy'], 'pricingType' => $adGroup['pricingType'], 'smartMessage' => $adGroup['smartMessage'], 'bidAmount' => $adGroup['bidAmount'], 'pacing' => ($adGroup['pacing'] ? $adGroup['pacing'] : 'NONE'), 'schedule' => $adGroup['schedule'] + ]; + + if (isset($adGroup['adServingCategories'])) + $ag['adServingCategories'] = $adGroup['adServingCategories']; + if (isset($adGroup['messageSendingInfo'])) + $ag['messageSendingInfo'] = $adGroup['messageSendingInfo']; + $data = array_merge($param, $ag); + $result = $this->getCall($request, NULL, $data, 'PUT'); + if ($result['id'] == $param['id']) + $this->db->setAdGroup($param); + return $result; + } + + public function setAdGroupsAiRun() + { //광고그룹 AI 실행 예산수정 aiConfig2 - Ai 2 + $adGroups = $this->db->getAdGroups(['ON'], " AND aiConfig2 = 'ON'"); + $step = 1; + $total = $adGroups->getNumRow(); + CLI::write("[".date("Y-m-d H:i:s")."]"."광고그룹 AI 업데이트를 시작합니다.", "light_red"); + foreach ($adGroups->getResultArray() as $adGroup) { + CLI::showProgress($step++, $total); + $rs = ['budget'=>'예산변경 대상 아님', 'bid'=>'입찰가변경 대상 아님']; + echo '['.$adGroup['account_name']. '][' .$adGroup['id'] . ']' . $adGroup['name'] . '/'; + $adAccountId = $adGroup['ad_account_id']; + if ($adAccountId) $this->ad_account_id = $adAccountId; + // $result = $adGroup['id']; + if ($adGroup['dailyBudgetAmount'] >= 200000) { //그룹예산 변경 + $data = ['id' => $adGroup['id'], 'budget' => 200000, 'type' => 'adgroup']; + $result = $this->setDailyBudgetAmount($data); + if($result == $adGroup['id']) { + $rs['budget'] = '예산변경 성공'; + } else { + $rs['budget'] = '예산변경 실패'; + } + sleep(1); + } + $bidAmount = ""; + if($adGroup['bidStrategy'] != 'AUTOBID') { //그룹 입찰가 변경 + $bidAmount = $adGroup['bidAmount']; + if($adGroup['bidAmount'] >= 750) { //현재 입찰가에서 200원 낮춰서 적용 + $bidAmount -= 200; + } else if($adGroup['bidAmount'] >= 650) { //현재 입찰가에서 150원 낮춰서 적용 + $bidAmount -= 150; + } else if($adGroup['bidAmount'] >= 500) { //현재 입찰가에서 100원 낮춰서 적용 + $bidAmount -= 100; + } else if($adGroup['bidAmount'] >= 180) { //현재 입찰가에서 50원 낮춰서 적용 + $bidAmount -= 50; + } + if($bidAmount >= 130 && $adGroup['bidAmount'] >= 180) { //수정 입찰가가 400원 이상이고, 최초 입찰가가 500원 이상일 때 + $result = $this->setAdGroupBidAmount($adGroup['id'], $bidAmount, $adAccountId); + if($result == $adGroup['id']) { //수정 성공 + $rs['bid'] = '입찰가변경 성공'; + } else { + $rs['bid'] = '입찰가변경 실패'; + } + } + sleep(1); + } + ob_flush(); + flush(); + echo @number_format($adGroup['dailyBudgetAmount']) . ' - ' . $rs['budget'] . '
' . PHP_EOL; + echo @number_format($adGroup['bidAmount']).'>'.@number_format($bidAmount) . ' - ' . $rs['bid'] . '

' . PHP_EOL; + } + } + + + private function setAdGroupDailyBudgetAmount($adGroupId = '', $dailyBudgetAmount = '10000') + { //3.5. 광고그룹 일예산 수정 + $request = 'adGroups/dailyBudgetAmount'; + $data = array('id' => $adGroupId, 'dailyBudgetAmount' => $dailyBudgetAmount); + $adAccountId = $this->db->getAdAccountIdByAdGroupId($adGroupId); + if ($adAccountId) $this->ad_account_id = $adAccountId; + $result = $this->getCall($request, NULL, $data, 'PUT'); + return $result; + } + + + public function setAdGroupBidAmount($adGroupId = '', $bidAmount = '10000', $adAccountId = '') + { //3.6. 광고그룹 최대 입찰금액 수정 + $request = 'adGroups/bidAmount'; + $data = array('id' => $adGroupId, 'bidAmount' => $bidAmount); + $adAccountId = $this->db->getAdAccountIdByAdGroupId($adGroupId); + if ($adAccountId) $this->ad_account_id = $adAccountId; + $result = $this->getCall($request, NULL, $data, 'PUT'); + if ($result['http_code'] == 200) { + $this->db->setAdGroupBidAmount($adGroupId, $bidAmount); + $result = $adGroupId; + } + return $result; + } + + + public function updateAdGroups() + { //전체 광고그룹 업데이트 + try { + $campaigns = $this->db->getCampaigns(["ON", "OFF"]); + $total = $campaigns->getNumRows(); + $step = 1; + CLI::write("[".date("Y-m-d H:i:s")."]"."{$total}개 캠페인의 광고그룹 수신을 시작합니다.", "light_red"); + $result = []; + foreach ($campaigns->getResultArray() as $campaign) { + CLI::showProgress($step++, $total); + //echo "{$campaign['id']}
"; + $adGroupList = $this->getAdGroups($campaign['id'], $campaign['ad_account_id']); + if (isset($adGroupList['content']) && count($adGroupList['content'])) { + $i = 0; + // $groupStep = 1; + // $groupTotal = count($adGroupList['content']); + // CLI::write("[".date("Y-m-d H:i:s")."]"."{$campaign['name']} 캠페인의 {$groupTotal}개 광고그룹을 수신중입니다.", "light_red"); + // CLI::newLine(); + $data = []; + foreach ($adGroupList['content'] as $row) { + // CLI::showProgress($groupStep++, $groupTotal); + if ($row['id'] && $row['config'] != 'DEL') { //echo $row['id'].'
'; + $adgroup = $this->getAdGroup($row['id']); + $data[$campaign['id']][$i] = $adgroup; + if (isset($adgroup['extras']) && $adgroup['extras']['detailCode'] == '32026') { + $delete = ['id' => $row['id'], 'config' => 'DEL']; + $this->db->setAdgroup($delete); + // CLI::write("[".date("Y-m-d H:i:s")."] {$campaign['ad_account_id']} - 광고그룹({$row['id']}) : 삭제"); + // CLI::newLine(); + continue; + //echo "{$campaign['ad_account_id']} - 광고그룹({$row['id']}) : 삭제" . PHP_EOL; + } + + /* if(!isset($adgroup['totalBudget'])) + $data[$campaign['id']][$i]['totalBudget'] = null; + if(!isset($adgroup['useMaxAutoBidAmount'])) + $data[$campaign['id']][$i]['useMaxAutoBidAmount'] = null; + if(!isset($adgroup['autoMaxBidAmount'])) + $data[$campaign['id']][$i]['autoMaxBidAmount'] = null; + if(!isset($adgroup['pacing'])) + $data[$campaign['id']][$i]['pacing'] = null; + if(!isset($adgroup['dailyBudgetAmount'])) + $data[$campaign['id']][$i]['dailyBudgetAmount'] = null; + if(!isset($adgroup['statusDescription'])) + $data[$campaign['id']][$i]['statusDescription'] = null; + if(!isset($adgroup['type'])) + $data[$campaign['id']][$i]['type'] = null; */ + + $i++; + } else if ($row['config'] == 'DEL') { + $delete = ['id' => $row['id'], 'config' => 'DEL']; + $this->db->setAdgroup($delete); + // CLI::write("[".date("Y-m-d H:i:s")."] {$campaign['ad_account_id']} - 광고그룹({$row['id']}) : 삭제"); + // CLI::newLine(); + continue; + //echo "{$campaign['ad_account_id']} - 광고그룹({$row['id']}) : 삭제" . PHP_EOL; + } + + $this->db->updateAdGroups($data); + } + $result = array_merge($result, $data); + } else { + print_r($adGroupList); exit; + } + } + //echo '
'.print_r($data,1).'
'; + $msgs = [ + 'channel' => $this->slackChannel, + 'text' => "[".date("Y-m-d H:i:s")."][" . getenv('MY_SERVER_NAME') . "][카카오][광고그룹] 수신 완료", + ]; + $this->slack->sendMessage($msgs); + return $result; + } catch (Exception $ex) { + $msgs = [ + 'channel' => $this->slackChannel, + 'text' => "[".date("Y-m-d H:i:s")."][" . getenv('MY_SERVER_NAME') . "][카카오][광고그룹] 수신 오류 : " . $ex->getMessage(), + ]; + $this->slack->sendMessage($msgs); + } + } + + public function getAdgroupStatusBudget($adgroupId) + { + $request = "adGroups/{$adgroupId}"; + $adAccountId = $this->db->getAdAccountIdByAdGroupId($adgroupId); + if ($adAccountId) $this->ad_account_id = $adAccountId; + $result = $this->getCall($request, '', '', 'GET', false); + $data = [ + 'id' => $result['id'], + 'status' => $result['config'], + 'budget' => $result['dailyBudgetAmount'] + ]; + return $data; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /* 4. 소재 */ + + public function getCreatives($adGroupId, $adAccountId = '') + { //4.1. 소재 리스트 조회 + $request = 'creatives'; + $param = array('adGroupId' => $adGroupId, 'config' => 'ON,OFF,DEL'); + if ($adAccountId) $this->ad_account_id = $adAccountId; + $result = $this->getCall($request, $param); + return $result; //Array ( [id] => 716600 [name] => 3514 [type] => DISPLAY [config] => ON ) + } + + + public function getCreative($creativeId, $adAccountId = '') + { //4.2. 소재 조회 + $request = "creatives/{$creativeId}"; + if ($adAccountId) $this->ad_account_id = $adAccountId; + $result = $this->getCall($request, '', '', 'GET', true); + return $result; //Array ( [id] => 716600 [creativeId] => 1470241 [name] => 3514 [format] => THUMBNAIL_FEED [bidAmount] => 130 [landingUrl] => http://hotevent.hotblood.co.kr/index.php/app_3514 [frequencyCap] => 2 [config] => ON [reviewStatus] => APPROVED [modifyReviewStatus] => NONE [statusDescription] => 운영중 ) + } + + + public function setCreativeOnOff($creativeId, $config = 'ON') + { //4.3. 소재 ON/OFF + $request = 'creatives/onOff'; + $data = array('id' => $creativeId, 'config' => $config); + $adAccountId = $this->db->getAdAccountIdByCreativeId($creativeId); + if ($adAccountId) $this->ad_account_id = $adAccountId; + $result = $this->getCall($request, NULL, $data, 'PUT'); + if ($result['http_code'] == 200) + $this->db->setCreativeOnOff($creativeId, $config); + sleep(1); + return $result; + } + + public function setCreative($param = [], $adAccountId = '') + { // 소재 수정하기 + $request = 'creatives'; + if (!isset($param['id']) || !$param['id']) $this->error('소재 아이디를 지정해주십시오.'); + if ($adAccountId) + $this->ad_account_id = $adAccountId; + else { + $adAccountId = $this->db->getAdAccountIdByCreativeId($param['id']); + if ($adAccountId) $this->ad_account_id = $adAccountId; + } + + $creative = $this->getCreative($param['id'], $this->ad_account_id); + + // echo '
' . print_r($creative, 1) . '
'; + $cv = [ + 'adGroupId' => $creative['adGroupId'], 'format' => $creative['format'] + ]; + + if($creative['format'] == 'IMAGE_NATIVE'){ + if(isset($creative['title'])) + $cv['title'] = $creative['title']; + + if(isset($creative['profileName'])) + $cv['profileName'] = $creative['profileName']; + + if(isset($creative['description'])) + $cv['description'] = $creative['description']; + + if(isset($creative['actionButton'])) + $cv['actionButton'] = $creative['actionButton']; + } + + if(isset($creative['altText'])) + $cv['altText'] = $creative['altText']; + if($creative['landingInfo']['landingType'] == 'BIZ_FORM') { + $cv['landingInfo']['landingType'] = $creative['landingInfo']['landingType']; + $cv['landingInfo']['bizFormId'] = $creative['landingInfo']['bizFormId']; + } else { + if(isset($creative['pcLandingUrl'])) + $cv['pcLandingUrl'] = $creative['pcLandingUrl']; + if(isset($creative['mobileLandingUrl'])) + $cv['mobileLandingUrl'] = $creative['mobileLandingUrl']; + if(isset($creative['rspvLandingUrl'])) + $cv['rspvLandingUrl'] = $creative['rspvLandingUrl']; + } + if (isset($creative['messageElement'])) + $cv['messageElement'] = $creative['messageElement']; + + $data = array_merge($param, $cv); + $result = $this->getCall($request, NULL, $data, 'PUT', true); + + if ($result['id'] == $param['id']) + $this->db->setCreative($param); + return $result; + } + + public function updateCreatives() + { //전체 소재 업데이트 + try { + $adgroups = $this->db->getAdGroups(["ON", "OFF"]); + $step = 1; + $total = count($adgroups->getResult()); + CLI::write("[".date("Y-m-d H:i:s")."]"."소재 수신을 시작합니다.", "light_red"); + $result = []; + foreach ($adgroups->getResultArray() as $adgroup) { + CLI::showProgress($step++, $total); + // echo "

{$adgroup['id']}, {$adgroup['ad_account_id']}

"; + $creativeList = $this->getCreatives($adgroup['id'], $adgroup['ad_account_id']); + // echo '
'.print_r($creativeList,1).'
'; + if (count($creativeList) > 0) { + $i = 0; + foreach ($creativeList as $lists) { + $data = []; + foreach ($lists as $row) { + if ($row['id'] && $row['config'] != 'DEL') { + $creative = $this->getCreative($row['id']); + $data[$adgroup['id']][$i] = $creative; + if (isset($creative['extras']) && $creative['extras']['detailCode'] == '33003') { + $delete = ['id' => $row['id'], 'config' => 'DEL']; + $this->db->setCreative($delete); + continue; + //echo "{$adgroup['ad_account_id']} - 소재({$row['id']}) : 삭제" . PHP_EOL; + } + $data[$adgroup['id']][$i]['type'] = $row['type']??""; + //landingUrl 필드 삭제 변경으로 인한 패치 + if (isset($creative['pcLandingUrl'])) + $data[$adgroup['id']][$i]['landingUrl'] = $data[$adgroup['id']][$i]['pcLandingUrl']; + if (isset($creative['mobileLandingUrl'])) + $data[$adgroup['id']][$i]['landingUrl'] = $data[$adgroup['id']][$i]['mobileLandingUrl']; + if (isset($creative['rspvLandingUrl'])) + $data[$adgroup['id']][$i]['landingUrl'] = $data[$adgroup['id']][$i]['rspvLandingUrl']; + if(!isset($row['bidAmount'])) + $data[$adgroup['id']][$i]['bidAmount'] = null; + if(!isset($row['altText'])) + $data[$adgroup['id']][$i]['altText'] = null; + if(!isset($row['hasExpandable'])) + $data[$adgroup['id']][$i]['hasExpandable'] = 0; + if(!isset($row['frequencyCap'])) + $data[$adgroup['id']][$i]['frequencyCap'] = null; + if(!isset($row['frequencyCapType'])) + $data[$adgroup['id']][$i]['frequencyCapType'] = null; + if(!isset($row['reviewStatus'])) + $data[$adgroup['id']][$i]['reviewStatus'] = null; + if(!isset($data[$adgroup['id']][$i]['landingUrl'])) + $data[$adgroup['id']][$i]['landingUrl'] = null; + $i++; + } else if ($row['config'] == 'DEL') { + $delete = ['id' => $row['id'], 'config' => 'DEL']; + $this->db->setCreative($delete); + continue; + //echo "{$adgroup['ad_account_id']} - 소재({$row['id']}) : 삭제" . PHP_EOL; + } + } + $this->db->updateCreatives($data); + $result = array_merge($result, $data); + } + } + } + + $msgs = [ + 'channel' => $this->slackChannel, + 'text' => "[".date("Y-m-d H:i:s")."][" . getenv('MY_SERVER_NAME') . "][카카오][소재] 수신 완료", + ]; + $this->slack->sendMessage($msgs); + return $result; + } catch (Exception $ex) { + $msgs = [ + 'channel' => $this->slackChannel, + 'text' => "[".date("Y-m-d H:i:s")."][" . getenv('MY_SERVER_NAME') . "][카카오][소재] 수신 오류 : " . $ex->getMessage(), + ]; + $this->slack->sendMessage($msgs); + } + } + + public function getAdStatusBudget($creativeId) + { + $request = "creatives/{$creativeId}"; + $adAccountId = $this->db->getAdAccountIdByCreativeId($creativeId); + if ($adAccountId) $this->ad_account_id = $adAccountId; + $result = $this->getCall($request, '', '', 'GET', false); + $data = [ + 'id' => $result['id'], + 'status' => $result['config'], + ]; + return $data; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /* 5. 보고서 */ + + public function getAdGroupReport($adGroupId, $level = 'AD_GROUP', $datePreset = 'TODAY', $dimension = 'CREATIVE_FORMAT', $metrics = 'BASIC') + { //5.3. 광고그룹 보고서 조회 + $request = 'adGroups/report'; + $param = array('adGroupId' => $adGroupId, 'level' => $level); + if (preg_match('/^[A-Z]+/', $datePreset)) + $param['datePreset'] = $datePreset; + else { + $date = preg_replace('/[^0-9]+/', '', $datePreset); + $param['start'] = $date; + $param['end'] = $date; + } + if ($dimension) + $param['dimension'] = $dimension; + if ($metrics) + $param['metricsGroup'] = $metrics; + $result = $this->getCall($request, $param); + return $result; + } + + + private function getCreativeReport($creativeId, $datePreset = 'TODAY', $dimension = 'CREATIVE_FORMAT', $metrics = 'BASIC') + { //5.4. 소재 보고서 조회 //3034514 + $request = 'creatives/report'; + $param = array('creativeId' => $creativeId); + if (preg_match('/^[A-Z]+/', $datePreset)) + $param['datePreset'] = $datePreset; + else { + $date = preg_replace('/[^0-9]+/', '', $datePreset); + $param['start'] = $date; + $param['end'] = $date; + } + if ($dimension) + $param['dimension'] = $dimension; + if ($metrics) + $param['metricsGroup'] = $metrics; + if(!$this->ad_account_id) $adAccountId = $this->db->getAdAccountIdByCreativeId($creativeId); + if(isset($adAccountId)) $this->ad_account_id = $adAccountId; + ob_flush();flush();sleep(5); + $result = $this->getCall($request, $param); + return $result; + } + + + public function updateBizform() + { + try { + require __DIR__ . '/bizformapi.php'; + new ChainsawKMBF(); + $msgs = [ + 'channel' => $this->slackChannel, + 'text' => "[".date("Y-m-d H:i:s")."][" . getenv('MY_SERVER_NAME') . "][카카오][잠재고객] 수신 완료", + ]; + $this->slack->sendMessage($msgs); + } catch (Exception $ex) { + $msgs = [ + 'channel' => $this->slackChannel, + 'text' => "[".date("Y-m-d H:i:s")."][" . getenv('MY_SERVER_NAME') . "][카카오][잠재고객] 수신 오류 : " . $ex->getMessage(), + ]; + $this->slack->sendMessage($msgs); + } + } + + + /* public function moveToLeads() + { //잠재고객 > event_leads 테이블로 이동 + $ads = $this->db->getBizFormUserResponse(); + $total = $ads->getNumRows(); + $step = 1; + if (!$total) { + return null; + } + CLI::write("[".date("Y-m-d H:i:s")."]"."event_leads 데이터 업데이트를 시작합니다.", "light_red"); + foreach ($ads->getResultArray() as $row) { + CLI::showProgress($step++, $total); + if (!empty($row['code'])) { + $title = trim($row['code']); + }else{ + $title = $row['name']; + } + $landing = $this->landingGroup($title, $row['landingUrl'] ?? ''); + if(is_null($landing)) { + echo '비즈폼 매칭 오류 발생 :
' . print_r($row, 1) . '
'; + continue; + } + //전화번호 + $phone = str_replace("+82010", "010", $row['phoneNumber']); + $phone = str_replace("+8210", "010", $phone); + $phone = preg_replace("/^8210(.+)$/", "010$1", $phone); + $phone = str_replace("+82 10", "010", $phone); + $phone = str_replace("-", "", $phone); + if ($row['email'] == '없음') $row['email'] = ''; + + //추가질문 + $questions = []; + $add = []; + $addr = $add1 = $add2 = $add3 = $add4 = $add5 = null; + $responses = json_decode($row['responses'], 1); + $acnt = 1; + foreach ($responses as $response) { + $qs = $this->db->getBizformQuestion($row['bizFormId'], $response['bizformItemId']); + if(is_null($qs)) continue; + if(!key_exists($qs['id'], $questions)) + $questions[$qs['id']] = $qs['title']; + $add[] = ${'add' . $acnt} = $questions[$response['bizformItemId']] . '::' . $response['response']; + $acnt++; + } + $result = []; + if ($landing['media']) { + $result['event_seq'] = $landing['event_seq']; + $result['site'] = $landing['site']??null; + $result['name'] = $row['nickname']; + $result['email'] = $row['email']??''; + $result['gender'] = $row['gender']??null; + $result['age'] = $row['age']??null; + $result['phone'] = $phone; + $result['add1'] = $add1; + $result['add2'] = $add2; + $result['add3'] = $add3; + $result['add4'] = $add4; + $result['add5'] = $add5; + $result['addr'] = $addr; + $result['reg_timestamp'] = strtotime($row['submitAt']); + $result['lead_id'] = $row['id']??null; + $result['encUserId'] = $row['encUserId']; + $result['bizFormId'] = $row['bizFormId']; + } + + if (is_array($result) && count($result)) { + $this->db->insertToLeads($result); + } + + // return $result; + } + } */ + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + public function updateCreativesReportBasic($datePreset = 'TODAY', $dimension = 'CREATIVE_FORMAT', $metrics = 'BASIC') + { //전체 소재 보고서 BASIC 업데이트 + $adgroups = $this->db->getAdGroups(['ON', 'OFF'], "ORDER BY B.ad_account_id DESC"); + $cnt = 1; + $step = 1; + $ids = []; + $this->ad_account_id = ''; + $total = $adgroups->getNumRows(); + CLI::write("[".date("Y-m-d H:i:s")."]"."{$total}개 광고그룹의 소재 보고서 수신을 시작합니다.", "light_red"); + $result = []; + foreach ($adgroups->getResultArray() as $adgroup) { + $new_ids = []; + if (!$this->ad_account_id) + $this->ad_account_id = $adgroup['ad_account_id']; + if ($adgroup['id']) { + if ($this->ad_account_id == $adgroup['ad_account_id']) + $ids[] = $adgroup['id']; + else { + $new_ids[] = $adgroup['id']; + } + } + CLI::showProgress($step++, $total); + // echo '

'.date('[H:i:s] ').$this->ad_account_id.','.$adgroup['ad_account_id'].'

'; + // echo '

'.$cnt.'

'; + if (count($ids) == 20 || $this->ad_account_id != $adgroup['ad_account_id'] || $adgroups->getNumRows() == $cnt) { + $adgroup_ids = implode(",", $ids); + // echo '

'.$adgroup_ids.'

'; + $data = []; + $report = $this->getAdGroupReport($adgroup_ids, 'CREATIVE', $datePreset, $dimension, $metrics); + if ($report['message'] == 'Success' && count($report['data']) > 0) { + $i = 0; + foreach ($report['data'] as $row) { + if (count($row['metrics'])) { + $data[$row['dimensions']['creative_id']][$i] = $row['metrics']; + $data[$row['dimensions']['creative_id']][$i]['cost'] = $row['metrics']['cost']; //부가세 제거 + $data[$row['dimensions']['creative_id']][$i]['date'] = $row['start']; + $i++; + } + } + } + $ids = $new_ids; + $this->ad_account_id = $adgroup['ad_account_id']; + ob_flush(); + flush(); + sleep(5); + $this->db->updateCreativesReportBasic($data); + $result = array_merge($result, $data); + } + $cnt++; + } + + return $result; + } + + public function updateHourReportBasic($datePreset = 'TODAY', $dimension = 'HOUR', $metrics = 'BASIC') + { //소재별 보고서 BASIC 업데이트 + try { + $startTime = microtime(true); // 시작 시간 기록 + + $creatives = $this->db->getCreatives(['ON', 'OFF']); + $cnt = 1; + $step = 1; + $result = []; + $_tmp = []; + foreach($creatives->getResultArray() as $creative) $_tmp[$creative['ad_account_id']][] = $creative['id']; + foreach($_tmp as $account_id => $row) $lists[$account_id] = array_chunk($row, 100); + $total = $creatives->getNumRows(); + CLI::write("[".date("Y-m-d H:i:s")."]"."{$total}개 소재 보고서 수신을 시작합니다.", "light_red"); + foreach($lists as $account_id => $list) { + $this->ad_account_id = $account_id; + $data = []; + $i = 0; + foreach($list as $ids) { + $step += @count($ids); + CLI::showProgress($step, $total); + $creative_ids = implode(",", $ids); + $report = $this->getCreativeReport($creative_ids, $datePreset, $dimension, $metrics); + if (isset($report['message']) && $report['message'] == 'Success' && isset($report['data'])) { + foreach ($report['data'] as $row) { + if (count($row['metrics'])) { + $data[$row['dimensions']['creative_id']][$i] = $row['metrics']; + $data[$row['dimensions']['creative_id']][$i]['hour'] = preg_replace('/^([0-9]{2}).+$/', '$1', $row['dimensions']['hour']); + $data[$row['dimensions']['creative_id']][$i]['cost'] = $row['metrics']['cost']; //부가세 제거 + $data[$row['dimensions']['creative_id']][$i]['date'] = $row['start']; + $i++; + } + } + } + } + $this->ad_account_id = $creative['ad_account_id']; + $this->db->updateCreativesReportBasic($data); + $result = array_merge($result, $data); + } + $endTime = microtime(true); // 종료 시간 기록 + $executionTime = round($endTime - $startTime, 2); // 실행 시간 계산 + + $msgs = [ + 'channel' => $this->slackChannel, + 'text' => "[".date("Y-m-d H:i:s")."][" . getenv('MY_SERVER_NAME') . "][카카오][보고서] {$datePreset} 수신 완료 (실행 시간: {$executionTime}초)", + ]; + $this->slack->sendMessage($msgs); + return $result; + } catch (Exception $ex) { + $msgs = [ + 'channel' => $this->slackChannel, + 'text' => "[".date("Y-m-d H:i:s")."][" . getenv('MY_SERVER_NAME') . "][카카오][보고서] {$datePreset} 수신 오류 : " . $ex->getMessage(), + ]; + $this->slack->sendMessage($msgs); + } + } + + + public function autoAiOn() { + $adgroups = $this->db->getInitCreatives(); + $step = 1; + $total = $adgroups->getNumRows(); + CLI::write("[".date("Y-m-d H:i:s")."]"."AI를 시작합니다.", "light_red"); + if(!$total) return; + foreach ($adgroups->getResultArray() as $adgroup) { + CLI::showProgress($step++, $total); + if($adgroup['report_date'] == date('Y-m-d') && $adgroup['report_update_time'] == '0000-00-00 00:00:00') { + $aiData = [ + 'campaign_id' => $adgroup['campaign_id'], + 'adgroup_id' => $adgroup['adgroup_id'] + ]; + $this->db->allAiOn($aiData); + echo "
[[[[[[[[[[Ai ON]]]]]]]]]]".PHP_EOL; + } + echo "[{$adgroup['account_name']}] 캠페인:{$adgroup['campaign_name']}({$adgroup['campaign_id']})/광고그룹:{$adgroup['adgroup_name']}({$adgroup['adgroup_id']})/report-{$adgroup['report_update_time']}[{$adgroup['report_date']}]/type-{$adgroup['campaign_type']}".PHP_EOL; + } + } + + + public function autoCreativeOnOff($onoff='on') { + /* + 1. 디비 0개 소재명의 디비단가 소진 > 해당 소재 off 익일 00시 on + 2. 디비 1개 이상 0% 이하 > 해당 소재 off 익일 00시 on + */ + $creatives = $this->db->getAutoCreativeOnOff($onoff); + $step = 1; + $total = $creatives->getNumRows(); + if(!$total) return; + if($onoff=='on') $set = 'off'; + else $set = 'on'; + CLI::write("[".date("Y-m-d H:i:s")."]"."소재 자동 변경을 시작합니다.", "light_red"); + foreach ($creatives->getResultArray() as $creative) { + CLI::showProgress($step++, $total); + if(!is_null($creative['aitype']) && strtolower($creative['creative_config']) == strtolower($onoff)) { + // echo '
'.print_r($creative,1).'
'; + // $result['http_code'] = 200; + $result = $this->setCreativeOnOff($creative['id'], strtoupper($set)); + if($result['http_code'] == 200) { + $this->db->insertCreativeAutoOnOff($creative, $set); + echo "[{$creative['id']}]{$creative['creative_name']}-CASE:{$creative['aitype']}-상태 {$set} 성공".PHP_EOL; + } + } + } + } + + public function updateReportByDate($sdate = null, $edate = null) + { //이미 입력된 리포트데이터를 다시 업데이트 함 + if (is_null($sdate) || is_null($edate)) + return false; + $creatives = $this->db->getCreativeReportBasic("AND report.date BETWEEN '{$sdate}' AND '{$edate}' ORDER BY report.date ASC"); + $total = $creatives->getNumRows(); + if (!$total) return null; + $i = 0; + $cnt = 1; + CLI::write("[".date("Y-m-d H:i:s")."]"."{$sdate}~{$edate} 리포트데이터 수신을 시작합니다.", "light_red"); + $result = []; + foreach ($creatives->getResultArray() as $row) { + $data = []; + CLI::showProgress($cnt++, $total); + $this->ad_account_id = $row['ad_account_id']; + if($row['date'] == date('Y-m-d')) $row['date'] = 'TODAY'; + $report = $this->getCreativeReport($row['id'], $row['date'], 'HOUR'); + if ($report['message'] == 'Success' && count($report['data']) > 0) { + // echo date('[H:i:s]') . " {$row['id']}/{$row['date']} 수신" . PHP_EOL; + foreach ($report['data'] as $v) { + if (count($v['metrics'])) { + $data[$v['dimensions']['creative_id']][$i] = $v['metrics']; + $data[$v['dimensions']['creative_id']][$i]['hour'] = preg_replace('/^([0-9]{2}).+$/', '$1', $v['dimensions']['hour']); + $data[$v['dimensions']['creative_id']][$i]['cost'] = $v['metrics']['cost']; + $data[$v['dimensions']['creative_id']][$i]['date'] = $v['start']; + $i++; + } + } + } + $this->db->updateCreativesReportBasic($data); + $result = array_merge($result, $data); + } + + return $result; + } + + public function setManualUpdate($campaigns) + { + if(!$campaigns){return false;} + foreach ($campaigns as $campaign) { + $campaignList = $this->getCampaign($campaign['id'], $campaign['ad_account_id']); + if ($campaignList['id'] && $campaignList['config'] != 'DEL') { + if (isset($campaignList['extras']) && $campaignList['extras']['detailCode'] == '31001') { + $delete = ['id' => $campaignList['id'], 'config' => 'DEL']; + $this->db->setCampaign($delete); + continue; + } + } else if ($campaignList['config'] == 'DEL') { + $delete = ['id' => $campaignList['id'], 'config' => 'DEL']; + $this->db->setCampaign($delete); + continue; + } + $result = $this->db->updateCampaign($campaignList); + if(!$result){return false;} + + $adGroupList = $this->getAdGroups($campaign['id'], $campaign['ad_account_id']); + if (isset($adGroupList['content']) && count($adGroupList['content'])) { + foreach ($adGroupList['content'] as $row) { + if ($row['id'] && $row['config'] != 'DEL') { + $adgroup = $this->getAdGroup($row['id']); + if (isset($adgroup['extras']) && $adgroup['extras']['detailCode'] == '32026') { + $delete = ['id' => $row['id'], 'config' => 'DEL']; + $this->db->setAdgroup($delete); + continue; + } + $adgroup['campaign_id'] = $adgroup['campaign']['id']; + if(!isset($row['totalBudget'])) + $adgroup['totalBudget'] = null; + if(!isset($row['useMaxAutoBidAmount'])) + $adgroup['useMaxAutoBidAmount'] = null; + if(!isset($row['autoMaxBidAmount'])) + $adgroup['autoMaxBidAmount'] = null; + if(!isset($row['pacing'])) + $adgroup['pacing'] = null; + if(!isset($row['dailyBudgetAmount'])) + $adgroup['dailyBudgetAmount'] = null; + if(!isset($row['statusDescription'])) + $adgroup['statusDescription'] = null; + if(!isset($row['type'])) + $adgroup['type'] = null; + } else if ($row['config'] == 'DEL') { + $delete = ['id' => $row['id'], 'config' => 'DEL']; + $this->db->setAdgroup($delete); + continue; + } + + $result = $this->db->updateAdGroup($adgroup); + if(!$result){return false;} + + $creativeList = $this->getCreatives($adgroup['id'], $campaign['ad_account_id']); + if (count($creativeList) > 0) { + foreach ($creativeList as $lists) { + foreach ($lists as $row) { + if ($row['id'] && $row['config'] != 'DEL') { + $creative = $this->getCreative($row['id']); + if (isset($creative['extras']) && $creative['extras']['detailCode'] == '33003') { + $delete = ['id' => $row['id'], 'config' => 'DEL']; + $this->db->setCreative($delete); + continue; + } + $creative['adgroup_id'] = $creative['adGroupId']; + $creative['type'] = $row['type'] ?? ''; + //landingUrl 필드 삭제 변경으로 인한 패치 + if (isset($creative['pcLandingUrl'])) + $creative['landingUrl'] = $creative['pcLandingUrl']; + if (isset($creative['mobileLandingUrl'])) + $creative['landingUrl'] = $creative['mobileLandingUrl']; + if (isset($creative['rspvLandingUrl'])) + $creative['landingUrl'] = $creative['rspvLandingUrl']; + if(!isset($row['bidAmount'])) + $creative['bidAmount'] = null; + if(!isset($row['altText'])) + $creative['altText'] = null; + if(!isset($row['hasExpandable'])) + $creative['hasExpandable'] = 0; + if(!isset($row['frequencyCap'])) + $creative['frequencyCap'] = null; + if(!isset($row['frequencyCapType'])) + $creative['frequencyCapType'] = null; + if(!isset($row['reviewStatus'])) + $creative['reviewStatus'] = null; + if(!isset($creative['landingUrl'])) + $creative['landingUrl'] = null; + } else if ($row['config'] == 'DEL') { + $delete = ['id' => $row['id'], 'config' => 'DEL']; + $this->db->setCreative($delete); + continue; + } + $result = $this->db->updateCreative($creative); + if(!$result){return false;} + } + } + } + } + } + } + + return true; + } + + public function landingGroup($title, $landingUrl = '') + { + if (empty($title)) return []; + preg_match_all('/(.+)?\#([0-9]+)?(\_([0-9]+))?([\s]+)?(\*([0-9]+)?)?([\s]+)?(\&([a-z]+))?([\s]+)?(\^([0-9]+))?/i', $title, $matches); + if (!empty($landingUrl) && preg_match("/hotblood\.co\.kr/i", $landingUrl)) { + $urls = parse_url($landingUrl); + parse_str($urls['query'], $urls['qs']); + $path = explode('/', $urls['path']); + $_event_id = explode('/', $urls['path']); + $event_id = @array_pop(preg_replace('/^([A-Z]{2})?([0-9]+)$/i', '$2', $_event_id)); + $site = $urls['qs']['site'] ?? ''; + } else { + $event_id = $matches[2][0] ?? ''; + $site = $matches[4][0] ?? ''; + } + if(@$urls['qs']['site'] != @$matches[4][0]) //제목 site값 우선 + $site = $matches[4][0]; + $media = ''; + if (isset($matches[10][0]) && $matches[10][0]) { + switch ($matches[10][0]) { + case 'ker': $media = '이벤트'; break; + case 'kercpm': $media = '이벤트_cpm'; break; + case 'ber':$media = '이벤트 비즈폼'; break; + case 'bercpm': $media = '이벤트 비즈폼_cpm';break; + case 'cpm': $media = 'cpm'; break; + default: $media = '';break; + } + } + + if ($media) { + $period_ad = isset($matches[13][0]) && $matches[13][0] ? $matches[13][0] : 0; + $result['name'] = $matches[0][0]; + $result['media'] = $media; + $result['event_seq'] = $event_id; + $result['site'] = $site; + $result['db_price'] = $matches[7][0]; + $result['period_ad'] = $period_ad; + $result['url'] = $landingUrl??null; + return $result; + } + return []; + } + + public function getCreativesUseLanding($date = null) + { //유효DB 개수 업데이트 + if ($date == null) { + $date = date('Y-m-d'); + } else { + $date = date('Y-m-d', strtotime($date)); + } + $creatives = $this->db->getAdLeads($date); + $step = 1; + $total = $creatives->getNumRows(); + if(!$total) return null; + $result = []; + $i = 0; + foreach ($creatives->getResultArray() as $row) { + $error = []; + CLI::showProgress($step++, $total); + if (!empty($row['code'])) { + $title = trim($row['code']); + }else{ + $title = $row['name']; + } + $landing = $this->landingGroup($title, $row['landingUrl'] ?? ''); + $data = []; + $data = [ + 'date' => $date + ,'creative_id' => $row['id'] + ]; + $data = array_merge($data, $landing); + + if (!empty($landing) && !preg_match('/cpm/', $landing['media'])) { + if (!$landing['event_seq']){ + $error[] = $row['name'] . '(' . $row['id'] . '): 이벤트번호 미입력' . PHP_EOL; + } + if (!$landing['db_price']){ + $error[] = $row['name'] . '(' . $row['id'] . '): DB단가 미입력' . PHP_EOL; + } + } + if(empty($landing) && isset($row['ad_name']) && preg_match('/&[a-z]+/', $row['name'])){ + $error[] = $row['name'] . '(' . $row['id'] . '): 인식 오류' . PHP_EOL; + } + + if(!empty($error)){ + foreach($error as $err) CLI::write("{$err}", "light_purple"); + } + + if(empty($landing)){ + continue; + } + $dp = $this->db->getDbPrice($data); + $leads = $this->db->getLeads($data); + $cpm = false; + if(is_null($leads) && isset($data['media']) && $data['media'] === 'cpm'){ + $cpm = true; + } + $db_price = $data['db_price'] ?? 0; + if(isset($dp['db_price']) && $data['date'] != date('Y-m-d')){ + $db_price = $data['db_price'] = $dp['db_price']; + } + /* + *수익, 매출액 계산 + !xxxcpm - 유효db n / 수익,매출0 + !cpm - 유효db 0 / 수익,매출0 + !period - ^25 = *0.25 + */ + $sp_data = json_decode($row['cost_data'],1); + $period_margin = []; + if(!isset($data['event_seq']) && isset($data['media'])) { + foreach($sp_data as $hour => $spend) { + $margin = 0; + if($data['period_ad']){ + $margin = $spend * ('0.' . $data['period_ad']); + } + $data['data'][] = ['hour' => $hour,'spend' => $spend,'count' => "",'sales' => "",'margin' => $margin]; + } + } + $initZero = false; + //cpm (fhrm, fhspcpm, jhrcpm) 계산을 무효화 + if(isset($data['media'])){ + if(preg_match('/cpm/i', $data['media'])){ + $initZero = true; + } + } + $lead = []; + if(!is_null($leads)) { + foreach($leads->getResultArray() as $row) { + $sales = 0; + $db_count = $row['db_count']; + if($db_price) $sales = $db_price * $db_count; + if($initZero) $sales = 0; + // if(preg_match('/cpm/i', $data['media'])) $db_count = 0; + $lead[$row['hour']] = [ + 'sales' => $sales + ,'db_count' => $db_count + ]; + } + } + for($i=0; $i<=23; $i++) { //DB수량이 없어도 지출금액이 갱신되어야하기 때문에 0~23시까지 모두 저장 + // if($data['ad_id'] == 23853888597370162) dd($lead); + $hour = $i; + $spend = $sp_data[$i]??0; + $count = $lead[$i]['db_count']??0; + $sales = $lead[$i]['sales']??0; + $margin = $sales - $spend; + if($initZero) $margin = $sales = 0; + // if(preg_match('/cpm/i', $data['media'])) $db_count = 0; + if($data['period_ad']) $margin = $spend * ('0.' . $data['period_ad']); + $data['data'][] = [ + 'hour' => $hour + ,'spend' => $spend + ,'count' => $count + ,'sales' => $sales + ,'margin' => $margin + ]; + $result = array_merge($result, $data); + } + if(isset($data['creative_id'])) + $this->db->updateReport($data); + } + return $result; + } + + + public function setDailyBudgetAmount($data) + { + switch ($data['type']) { + case 'campaign': + if ($data['budget'] && ($data['budget'] < 50000 || $data['budget'] > 1000000000 || $data['budget'] % 10 != 0)) { + $return['code'] = false; + $return['msg'] = '캠페인 일예산 설정값은 최소 50,000원에서 최대 1,000,000,000원까지 설정 가능하며 10원 단위로 가능합니다'; + return $return; + } + if ($data['budget'] == 0) $data['budget'] = ''; + $result = $this->setCampaignDailyBudgetAmount($data['id'], $data['budget']); + if ($result['http_code'] == 200) { + $this->db->setCampaignDailyBudgetAmount($data['id'], $data['budget']); + $return = $data['id']; + } else if (isset($result['extras'])) { + $return['code'] = $result['extras']['detailCode']; + $return['msg'] = $result['extras']['detailMsg']; + } + return $return; + break; + case 'adgroup': + if ($data['budget'] < 10000 || $data['budget'] > 1000000000 || $data['budget'] % 10 != 0) { + $return['code'] = false; + $return['msg'] = '광고그룹 일예산 설정값은 최소 10,000원에서 최대 1,000,000,000원까지 설정 가능하며 10원 단위로 가능합니다'; + return $return; + } + $result = $this->setAdGroupDailyBudgetAmount($data['id'], $data['budget']); + if ($result['http_code'] == 200) { + $this->db->setAdGroupDailyBudgetAmount($data['id'], $data['budget']); + $return = $data['id']; + } else if (isset($result['extras'])) { + $return['code'] = $result['extras']['detailCode']; + $return['msg'] = $result['extras']['detailMsg']; + } + return $return; + break; + } + } + + + public function autoLimitBudget($data = []) + { + if (!isset($data['date'])) $data['date'] = date('Y-m-d'); + $campaigns = $this->db->getAutoLimitBudgetCampaign($data); + $step = 1; + $total = $campaigns->getNumRows(); + if ($total) { + CLI::write("[".date("Y-m-d H:i:s")."]"."자동 예산한도 설정을 시작합니다.", "light_red"); + foreach ($campaigns->getResultArray() as $row) { + CLI::showProgress($step++, $total); + preg_match_all('/@([0-9]+)/', $row['name'], $matches); //제목에서 @숫자 추출 + $row['limit_db'] = $matches[1][0]; //설정DB 개수 + if ($row['limit_db'] <= $row['unique_total'] && $row['cost'] && $row['already'] == 0) { + // echo '
'.print_r($row,true).'
'; + $data = ['id' => $row['id'], 'date' => $data['date'], 'set_db' => $row['limit_db'], 'valid_db' => $row['unique_total'], 'budget' => $row['cost'], 'type' => 'campaign']; + $result = $this->setDailyBudgetAmount($data); + sleep(5); + if ($result == $row['id']) { + $this->db->setAutoLimitBudgetCampaign($data); + echo '변경완료 '.json_encode($row,JSON_UNESCAPED_UNICODE).''.PHP_EOL; + } else { + echo '변경실패 ' . print_r($result) . '' . PHP_EOL; + } + } else { + echo '대상 아님 '.json_encode($row,JSON_UNESCAPED_UNICODE).''.PHP_EOL; + } + } + } + } + + + public function autoLimitBudgetReset($data = []) + { //23시 55분에 예산 리셋 + if (!isset($data['date'])) $data['date'] = date('Y-m-d'); + $campaigns = $this->db->getAutoLimitBudgetCampaign($data); + $step = 1; + $total = $campaigns->getNumRows(); + if ($total) { + CLI::write("[".date("Y-m-d H:i:s")."]"."자동 예산한도 리셋을 시작합니다.", "light_red"); + foreach ($campaigns->getResultArray() as $row) { + CLI::showProgress($step++, $total); + preg_match_all('/@([0-9]+)/', $row['name'], $matches); //제목에서 @숫자 추출 + $row['limit_db'] = $matches[1][0]; //설정DB 개수 + if ($row['already'] == 1) { + $data = ['id' => $row['id'], 'date' => $data['date'], 'set_db' => $row['limit_db'], 'valid_db' => $row['unique_total'], 'budget' => "0", 'type' => 'campaign']; + $result = $this->setDailyBudgetAmount($data); + sleep(5); + if ($result == $row['id']) { + $this->db->setAutoLimitBudgetCampaign($data); + echo '변경완료 '.json_encode($row,JSON_UNESCAPED_UNICODE).''.PHP_EOL; + } else { + echo '변경실패 ' . print_r($result) . '' . PHP_EOL; + } + } + } + } + } + + public function autoLimitBidAmount($data = []) + { + /* + Ai 1 + Level 1. 유효DB 1개이상, 수익률 20% 이하 > 입찰가 -30원 + Level 2. 유효DB 1개이상, 수익률 -100% 이하 > 광고그룹 OFF + Level 3. 유효DB 1개이상, 수익 -10만원 이하 > 광고그룹 OFF + Level 4. 유효DB 0개, 설정한 DB단가보다 소진금액이 높을 때 > 입찰가 -30원 + 광고그룹 OFF + */ + if (!isset($data['date'])) { + $data['date'] = $date = date('Y-m-d'); + } + $adgroups = $this->db->getAutoLimitBidAmountAdGroup($data); + $step = 1; + $total = $adgroups->getNumRows(); + if ($total) { + CLI::write("[".date("Y-m-d H:i:s")."]"."자동 입찰가 설정을 시작합니다.", "light_red"); + foreach ($adgroups->getResultArray() as $row) { + CLI::showProgress($step++, $total); + $data = []; + unset($result); + // echo '내역
'.print_r($row,true).'
'; + if ($row['id'] && $row['campaign_config'] == 'ON' && $row['config'] == 'ON') { + if (!is_null($row['unique_total']) && $row['unique_total'] > 0) { //유효DB가 1개 이상일 때 + if ($row['margin_ratio'] <= 20 && $row['goal'] != 'CONVERSION' && $row['already_1'] == 0 && $row['already_2'] == 0 && $row['already_3'] == 0) { //Level 1-수익률이 20% 이하일 때 입찰가에 -30원 조정(전환캠페인은 제외) + echo "Level 1:{$row['id']}" . PHP_EOL; + $setBidAmount = ($row['bidAmount'] < 100) ? $row['bidAmount'] - 10 : $row['bidAmount'] - 30; + $data = ['level' => '1', 'date' => $date, 'id' => $row['id'], 'bidAmount' => $setBidAmount, 'adAccountId' => $row['ad_account_id'], 'msg' => "Level 1({$row['bidAmount']}=>{$setBidAmount})"]; + if($row['bidStrategy'] == 'AUTOBID') continue; //자동입찰일 경우 건너띄기 + $result = $this->setAdGroupBidAmount($data['id'], $data['bidAmount'], $data['adAccountId']); //현재입찰가에 -30원 조정 + } else if ($row['margin_ratio'] <= -100 && $row['already_2'] == 0) { //Level 2-수익률이 -100%가 넘으면 상태 OFF + echo "Level 2:{$row['id']}" . PHP_EOL; + $data = ['level' => '2', 'date' => $date, 'id' => $row['id'], 'config' => 'OFF', 'adAccountId' => $row['ad_account_id'], 'msg' => "Level 2({$row['config']}=>OFF)"]; + $result = $this->setAdGroupOnOff($data['id'], $data['config'], $data['adAccountId']); + } else if ($row['margin'] <= -100000 && $row['already_3'] == 0) { //Level 3-수익이 -10만원이 넘으면 상태 OFF + echo "Level 3:{$row['id']}" . PHP_EOL; + $data = ['level' => '3', 'date' => $date, 'id' => $row['id'], 'config' => 'OFF', 'adAccountId' => $row['ad_account_id'], 'msg' => "Level 3({$row['config']}=>OFF)"]; + $result = $this->setAdGroupOnOff($data['id'], $data['config'], $data['adAccountId']); + } else { + echo 'LEVEL1,2,3 대상 아님'.json_encode($row,JSON_UNESCAPED_UNICODE).''.PHP_EOL; + } + } else { //유효DB가 없을 때 + preg_match_all('/\*([0-9]+)/', $row['ad_name'], $matches); //제목에서 *숫자 추출 + $set_cpa = $matches[1][0]; //DB단가 + if ($set_cpa && $row['cost'] >= $set_cpa && $row['already_4'] == 0) { //제목에 설정한 DB단가보다 소진금액이 높을 때 + echo "Level 4:{$row['id']}" . PHP_EOL; + $setBidAmount = ($row['bidAmount'] < 100) ? $row['bidAmount'] - 10 : $row['bidAmount'] - 30; + $data = ['level' => '4', 'date' => $date, 'id' => $row['id'], 'cost' => $row['cost'], 'set_cpa' => $set_cpa, 'config' => 'OFF', 'bidAmount' => $setBidAmount, 'adAccountId' => $row['ad_account_id'], 'msg' => "Level 3({$row['bidAmount']}=>{$setBidAmount})"]; + $result = $this->setAdGroupOnOff($data['id'], $data['config'], $data['adAccountId']); + sleep(5); + if ($row['goal'] != 'CONVERSION' && $row['bidStrategy'] != 'AUTOBID') { + $data['msg'] = "Level 4({$row['bidAmount']}=>{$setBidAmount}, {$row['config']}=>OFF)"; + $result = $this->setAdGroupBidAmount($data['id'], $data['bidAmount'], $data['adAccountId']); //현재입찰가 -30원으로 조정 + } + } else { + echo 'LEVEL4 대상 아님'.json_encode($row,JSON_UNESCAPED_UNICODE).''.PHP_EOL; + } + } + if ($result == $row['id'] || @$result['result'] == true || $result['http_code'] == 200) { + $this->db->setAutoLimitBidAmountAdGroup($data); + sleep(5); + echo '변경완료
' . json_encode($data, JSON_UNESCAPED_UNICODE) . json_encode($row, JSON_UNESCAPED_UNICODE) . '
'; + } else if (isset($result)) { + echo '변경실패
' . json_encode($result, JSON_UNESCAPED_UNICODE) . json_encode($row, JSON_UNESCAPED_UNICODE) . '
' . PHP_EOL; + } + } + } + } + } + + + public function autoLimitBidAmountReset($data = []) + { //23시 55분에 ON + if (!isset($data['date'])) { + $data['date'] = $date = date('Y-m-d'); + } + $adgroups = $this->db->getAutoLimitBidAmountAdGroup($data); + $step = 1; + $total = $adgroups->getNumRows(); + if ($total) { + CLI::write("[".date("Y-m-d H:i:s")."]"."자동 입찰가한도 리셋을 시작합니다.", "light_red"); + foreach ($adgroups->getResultArray() as $row) { + CLI::showProgress($step++, $total); + if ($row['campaign_config'] == 'ON' && $row['config'] == 'OFF') { + if ($row['already_2'] == 1 || $row['already_3'] == 1 || $row['already_4'] == 1) { + if ($row['already_2']) $level = "2"; + else if ($row['already_3']) $level = "3"; + else if ($row['already_4']) $level = "4"; + echo "Level {$level}" . PHP_EOL; + $data = ['level' => $level, 'date' => $date, 'id' => $row['id'], 'config' => 'ON', 'adAccountId' => $row['ad_account_id'], 'msg' => "Level {$level}({$row['config']}=>ON)"]; + $result = $this->setAdGroupOnOff($data['id'], $data['config'], $data['adAccountId']); + sleep(5); + if ($result['http_code'] == 200) { + $this->db->setAutoLimitBidAmountAdGroup($data); + echo '변경완료 ' . print_r($data) . ''; + } else if (isset($result)) { + echo '변경실패 ' . print_r($result) . print_r($data) . '' . PHP_EOL; + } + } + } + } + } + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + private function getCall($request, $param = '', $data = '', $type = 'GET', $getError = false) + { + if (preg_match('/^http/', $request)) { + $url = $request; + } else { + $url = $this->host . '/openapi/v4/' . $request; + if (preg_match('/^\//', $request)) + $url = $this->host . '' . $request; + } + if ($param) { + $url .= '?' . http_build_query($param); + } + $response = $this->curl($url, $this->access_token, $data, $type, false, $getError); + return $response; + } + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + protected function curl($url, $api_key, $data, $type = "GET", $multipart = false, $getError = false) + { + if ($api_key != NULL) + $headers = array("Authorization: Bearer {$api_key}"); + else + $headers = array(); + + if ($this->ad_account_id) { + $headers[] = "adAccountId: {$this->ad_account_id}"; + } + + if ($multipart == true && is_array($data)) { + $headers[] = 'Content-type: multipart/form-data'; + $data['image'] = new CURLFile($data['image']['tmp_name'], $data['image']['type'], $data['image']['name']); + } + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + switch ($type) { + case 'POST': + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); + break; + case 'GET': + break; + case 'PUT': + $headers[] = 'Content-type: application/json'; + default: + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $type); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); + break; + } + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + // curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + //curl_setopt($ch, CURLOPT_VERBOSE, true); + //curl_setopt($ch, CURLINFO_HEADER_OUT, true); + + $result = curl_exec($ch); + $info = curl_getinfo($ch); + $result = json_decode($result, true); + // echo json_encode($data); + // echo '
headers:'.print_r($headers,1).'
'; + // echo '
data:'.print_r($data,1).'
'; + // echo '
info:'.print_r($info,1).'
'; + // echo '
result:'.print_r($result,1).'
'; + if (isset($result['error'])) { + $this->error($result['error'], $result['error_description']); + } + switch ($info['http_code']) { + case 200: + if ($info['download_content_length'] == 0) { + $result = array(); + $result['http_code'] = 200; + } + break; + case 302: + header('Location: ' . $info['redirect_url']); + break; + case 400: + case 403: + case 405: + case 429: + case 500: + if (!$getError) { + echo '
headers:' . print_r($headers, 1) . '
'; + echo '
data:' . print_r($data, 1) . '
'; + echo '
info:' . print_r($info, 1) . '
'; + echo '
result:' . print_r($result, 1) . '
'; + if (isset($result['extras'])) + $this->apiError($result); + else + $this->error($info['http_code'], $result['msg']??''); + } + return $result; + break; + default: + d($info); + $this->error($info['http_code']); + break; + } + curl_close($ch); + + return $result; + } + + protected function error($title, $desc = '') + { + echo '

' . $title . '

'; + if ($desc) + echo '

' . $desc . '

'; + // exit; + } + + protected function apiError($data) + { + dd($data); + // exit; + } + + public function grid($data, $link = null) + { + if (empty($data)) { + echo '

null data

'; + return; + } + $table = ''; + foreach ($data as $row) { + if (is_array($row)) { + $table .= ''; + foreach ($row as $key => $var) { + if ($link) { + foreach ($link as $k => $v) { + if ($k == $key) $var = str_replace('{' . $k . '}', $var, $v); + } + } + $table .= '' . (is_object($var) ? $var->load() : $var) . ''; + } + $table .= ''; + } + } + if (isset($row) && is_array($row)) { + $thead = ''; + foreach ($row as $key => $tmp) { + $thead .= '' . $key . ''; + } + $thead .= ''; + } else { + $thead = ''; + $table = ''; + foreach ($data as $k => $v) { + $thead .= '' . $k . ''; + $table .= '' . $v . ''; + } + $thead .= ''; + $table .= ''; + } + echo '' . $thead . $table . '
'; + } + + public function getMemo($data) + { + $response = $this->db->getMemo($data); + return $response; + } + + public function addMemo($data) + { + return $this->db->addMemo($data); + } +}