Joywork/engine/classes/AdvertStats.php

2573 lines
118 KiB
PHP
Raw Permalink Normal View History

2026-05-22 20:21:54 +02:00
<?php
class AdvertStats {
public $debug = false;
public $errors = [];
public $logs = [];
private $_db = null;
private $_user = null;
private $_agency_id;
private $_session_key = 'advert_stats';
private $_is_cli = false;
private $_api_attempts = 0;
private $_curl_attempts = 0;
private $_tokens = [];
private $_api_id = 0;
public static $_serviceList = [
1 => 'avito',
2 => 'cian',
3 => 'yandex',
4 => 'domclick',
];
public function __construct($db = null, $debug = false) {
if ($debug == true) {
$this->debug = true;
error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', 1);
}
if (isset($_SESSION['id'])) {
if (isset($user)) {
$this->_user = $user;
} else {
$user_id = intval($_SESSION['id']);
$user = new User;
$user->get($user_id);
$this->_user = $user;
}
} else {
$this->_user = null;
}
if (!is_null($this->_user))
$this->_agency_id = User::getUserAgencyID($this->_user->id);
if (!is_null($db)) {
$this->_db = $db;
} else {
$pdo = new MysqlPdo(hst, ndb, user, pass);
$pdo->query("SET NAMES 'utf8'");
$this->_db = $pdo;
}
$this->_is_cli = isset($_SESSION);
}
private function _request($url, $options = null, $test = false) {
$this->_curl_attempts++;
if ($this->debug)
$this->logs[] = 'Попытка запроса: ' . $this->_curl_attempts . ' по URL: ' . $url;
$headers = [];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CERTINFO, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); // запретить проверку сертификата удаленного сервера
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0");
curl_setopt($ch, CURLOPT_REFERER, "https://joywork.ru/");
curl_setopt($ch, CURLOPT_HEADER, 0); // При установке этого параметра в 1 результат будет включать полученные заголовки.
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // При установке этого параметра в ненулевое значение CURL будет возвращать результат, а не выводить его.
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); //при получении HTTP заголовка "Location: " будет происходить перенаправление на указанный этим заголовком URL
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ch, CURLOPT_TIMEOUT, 20);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
if (!is_null($options)) {
if (isset($options['auth']) && isset($options['token'])) {
if ($options['auth'] == 'bearer') {
$headers[] = "Authorization: Bearer " . $options['token'];
} else if ($options['auth'] == 'oauth') {
$headers[] = "Authorization: OAuth " . $options['token'];
} else if ($options['auth'] == 'token') {
$headers[] = "Authorization: Token " . $options['token'];
}
}
if (isset($options['method'])) {
if ($options['method'] == 'post') {
curl_setopt($ch, CURLOPT_POST, 1);
}
} else {
curl_setopt($ch, CURLOPT_POST, 0);
}
if (isset($options['data'])) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($options['data']));
}
if (isset($options['type'])) {
if ($options['type'] == 'json') {
$headers[] = "Accept: application/json";
$headers[] = "Content-Type: application/json";
} else if ($options['type'] == 'xml') {
$headers[] = "Accept: application/xml";
$headers[] = "Content-Type: application/xml";
}
}
if (isset($options['headers']) && is_array($options['headers'])) {
$headers = array_merge($headers, $options['headers']);
}
}
if (!empty($headers)) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
$content = curl_exec($ch);
if (isset($_GET['dev']))
echo "<pre style='color: darkgreen; font-family: monospace;'>" . var_export(curl_getinfo($ch), true) . "</pre>";
if ($test) {
$error = curl_error($ch);
// var_dump($error);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
// var_dump(curl_getinfo($ch));
return [
'success' => ((int)$code === 200)
];
}
curl_close($ch);
if ((is_null($content) || $content == false) && !$test && $this->_curl_attempts < 3) {
return $this->_request($url, $options, $test);
} else {
$this->_curl_attempts = 0;
}
return $content;
}
private function _getAuthToken($service = null, $client_id = null, $secret_key = null) {
if (is_null($service))
$this->errors[] = 'Не указана площадка для получения токена авторизации API';
if (is_null($client_id) && strtolower($service) == 'avito')
$this->errors[] = 'Не указан `client_id` для получения токена авторизации API';
if (is_null($secret_key))
$this->errors[] = 'Не указан `secret_key` для получения токена авторизации API';
if (is_null($service) || (is_null($client_id) && strtolower($service) == 'avito') || is_null($secret_key))
return false;
$token = null;
switch (strtolower($service)) {
case 'avito' :
if (isset($_SESSION[$this->_session_key]['avito'])) {
$stored = $_SESSION[$this->_session_key]['avito'];
if (time() <= intval($stored['expires'])) {
$token = $stored['token'];
}
}
if (is_null($token) || $this->_is_cli) {
//var_dump($this->_tokens);
if (isset($this->_tokens['avito']) && !is_null($this->_tokens['avito'])) {
$stored = $this->_tokens['avito'];
if (time() <= intval($stored['expires'])) {
$token = $stored['token'];
}
}
// var_dump($this->_api_id);
if(empty($token) && $this->_api_id > 0){
$sql = "SELECT * FROM users_api WHERE id = {$this->_api_id}";
echo $sql;
$q = $this->_db->query($sql);
$api = $this->_db->fetch_assoc($q);
if(isset($api['token']) && !empty($api['token'])){
if (time() <= intval($api['expires_in'])) {
$token = $api['token'];
}
}
}
if (is_null($token)) {
$url = "https://api.avito.ru/token/?grant_type=client_credentials&client_id=$client_id&client_secret=$secret_key";
$response = $this->_request($url, ['type' => 'json', 'method' => 'post']);
if ($this->debug)
$this->logs["https://api.avito.ru/token/?grant_type=client_credentials&client_id=$client_id&client_secret=$secret_key"] = $response;
$data = json_decode($response, true);
$token = $data['access_token'];
if($this->_api_id > 0){
$expires = intval($data['expires_in']) + time();
$sql_in = "UPDATE users_api set token='{$token}', expires_in='{$expires}' WHERE id = {$this->_api_id}";
$this->_db->query($sql_in);
}
if ($this->_is_cli) {
$this->_tokens['avito'] = [
'expires' => intval($data['expires_in']) + time(),
'type' => strtolower($data['token_type']),
'token' => $token,
];
return $token;
} else {
if ($token) {
$_SESSION[$this->_session_key]['avito'] = [
'expires' => intval($data['expires_in']) + time(),
'type' => strtolower($data['token_type']),
'token' => $token,
];
}
}
}
}
break;
case 'cian' :
$token = $secret_key;
break;
case 'yandex' :
$token = $secret_key;
break;
case 'domclick' :
$token = $secret_key;
break;
}
return $token;
}
private function _getObjectsIds($service = null, $agency_id = null) {
$sql = "SELECT `objects`.`id`, `objects`.`nazv`
FROM `objects` AS `objects`
WHERE `objects`.`archive` <> 1 AND
`objects`.`use_in_advert` > 0";
switch (strtolower($service)) {
case 'avito' :
$sql .= " AND `objects`.`add_to_avito_feed` > 0";
break;
case 'cian' :
$sql .= " AND `objects`.`add_to_cian_feed` > 0";
break;
case 'yandex' :
$sql .= " AND `objects`.`add_to_bn_feed` > 0";
break;
case 'domclick' :
$sql .= " AND `objects`.`add_to_domclick_feed` > 0";
break;
}
$sql .= " AND `objects`.`id_add_user` IN (
SELECT `id` FROM `users`
WHERE `id` = $agency_id OR
`id_manager` = $agency_id OR
`id_manager` IN (
SELECT `id` FROM `users`
WHERE `id_manager` = $agency_id
) OR
`id_manager` IN (
SELECT `id` FROM `users`
WHERE `id_manager` IN (
SELECT `id` FROM `users`
WHERE `id_manager` = $agency_id
)
)
)";
$rez = $this->_db->query($sql);
$obj_ids = [];
while ($object = $this->_db->fetch_assoc($rez)) {
$obj_id = $object['id'];
$obj_ids[$obj_id] = $object['nazv'];
}
return $obj_ids;
}
private static function _getServiceList() {
return self::$_serviceList;
}
public static function getServiceName($service_id = null) {
$serviceList = self::_getServiceList();
return $serviceList[$service_id];
}
public static function getServiceByName($service = null) {
return array_search($service, self::_getServiceList());
}
public static function cleanUpStats($service = null, $object_id = null, $agency_id = null) {
if (is_null($agency_id))
$agency_id = User::getUserAgencyID();
$service_id = self::getServiceByName($service);
if (!is_null($service_id) && !is_null($object_id) && !is_null($agency_id)) {
$sql = "DELETE FROM `ads_stats` WHERE `service_id` = '$service_id' AND `object_id` = '$object_id' AND `agency_id` = '$agency_id'";
return mysql_query($sql);
}
return false;
}
private function _getAvitoReportsIds($ext_user_id, $client_id, $secret_key, $page = 1) {
$reportIds = [];
if ($page > 1)
$url = "https://api.avito.ru/autoload/v1/accounts/$ext_user_id/reports/?page=".intval($page);
else
$url = "https://api.avito.ru/autoload/v1/accounts/$ext_user_id/reports/";
$options = [
'auth' => 'bearer',
'token' => $this->_getAuthToken('avito', $client_id, $secret_key),
'type' => 'json'
];
if ($response = $this->_request($url, $options))
$this->logs[] = "Успешное обращение к серверу API Авито.";
else
$this->logs[] = "Произошла ошибка обращения к серверу API Авито.";
if ($this->debug)
$this->logs[$url] = $response;
$results = null;
try {
$results = json_decode($response, true);
$this->logs[] = $results;
if (is_array($results)) {
// собираем ИД последних рапортов за сутки по выгрузке и индексации фидов
$r_count = 0;
foreach ($results['reports'] as $report) {
if (!is_null($report['finished_at']) && $report['export_success'] == true) {
//if (strtotime($report['finished_at']) >= strtotime('-7 days')) {
$r_count++;
$reportIds[] = $report['id'];
//}
}
}
$this->logs[] = "Обработано " . $r_count . " рапортов о выгрузке от Avito";
$pages = intval($results['meta']['pages']);
$page = intval($results['meta']['page']);
$per_page = intval($results['meta']['per_page']);
$this->logs[] = "Текущая страница (оффсет): " . $page . " (" . ($page*$per_page) . ")";
if ($pages > $page) {
$page++;
$reportIds = array_merge($reportIds, $this->_getAvitoReportsIds($ext_user_id, $client_id, $secret_key, $page));
}
}
} catch (\Exception $exception) {
$this->logs[] = $exception;
}
return $reportIds;
}
public function getStats($service_id = null, $period = null, $client_id = null, $secret_key = null, $ext_user_id = null, $object_id = null, $is_manual = false, $agency_id = null, $offset = 0) {
ini_set('memory_limit', '256M');
$this->errors = [];
$this->_api_attempts++;
if (!$is_manual)
echo "<pre>_api_attempts " .var_export($this->_api_attempts, true). "</pre>";
$service = $this->getServiceName($service_id);
if (is_null($service))
$this->errors[] = 'Не указана площадка для получения статистики';
if (is_null($client_id) && (strtolower($service) == 'avito' || strtolower($service) == 'domclick'))
$this->errors[] = 'Не указан `client_id` для получения статистики';
if (is_null($secret_key))
$this->errors[] = 'Не указан `secret_key` для получения статистики';
if (is_null($ext_user_id) && strtolower($service) == 'avito')
$this->errors[] = 'Не указан `ext_user_id` обязательный для API Avito';
if (is_null($service) || (is_null($client_id) && (strtolower($service) == 'avito' || strtolower($service) == 'domclick')) || is_null($secret_key))
return false;
if (is_array($period)) {
$date_from = $period['date_from'];
$date_to = $period['date_to'];
} else {
$date_to = date('Y-m-d');
switch (strtolower($period)) {
case 'hour' :
$date_from = date('Y-m-d', strtotime('-1 hour'));
break;
case 'day' :
$date_from = date('Y-m-d', strtotime('-1 day'));
break;
case 'week' :
$date_from = date('Y-m-d', strtotime('-1 week'));
break;
case 'month' :
$date_from = date('Y-m-d', strtotime('-1 month'));
break;
default :
$date_from = date('Y-m-d', strtotime('-1 week'));
break;
}
}
$output = [];
$reports = [];
if (is_null($agency_id))
$agency_id = $this->_agency_id;
switch (strtolower($service)) {
case 'avito' :
// собираем ИД последних рапортов по выгрузке и индексации фидов
$reportIds = $this->_getAvitoReportsIds($ext_user_id, $client_id, $secret_key, 1, 1);
// Инвертируем список рапортов, будем шагать от старого к новому
//$reportIds = array_reverse($reportIds);
if (!$is_manual) {
echo "<pre>Всего обработано рапортов о выгрузке: " .count($reportIds). "</pre>";
echo "<pre>Рапорты о выгрузке: " . var_export($reportIds, true) . "</pre>";
}
if (count($reportIds)) {
$ads = [];
$objs = [];
$adsIds = [];
$service = $this->getServiceName($service_id);
$obj_ids = $this->_getObjectsIds($service, $agency_id);
if (!$is_manual) {
echo "<pre>Всего выгружается объектов: " . count($obj_ids) . "</pre>";
echo "<pre>Выгружаемые объекты: " . var_export($obj_ids, true) . "</pre>";
}
// обработка каждого рапорта и сбор ИД объявлений/объектов
$report_num = 0;
foreach ($reportIds as $reportId) {
if (!$is_manual)
echo "<pre>Обработка рапорта №: " . $reportId . "</pre>";
$report_status = false;
if (!is_null($reportId)) {
$url = "https://api.avito.ru/autoload/v1/accounts/$ext_user_id/reports/$reportId/";
$options = [
'auth' => 'bearer',
'token' => $this->_getAuthToken('avito', $client_id, $secret_key),
'type' => 'json'
];
if ($response = $this->_request($url, $options))
$this->logs[date('Y-m-d H:i:s')][] = "Успешное обращение к серверу API Авито.";
else
$this->logs[date('Y-m-d H:i:s')][] = "Произошла ошибка обращения к серверу API Авито.";
if ($this->debug)
$this->logs["https://api.avito.ru/autoload/v1/accounts/$ext_user_id/reports/$reportId/"] = $response;
$results = null;
try {
$results = json_decode($response, true);
if (is_array($results)) {
if (!$is_manual)
echo "<pre>В рапорте № " . $reportId . " объвлений: ". count($results['report']['ads']) ."</pre>";
$added_count = 0;
foreach ($results['report']['ads'] as $offer) {
//if (isset($offer['avito_id']) && isset($offer['ad_id'])) {
//if ($offer['statuses']['avito']) {
$ads_id = intval($offer['avito_id']);
$obj_id = intval($offer['ad_id']);
//if (array_key_exists($obj_id, array_keys($obj_ids))) { // только существующие и рекламируемые объекты JW
if (!array_key_exists($obj_id, $ads)) {
$ads[$obj_id] = array_merge($offer, ['object_id' => $obj_id]);
$adsIds[] = $ads_id;
$objs[$ads_id] = $obj_id;
$added_count++;
if (!$is_manual)
echo "<pre> - получен ИД объекта № " . $obj_id . ", ИД объвления на Авито: " . $ads_id . "</pre>";
}
if (!isset($offer['avito_id']) && !$is_manual)
echo "<pre style='color: #a4402c;'>- для объекта $obj_id не присвоен ИД объвления на авито</pre>";
if (!isset($offer['ad_id']) && !$is_manual)
echo "<pre style='color: #a4402c;'>- не присвоен ИД объекта для объявления $ads_id на авито</pre>";
//}
//}
//}
}
$report_status = true;
if (!$is_manual)
echo "<pre> По рапорту № " . $reportId . " обработано всего ИД объвлений: ". $added_count ."</pre>";
}
} catch (\Exception $exception) {
$this->logs[date('Y-m-d H:i:s')][] = $exception;
}
}
if (!$is_manual)
echo "<pre>Статус обработки рапорта №: " . $reportId . " - завершено ". ($report_status) ? 'успешно' : 'с ошибкой' ."</pre>";
sleep(5);
$report_num++;
if ($report_num > 5) // (!) обрабатывает только 3 последних рапорта
break;
}
$not_stored_obj = array_diff(array_keys($obj_ids), array_values($objs));
if ($this->debug)
$this->logs[date('Y-m-d H:i:s')][] = "Объекты, по которым не удалось получить статистику: " . implode(', ', $not_stored_obj);
if (!$is_manual) {
echo "<pre>Всего объявлений получено: " . count($ads) . "</pre>";
echo "<pre>Объявления: " . var_export($ads, true) . "</pre>";
echo "<pre>Объекты, по которым не удалось получить статистику: " . implode(', ', $not_stored_obj) . "</pre>";
}
$adsIds = array_filter($adsIds, function($value) {
return ($value !== null && $value !== false && $value !== 0);
});
if (count($ads) > 0 && count($adsIds) > 0) {
if (is_null($offset) || !is_numeric($offset))
$offset = 0;
if (!$is_manual)
echo "<pre>Собираем статистику для объявлений: " .var_export($adsIds, true). "</pre>";
$itemsIds = array_slice($adsIds, $offset, 200);
if (count($itemsIds)) {
$_offset = 0;
$_total = count($ads);
if ($_total > $_offset && $offset !== $_offset) {
$_offset += 200;
$offset = $_offset;
} else {
$offset = null;
}
$this->logs["count(itemsIds)"][] = count($itemsIds);
$this->logs["itemsIds"][] = $itemsIds;
$this->logs["total"][] = $_total;
$this->logs["offset"][] = $offset;
if ($this->debug)
$this->logs["avito->total"][] = $_total;
if ($this->debug)
$this->logs["avito->offset"][] = $offset;
if (!$is_manual) {
echo "<pre>total " . $_total . "</pre>";
echo "<pre>offset " . $offset . "</pre>";
}
// обработка ошибок и сбор мета-данных по каждому объявлению
foreach ($ads as $offer) {
$obj_id = $offer['object_id'];
if (count($offer['messages']) > 0) {
foreach ($offer['messages'] as $message) {
//if ($message['type'] == 'error' || $message['type'] == 'warning') {
if ($message['type'] == 'error') {
if (!is_null($message['description'])) {
$reports[$obj_id]['errors'][] = $message['description'];
}
if (!$is_manual)
echo "<pre> - ошибка размещения у объекта $obj_id: " .$message['description']. "</pre>";
}
}
// Запись в сфинкс флага об ошибке размещения
try {
if (!is_null($this->_db_sphinx)) {
if (count($reports[$obj_id]['errors']) > 0)
$this->_db_sphinx->query("UPDATE objects SET ads_error = 1 WHERE id = $obj_id");
else
$this->_db_sphinx->query("UPDATE objects SET ads_error = 0 WHERE id = $obj_id");
}
} catch (\Exception $exception) {
$this->errors[] = $exception;
}
}
if ($offer['statuses']['general']['value'] == 'success' || $offer['statuses']['avito']['value'] == 'active')
$reports[$obj_id]['success'] = true;
else
$reports[$obj_id]['success'] = false;
if (isset($offer['url']))
$reports[$obj_id]['url'] = $offer['url'];
else
$reports[$obj_id]['url'] = null;
}
// Запрос и сбор статистики по просмотрам
$url = "https://api.avito.ru/stats/v1/accounts/$ext_user_id/items";
$options = [
'auth' => 'bearer',
'token' => $this->_getAuthToken('avito', $client_id, $secret_key),
'method' => 'post',
'type' => 'json',
'data' => [
'dateFrom' => $date_from,
'dateTo' => $date_to,
'fields' => [
'uniqViews',
'uniqContacts',
'uniqFavorites'
],
'itemIds' => array_values($itemsIds)
]
];
if (!$is_manual)
echo "<pre>Собираем статистику лишь для объявлений: " .var_export($itemsIds, true). "</pre>";
$response = $this->_request($url, $options);
if ($this->debug)
$this->logs["https://api.avito.ru/stats/v1/accounts/$ext_user_id/items"] = $response;
if (!$is_manual)
echo "<pre>response " .var_export($response, true). "</pre>";
try {
if ($results = json_decode($response, true)) {
if (isset($results['result']['items'])) {
foreach ($results['result']['items'] as $item) {
//$this->logs[date('Y-m-d H:i:s')][] = $results['result']['items'];
$ad_id = $item['itemId'];
if ($obj_id = $objs[$ad_id]) {
foreach ($item['stats'] as $stats) {
$reports[$obj_id]['views'] += intval($stats['uniqViews']);
$reports[$obj_id]['contacts'] += intval($stats['uniqContacts']);
$reports[$obj_id]['favorites'] += intval($stats['uniqFavorites']);
}
}
}
}
} else {
$this->logs[date('Y-m-d H:i:s')][] = "Ошибка разбора ответа от API Авито.";
}
} catch (\Exception $exception) {
$this->logs[date('Y-m-d H:i:s')][] = $exception;
}
sleep(5);
// запрос и сбор статистики по звонкам
$url = "https://api.avito.ru/core/v1/accounts/$ext_user_id/calls/stats/";
$options = [
'auth' => 'bearer',
'token' => $this->_getAuthToken('avito', $client_id, $secret_key),
'method' => 'post',
'type' => 'json',
'data' => [
'dateFrom' => $date_from,
'dateTo' => $date_to,
'itemIds' => array_values($itemsIds)
]
];
$response = $this->_request($url, $options);
if ($this->debug)
$this->logs["https://api.avito.ru/core/v1/accounts/$ext_user_id/calls/stats/"] = $response;
try {
if ($results = json_decode($response, true)) {
if (isset($results['result']['items'])) {
$this->logs = [];
foreach ($results['result']['items'] as $item) {
//$this->logs[date('Y-m-d H:i:s')][] = $results['result']['items'];
$ad_id = $item['itemId'];
if ($obj_id = $objs[$ad_id]) {
foreach ($item['days'] as $stats) {
$reports[$obj_id]['calls'] += intval($stats['calls']);
}
}
}
$this->logs[date('Y-m-d H:i:s')][] = $ads;
}
} else {
$this->logs[date('Y-m-d H:i:s')][] = "Ошибка разбора ответа от API Авито.";
}
} catch (\Exception $exception) {
$this->logs[date('Y-m-d H:i:s')][] = $exception;
}
if (!$is_manual)
echo "<pre>reports " .var_export($reports, true). "</pre>";
if (!is_null($object_id) && in_array($object_id, $objs)) {
$output = $reports[$object_id];
}
sleep(5);
}
}
/*if (count($not_stored_obj) > 0) {
}*/
}
break;
case 'cian' :
$url = "https://public-api.cian.ru/v1/get-order";
$options = [
'auth' => 'bearer',
'token' => $this->_getAuthToken('cian', null, $secret_key),
'type' => 'json'
];
if ($response = $this->_request($url, $options))
$this->logs[] = "Успешное обращение к серверу API ЦИАН.";
else
$this->logs[] = "Произошла ошибка обращения к серверу API ЦИАН.";
if ($this->debug)
$this->logs["https://public-api.cian.ru/v1/get-order"] = $response;
$results = null;
try {
$results = json_decode($response, true);
} catch (\Exception $exception) {
$this->logs[] = $exception;
}
if (is_array($results)) {
$stored_ids = [];
foreach ($results['result']['offers'] as $offer) {
$ad_id = $offer['offerId'];
$offer_id = $offer['offerId'];
$url = "https://public-api.cian.ru/v1/get-views-statistics-by-days?offerId=$ad_id&dateFrom=$date_from&dateTo=$date_to";
$options = [
'auth' => 'bearer',
'token' => $this->_getAuthToken('cian', null, $secret_key),
'type' => 'json'
];
$response = $this->_request($url, $options);
if ($this->debug)
$this->logs["https://public-api.cian.ru/v1/get-views-statistics-by-days?offerId=$ad_id&dateFrom=$date_from&dateTo=$date_to"] = $response;
try {
$results2 = json_decode($response, true);
$report = [];
$report['errors'] = [];
if (isset($offer['result']['message'])) {
$report['errors'] = [$offer['result']['message']];
}
if (count($offer['errors']) > 0)
$report['errors'] = array_merge($report['errors'], $offer['errors']);
//if (count($offer['warnings']) > 0)
// $report['errors'] = array_merge($report['errors'], $offer['warnings']);
if ($offer['status'] == "Published") {
$report['success'] = true;
} else {
switch ($offer['status']) {
case "Blocked" :
$report['errors'][] = "Объявление снято с публикации по причине применения санкции.";
break;
case "Deactivated" :
$report['errors'][] = "Объявление было деактивировано (было скрыто).";
break;
case "Deleted" :
$report['errors'][] = "Объявление было удалёно.";
break;
case "Draft" :
$report['errors'][] = "Объявление является черновиком.";
break;
case "Moderate" :
$report['errors'][] = "Объявление требует модерации.";
break;
case "Refused" :
$report['errors'][] = "Объявление было отклонено модератором.";
break;
case "RemovedByModerator" :
$report['errors'][] = "Объявление было удалено модератором.";
break;
case "Sold" :
$report['errors'][] = "Объявление не активно (объект продан/сдан).";
break;
}
$report['success'] = false;
}
if (isset($offer['url']))
$report['url'] = $offer['url'];
else
$report['url'] = null;
if (isset($results2['result']['viewsByDays'])) {
foreach ($results2['result']['viewsByDays'] as $stats) {
if (isset($stats['views']))
$report['views'] += intval($stats['views']);
}
} else {
$this->logs[] = "Ошибка разбора ответа от API ЦИАН.";
}
$report['calls'] = null;
$report['favorites'] = null;
if (isset($results2['result']['phoneShowsByDays'])) {
foreach ($results2['result']['phoneShowsByDays'] as $stats) {
if (isset($stats['phoneShows']))
$report['contacts'] += intval($stats['phoneShows']);
}
} else {
$this->logs[] = "Ошибка разбора ответа от API ЦИАН.";
}
$ad_id = $offer['externalId'];
$stored_ids[$offer_id] = $ad_id;
$reports[$ad_id] = $report;
// Запись в сфинкс флага об ошибке размещения
try {
if (!is_null($this->_db_sphinx)) {
if (count($reports[$ad_id]['errors']) > 0)
$this->_db_sphinx->query("UPDATE objects SET ads_error = 1 WHERE id = $ad_id");
else
$this->_db_sphinx->query("UPDATE objects SET ads_error = 0 WHERE id = $ad_id");
}
} catch (\Exception $exception) {
$this->errors[] = $exception;
}
if (!is_null($object_id) && $object_id == $ad_id) {
$output = $reports[$ad_id];
}
} catch (\Exception $exception) {
$this->logs[] = $exception;
}
}
//...
$part = 0;
$limit = 0;
$ads_query = [];
$ads_ids_query = '';
foreach ($results['result']['offers'] as $offer) {
if (!empty($ads_ids_query))
$ads_ids_query .= "&offersIds=" . $offer['offerId'];
else
$ads_ids_query .= "?offersIds=" . $offer['offerId'];
$ads_query[$part] = "https://public-api.cian.ru/v1/get-views-statistics" . $ads_ids_query;
if ($limit > 9) {
$ads_ids_query = '';
$limit = 0;
$part++;
} else {
$limit++;
}
}
if (isset($_GET['dev'])) {
var_export($ads_query);
}
if (!empty($ads_query)) {
foreach ($ads_query as $url) {
$options = [
'auth' => 'bearer',
'token' => $this->_getAuthToken('cian', null, $secret_key),
'type' => 'json'
];
$response = $this->_request($url, $options);
if ($this->debug)
$this->logs[$url] = $response;
try {
$offer = json_decode($response, true);
if (isset($offer['result']['statistics'])) {
$add_report = [];
$add_report['contacts'] = null;
$add_report['views'] = null;
$statistics = $offer['result']['statistics'];
foreach ($statistics as $offer_stats) {
if (isset($_GET['dev'])) {
var_export($offer_stats);
}
$add_report['contacts'] = intval($offer_stats['phoneShows']);
$add_report['views'] = intval($offer_stats['totalViews']);
$offer_id = $offer_stats['offerId'];
$ad_id = $stored_ids[$offer_id];
if (isset($_GET['dev'])) {
var_export($reports[$ad_id]);
var_export($add_report);
}
//if (isset($reports[$ad_id])) {
$reports[$ad_id] = array_merge($reports[$ad_id], [
'contacts' => !is_null($add_report['contacts']) ? $add_report['contacts'] : $reports[$ad_id]['contacts'],
'views' => !is_null($add_report['views']) ? $add_report['views'] : $reports[$ad_id]['views']
]);
if (!is_null($object_id) && $object_id == $ad_id) {
$output = $reports[$ad_id];
}
//}
}
}
} catch (\Exception $exception) {
$this->logs[] = $exception;
}
sleep(2);
}
}
}
break;
case 'yandex' :
$url = "https://api.realty.yandex.net/2.0/crm/feeds";
$options = [
'auth' => 'oauth',
'token' => $this->_getAuthToken('yandex', null, $secret_key),
'method' => 'get',
'type' => 'json',
'headers' => [
'X-Authorization: Vertis crm-dff153a8ef1a90d3bff5ee378dee416606cf8915'
],
];
if ($response = $this->_request($url, $options))
$this->logs[] = "Успешное обращение к серверу API Яндекс.Недвижимость.";
else
$this->logs[] = "Произошла ошибка обращения к серверу API Яндекс.Недвижимость.";
if ($this->debug)
$this->logs["https://api.realty.yandex.net/2.0/crm/feeds"] = $response;
$results = null;
try {
$results = json_decode($response, true);
} catch (\Exception $exception) {
$this->logs[] = $exception;
}
if (is_array($results)) {
if (isset($results['feeds'])) {
$feed_uid = null;
foreach ($results['feeds'] as $feed) {
if ($feed['url'] == "https://joywork.ru/bn_ya_feeds/$agency_id.xml") {
if ($feed['status'] == "ACCEPTED" || $feed['status'] == "ACCEPTED_WITH_REMARKS")
$feed_uid = $feed['id'];
/*if ($feed['status'] == "ACCEPTED_WITH_REMARKS")
$reports['errors'] = ["XML-фид содержащий объект обработан с замечаниями публикации."];*/
}
}
if (!is_null($feed_uid)) {
if ($offset)
$url = "https://api.realty.yandex.net/2.0/crm/offers?offset=".$offset;
else
$url = "https://api.realty.yandex.net/2.0/crm/offers";
$options = [
'auth' => 'oauth',
'token' => $this->_getAuthToken('yandex', null, $secret_key),
'method' => 'get',
'type' => 'json',
'headers' => [
'X-Authorization: Vertis crm-dff153a8ef1a90d3bff5ee378dee416606cf8915'
],
];
$response = $this->_request($url, $options);
if ($this->debug)
$this->logs["https://api.realty.yandex.net/2.0/crm/offers"] = $response;
try {
$results2 = json_decode($response, true);
$_offset = 0;
$_total = $results2['listing']['slicing']['total'];
if (isset($results2['listing']['slicing']['range']['to']))
$_offset = intval($results2['listing']['slicing']['range']['to']);
elseif (isset($results2['listing']['slicing']['fragment']['offset']))
$_offset = intval($results2['listing']['slicing']['fragment']['offset']) + 100;
if ($_total > $_offset && $offset !== $_offset)
$offset = $_offset;
else
$offset = null;
if ($this->debug)
$this->logs["yandex->offset"][] = $offset;
$this->logs['yandex->offers'] = $results2;
if (isset($results2['listing']['snippets'])) {
foreach ($results2['listing']['snippets'] as $value) {
$offer = $value['offer'];
if ($feed_uid == $offer['feedId']) {
$report = [];
$ad_id = $offer['id'];
$url = "https://api.realty.yandex.net/2.0/crm/offer/$ad_id/stats?startTime=$date_from&endTime=$date_to";
$options = [
'auth' => 'oauth',
'token' => $this->_getAuthToken('yandex', null, $secret_key),
'method' => 'get',
'type' => 'json',
'headers' => [
'X-Authorization: Vertis crm-dff153a8ef1a90d3bff5ee378dee416606cf8915'
],
];
$response = $this->_request($url, $options);
if ($this->debug)
$this->logs["https://api.realty.yandex.net/2.0/crm/offer/$ad_id/stats?startTime=$date_from&endTime=$date_to"] = $response;
try {
$report['success'] = (empty($offer['state'])) ? true : false;
/*if (count($offer['state']['errors']) > 0)
$report['errors'] = array_merge($reports['errors'], $offer['state']['errors']['type']);*/
if (count($offer['state']['errors']) > 0) {
foreach ($offer['state']['errors'] as $error) {
switch ($error['type']) {
case 'AD_ON_PHOTO' :
$report['errors'][] = "На фотографиях размещена рекламная информация.";
break;
case 'AGENT_PHONE_NOT_SET' :
$report['errors'][] = "Телефон агента или продавца не указан или указан в неправильном формате.";
break;
case 'BAD_PHOTO' :
$report['errors'][] = "В объявлении используются неинформативные фотографии.";
break;
case 'BAN_OFFERS_WITHOUT_CADASTRAL_NUMBER' :
$report['errors'][] = "Пропущено обязательное поле.";
break;
case 'BANNED_AGENCY' :
$report['errors'][] = "Объявления этого агентства имеют низкий уровень достоверности.";
break;
case 'CHECK_ALREADY_BOOKED' :
$report['errors'][] = "При проверке выяснилось, что объект находится под залогом.";
break;
case 'CHECK_INCORRECT_WATERMARK' :
$report['errors'][] = "В объявлении используются фотографии, на которых есть посторонние изображения.";
break;
case 'CHECK_OFFER_IS_AD' :
$report['errors'][] = "Проверка модератором: объявление носит рекламный характер.";
break;
case 'CHECK_OFFER_SOLD_OUT' :
$report['errors'][] = "Проверка модератором: объект из объявления продан.";
break;
case 'CHECK_STOPWORD' :
$report['errors'][] = "В описании объявления или в имени автора используются нецензурные выражения или реклама.";
break;
case 'CHECK_UNAVAILABLE' :
$report['errors'][] = "До продавца невозможно дозвониться.";
break;
case 'CHECK_UNKNOWN_OBJECT' :
$report['errors'][] = "Контактное лицо, указанное в объявлении, не владеет информацией об объекте.";
break;
case 'CHECK_UNKNOWN_REASON' :
$report['errors'][] = "Объявление заблокировано по жалобе пользователя.";
break;
case 'CHECK_WRONG_ADDRESS' :
$report['errors'][] = "Проверка модератором: указан неверный адрес объекта.";
break;
case 'CHECK_WRONG_DATA' :
$report['errors'][] = "Проверка модератором: несоответствие параметров в объявлении.";
break;
case 'CHECK_WRONG_PHOTO' :
$report['errors'][] = "Объявление содержит фотографии низкого качества или фотографии, не относящиеся к объекту.";
break;
case 'CHECK_WRONG_PRICE' :
$report['errors'][] = "Проверка модератором: в объявлении указана неверная цена.";
break;
case 'CLONE' :
$report['errors'][] = "У вас уже есть такое объявление.";
break;
case 'COORDINATES_NOT_FOUND' :
$report['errors'][] = "Географические координаты объекта вычислены неправильно.";
break;
case 'COMMERCIAL_IN_LIVING' :
$report['errors'][] = "Тип объекта не соответствует разделу сервиса.";
break;
case 'COMPLAINT_FROM_OWNER' :
$report['errors'][] = "Информация о собственнике скрыта или объявление размещено без согласия собственника.";
break;
case 'CONTACT_IN_DESCRIPTION' :
$report['errors'][] = "Контакты в описании.";
break;
case 'CREATION_DATE_NOT_SET' :
$report['errors'][] = "Дата создания объявления не указана или указана в неподходящем формате.";
break;
case 'DAMAGED_PHOTO' :
$report['errors'][] = "В объявлении используются маленькие фотографии или фотографии низкого качества.";
break;
case 'HOTEL' :
$report['errors'][] = "Яндекс.Недвижимость не размещает объявления об аренде номеров в гостиницах и хостелах.";
break;
case 'HOUSE_IN_APARTMENT' :
$report['errors'][] = "Тип объекта не соответствует разделу сервиса.";
break;
case 'HOUSE_IN_LOT' :
$report['errors'][] = "Тип объекта не соответствует разделу сервиса.";
break;
case 'ILLEGAL_SELL_FOR_LEGAL_ADDRESS' :
$report['errors'][] = "В объявлении о продаже коммерческого объекта указана категория «legal address» (юридический адрес).";
break;
case 'INACTIVE_CAMPAIGN' :
$report['errors'][] = "Рекламная кампания неактивна.";
break;
case 'INTERNAL_ID_NOT_SET' :
$report['errors'][] = "Не указан идентификатор объявления.";
break;
case 'INVALID_COMMERCIAL_TYPES' :
$report['errors'][] = "Не указана категория коммерческого объекта.";
break;
case 'INVALID_COMMISSION' :
$report['errors'][] = "Неправильно указан размер комиссии.";
break;
case 'INVALID_ELECTRIC_CAPACITY' :
$report['errors'][] = "Неправильно указана выделенная электрическая мощность.";
break;
case 'INVALID_FULL_OPTION_SALE' :
$report['errors'][] = "Нельзя размещать переуступку на минимальном тарифе.";
break;
case 'INVALID_GARAGE_TYPE' :
$report['errors'][] = "Не указан тип гаража.";
break;
case 'INVALID_PALLET_PRICE' :
$report['errors'][] = "Неправильно указана стоимость палето-места.";
break;
case 'INVALID_PARKING_GUEST_PLACES' :
$report['errors'][] = "Неправильно указано количество гостевых парковочных мест.";
break;
case 'INVALID_PARKING_PLACE_PRICE' :
$report['errors'][] = "Неправильно указана стоимость парковочного места.";
break;
case 'INVALID_PARKING_PLACES' :
$report['errors'][] = "Неправильно указано количество предоставляемых парковочных мест.";
break;
case 'INVALID_PHONE_LINES' :
$report['errors'][] = "Неправильно указано количество телефонных линий.";
break;
case 'INVALID_PRICE' :
$report['errors'][] = "Недостоверная цена.";
break;
case 'INVALID_PRIMARY_SALE' :
$report['errors'][] = "Объявления «от застройщика» могут быть размещены только авторизованными партнерами.";
break;
case 'INVALID_SECURITY_PAYMENT' :
$report['errors'][] = "Неправильно указан размер обеспечительного платежа.";
break;
case 'INVALID_USE_OF_OPEN_PLAN' :
$report['errors'][] = "Значение «свободная планировка» используется только для объявлений о продаже квартир и коммерческой недвижимости.";
break;
case 'INVALID_USE_OF_STUDIO' :
$report['errors'][] = "Значение «студия» используется только для объявлений о продаже квартир.";
break;
case 'LIVING_SPACE_IS_TOO_HIGH' :
$report['errors'][] = "Неправильно указана жилая площадь.";
break;
case 'LOCATION_NOT_FOUND' :
$report['errors'][] = "Неизвестно местоположение объекта.";
break;
case 'LOT_AREA_NOT_SET' :
$report['errors'][] = "Не указана площадь участка.";
break;
case 'LOT_HAS_AREA_AND_LOT_AREA' :
$report['errors'][] = "В объявлении о продаже участка без дома площадь участка передана в теге area.";
break;
case 'LOT_RENT' :
$report['errors'][] = "Яндекс.Недвижимость не размещает объявления об аренде участков.";
break;
case 'LOW_ACTUALITY' :
$report['errors'][] = "Объявление не соответствуют требованиям Яндекс.Недвижимости.";
break;
case 'NEW_IN_OLD' :
$report['errors'][] = "Тип объекта не соответствует разделу сервиса.";
break;
case 'NO_IMAGES' :
$report['errors'][] = "Отсутствуют фотографии объекта.";
break;
case 'NO_INFO' :
$report['errors'][] = "Объект закрыт для просмотра или не существует.";
break;
case 'NO_PLACEMENT' :
$report['errors'][] = "Необходимо оплатить размещение объявлений.";
break;
case 'NO_PLAN_PHOTO' :
$report['errors'][] = "В объявлении о продаже квартиры в новостройке нет изображения планировки.";
break;
case 'NO_ROOMS_IN_APARTMENT' :
$report['errors'][] = "Не указано количество комнат в квартире.";
break;
case 'NO_ROOMS_OFFERED_FOR_ROOMS' :
$report['errors'][] = "В объявлении о продаже или аренде комнат не указано количество комнат, участвующих в сделке, и общее количество комнат.";
break;
case 'NO_SHOW' :
$report['errors'][] = "Объект закрыт для просмотра.";
break;
case 'NOT_REALTY' :
$report['errors'][] = "Объявление содержит информацию о продаже товаров или услуг.";
break;
case 'OFFER_TOO_OLD' :
$report['errors'][] = "Слишком старое объявление.";
break;
case 'OLD_PHOTO' :
$report['errors'][] = "В объявлении используются старые фотографии.";
break;
case 'PARTIALLY_ADDRESS' :
$report['errors'][] = "Неполный адрес или неточная метка на карте.";
break;
case 'PEOPLE_ON_PHOTO' :
$report['errors'][] = "На снимках есть люди или посторонние предметы.";
break;
case 'PHONE_NOT_EXIST' :
$report['errors'][] = "Указан неверный или недействительный телефон.";
break;
case 'PHONE_UNAVAILABLE' :
$report['errors'][] = "Указан неверный или недействительный телефон.";
break;
case 'PHOTO_STEAL' :
$report['errors'][] = "Недостоверные или чужие фотографии.";
break;
case 'REGISTRATION' :
$report['errors'][] = "Объявление содержит информацию об услугах.";
break;
case 'RENT_IN_SELL' :
$report['errors'][] = "Тип сделки не соответствует разделу сервиса.";
break;
case 'PRICE_ERROR' :
$report['errors'][] = "Недостоверная цена.";
break;
case 'PRICE_NOT_SET' :
$report['errors'][] = "Не указана цена объекта.";
break;
case 'PRICE_PERIOD_NOT_SET_FOR_RENT' :
$report['errors'][] = "Срок аренды указан в неподходящем формате.";
break;
case 'PRICE_PERIOD_SET_FOR_SELL' :
$report['errors'][] = "В объявлении о продаже объекта указан период для расчета стоимости аренды.";
break;
case 'PRICE_PERIOD_UNKNOWN' :
$report['errors'][] = "Неправильно указан период для расчета стоимости аренды.";
break;
case 'PRICE_UNIT_UNKNOWN' :
$report['errors'][] = "Неизвестная единица измерения площади.";
break;
case 'ROOM_IN_APARTMENT' :
$report['errors'][] = "Тип объекта не соответствует разделу сервиса.";
break;
case 'ROOMS_OFFERED_GREATER_OR_EQUAL_THAN_ROOMS' :
$report['errors'][] = "Количество комнат в квартире, предлагаемых для аренды или покупки, превышает общее количество комнат в квартире.";
break;
case 'ROOMS_SPACE_NOT_MATCH_ROOMS_COUNT' :
$report['errors'][] = "Количество переданных значений площади комнат не соответствует количеству комнат.";
break;
case 'SERVICE_SUGGEST' :
$report['errors'][] = "В объявлении предлагаются услуги или другие объекты.";
break;
case 'SITE_OFFER_BASE_FIELD_NOT_SET' :
$report['errors'][] = "Отсутствуют поля, обязательные для новостроек.";
break;
case 'STRANGE_DISTANCE_FOR_MANUAL_POINT' :
$report['errors'][] = "Указанные координаты не соответствуют действительности.";
break;
case 'SUSPICIOUS_OFFER_AGE' :
$report['errors'][] = "Объявление не соответствует требованиям к срокам размещения.";
break;
case 'TEXT_IN_PHOTO' :
$report['errors'][] = "В объявлении используются фотографии, на которых есть посторонние изображения.";
break;
case 'TOO_BIG_LOT_AREA' :
$report['errors'][] = "Объекты площадью более 1 гектара считаются участками коммерческого назначения.";
break;
case 'UNKNOWN_CATEGORY' :
$report['errors'][] = "Неправильно указаны категория объекта или тип продавца (арендодателя).";
break;
case 'UNKNOWN_LOCATION_TYPE' :
$report['errors'][] = "Недостаточно информации для определения точного местоположения объекта.";
break;
case 'UNKNOWN_NEWBUILDING' :
$report['errors'][] = "Объявление об объекте в неизвестной новостройке.";
break;
case 'UNKNOWN_TYPE' :
$report['errors'][] = "Неправильно указан тип сделки.";
break;
case 'URL_NOT_SET' :
$report['errors'][] = "Не указана ссылка на объявление.";
break;
case 'VILLAGE_NON_TARGET_SALE' :
$report['errors'][] = "В этом посёлке нельзя размещать вторичку.";
break;
case 'WRONG_AREA' :
$report['errors'][] = "Неверно указана площадь объекта.";
break;
case 'WRONG_CADASTRAL' :
$report['errors'][] = "Неверный или недействительный кадастровый номер.";
break;
case 'WRONG_FLOOR' :
$report['errors'][] = "Неверно указан этаж или количество этажей в здании.";
break;
case 'WRONG_LOT_AREA' :
$report['errors'][] = "Неверно указана площадь участка.";
break;
case 'WRONG_NAME' :
$report['errors'][] = "Имя продавца указано некорректно.";
break;
case 'WRONG_PIN' :
$report['errors'][] = "Неполный адрес или неточная метка на карте.";
break;
case 'WRONG_PRICE_PERIOD' :
$report['errors'][] = "Цена не соответствует периоду аренды.";
break;
case 'WRONG_ROOMS' :
$report['errors'][] = "Неверно указано число комнат.";
break;
}
}
}
if (isset($offer['url']))
$report['url'] = $offer['url'];
else
$report['url'] = null;
$results3 = json_decode($response, true);
if (isset($results3['stats']['daily'])) {
foreach ($results3['stats']['daily'] as $stats) {
$report['views'] += intval($stats['cardShows']);
$report['contacts'] += intval($stats['phoneShows']);
$report['favorites'] = null;
$report['calls'] += intval($stats['calls']);
}
} else {
$this->logs[] = "Ошибка разбора ответа от API Яндекс.Недвижимость.";
}
$ad_id = $offer['internalId'];
$reports[$ad_id] = $report;
// Запись в сфинкс флага об ошибке размещения
try {
if (!is_null($this->_db_sphinx)) {
if (count($reports[$ad_id]['errors']) > 0)
$this->_db_sphinx->query("UPDATE objects SET ads_error = 1 WHERE id = $ad_id");
else
$this->_db_sphinx->query("UPDATE objects SET ads_error = 0 WHERE id = $ad_id");
}
} catch (\Exception $exception) {
$this->errors[] = $exception;
}
if (!is_null($object_id) && $object_id == $ad_id) {
$output = $reports[$ad_id];
}
} catch (\Exception $exception) {
$this->logs[] = $exception;
}
}
}
} else {
$this->logs[] = "Ошибка разбора ответа от API Яндекс.Недвижимость.";
}
} catch (\Exception $exception) {
$this->logs[] = $exception;
}
} else {
$this->logs[] = "Не найден принятый и обработанный фид в Яндекс.Недвижимость.";
}
} else {
$this->logs[] = "Ошибка разбора ответа от API Яндекс.Недвижимость.";
}
}
break;
case 'domclick' :
$url = "https://my.domclick.ru/api/v1/company/$client_id/report";
$options = [
'auth' => 'token',
'token' => $this->_getAuthToken('domclick', $client_id, $secret_key),
'method' => 'get',
'type' => 'xml',
];
if ($response = $this->_request($url, $options))
$this->logs[] = "Успешное обращение к серверу API Домклик.";
else
$this->logs[] = "Произошла ошибка обращения к серверу API Домклик.";
if ($this->debug)
$this->logs["https://my.domclick.ru/api/v1/company/$client_id/report"] = $response;
$results = null;
try {
$xml = simplexml_load_string($response, null, LIBXML_NOCDATA);
$results = json_decode(json_encode((array)$xml), true);
$results = array($xml->getName() => $results);
} catch (\Exception $exception) {
$this->logs[] = $exception;
}
if (is_array($results)) {
if ($results['Report']['OfferList']['Offer']) {
foreach ($results['Report']['OfferList']['Offer'] as $offer) {
if ($offer['@attributes']['source'] == 'feed' && isset($offer['ExternalId'])) {
$report = [];
$ad_id = null;
$ads_url = $offer['Publication']['DomclickURL'];
$report['url'] = $ads_url;
$report['success'] = (!empty($ads_url)) ? true : false;
if (preg_match("/\_\_(\d+)+$/", $ads_url, $matches)) {
$ad_id = $matches[1];
if (!is_null($ad_id)) {
$report['views'] += intval($offer['Publication']['ViewsCount']);
$report['contacts'] = null;
$report['favorites'] = null;
$report['calls'] += intval($offer['Publication']['CallsCount']);
}
}
$ad_id = $offer['ExternalId'];
$reports[$ad_id] = $report;
// Запись в сфинкс флага об ошибке размещения
try {
if (!is_null($this->_db_sphinx)) {
if (count($reports[$ad_id]['errors']) > 0)
$this->_db_sphinx->query("UPDATE objects SET ads_error = 1 WHERE id = $ad_id");
else
$this->_db_sphinx->query("UPDATE objects SET ads_error = 0 WHERE id = $ad_id");
}
} catch (\Exception $exception) {
$this->errors[] = $exception;
}
if (!is_null($object_id) && $object_id == $ad_id) {
$output = $reports[$ad_id];
}
}
}
}
}
break;
}
$this->logs['save_report_status'] = $this->saveReports($service_id, $agency_id, $reports, $is_manual);
if (!$is_manual)
echo "<pre> Отчёт о сохранении статистики: " . var_export($this->logs['save_report_status'], true) ."</pre>";
if ($offset) {
return $this->getStats($service_id, $period, $client_id, $secret_key, $ext_user_id, $object_id, $is_manual, $agency_id, $offset);
} else {
if (!is_null($object_id)) {
if (!$is_manual)
echo "<pre> Результат выборки статистики: " . var_export($output, true) ."</pre>";
return $output;
} else {
if (!$is_manual)
echo "<pre> Результат выборки статистики: " . var_export($reports, true) ."</pre>";
return $reports;
}
}
}
public function getReports($service_id = null, $agency_id = null, $object_id = null) {
$processed_at = date('Y-m-d H:i:s', strtotime('-1 hours'));
$sql = "SELECT * FROM `ads_stats`
WHERE `object_id` = '$object_id' AND
`agency_id` = '$agency_id'";
if (!is_null($service_id)) {
$sql .= " AND `service_id` = '$service_id' LIMIT 1";
}
$sql .= " ORDER BY `processed_at` DESC";
if ($query = mysql_query($sql)) {
if (mysql_num_rows($query) > 0) {
$reports = [];
while ($row = mysql_fetch_assoc($query)) {
$service_id = intval($row['service_id']);
if ($serviceName = $this->getServiceName($service_id)) {
$report = [
'views' => (!is_null($row['views'])) ? intval($row['views']) : '-',
'contacts' => (!is_null($row['contacts'])) ? intval($row['contacts']) : '-',
'favorites' => (!is_null($row['favorites'])) ? intval($row['favorites']) : '-',
'calls' => (!is_null($row['calls'])) ? intval($row['calls']) : '-',
'url' => strval($row['url']),
'errors' => array_unique(json_decode($row['errors'])),
];
if (!isset($reports[$serviceName]))
$reports[$serviceName] = $report;
else
continue;
}
}
return $reports;
}
}
return null;
}
public function saveReports($service_id = null, $agency_id = null, $reports = [], $is_manual = false) {
if (is_null($service_id) || $service_id == 0)
return false;
if (is_null($agency_id) || $agency_id == 0)
return false;
if (count($reports) > 0) {
$is_manual = ($is_manual) ? '1' : '0';
$processed_at = date('Y-m-d H:i:s');
$sql = "DELETE FROM `ads_stats` WHERE `service_id` = '$service_id' AND (`agency_id` = '$agency_id' OR `agency_id` = 0)";
$sql2 = "INSERT INTO `ads_stats` (
`object_id`,
`service_id`,
`views`,
`contacts`,
`favorites`,
`calls`,
`url`,
`errors`,
`is_error`,
`is_manual`,
`agency_id`,
`status`,
`processed_at`
) VALUES ";
$ids = [];
$values = [];
foreach ($reports as $object_id => $report) {
$errors = json_encode($report['errors'], JSON_UNESCAPED_UNICODE);
if ($errors == "[]" || $errors == "null")
$errors = null;
$views = 'NULL';
if (!is_null($report['views']))
$views = $report['views'];
$contacts = 'NULL';
if (!is_null($report['contacts']))
$contacts = $report['contacts'];
$favorites = 'NULL';
if (!is_null($report['favorites']))
$favorites = $report['favorites'];
$calls = 'NULL';
if (!is_null($report['calls']))
$calls = $report['calls'];
$url = 'NULL';
if (!is_null($report['url']))
$url = "'$report[url]'";
if (is_null($errors))
$errors = 'NULL';
else
$errors = "'".addslashes($errors)."'";
$is_error = (count($report['errors']) > 0) ? '1' : '0';
$status = ($report['success']) ? '1' : '0';
$values[] = "(
'$object_id',
'$service_id',
$views,
$contacts,
$favorites,
$calls,
$url,
$errors,
'$is_error',
'$is_manual',
'$agency_id',
'$status',
'$processed_at'
)";
$ids[] = $object_id;
}
$sql .= " AND `object_id` IN (" . implode(', ', $ids) . ")";
$sql2 .= implode(', ', $values);
if (((count($ids) > 0) ? mysql_query($sql) : true) && mysql_query($sql2))
return ['success' => true, 'query' => [
'sql' => ((count($ids) > 0) ? $sql : null),
'sql2' => $sql2,
],
'object_ids' => $ids,
'processed' => count($ids)
];
else
return ['success' => false, 'query' => [
'sql' => ((count($ids) > 0) ? $sql : null),
'sql2' => $sql2,
],
'object_ids' => $ids,
'processed' => count($ids),
'errors' => mysql_error()
];
}
return false;
}
public function getApiSettings($agency_id = null, $only_active = true) {
$settings = [];
if (is_null($agency_id))
$agency_id = User::getUserAgencyID();
$sql = "SELECT * FROM `users_api` AS `api` WHERE `api`.`agency_id` = '$agency_id'";
if ($only_active)
$sql .= " AND `status` > 0";
if ($query = mysql_query($sql)) {
if (mysql_num_rows($query) > 0) {
while ($row = mysql_fetch_assoc($query)) {
$service_id = $row['service_id'];
if ($serviceName = $this->getServiceName($service_id)) {
$settings[$serviceName] = [
'service_id' => $row['service_id'],
'client_id' => $row['client_id'],
'secret_key' => $row['secret_key'],
'ext_user_id' => $row['ext_user_id'],
];
}
}
}
}
return $settings;
}
public function testAdvertApi($service = null, $client_id = null, $secret_key = null, $ext_user_id = null) {
if (empty($service))
$service = null;
if (empty($client_id))
$client_id = null;
if (empty($secret_key))
$secret_key = null;
if (empty($ext_user_id))
$ext_user_id = null;
$this->errors = [];
if (is_null($service))
$this->errors[] = 'Не указана площадка для получения статистики';
if (is_null($client_id) && (strtolower($service) == 'avito' || strtolower($service) == 'domclick'))
$this->errors[] = 'Не указан `client_id` для получения статистики';
if (is_null($secret_key))
$this->errors[] = 'Не указан `secret_key` для получения статистики';
if (is_null($ext_user_id) && strtolower($service) == 'avito')
$this->errors[] = 'Не указан `ext_user_id` обязательный для API Avito';
$result = false;
if (is_null($service) || (is_null($client_id) && (strtolower($service) == 'avito' || strtolower($service) == 'domclick')) || is_null($secret_key))
return ['success' => $result, 'errors' => $this->errors];
$this->_session_key .= "_test";
switch (strtolower($service)) {
case 'avito' :
$url = "https://api.avito.ru/token/?grant_type=client_credentials&client_id=$client_id&client_secret=$secret_key";
$options = [
'auth' => 'bearer',
'token' => $this->_getAuthToken('avito', $client_id, $secret_key),
'method' => 'post',
'type' => 'json'
];
$result = $this->_request($url, $options, true);
if ($this->debug)
$this->logs["https://api.avito.ru/token/?grant_type=client_credentials&client_id=$client_id&client_secret=$secret_key"] = $result;
break;
case 'cian' :
$url = "https://public-api.cian.ru/v1/get-last-order-info";
$options = [
'auth' => 'bearer',
'token' => $this->_getAuthToken('cian', null, $secret_key),
'type' => 'json'
];
$result = $this->_request($url, $options, true);
if ($this->debug)
$this->logs["https://public-api.cian.ru/v1/get-last-order-info"] = $result;
break;
case 'yandex' :
$url = "https://api.realty.yandex.net/2.0/crm/offers";
$options = [
'auth' => 'oauth',
'token' => $this->_getAuthToken('yandex', null, $secret_key),
'method' => 'get',
'type' => 'json',
'headers' => [
'X-Authorization: Vertis crm-dff153a8ef1a90d3bff5ee378dee416606cf8915'
],
];
$result = $this->_request($url, $options, true);
if ($this->debug)
$this->logs["https://api.realty.yandex.net/2.0/crm/offers"] = $result;
break;
case 'domclick' :
$token = $this->_getAuthToken('domclick', $client_id, $secret_key);
$url = "https://public-api.domclick.ru/stats/v1/companies/$client_id/offers?token=$token&limit=10";
$options = [
'method' => 'get',
'type' => 'json',
];
$result = $this->_request($url, $options, true);
if ($this->debug)
$this->logs["https://my.domclick.ru/api/v1/company/$client_id/report"] = $result;
break;
}
return $result;
}
private function _getAgencies() {
$ids = [];
$sql = "SELECT *
FROM `users`
WHERE (now() <= DATE_ADD(
`date_tarif`, INTERVAL (
SELECT `t`.`period`
FROM `tariffs` `t`
WHERE t.id = `id_tarif`
LIMIT 1
) DAY)
) AND
`blocked` = 0";
$results = mysql_query($sql);
while($agency = mysql_fetch_assoc($results)) {
$ids[] = $agency['id'];
}
return array_unique($ids);
}
public function run($service = null, $agency_id = null) {
if (is_null($service))
throw new Exception("Service must be set.");
if (is_numeric($service) && !is_null($this->getServiceName($service)))
$service = $this->getServiceName($service);
if (!is_null($agency_id))
$agencies = [$agency_id];
else
$agencies = $this->_getAgencies();
if (!is_null($service) && count($agencies)) {
foreach ($agencies as $agency_id) {
$settings = $this->getApiSettings($agency_id, true);
if (isset($settings[$service])) {
if ($_GET['dev'])
var_export($settings[$service]);
$period = [
'date_from' => date('Y-m-d', strtotime("-6 month")),
'date_to' => date('Y-m-d'),
];
if ($service == 'yandex') {
$period['date_from'] = date('Y-m-d', strtotime('-119 days'));
} else if ($service == 'cian') {
$period['date_from'] = date('Y-m-d', strtotime('-179 days'));
} else if ($service == 'avito') {
$period['date_from'] = date('Y-m-d', strtotime('-269 days'));
}
if ($_GET['dev'])
var_export($period);
$service_id = $settings[$service]['service_id'];
$client_id = $settings[$service]['client_id'];
$secret_key = $settings[$service]['secret_key'];
$ext_user_id = $settings[$service]['ext_user_id'];
$this->getStats($service_id, $period, $client_id, $secret_key, $ext_user_id, null, false, $agency_id);
}
}
}
}
public function set_api_id($api_id){
$this->_api_id = $api_id;
}
public function on_message($service = null, $client_id = null, $secret_key = null, $ext_user_id = null, $api_id) {
if($api_id > 0){
$this->set_api_id($api_id);
}
if (empty($service))
$service = null;
if (empty($client_id))
$client_id = null;
if (empty($secret_key))
$secret_key = null;
if (empty($ext_user_id))
$ext_user_id = null;
$this->errors = [];
if (is_null($service))
$this->errors[] = 'Не указана площадка для получения статистики';
if (is_null($client_id) && (strtolower($service) == 'avito' || strtolower($service) == 'domclick'))
$this->errors[] = 'Не указан `client_id` для получения статистики';
if (is_null($secret_key))
$this->errors[] = 'Не указан `secret_key` для получения статистики';
if (is_null($ext_user_id) && strtolower($service) == 'avito')
$this->errors[] = 'Не указан `ext_user_id` обязательный для API Avito';
$result = false;
if (is_null($service) || (is_null($client_id) && (strtolower($service) == 'avito' || strtolower($service) == 'domclick')) || is_null($secret_key))
return ['success' => $result, 'errors' => $this->errors];
// $this->_session_key .= "_test";
switch (strtolower($service)) {
case 'avito' :
$url = "https://api.avito.ru/messenger/v3/webhook";
$url_webhook = 'https://joywork.ru/webhooks/avito_mess.php?api='.$api_id;
$options = [
'auth' => 'bearer',
'token' => $this->_getAuthToken('avito', $client_id, $secret_key),
'method' => 'post',
'type' => 'json',
'data' => [
'url' => $url_webhook,
"version" => "3"
],
];
//var_dump($options);
$result = json_decode($this->_request($url, $options),true);
if($result['ok']){
$result['success'] = true;
if(!empty($this->_agency_id)){
$sql = "UPDATE `users_api` SET `is_messages` = '1' WHERE agency_id={$this->_agency_id} AND service_id = 1";
$this->_db->query($sql);
//$this->add_users_service($service, $client_id, $secret_key, $ext_user_id);
}
} else {
return ['success' => false, 'errors' => $result['result']['message']];
}
if ($this->debug)
$this->logs["https://api.avito.ru/messenger/v3/webhook"] = $result;
break;
case 'cian' :
if(!empty($this->_agency_id)){
$url_webhook = 'https://joywork.ru/webhooks/cian/'.$this->_agency_id.'/cian_mess.php';
if(!file_exists($_SERVER['DOCUMENT_ROOT']."/webhooks/cian/".$this->_agency_id."/cian_mess.php")){
if (!is_dir($_SERVER['DOCUMENT_ROOT'] . "/webhooks/cian")) {
mkdir($_SERVER['DOCUMENT_ROOT'] . "/webhooks/cian");
}
if (!is_dir($_SERVER['DOCUMENT_ROOT'] . "/webhooks/cian/".$this->_agency_id)) {
mkdir($_SERVER['DOCUMENT_ROOT'] . "/webhooks/cian/".$this->_agency_id);
}
copy($_SERVER['DOCUMENT_ROOT'] ."/webhooks/cian_mess.php", $_SERVER['DOCUMENT_ROOT'] ."/webhooks/cian/".$this->_agency_id."/cian_mess.php");
}
$url = "https://public-api.cian.ru/v2/subscribe-webhooks";
$options = [
'auth' => 'bearer',
'token' => $this->_getAuthToken('cian', null, $secret_key),
'type' => 'json',
'data' => [
'webhookTypes' => ["offersMessagesIncoming", "offersMessagesApiOutgoing", "offersMessagesLkOutgoing"],
'url' => $url_webhook,
],
];
$result = json_decode($this->_request($url, $options),true);
//var_dump($result);
if(isset($result['result']['errors'])){
return ['success' => false, 'errors' => $result['result']['message']];
} else {
$result['success'] = true;
if(!empty($this->_agency_id)){
$sql = "UPDATE `users_api` SET `is_messages` = '1' WHERE agency_id={$this->_agency_id} AND service_id = 2";
$this->_db->query($sql);
}
}
if ($this->debug)
$this->logs["https://public-api.cian.ru/v2/subscribe-webhooks"] = $result;
}
break;
}
// $result['logs'] = $this->logs;
return $result;
}
public function off_message($service = null, $client_id = null, $secret_key = null, $ext_user_id = null, $api_id) {
if($api_id > 0){
$this->set_api_id($api_id);
}
if (empty($service))
$service = null;
if (empty($client_id))
$client_id = null;
if (empty($secret_key))
$secret_key = null;
if (empty($ext_user_id))
$ext_user_id = null;
$this->errors = [];
if (is_null($service))
$this->errors[] = 'Не указана площадка для получения статистики';
if (is_null($client_id) && (strtolower($service) == 'avito' || strtolower($service) == 'domclick'))
$this->errors[] = 'Не указан `client_id` для получения статистики';
if (is_null($secret_key))
$this->errors[] = 'Не указан `secret_key` для получения статистики';
if (is_null($ext_user_id) && strtolower($service) == 'avito')
$this->errors[] = 'Не указан `ext_user_id` обязательный для API Avito';
$result = false;
if (is_null($service) || (is_null($client_id) && (strtolower($service) == 'avito' || strtolower($service) == 'domclick')) || is_null($secret_key))
return ['success' => $result, 'errors' => $this->errors];
// $this->_session_key .= "_test";
switch (strtolower($service)) {
case 'avito' :
$url = "https://api.avito.ru/messenger/v1/webhook/unsubscribe";
$options = [
'auth' => 'bearer',
'token' => $this->_getAuthToken('avito', $client_id, $secret_key),
'method' => 'post',
'type' => 'json',
'data' => [
'url' => 'https://joywork.ru/webhooks/avito_mess.php?api='.$api_id,
"version" => "3"
],
];
$result = json_decode($this->_request($url, $options),true);
if($result['ok']){
$result['success'] = true;
if(!empty($this->_agency_id)){
$sql = "UPDATE `users_api` SET `is_messages` = '0' WHERE agency_id={$this->_agency_id} AND service_id = 1";
$this->_db->query($sql);
//$this->add_users_service($service, $client_id, $secret_key, $ext_user_id);
}
} else {
return ['success' => false, 'errors' => $result['result']['message']];
}
if ($this->debug)
$this->logs["https://api.avito.ru/messenger/v1/webhook/unsubscribe"] = $result;
break;
case 'cian' :
if(!empty($this->_agency_id)){
$url_webhook = 'https://joywork.ru/webhooks/cian/'.$this->_agency_id.'/cian_mess.php';
$url = "https://public-api.cian.ru/v2/unsubscribe-webhooks";
$options = [
'auth' => 'bearer',
'token' => $this->_getAuthToken('cian', null, $secret_key),
'type' => 'json',
'data' => [
'url' => $url_webhook,
'webhookTypes' => ['offersMessages', 'systemMessages' ]
],
];
$result = json_decode($this->_request($url, $options),true);
if(isset($result['result']['errors'])){
return ['success' => false, 'errors' => $result['result']['message']];
} else {
$result['success'] = true;
$sql = "UPDATE `users_api` SET `is_messages` = '0' WHERE agency_id={$this->_agency_id} AND service_id = 2";
$this->_db->query($sql);
//$this->add_users_service($service, $client_id, $secret_key, $ext_user_id);
}
if ($this->debug)
$this->logs["https://public-api.cian.ru/v2/unsubscribe-webhooks"] = $result;
}
break;
}
// $result['logs'] = $this->logs;
return $result;
}
public function send_message($service = null, $client_id = null, $secret_key = null, $ext_user_id = null, $text, $chatId) {
if (empty($service))
$service = null;
if (empty($client_id))
$client_id = null;
if (empty($secret_key))
$secret_key = null;
if (empty($ext_user_id)){
$ext_user_id = null;
} else {
$ext_user_id = trim(str_replace(' ','',$ext_user_id));
}
$this->errors = [];
if (is_null($service))
$this->errors[] = 'Не указана площадка для получения статистики';
if (is_null($client_id) && (strtolower($service) == 'avito' || strtolower($service) == 'domclick'))
$this->errors[] = 'Не указан `client_id` для получения статистики';
if (is_null($secret_key))
$this->errors[] = 'Не указан `secret_key` для получения статистики';
if (is_null($ext_user_id) && strtolower($service) == 'avito')
$this->errors[] = 'Не указан `ext_user_id` обязательный для API Avito';
$result = false;
if (is_null($service) || (is_null($client_id) && (strtolower($service) == 'avito' || strtolower($service) == 'domclick')) || is_null($secret_key))
return ['success' => $result, 'errors' => $this->errors];
// $this->_session_key .= "_test";
switch (strtolower($service)) {
case 'avito' :
$url = "https://api.avito.ru/messenger/v1/accounts/{$ext_user_id}/chats/{$chatId}/messages";
$options = [
'auth' => 'bearer',
'token' => $this->_getAuthToken('avito', $client_id, $secret_key),
'method' => 'post',
'type' => 'json',
'data' => [
"message"=> [
"text"=> $text,
],
"type"=> "text"
],
];
//var_dump($options);
$result = json_decode($this->_request($url, $options),true);
if(isset($result['created'])){
$result['created_at'] = date('d.m.Y H:i', $result['created']);
}
//var_dump($result);
if ($this->debug)
$this->logs["https://api.avito.ru/messenger/v1/accounts/{$ext_user_id}/chats/{$chatId}/messages"] = $result;
break;
case 'cian' :
$url = "https://public-api.cian.ru/v1/send-message";
$options = [
'auth' => 'bearer',
'token' => $this->_getAuthToken('cian', null, $secret_key),
'type' => 'json',
'data' => [
'chatId' => $chatId,
'content' => [
'text' => $text
],
],
];
// var_dump($options);
$result = json_decode($this->_request($url, $options), true);
//var_dump($result);
if(isset($result['result']['errors'])){
return ['success' => false, 'errors' => $result['result']['message']];
} else {
$result['success'] = true;
$result['created_at'] = date('d.m.Y H:i');
}
if ($this->debug)
$this->logs["https://public-api.cian.ru/v1/send-message"] = $result;
break;
}
// $result['logs'] = $this->logs;
return $result;
}
public function get_agent($service = null, $client_id = null, $secret_key = null, $ext_user_id = null, $agent_id) {
if (empty($service))
$service = null;
if (empty($client_id))
$client_id = null;
if (empty($secret_key))
$secret_key = null;
if (empty($ext_user_id)){
$ext_user_id = null;
} else {
$ext_user_id = trim(str_replace(' ','',$ext_user_id));
}
$this->errors = [];
if (is_null($service))
$this->errors[] = 'Не указана площадка для получения статистики';
if (is_null($client_id) && (strtolower($service) == 'avito' || strtolower($service) == 'domclick'))
$this->errors[] = 'Не указан `client_id` для получения статистики';
if (is_null($secret_key))
$this->errors[] = 'Не указан `secret_key` для получения статистики';
if (is_null($ext_user_id) && strtolower($service) == 'avito')
$this->errors[] = 'Не указан `ext_user_id` обязательный для API Avito';
$result = false;
if (is_null($service) || (is_null($client_id) && (strtolower($service) == 'avito' || strtolower($service) == 'domclick')) || is_null($secret_key))
return ['success' => $result, 'errors' => $this->errors];
// $this->_session_key .= "_test";
switch (strtolower($service)) {
case 'cian' :
$url = "https://public-api.cian.ru/v1/get-agents?page=0&pageSize=1&userIds=".$agent_id;
$options = [
'auth' => 'bearer',
'token' => $this->_getAuthToken('cian', null, $secret_key),
'type' => 'json'
];
// var_dump($options);
$result = json_decode($this->_request($url, $options), true);
//var_dump($result);
if(isset($result['result']['errors'])){
return ['success' => false, 'errors' => $result['result']['message']];
} else {
$result['success'] = true;
}
if ($this->debug)
$this->logs["https://public-api.cian.ru/v1/get-agents?page=0&pageSize=1&userIds=".$agent_id] = $result;
break;
}
// $result['logs'] = $this->logs;
return $result;
}
public function get_chat($api, $chat_id){
if(empty($chat_id)){
return ['success' => false, 'errors' => "Пустой чат id"];
}
if($api['id'] > 0){
$this->set_api_id($api['id']);
}
$client_id = trim($api['client_id']);
$secret_key = trim($api['secret_key']);
$ext_user_id = trim(str_replace(' ','',$api['ext_user_id']));
if(!empty($api['token'])){
$this->_tokens['avito'] = array('expires'=>$api['expires_in'], 'token' => $api['token']);
}
$service = 'avito';
if (empty($client_id))
$client_id = null;
if (empty($secret_key))
$secret_key = null;
if (empty($ext_user_id))
$ext_user_id = null;
$this->errors = [];
if (is_null($service))
$this->errors[] = 'Не указана площадка для получения статистики';
if (is_null($client_id) && (strtolower($service) == 'avito' || strtolower($service) == 'domclick'))
$this->errors[] = 'Не указан `client_id` для получения статистики';
if (is_null($secret_key))
$this->errors[] = 'Не указан `secret_key` для получения статистики';
if (is_null($ext_user_id) && strtolower($service) == 'avito')
$this->errors[] = 'Не указан `ext_user_id` обязательный для API Avito';
$result = false;
if (is_null($service) || (is_null($client_id) && (strtolower($service) == 'avito' || strtolower($service) == 'domclick')) || is_null($secret_key))
return ['success' => $result, 'errors' => $this->errors];
$url = "https://api.avito.ru/messenger/v2/accounts/{$ext_user_id}/chats/{$chat_id}";
$options = [
'auth' => 'bearer',
'token' => $this->_getAuthToken('avito', $client_id, $secret_key),
'method' => 'get',
'type' => 'json',
];
$result = json_decode($this->_request($url, $options),true);
$result['success'] = true;
return $result;
}
}
?>