[], "bus" => [], "motorhome" => [], "mobile_crane" => [], "bulldozer" => [], "atv" => [], "truck" => [], "building" => [], "misc" => [], "municipal" => [], "forestry" => [], "loader" => [], "semi_trailer" => [], "trailer" => [], "truck_tractor" => [], "tractor" => [], "excavator" => [], ]; protected $special_frames_mapping = [ "BUS" => "bus", "TRUCK" => "truck", "TRUCK_TRACTOR" => "truck_tractor", "MOTORHOME" => "motorhome", "BUILDING" => "building", "CRANE" => "mobile_crane", "LOADER" => "loader", "TRAILER" => "trailer", "SEMITRAILER" => "semi_trailer", "EXCAVATOR" => "excavator", "FARM" => "tractor", "MISC" => "misc", "FORESTRY" => "forestry", "MUNICIPAL" => "municipal", "ATV" => "atv", "BULLDOZER" => "bulldozer", "QUADBIKE" => "atv", "SNOWMOBILE" => "atv", "SCOOTER" => "misc", ]; protected $special_frames = []; protected $xml_cars = null; protected $xml_special = null; protected $offers_cars = null; protected $offers_special = null; protected $total = 0; protected $found_cars = 0; protected $found_special = 0; protected $valid_cars = 0; protected $valid_special = 0; protected $invalid_special = 0; protected $not_found_special = 0; protected $p1 = 0; protected $p2 = 0; protected $p3 = 0; protected $p4 = 0; protected $fuels = [ "БЕНЗИН" => "GASOLINE", "ГАЗ" => "GAS", "ДИЗЕЛЬ" => "DIESEL", "ЭЛЕКТРИЧЕСКИЙ" => "ELECTRICITY", ]; protected $errors = ""; function __construct() { $this->xml_cars = new SimpleXMLElement(""); $this->offers_cars = $this->xml_cars->addChild('Offers'); $this->xml_special = new SimpleXMLElement(""); $this->offers_special = $this->xml_special->addChild('SpecOffers'); $this->loadTypes(); foreach($this->dictionaries AS $type => $v) { $structure = [ "brands" => [], "models" => [], "cities" => [], "bodies" => [], "colors" => [], "transmissions" => [], "engines" => [], "wheels" => [], "fuels" => [], ]; $url = "https://www.drom.ru/cached_files/autoload/files/"; if($type === "car") { $url = $url."ref.xml"; } else { $url = $url."ref_".$type.".xml"; } $response_xml = file_get_contents($url); file_put_contents("/home/bitrix/www/local/ref_".$type.".xml", $response_xml); $structure_object = new SimpleXMLElement($response_xml); foreach($structure_object->MarksSpec->MarkSpec AS $mark) { $k = mb_strtoupper((string) $mark->sMarkSpec); $n = (int) $mark->idMarkSpec; $models = []; foreach($structure_object->ModelsSpec->ModelSpec AS $model) { $mmn = (int) $model->idMarkSpec; if($mmn === $n) { $km = mb_strtoupper((string) $model->sModelSpec); $nm = (int) $model->idModelSpec; $models[ $km ] = $nm; $structure['models'][ $km ] = $nm; } } $structure['brands'][ $k ] = [ "id" => $n, "models" => $models ]; } foreach($structure_object->Marks->Mark AS $mark) { $k = mb_strtoupper((string) $mark->sMark); $n = (int) $mark->idMark; $models = []; foreach($structure_object->Models->Model AS $model) { $mmn = (int) $model->idMark; if($mmn === $n) { $km = mb_strtoupper((string) $model->sModel); $nm = (int) $model->idModel; $models[ $km ] = $nm; } } $structure['brands'][ $k ] = [ "id" => $n, "models" => $models ]; } foreach($structure_object->Cities->City AS $city) { $k = mb_strtoupper((string) $city->sCity); $n = (int) $city->idCity; $structure['cities'][ $k ] = $n; } foreach($structure_object->FrameTypes->FrameType AS $frame_type) { $k = mb_strtoupper((string) $frame_type->sFrameType); $n = (int) $frame_type->idFrameType; $structure['bodies'][ $k ] = $n; } foreach($structure_object->Colors->Color AS $color) { $k = mb_strtoupper((string) $color->sColor); $n = (int) $color->idColor; $structure['colors'][ $k ] = $n; } foreach($structure_object->WheelFormulaTypes->WheelFormulaType AS $wheel_type) { $k = mb_strtoupper((string) $wheel_type->sWheelFormulaType); $n = (int) $wheel_type->idWheelFormulaType; $structure['wheels'][ $k ] = $n; } foreach($structure_object->EngineTypesSpec->EngineTypeSpec AS $engine_type) { $k = mb_strtoupper((string) $engine_type->sEngineTypeSpec); $n = (int) $engine_type->idEngineTypeSpec; $structure['fuels'][ $k ] = $n; } $this->dictionaries[ $type ] = $structure; } } function addOffer($entry) { $this->total++; $type = $entry['PROPERTIES']['VEHICLE_SUBTYPE']['VALUE']; //print $type."\n"; if($type === "Легковой автомобиль") { $this->found_cars++; $this->buildOffer(false, [ 'group' => 'car' ], $entry); /* $idMark = $this->getDictionaryRecordId($this->dictionaries['car']['brands'], mb_strtoupper($entry['PROPERTIES']['BRAND']['RELATED']['NAME'])); //print $entry['CODE']." - ".$entry['PROPERTIES']['BRAND']['RELATED']['NAME']." - ".$entry['PROPERTIES']['MODEL']['RELATED']['NAME']." - [".$idMark."] - [".$idModel."]\n"; //if(is_null($idMark)) { $this->errors .= "Не найдена марка ".$entry['PROPERTIES']['BRAND']['RELATED']['NAME']."\n"; continue; } if($idMark !== null) { //* id марки авто (см. файл-справочник); если не можете указать id, то укажите название марки текстом в поле sMark $offer['idMark'] = $idMark; } else { //* название марки авто (Toyota, Honda, BMW и т.п.); указывать обязательно только в том случае, если не можете указать idMark $offer['sMark'] = $entry['PROPERTIES']['BRAND']['RELATED']['NAME']; } $idModel = $this->getDictionaryRecordId($this->dictionaries['car']['models'], mb_strtoupper($entry['PROPERTIES']['MODEL']['RELATED']['NAME'])); //if(is_null($idModel)) { $this->errors .= "Не найдена модель ".$entry['PROPERTIES']['MODEL']['RELATED']['NAME']." для ".".$entry['PROPERTIES']['BRAND']['RELATED']['NAME']."."\n"; continue; } if($idModel !== null) { //* id модели авто (см. файл-справочник); если не можете указать id, то укажите название модели текстом в поле sModel $offer['idModel'] = $idModel; } else { //* название модели авто (Land Cruiser, Accord, X5 и т.п.); указывать обязательно только в том случае, если не можете указать idModel $offer['sModel'] = $entry['PROPERTIES']['MODEL']['RELATED']['NAME']; } */ /* $payload = [ "idOffer" => $entry['CODE'], //* уникальный id объявления в вашей базе данных "idMark" => "", //* id марки авто (см. файл-справочник); если не можете указать id, то укажите название марки текстом в поле sMark "idModel" => "", //* id модели авто (см. файл-справочник); если не можете указать id, то укажите название модели текстом в поле sModel "sMark" => "", //* название марки авто (Toyota, Honda, BMW и т.п.); указывать обязательно только в том случае, если не можете указать idMark "sModel" => "", //* название модели авто (Land Cruiser, Accord, X5 и т.п.); указывать обязательно только в том случае, если не можете указать idModel "idCountry" => "", //id страны, где находится авто (см. файл-справочник, по умолчанию — 0) "idCity" => "", //id города, в котором находится авто (см. файл-справочник) "sCity" => "", //название города, в котором находится авто (см. файл-справочник) "YearOfMade" => "", //год выпуска ТС (только год, 4 цифры: 1995, 2003, 2018 и т.п.) "VIN" => $entry['PROPERTIES']['VIN']['VALUE'], //* VIN или номер кузова, если VIN отсутствует "Price" => $entry['PROPERTIES']['PRICE']['VALUE'], //цена в рублях "NewType" => 0, //признак, что автомобиль новый; 1 — новый, 0 — не новый (с пробегом) "Volume" => $entry['PROPERTIES']['ENGINE_VOLUME']['VALUE'], //объем двигателя в куб.см (пример: 599, 1300, 2631 и т.п.) "FrameType" => "???", //тип кузова (см. файл-справочник) "Color" => "???", //цвет кузова (см. файл-справочник) "idTransmission" => "???", //id типа трансмиссии (см. файл-справочник) "sTransmission" => "???", //название типа трансмиссии "idEngineType" => "", //id типа двигателя (см. файл-справочник) "sEngineType" => "", //название типа двигателя "idHybridType" => "", //гибрид (см. файл-справочник) "sHybridType" => "", //гибрид (да, нет) "idGbo" => "", //ГБО (см. файл-справочник) "sGbo" => "", //ГБО (да, нет) "idDriveType" => "???", //id типа двигателя (см. файл-справочник) "sDriveType" => "", //название типа двигателя "sWheelType" => "", //положение руля (левый, правый) "Haul" => "", //пробег (показания одометра в километрах) "sComplectation" => "", //название комплектации (в соответствии с каталогом) "idComplectation" => "", //id комплектации на Дроме (в соответствии с каталогом) "Additional" => "", //текстовое описание ТС (комплектация, оснащение, тюнинг и т.п.), здесь можно указать сссылку на видео, размещенное на YouTube "Photos" => "", //секция со списком фотографий (ниже есть подробное описание секции) "Phone" => "", //номер телефона (поле не должно быть больше 20 символов) "Whereabouts" => "", //авто в наличии или под заказ (см. файл-справочник) "Power" => $entry['PROPERTIES']['ENGINE_POWER']['VALUE'], //мощность автомобиля в лошадиных силах "idCertProgram" => "", //программа сертификации (см. файл-справочник) "DamagedType" => "", //признак для поврежденных автомобилей (0 - небитые, 1 - битые или не на ходу) "SOR" => "", //номер свидетельства о регистрации ТС для авто с пробегом (10 символов) ]; */ } else { $this->found_special++; $frame = $this->getFrameType(mb_strtoupper($type), mb_strtoupper($entry['PROPERTIES']['MODEL']['RELATED']['NAME'])); if(!is_null($frame)) { $this->buildOffer(true, $frame, $entry); } else { $this->invalid_special++; print $this->invalid_special." НЕ УДАЛОСЬ ОПРЕДЕЛИТЬ ТИП: ".mb_strtoupper($type)." \t\t[ ".$entry['CODE']." ][ ".$entry['PROPERTIES']['BRAND']['RELATED']['NAME']." ][ ".$entry['PROPERTIES']['MODEL']['RELATED']['NAME']." ]\n"; //$this->not_found_special++; } } } private function buildOffer($special = false, $frame, $entry) { //print $entry['CODE']." - ".$type."\n"; $payload = [ "idOffer" => $entry['CODE'], //* уникальный id объявления в вашей базе данных "YearOfMade" => $entry['PROPERTIES']['YEAR']['VALUE'], //год выпуска ТС (только год, 4 цифры: 1995, 2003, 2018 и т.п.) "VIN" => $entry['PROPERTIES']['VIN']['VALUE'], //* VIN или номер кузова, если VIN отсутствует "Price" => $entry['PROPERTIES']['PRICE']['VALUE'], //цена в рублях "NewType" => 0, //признак, что автомобиль новый; 1 — новый, 0 — не новый (с пробегом) "Volume" => $entry['PROPERTIES']['ENGINE_VOLUME']['VALUE'], //объем двигателя в куб.см (пример: 599, 1300, 2631 и т.п.) "Power" => $entry['PROPERTIES']['ENGINE_POWER']['VALUE'], //мощность автомобиля в лошадиных силах ]; if(!empty($entry['PROPERTIES']['MILEAGE']['VALUE'])) { $payload["Haul"] = $entry['PROPERTIES']['MILEAGE']['VALUE']; } if(!empty($entry['PROPERTIES']['AFTER_ACCIDENT']['VALUE'])) { $payload[ $special ? "idDamagedType" : "DamagedType" ] = $entry['PROPERTIES']['AFTER_ACCIDENT']['XML_VALUE'] == "YES" ? 1 : 0; } if($special) { $payload['idFrameTypeSpec'] = $frame['id']; $payload['idWheelType'] = 2; if(in_array($frame['group'], [ "bus", "motorhome" ])) { $this->invalid_special++; print $this->invalid_special." НЕВОЗМОЖНО УКАЗААТЬ DriveTypeSpec: ".$entry['CODE']." ".$entry['PROPERTIES']['BRAND']['RELATED']['NAME']." ".$entry['PROPERTIES']['MODEL']['RELATED']['NAME']."\n"; return; } if(in_array($frame['group'], [ "trailer", "semi_trailer" ])) { $this->invalid_special++; print $this->invalid_special." НЕВОЗМОЖНО УКААЗАТЬ КОЛИЧЕСТВО ОСЕЙ Axles: ".$entry['CODE']." ".$entry['PROPERTIES']['BRAND']['RELATED']['NAME']." ".$entry['PROPERTIES']['MODEL']['RELATED']['NAME']."\n"; return; } if(in_array($frame['group'], [ "truck", "truck_tractor", "mobile_crane", "municipal", ])) { $item_name = str_replace("Х", "X", mb_strtoupper($entry['PROPERTIES']['MODEL']['RELATED']['NAME'])); preg_match('/\dX\d/', $item_name, $wheel_type_matches); $idWheelFormulaType = $this->getDictionaryRecordId($this->dictionaries[ $frame['group'] ]['wheels'], $wheel_type_matches[0]); if(!is_null($idWheelFormulaType)) { $payload['idWheelFormulaType'] = $idWheelFormulaType; } else { $this->invalid_special++; print $this->invalid_special." НЕТ КОЛЕСНОЙ ФОРМУЛЫ: ".$entry['CODE']." - ".$item_name." [".$wheel_type_matches[0]."]\n"; return; } } if(in_array($frame['group'], [ "bus", "truck", "truck_tractor", "mobile_crane", "loader", "municipal", "atv", "motorhome" ])) { if(!empty($entry['PROPERTIES']['ENGINE_FUEL']['VALUE'])) { $f = mb_strtoupper($entry['PROPERTIES']['ENGINE_FUEL']['VALUE']); if(isset($this->fuels[$f])) { $idEngineTypeSpec = $this->getDictionaryRecordId($this->dictionaries[ $frame['group'] ]['fuels'], $this->fuels[$f]); if(!is_null($idEngineTypeSpec)) { $payload['idEngineTypeSpec'] = $idEngineTypeSpec; } } } } } if($special) { $patterns = array('/\s\dX\d/i', '/\s\dХ\d/i', '/САМОСВАЛ/i'); $replacements = array('', '', ''); $model_name = preg_replace($patterns, $replacements, mb_strtoupper($entry['PROPERTIES']['MODEL']['RELATED']['NAME'])); $model_name = ltrim(rtrim($model_name)); $model_name_chunks = explode(" ", $model_name); array_unshift($model_name_chunks, implode('', $model_name_chunks)); $idModel = null; foreach($model_name_chunks AS $c) { $idModel = $this->getDictionaryRecordId($this->dictionaries[ $frame['group'] ]['models'], $c); if(!is_null($idModel)) { break; } } if(!is_null($idModel)) { $payload['idModelSpec'] = $idModel; } else { $this->invalid_special++; print $this->invalid_special." НЕВОЗМОЖНО ОПРЕДЕЛИТЬ МОДЕЛЬ ДЛЯ МАРКИ ".$entry['PROPERTIES']['BRAND']['RELATED']['NAME'].": ".$entry['CODE']." - ".$entry['PROPERTIES']['MODEL']['RELATED']['NAME']."\n"; return; } } else { $idMark = $this->findInDictionaryRecordId($this->dictionaries[ $frame['group'] ]['brands'], mb_strtoupper($entry['PROPERTIES']['BRAND']['RELATED']['NAME'])); //print $type." - ".$frame['group']." - ".$idMark['id']."\n"; if(!is_null($idMark)) { if(!$special) { $payload['idMark'] = $idMark['id']; } $this->p1++; $patterns = array('/\s\dX\d/i', '/\s\dХ\d/i', '/САМОСВАЛ/i'); $replacements = array('', '', ''); $model_name = preg_replace($patterns, $replacements, mb_strtoupper($entry['PROPERTIES']['MODEL']['RELATED']['NAME'])); $model_name = ltrim(rtrim($model_name)); $model_name_chunks = explode(" ", $model_name); array_unshift($model_name_chunks, implode('', $model_name_chunks)); $idModel = null; foreach($model_name_chunks AS $c) { $idModel = $this->getDictionaryRecordId($this->dictionaries[ $frame['group'] ]['brands'][ mb_strtoupper($entry['PROPERTIES']['BRAND']['RELATED']['NAME']) ]['models'], $c); if(!is_null($idModel)) { $idModel = $this->findInDictionaryRecordId($this->dictionaries[ $frame['group'] ]['brands'][ mb_strtoupper($entry['PROPERTIES']['BRAND']['RELATED']['NAME']) ]['models'], mb_strtoupper($c)); if(!is_null($idModel)) { break; } } } if(!is_null($idModel)) { $payload['idModel'] = $idModel; } else { $payload['sModel'] = $model_name; } } else { $this->p2++; if(!$special) { $payload['sMark'] = $entry['PROPERTIES']['BRAND']['RELATED']['NAME']; $payload['sModel'] = $entry['PROPERTIES']['MODEL']['RELATED']['NAME']; } else { $this->invalid_special++; print $this->invalid_special." НЕВОЗМОЖНО ОПРЕДЕЛИТЬ МАРКУ: ".$entry['CODE']." (ТИП ".$frame['group'].") - ".$entry['PROPERTIES']['BRAND']['RELATED']['NAME']." ".$entry['PROPERTIES']['MODEL']['RELATED']['NAME']."\n"; return; } //print $entry['PROPERTIES']['BRAND']['RELATED']['NAME']."\n"; } } $idCity = $this->getDictionaryRecordId($this->dictionaries[ $frame['group'] ]['cities'], mb_strtoupper($entry['PROPERTIES']['PARKING_CITY']['VALUE'])); if($idCity !== null) { //* id города, в котором находится авто (см. файл-справочник) $payload['idCity'] = $idCity; } else { if(!$special) { //* название города, в котором находится авто (см. файл-справочник) $payload['sCity'] = $entry['PROPERTIES']['PARKING_CITY']['VALUE']; } else { $this->invalid_special++; print $this->invalid_special." НЕВОЗМОЖНО ОПРЕДЕЛИТЬ ГОРОД: ".$entry['CODE']." ".$entry['PROPERTIES']['BRAND']['RELATED']['NAME']." ".$entry['PROPERTIES']['MODEL']['RELATED']['NAME']."\n"; return; } //if(is_empty($idModel)) { $this->errors .= "Не найдена модель ".$entry['PROPERTIES']['MODEL']['RELATED']['NAME']." для ".".$entry['PROPERTIES']['BRAND']['RELATED']['NAME']."."\n"; continue; } } //"idCountry" => "", //id страны, где находится авто (см. файл-справочник, по умолчанию — 0) //"idCity" => "", //id города, в котором находится авто (см. файл-справочник) //"sCity" => "", //название города, в котором находится авто (см. файл-справочник) if($special) { $this->valid_special++; } else { $this->valid_cars++; } $offer = $special ? $this->offers_special->addChild('SpecOffer') : $this->offers_cars->addChild('Offer'); foreach($payload AS $k => $v) { $offer->addChild($k, $v); } $offer->addChild("Additional", "Артикул: ".$entry['CODE']."\n".htmlspecialchars(str_replace([" ", "
", "
"], [" ", "", ""], strip_tags($entry['DETAIL_TEXT'])))); if(count($entry['PHOTOS_1080']) > 0) { $photos = $offer->addChild("Photos"); $photos->addAttribute('PhotoMain', "https://".SITE_SERVER_NAME.$entry['PHOTOS_1080'][0]); foreach($entry['PHOTOS_1080'] AS $photo) { $photos->addChild("Photo", "https://".SITE_SERVER_NAME.$photo); } } //print $type." MATCH"."\n"; } private function normalize_string($str) { return str_replace(["Ё", "C"], ["Е", "С"], $str); } private function getFrameType($type, $model) { if($type === "ПРИЦЕП") { $type = "ДРУГИЕ ПРИЦЕПЫ"; } if($type === "ТЯГАЧ") { $type = "СЕДЕЛЬНЫЙ ТЯГАЧ"; } if(isset($this->special_frames[ $type ])) { return $this->special_frames[ $type ]; } else { $found = []; foreach($this->special_frames AS $k => $v) { if(strpos($this->normalize_string($model), $k) > -1) { $found[ strlen($k) ] = $this->special_frames[ $k ]; } } if(count($found) > 0) { krsort($found); // print_r($found); foreach($found AS $f) { return $f; } // return $found[0]; } } //print "[".$this->normalize_string(mb_strtoupper($k))."] <---\n"; return null; } private function getDictionaryRecordId($branch, $name) { if(isset($branch[ $name ])) { return $branch[ $name ]; } return null; } private function findInDictionaryRecordId($branch, $name) { foreach($branch AS $k => $v) { if(strpos($name, $k) > -1) { return $v; } } return null; } function save() { if($this->total > 0) { print "ИТОГО: валидно ".$this->valid_cars + $this->valid_special." из ".$this->total." - ".number_format(($this->valid_cars + $this->valid_special) / (($this->found_cars + $this->found_special) / 100), 2, ".")."%\n"; if($this->found_cars > 0) { print "ЛКТ: валидно ".$this->valid_cars." из ".$this->found_cars." - ".number_format($this->valid_cars / ($this->found_cars / 100), 2, ".")."%\n"; } if($this->found_special > 0) { print "СПЕЦТЕХНИКА: валидно ".$this->valid_special." из ".$this->found_special." - ".number_format($this->valid_special / ($this->found_special / 100), 2, ".")."%\n"; } file_put_contents("/home/bitrix/www/drom-offers.xml", $this->xml_cars->asXML()); file_put_contents("/home/bitrix/www/drom-offers-special.xml", $this->xml_special->asXML()); } } private function loadTypes() { $types_url = "https://www.drom.ru/cached_files/autoload/files/ref_frame_types.xml"; $response_types_xml = file_get_contents($types_url); file_put_contents("/home/bitrix/www/local/ref_frame_types.xml", $response_types_xml); $types_object = new SimpleXMLElement($response_types_xml); foreach($types_object AS $group => $branch) { foreach($branch AS $spec) { $g = (string) $group; $k = (string) $spec->sFrameTypeSpec; $n = (int) $spec->idFrameTypeSpec; //print $g." - ".$k."\n"; $this->special_frames[ mb_strtoupper($k) ] = [ "group" => $this->special_frames_mapping[ $g ], "id" => $n, ]; } } } }