1690 lines
83 KiB
PHP
1690 lines
83 KiB
PHP
<?php
|
|
namespace App\ThirdParty\moment_api;
|
|
|
|
set_time_limit(0);
|
|
ini_set('memory_limit', '-1');
|
|
|
|
use CodeIgniter\API\ResponseTrait;
|
|
use CodeIgniter\CLI\CLI;
|
|
use Exception;
|
|
use App\Libraries\slack_api\SlackChat;
|
|
|
|
class ZenithKM
|
|
{
|
|
use ResponseTrait;
|
|
//// private $app_id = '243424';
|
|
//// private $app_key = '500a99d34478a54c7c4fbfc04ff90512';
|
|
//// private $client_secret = 'V1lTM4d4FrLoxVhnISLqGaLdhwsvcGTT';
|
|
private $app_id;
|
|
private $app_key;
|
|
private $client_secret;
|
|
private $redirect_uri;
|
|
private $oauth_url = 'https://kauth.kakao.com/oauth';
|
|
private $code;
|
|
private $host = 'https://apis.moment.kakao.com';
|
|
private $db;
|
|
private $access_token;
|
|
private $refresh_token;
|
|
private $ad_account_id;
|
|
private $slack, $slackChannel = '광고API';
|
|
|
|
public function __construct()
|
|
{
|
|
// @set_exception_handler(array($this, 'exception_handler'));
|
|
$this->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 '<pre>'.print_r($data,1).'</pre>';
|
|
$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 '<pre>'.print_r($result,1).'</pre>'; 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 '<pre>'.print_r($adGroup,1).'</pre>';
|
|
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'] . '<br>' . PHP_EOL;
|
|
echo @number_format($adGroup['bidAmount']).'>'.@number_format($bidAmount) . ' - ' . $rs['bid'] . '<br><br>' . 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']}<br>";
|
|
$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'].'<br>';
|
|
$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 '<pre>'.print_r($data,1).'</pre>';
|
|
$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 '<pre>' . print_r($creative, 1) . '</pre>';
|
|
$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 "<p>{$adgroup['id']}, {$adgroup['ad_account_id']}</p>";
|
|
$creativeList = $this->getCreatives($adgroup['id'], $adgroup['ad_account_id']);
|
|
// echo '<pre>'.print_r($creativeList,1).'</pre>';
|
|
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 '비즈폼 매칭 오류 발생 : <pre>' . print_r($row, 1) . '</pre>';
|
|
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 '<h1>'.date('[H:i:s] ').$this->ad_account_id.','.$adgroup['ad_account_id'].'</h1>';
|
|
// echo '<h2>'.$cnt.'</h2>';
|
|
if (count($ids) == 20 || $this->ad_account_id != $adgroup['ad_account_id'] || $adgroups->getNumRows() == $cnt) {
|
|
$adgroup_ids = implode(",", $ids);
|
|
// echo '<h3>'.$adgroup_ids.'</h3>';
|
|
$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 "<br>[[[[[[[[[[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 '<pre>'.print_r($creative,1).'</pre>';
|
|
// $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 '<pre>'.print_r($row,true).'</pre>';
|
|
$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 '<strong>변경완료</strong> '.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 '<strong>변경완료</strong> '.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 '내역<pre>'.print_r($row,true).'</pre>';
|
|
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 '<strong>변경완료</strong> <pre>' . json_encode($data, JSON_UNESCAPED_UNICODE) . json_encode($row, JSON_UNESCAPED_UNICODE) . '</pre>';
|
|
} else if (isset($result)) {
|
|
echo '변경실패 <pre>' . json_encode($result, JSON_UNESCAPED_UNICODE) . json_encode($row, JSON_UNESCAPED_UNICODE) . '</pre>' . 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 '<strong>변경완료</strong> ' . 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 '<pre>headers:'.print_r($headers,1).'</pre>';
|
|
// echo '<pre>data:'.print_r($data,1).'</pre>';
|
|
// echo '<pre>info:'.print_r($info,1).'</pre>';
|
|
// echo '<pre>result:'.print_r($result,1).'</pre>';
|
|
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 '<pre>headers:' . print_r($headers, 1) . '</pre>';
|
|
echo '<pre>data:' . print_r($data, 1) . '</pre>';
|
|
echo '<pre>info:' . print_r($info, 1) . '</pre>';
|
|
echo '<pre>result:' . print_r($result, 1) . '</pre>';
|
|
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 '<h1>' . $title . '</h1>';
|
|
if ($desc)
|
|
echo '<p>' . $desc . '</p>';
|
|
// exit;
|
|
}
|
|
|
|
protected function apiError($data)
|
|
{
|
|
dd($data);
|
|
// exit;
|
|
}
|
|
|
|
public function grid($data, $link = null)
|
|
{
|
|
if (empty($data)) {
|
|
echo '<p>null data</p>';
|
|
return;
|
|
}
|
|
$table = '';
|
|
foreach ($data as $row) {
|
|
if (is_array($row)) {
|
|
$table .= '<tr>';
|
|
foreach ($row as $key => $var) {
|
|
if ($link) {
|
|
foreach ($link as $k => $v) {
|
|
if ($k == $key) $var = str_replace('{' . $k . '}', $var, $v);
|
|
}
|
|
}
|
|
$table .= '<td>' . (is_object($var) ? $var->load() : $var) . '</td>';
|
|
}
|
|
$table .= '</tr>';
|
|
}
|
|
}
|
|
if (isset($row) && is_array($row)) {
|
|
$thead = '<thead><tr>';
|
|
foreach ($row as $key => $tmp) {
|
|
$thead .= '<th>' . $key . '</th>';
|
|
}
|
|
$thead .= '</tr></thead>';
|
|
} else {
|
|
$thead = '<thead><tr>';
|
|
$table = '<tr>';
|
|
foreach ($data as $k => $v) {
|
|
$thead .= '<th>' . $k . '</th>';
|
|
$table .= '<td>' . $v . '</td>';
|
|
}
|
|
$thead .= '</tr></thead>';
|
|
$table .= '</tr>';
|
|
}
|
|
echo '<table class="_dev_util_grid" border="1">' . $thead . $table . '</table>';
|
|
}
|
|
|
|
public function getMemo($data)
|
|
{
|
|
$response = $this->db->getMemo($data);
|
|
return $response;
|
|
}
|
|
|
|
public function addMemo($data)
|
|
{
|
|
return $this->db->addMemo($data);
|
|
}
|
|
}
|