Last active
September 8, 2024 19:58
-
-
Save di7spider/1d183bbe1657538190a8 to your computer and use it in GitHub Desktop.
1C-Bitrix Loc2Fias :: Связка ФИАС (kladr-api.ru) с 1С-Битрикс местоположениями версии 2.0 (города/села) по ZIP коду
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Exchanges; | |
/** | |
* Связка ФИАС (kladr-api.ru) с 1С-Битрикс местоположениями версии 2.0 (города/села) по ZIP коду | |
* | |
* https://kladr-api.ru/ | |
* https://dev.1c-bitrix.ru/learning/course/?COURSE_ID=43&LESSON_ID=3570 | |
*/ | |
class Loc2Fias | |
{ | |
/** URL API */ | |
const URL = 'http://kladr-api.ru/api.php'; | |
/** Параметры запрса */ | |
static protected $params = Array( | |
'token' => '' | |
); | |
/** | |
* Типы (/bitrix/admin/sale_location_type_list.php?lang=ru) | |
* BX => kladr-api.ru | |
*/ | |
static protected $types = Array( | |
'CITY' => 'Город', | |
'VILLAGE' => 'Село' | |
); | |
static protected $extFiasId = null; | |
static protected $zip2Loc = Array(); | |
static protected $status = Array(); | |
static protected $codes = Array(); | |
/** Импорт */ | |
static public function import($params) | |
{ | |
$result = Array(); | |
$init = self::init(); | |
if($init['id']){ | |
if( is_array($params['query']) ){ | |
self::$params = array_merge(self::$params, $params['query']); | |
} | |
$dataZip = self::data('ZIP'); | |
if($init['status'] == 1){ | |
$dataFias = self::data('FIAS'); | |
$dataZip = array_diff_key($dataZip, $dataFias); | |
} | |
if( !empty($dataZip) ){ | |
self::$extFiasId = $init['id']; | |
self::$zip2Loc = array_flip($dataZip); | |
self::query( | |
Array( | |
'zip' => array_values($dataZip), | |
'limit' => $params['limit'] | |
) | |
); | |
} | |
} | |
return self::status('get'); | |
} | |
/** Статус обработки */ | |
static public function status($type, $data) | |
{ | |
if($type == 'get'){ | |
return self::$status; | |
}else{ | |
self::$status[$type][] = $data; | |
} | |
} | |
/** Добавление новой записи в БД */ | |
static public function add($zip, $code) | |
{ | |
if($zip && $code){ | |
if(self::$codes[$code]){ | |
self::status('err', Array('err_double_code', $zip, $code) ); | |
}else{ | |
$add = Array( | |
'SERVICE_ID' => self::$extFiasId, | |
'XML_ID' => $code, | |
'LOCATION_ID' => self::$zip2Loc[$zip] | |
); | |
$res = \Bitrix\Sale\Location\ExternalTable::add($add); | |
if( $res-> isSuccess() ){ | |
self::status('success', $add); | |
self::$codes[$code] = 1; | |
}else{ | |
self::status('err', $add); | |
} | |
} | |
}else{ | |
self::status('err', Array('err_zip_code', $zip, $code) ); | |
} | |
} | |
/** Существует ли тип ФИАС в БД сайта, если нет то создаем */ | |
static public function init() | |
{ | |
$item = \Bitrix\Sale\Location\ExternalServiceTable::getList( | |
array( | |
'limit' => 1, | |
'filter' => Array( | |
'CODE' => 'FIAS' | |
), | |
'select' => Array( | |
'ID' | |
) | |
) | |
)-> fetch(); | |
if( is_array($item) ){ | |
return Array( | |
'id' => $item['ID'], | |
'status' => 1 | |
); | |
}else{ | |
$res = \Bitrix\Sale\Location\ExternalServiceTable::add( | |
array( | |
'CODE' => 'FIAS' | |
) | |
); | |
if( $res-> isSuccess() ){ | |
return Array( | |
'id' => $res-> getId(), | |
'status' => 2 | |
); | |
}else{ | |
self::status('err', 'fias_type_add'); | |
return Array( | |
'id' => null, | |
'status' => 3 | |
); | |
} | |
} | |
} | |
/** Возвращает список loc = zip/fias */ | |
static public function data($code) | |
{ | |
if( empty($code) ){ return; } | |
$ext = \Bitrix\Sale\Location\ExternalTable::getList( | |
Array( | |
'filter' => Array( | |
'=SERVICE.CODE' => $code, | |
'=LOCATION.TYPE.CODE' => array_keys(self::$types) | |
), | |
'select' => Array( | |
'LOCATION_ID', | |
'XML_ID', | |
'SERVICE.CODE' | |
) | |
) | |
); | |
$result = $is = Array(); | |
while( $item = $ext-> fetch() ){ | |
$loc = (int) $item['LOCATION_ID']; | |
$xmlId = (string) $item['XML_ID']; | |
if( $loc && !empty($xmlId) && !$result[$loc] && !$is[$xmlId] ){ | |
$result[$loc] = $xmlId; | |
$is[$xmlId] = 1; | |
} | |
} | |
return $result; | |
} | |
/** Анализатор ответа ФИАС (kladr-api.ru) */ | |
static public function analyze($zip, $params) | |
{ | |
$params = json_decode($params, true); | |
$params = $params['result']; | |
if( !empty($zip) && !empty($params) ){ | |
$params = array_shift($params); | |
if( is_array($params['parents']) ){ | |
foreach($params['parents'] as $item){ | |
$id = preg_replace("/[^\d]+/", "", $item['id']); | |
if( !empty($id) && ( | |
in_array($item['type'], self::$types) || $item['contentType'] == 'city' ) ){ | |
self::add($zip, $id); | |
return $id; | |
}else{ | |
$err = 'err_no_detect_city'; | |
} | |
} | |
}else{ | |
$err = 'err_no_parents'; | |
} | |
}else{ | |
$err = 'err_query_response'; | |
} | |
$err && self::status( | |
'err', | |
Array( | |
$err, | |
$zip, | |
$params | |
) | |
); | |
} | |
/** Получаем родительские объекты по ZIP из ФИАС (kladr-api.ru) */ | |
static public function query($params) | |
{ | |
if( !empty($params['zip']) ){ | |
$base = array_merge( | |
Array( | |
'contentType' => 'building', | |
'limit' => 1, | |
'withParent' => 1 | |
), | |
self::$params | |
); | |
$listZip = array_chunk( | |
array_values($params['zip']), | |
isset($params['limit']) ? (int) $params['limit']: 50 | |
); | |
$loc = array_flip($loc); | |
$mh = curl_multi_init(); | |
foreach($listZip as $chunkZip){ | |
foreach($chunkZip as $zip){ | |
$query[$zip] = curl_init(); | |
curl_setopt_array( | |
$query[$zip], | |
Array( | |
CURLOPT_URL => self::URL."?".http_build_query( | |
array_merge( | |
$base, | |
Array( | |
'zip' => $zip | |
) | |
) | |
), | |
CURLOPT_HEADER => 0, | |
CURLOPT_NOBODY => 0, | |
CURLOPT_RETURNTRANSFER => 1, | |
CURLOPT_FOLLOWLOCATION => 1, | |
CURLOPT_SSL_VERIFYPEER => 0, | |
CURLOPT_MAXREDIRS => 3, | |
CURLOPT_CONNECTTIMEOUT => 10, | |
CURLOPT_TIMEOUT => 20, | |
CURLOPT_SSL_VERIFYPEER => 0, | |
CURLOPT_SSL_VERIFYHOST => 0 | |
) | |
); | |
curl_multi_add_handle($mh, $query[$zip]); | |
} | |
$active = null; | |
do{ | |
$mrc = curl_multi_exec($mh, $active); | |
}while($mrc == CURLM_CALL_MULTI_PERFORM); | |
while($active && $mrc == CURLM_OK){ | |
if (curl_multi_select($mh) != -1) { | |
do{ | |
$mrc = curl_multi_exec($mh, $active); | |
}while($mrc == CURLM_CALL_MULTI_PERFORM); | |
if( $mhinfo = curl_multi_info_read($mh) ){ | |
$zip = array_search($mhinfo['handle'], $query); | |
if($zip !== false){ | |
self::analyze( | |
$zip, | |
curl_multi_getcontent($mhinfo['handle']) | |
); | |
} | |
curl_multi_remove_handle($mh, $mhinfo['handle']); | |
curl_close($mhinfo['handle']); | |
} | |
} | |
} | |
} | |
curl_multi_close($mh); | |
} | |
} | |
} | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Пример использования: