setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } return $pdo; } function oiHttp($url, $headers = [], $timeout = 30) { $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => $timeout, CURLOPT_FOLLOWLOCATION => true, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_HTTPHEADER => $headers, CURLOPT_USERAGENT => 'WEVADS-Importer/4.0' ]); $resp = curl_exec($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $err = curl_error($ch); curl_close($ch); return ['body' => $resp, 'code' => $code, 'error' => $err]; } function oiNextId($table) { return (int)oiDb()->query("SELECT COALESCE(MAX(id),0)+1 FROM $table")->fetchColumn(); } function oiGetNetwork($id) { $stmt = oiDb()->prepare("SELECT * FROM affiliate.affiliate_networks WHERE id = ? AND status = 'Activated'"); $stmt->execute([$id]); return $stmt->fetch(PDO::FETCH_ASSOC); } function oiUpsertOffer($network, $data) { $today = date('Y-m-d'); $un = 'import@wevads'; $prodId = (string)$data['production_id']; $stmt = oiDb()->prepare("SELECT id FROM affiliate.offers WHERE affiliate_network_id = ? AND production_id = ?"); $stmt->execute([$network['id'], $prodId]); $existing = $stmt->fetch(); $payout = number_format(floatval(str_replace(['$','EUR'], '', $data['payout'] ?? '0')), 2, '.', ''); if ($existing) { $sql = "UPDATE affiliate.offers SET name=?, campaign_id=?, payout=?, countries=?, description=?, offer_url=?, unsub_url=?, default_suppression_link=?, status='Activated', last_updated_date=?, last_updated_by=? WHERE id=?"; oiDb()->prepare($sql)->execute([ $data['name'], $data['campaign_id'] ?? $prodId, $payout, $data['countries'] ?? '', base64_encode($data['description'] ?? ''), $data['tracking_url'] ?? '', $data['unsub_url'] ?? '', $data['suppression_link'] ?? '', $today, $un, $existing['id'] ]); return (int)$existing['id']; } else { $nid = oiNextId('affiliate.offers'); $sql = "INSERT INTO affiliate.offers (id, name, affiliate_network_id, affiliate_network_name, production_id, campaign_id, payout, type, countries, description, rules, offer_url, unsub_url, default_suppression_link, status, created_by, created_date, last_updated_by, last_updated_date, available_days, verticals_ids, expiration_date) VALUES (?,?,?,?,?,?,?,'CPA',?,?,?,?,?,?,'Activated',?,?,?,?,'mon,tue,wed,thu,fri,sat,sun','',?)"; oiDb()->prepare($sql)->execute([ $nid, $data['name'], $network['id'], $network['name'], $prodId, $data['campaign_id'] ?? $prodId, $payout, $data['countries'] ?? '', base64_encode($data['description'] ?? ''), base64_encode(''), $data['tracking_url'] ?? '', $data['unsub_url'] ?? '', $data['suppression_link'] ?? '', $un, $today, $un, $today, date('Y-m-d', strtotime('+1 year')) ]); return $nid; } } function oiUpsertCreative($dbOfferId, $networkId, $index, $html) { $today = date('Y-m-d'); $name = "offer_creative_" . $index; $stmt = oiDb()->prepare("SELECT id FROM affiliate.creatives WHERE offer_id = ? AND name = ?"); $stmt->execute([$dbOfferId, $name]); $ex = $stmt->fetch(); if ($ex) { oiDb()->prepare("UPDATE affiliate.creatives SET value=?, last_updated_date=?, last_updated_by='import@wevads' WHERE id=?") ->execute([base64_encode($html), $today, $ex['id']]); return (int)$ex['id']; } else { $nid = oiNextId('affiliate.creatives'); oiDb()->prepare("INSERT INTO affiliate.creatives (id, offer_id, affiliate_network_id, name, value, status, created_by, created_date, last_updated_by, last_updated_date) VALUES (?,?,?,?,?,'Activated','import@wevads',?,'import@wevads',?)") ->execute([$nid, $dbOfferId, $networkId, $name, base64_encode($html), $today, $today]); return $nid; } } function oiUpsertLink($dbOfferId, $networkId, $creativeId, $type, $value) { $today = date('Y-m-d'); $stmt = oiDb()->prepare("SELECT id FROM affiliate.links WHERE offer_id = ? AND creative_id = ? AND type = ?"); $stmt->execute([$dbOfferId, $creativeId, $type]); $ex = $stmt->fetch(); if ($ex) { oiDb()->prepare("UPDATE affiliate.links SET value=?, last_updated_date=? WHERE id=?")->execute([$value, $today, $ex['id']]); } else { $nid = oiNextId('affiliate.links'); oiDb()->prepare("INSERT INTO affiliate.links (id, offer_id, affiliate_network_id, creative_id, type, value, status, created_by, created_date, last_updated_by, last_updated_date) VALUES (?,?,?,?,?,?,'Activated','import@wevads',?,'import@wevads',?)") ->execute([$nid, $dbOfferId, $networkId, $creativeId, $type, $value, $today, $today]); } } function oiUpsertFromName($dbOfferId, $networkId, $index, $value) { $today = date('Y-m-d'); $stmt = oiDb()->prepare("SELECT id FROM affiliate.from_names WHERE offer_id = ? AND value = ?"); $stmt->execute([$dbOfferId, $value]); if (!$stmt->fetch()) { $nid = oiNextId('affiliate.from_names'); oiDb()->prepare("INSERT INTO affiliate.from_names (id, offer_id, affiliate_network_id, name, value, status, created_by, created_date, last_updated_by, last_updated_date) VALUES (?,?,?,?,?,'Activated','import@wevads',?,'import@wevads',?)") ->execute([$nid, $dbOfferId, $networkId, "offer_from_name_$index", $value, $today, $today]); } } function oiUpsertSubject($dbOfferId, $networkId, $index, $value) { $today = date('Y-m-d'); $stmt = oiDb()->prepare("SELECT id FROM affiliate.subjects WHERE offer_id = ? AND value = ?"); $stmt->execute([$dbOfferId, $value]); if (!$stmt->fetch()) { $nid = oiNextId('affiliate.subjects'); oiDb()->prepare("INSERT INTO affiliate.subjects (id, offer_id, affiliate_network_id, name, value, status, created_by, created_date, last_updated_by, last_updated_date) VALUES (?,?,?,?,?,'Activated','import@wevads',?,'import@wevads',?)") ->execute([$nid, $dbOfferId, $networkId, "offer_subject_$index", $value, $today, $today]); } } // ============== EVERFLOW ============== function importEverflow($network, $offerIds, $maxCreatives, $getAll) { $apiKey = $network['api_key']; $apiUrl = rtrim($network['api_url'], '/'); $imported = 0; $updated = 0; $errors = []; $resp = oiHttp($apiUrl . '/v1/affiliates/alloffers', ['X-Eflow-API-Key: ' . $apiKey]); if ($resp['code'] != 200) return ['imported'=>0,'updated'=>0,'errors'=>['Everflow HTTP '.$resp['code']]]; $body = json_decode($resp['body'], true); if (!is_array($body) || empty($body['offers'])) return ['imported'=>0,'updated'=>0,'errors'=>['No offers from Everflow']]; $offers = $body['offers']; $total = count($offers); if (!$getAll && !empty($offerIds)) { $offers = array_values(array_filter($offers, function($o) use ($offerIds) { return in_array((string)($o['network_offer_id']??''), $offerIds) || in_array((string)($o['network_id']??''), $offerIds); })); } foreach ($offers as $offer) { try { $oid = $offer['network_offer_id'] ?? $offer['network_id'] ?? ''; $countries = ''; if (!empty($offer['countries'])) { $cc = []; foreach ((array)$offer['countries'] as $c) { $cc[] = is_array($c) ? ($c['country_code']??'') : (string)$c; } $countries = implode('/', array_filter($cc)); } $chk = oiDb()->prepare("SELECT id FROM affiliate.offers WHERE affiliate_network_id=? AND production_id=?"); $chk->execute([$network['id'], (string)$oid]); $isUp = (bool)$chk->fetch(); $dbOid = oiUpsertOffer($network, [ 'production_id'=>$oid, 'campaign_id'=>(string)$oid, 'name'=>$offer['name']??'', 'payout'=>$offer['payout']??0, 'tracking_url'=>$offer['tracking_url']??'', 'unsub_url'=>'', 'suppression_link'=>$offer['preview_url']??'', 'description'=>$offer['description']??'', 'countries'=>$countries ]); if ($isUp) $updated++; else $imported++; if ($maxCreatives != 0) { $dr = oiHttp($apiUrl.'/v1/affiliates/offers/'.$oid, ['X-Eflow-API-Key: '.$apiKey], 15); if ($dr['code']==200) { $det = json_decode($dr['body'], true); if (is_array($det)) { $ci = 0; if (!empty($det['creatives'])) { foreach ($det['creatives'] as $cr) { if ($maxCreatives>0 && $ci>=$maxCreatives) break; $ci++; $h = $cr['html_code'] ?? $cr['content'] ?? ''; if (empty($h) && !empty($offer['tracking_url'])) $h = ''.htmlspecialchars($offer['name']??'Offer').''; if (!empty($h)) { $cid = oiUpsertCreative($dbOid, $network['id'], $ci, $h); if (!empty($offer['tracking_url'])) oiUpsertLink($dbOid, $network['id'], $cid, 'preview', $offer['tracking_url']); } } } if ($ci==0 && !empty($offer['tracking_url'])) { $h = ''.htmlspecialchars($offer['name']??'Offer').''; $cid = oiUpsertCreative($dbOid, $network['id'], 1, $h); oiUpsertLink($dbOid, $network['id'], $cid, 'preview', $offer['tracking_url']); } if (!empty($det['email_instructions']['from_lines'])) { $fi = 0; foreach ($det['email_instructions']['from_lines'] as $fl) { $fi++; $v = is_array($fl)?($fl['value']??$fl['name']??''):(string)$fl; if (!empty(trim($v))) oiUpsertFromName($dbOid, $network['id'], $fi, trim($v)); } } if (!empty($det['email_instructions']['subject_lines'])) { $si = 0; foreach ($det['email_instructions']['subject_lines'] as $sl) { $si++; $v = is_array($sl)?($sl['value']??$sl['name']??''):(string)$sl; if (!empty(trim($v))) oiUpsertSubject($dbOid, $network['id'], $si, trim($v)); } } } } usleep(100000); } } catch (\Exception $e) { $errors[] = "Offer $oid: ".$e->getMessage(); } } return ['imported'=>$imported,'updated'=>$updated,'total_available'=>$total,'processed'=>count($offers),'errors'=>$errors]; } // ============== CAKE (CX3) ============== function importCake($network, $offerIds, $maxCreatives, $getAll) { $apiKey = $network['api_key']; $apiUrl = str_replace('http://', 'https://', rtrim($network['api_url'], '/')); $affId = $network['affiliate_id']; $imported = 0; $updated = 0; $errors = []; $feedUrl = $apiUrl.'/Offers/Feed.asmx/OfferFeed?api_key='.urlencode($apiKey) .'&affiliate_id='.$affId.'&offer_status_id=0&campaign_name=&media_type_category_id=0&vertical_category_id=0&vertical_id=0&offer_tag_id=0&start_at_row=1&row_limit=0'; $resp = oiHttp($feedUrl, [], 60); if ($resp['code'] != 200 || strpos($resp['body'],'temporarily unavailable')!==false) { return ['imported'=>0,'updated'=>0,'errors'=>['CX3/CAKE API unavailable (HTTP '.$resp['code'].'). Try again later.'],'total_available'=>0]; } $bodyClean = preg_replace('/^\xEF\xBB\xBF/', '', $resp['body']); $xml = @simplexml_load_string($bodyClean); $offers = []; if ($xml) { $nodes = $xml->xpath('//offer') ?: $xml->xpath('//Offer') ?: $xml->xpath('//row') ?: []; foreach ($nodes as $n) { $o = []; $o['offer_id'] = (string)($n->offer_id ?? $n->OfferId ?? ''); $o['campaign_id'] = (string)($n->campaign_id ?? $n->CampaignId ?? $o['offer_id']); $o['name'] = (string)($n->offer_name ?? $n->OfferName ?? $n->name ?? ''); $o['payout'] = (string)($n->payout ?? $n->Payout ?? '0'); $o['offer_link'] = (string)($n->offer_link ?? $n->OfferLink ?? $n->unique_link ?? ''); $o['description'] = (string)($n->description ?? $n->Description ?? ''); $o['suppression_link'] = (string)($n->suppression_link ?? $n->SuppressionLink ?? ''); $o['countries'] = ''; $ccn = $n->xpath('.//allowed_countries/country') ?: $n->xpath('.//country') ?: []; $cc = []; foreach ($ccn as $cn) { $c=(string)($cn->country_code??$cn->CountryCode??$cn); if(!empty($c)&&strlen($c)<=3)$cc[]=$c; } $o['countries'] = implode('/', $cc); if (empty($o['offer_link']) && !empty($o['campaign_id'])) $o['offer_link'] = 'https://e36lbat.com/?offer_id='.$o['campaign_id'].'&aff_id='.$affId; if (!empty($o['offer_id'])||!empty($o['campaign_id'])) $offers[] = $o; } } $total = count($offers); if ($total == 0) return ['imported'=>0,'updated'=>0,'errors'=>['No offers parsed (body: '.strlen($resp['body']).'b)'],'total_available'=>0]; if (!$getAll && !empty($offerIds)) { $offers = array_values(array_filter($offers, function($o) use ($offerIds) { return in_array($o['offer_id'], $offerIds) || in_array($o['campaign_id'], $offerIds); })); } foreach ($offers as $offer) { try { $pid = $offer['offer_id'] ?: $offer['campaign_id']; $cid = $offer['campaign_id'] ?: $offer['offer_id']; $chk = oiDb()->prepare("SELECT id FROM affiliate.offers WHERE affiliate_network_id=? AND production_id=?"); $chk->execute([$network['id'], $pid]); $isUp = (bool)$chk->fetch(); $dbOid = oiUpsertOffer($network, [ 'production_id'=>$pid, 'campaign_id'=>$cid, 'name'=>$offer['name'], 'payout'=>$offer['payout'], 'tracking_url'=>$offer['offer_link'], 'unsub_url'=>$offer['suppression_link'], 'suppression_link'=>$offer['suppression_link'], 'description'=>$offer['description'], 'countries'=>$offer['countries'] ]); if ($isUp) $updated++; else $imported++; if ($maxCreatives != 0 && !empty($cid)) { $cUrl = $apiUrl.'/Offers/Creative.asmx/Creatives?api_key='.urlencode($apiKey).'&affiliate_id='.$affId.'&campaign_id='.$cid; $cr = oiHttp($cUrl, [], 15); if ($cr['code']==200) { $cx = @simplexml_load_string(preg_replace('/^\xEF\xBB\xBF/','',$cr['body'])); if ($cx) { $ci = 0; foreach ($cx->xpath('//creative')?:$cx->xpath('//Creative')?:[] as $cn) { if ($maxCreatives>0 && $ci>=$maxCreatives) break; $ci++; $h = (string)($cn->html_code??$cn->HtmlCode??$cn->content??''); $cl = (string)($cn->unique_link??$cn->UniqueLink??''); if (empty($h)&&!empty($cl)) $h=''.htmlspecialchars($offer['name']).''; if (empty($h)&&!empty($offer['offer_link'])) $h=''.htmlspecialchars($offer['name']).''; if (!empty($h)) { $creaId = oiUpsertCreative($dbOid, $network['id'], $ci, $h); $lv = !empty($cl)?$cl:$offer['offer_link']; if (!empty($lv)) oiUpsertLink($dbOid, $network['id'], $creaId, 'preview', $lv); } } } } $gUrl = $apiUrl.'/Offers/Feed.asmx/GetCampaign?api_key='.urlencode($apiKey).'&affiliate_id='.$affId.'&campaign_id='.$cid; $gr = oiHttp($gUrl, [], 15); if ($gr['code']==200) { $gx = @simplexml_load_string(preg_replace('/^\xEF\xBB\xBF/','',$gr['body'])); if ($gx) { $fi=0; foreach ($gx->xpath('//from_line')?:$gx->xpath('//FromLine')?:[] as $fl) { $fi++; $v=trim((string)$fl); if(!empty($v)) oiUpsertFromName($dbOid,$network['id'],$fi,$v); } $si=0; foreach ($gx->xpath('//subject_line')?:$gx->xpath('//SubjectLine')?:[] as $sl) { $si++; $v=trim((string)$sl); if(!empty($v)) oiUpsertSubject($dbOid,$network['id'],$si,$v); } } } usleep(100000); } } catch (\Exception $e) { $errors[] = "Offer ".($offer['offer_id']??'?').": ".$e->getMessage(); } } return ['imported'=>$imported,'updated'=>$updated,'total_available'=>$total,'processed'=>count($offers),'errors'=>$errors]; } // ============== ROUTER ============== $networkId = intval($_POST['affiliate-network-id'] ?? $_GET['network_id'] ?? 0); $getAll = ($_POST['get-all'] ?? '') === 'on'; $maxCreatives = intval($_POST['max-creatives'] ?? 1); $offerIdsRaw = $_POST['production-ids'] ?? ''; $offerIds = array_filter(array_map('trim', explode("\n", $offerIdsRaw))); if ($networkId <= 0) die(json_encode(['status'=>400,'message'=>'Missing affiliate-network-id','httpStatus'=>400])); $network = oiGetNetwork($networkId); if (!$network) die(json_encode(['status'=>404,'message'=>"Network $networkId not found",'httpStatus'=>404])); try { switch ($network['api_type']) { case 'everflow': $r = importEverflow($network, $offerIds, $maxCreatives, $getAll); break; case 'cake': $r = importCake($network, $offerIds, $maxCreatives, $getAll); break; case 'hitpath': die(json_encode(['status'=>501,'message'=>'HitPath: coming soon','httpStatus'=>501])); default: die(json_encode(['status'=>400,'message'=>'Unknown type: '.$network['api_type'],'httpStatus'=>400])); } $msg = $network['name'].': '.$r['imported'].' new, '.($r['updated']??0).' updated'; if (!empty($r['total_available'])) $msg .= ' (from '.$r['total_available'].' available)'; if (!empty($r['errors'])) $msg .= ' | '.count($r['errors']).' errors'; echo json_encode(['status'=>200,'message'=>$msg,'httpStatus'=>200,'data'=>$r]); } catch (\Exception $e) { echo json_encode(['status'=>500,'message'=>'Error: '.$e->getMessage(),'httpStatus'=>500]); }