Продолжаю делиться скромным опытом. Стояла такая задача. Есть инфоблок КОМПАНИИ с адресами компаний. В свойстве ADDR хранится адрес без города, город лежит в свойстве CITY - связанном с инфоблоком ГОРОДА. В инфоблоке ГОРОДА хранятся просто названия городов в NAME и координаты центра города в свойстве Y_LL в формате "37.617671,55.755768". Первое число долгота, второе широта.
Городов мало, адресов много. Для инфоблока КОМПАНИИ добавляются свойства широта, долгота YLAT и YLON. Вот их и необходимо заполнить. [spoiler] В принципе я так понимаю, что геокодер Яндекса решил бы задачу и без подсовывания ему координат центров городов, но я все же решил ему слегка помочь.
Был написан следующий скрипт (используемую тут функцию urlGetContents я когда-то нашел на просторах инета, к сожалению не помню уже где, и еще должен признаться, что не на 100% понимаю её код, но он работает).
<?
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");
CPageOption::SetOptionString("main", "nav_page_in_session", "N");
$apiKey = "&key=ВАШ_API_КЛЮЧ";
//функция возращает страницу по запрошенному адресу
function urlGetContents($url, $timeout = 5){
$url_parsed = parse_url($url);
$host = $url_parsed["host"];
if ($url == '' || $host == '') {
return false;
}
$hostName = gethostbyname($host);
$ip = ip2long($hostName);
if ($ip === -1 || $ip === false) {
return false;
}
$port = ($url_parsed["port"] == 0 ? 80 : $url_parsed["port"]);
$path = (empty($url_parsed["path"]) ? '/' : $url_parsed["path"]);
$path.= (!empty($url_parsed["query"]) ? '?'.$url_parsed["query"] : '');
$out = "GET $path HTTP/1.0\r\nHost: $host\r\nConnection: Close\r\n\r\n";
$fp = fsockopen($host, $port, $errno, $errstr, intval($timeout));
if (!$fp) {
return false;
}
stream_set_timeout($fp, intval($timeout));
fwrite($fp, $out);
$headers = '';
$content = '';
$buf = '';
$isBody = false;
while (!feof($fp)) {
$buf = fgets($fp, 1024);
if ($isBody) {
$content .= $buf;
} else {
$headers .= $buf;
}
if ($buf == "\r\n" ) {
$isBody = true;
}
}
preg_match('#HTTP/1.[0-9]{1}\s+([0-9]{3}).*#is', $headers, $match);
fclose($fp);
if($match[1] != 200) {
return false;
}
return array('headers'=>$headers,'body'=>$content);
}
if(CModule::IncludeModule('iblock')){
$elements = CIBlockElement::GetList(
array("id"=>"desc"),
array("IBLOCK_ID"=>17),
false,
array("nTopCount"=>110), //тут можно поставить false - не ограничивая выборку
array("IBLOCK_ID","ID","NAME","PROPERTY_CITY","PROPERTY_ADDR")
);
if ($elements->SelectedRowsCount()>0){
while($element = $elements->GetNextElement()){
$item = $element->GetFields();
$item["PROPERTY_ADDR_VALUE"]=trim($item["PROPERTY_ADDR_VALUE"]);
$ll="";$spn="";$rspn="";
if ($item["PROPERTY_ADDR_VALUE"]){
if ($city = GetIBlockElement($item["PROPERTY_CITY_VALUE"])){ //кто подскажет как вытаскивать имя города более экономно?
$city["NAME"] = trim($city["NAME"]);
$geocode="&geocode=".htmlentities(urlencode($city["NAME"].', '.$item["PROPERTY_ADDR_VALUE"]));
//используем подсказку с координатами центра города
$ll=$city["PROPERTIES"]["Y_LL"]["VALUE"];
if ($ll){
$ll="&ll=".urlencode($ll);
$spn="&spn=".urlencode("0.8,0.8");// это охват территории от центра города в градусах, подобрано эмпирически с запасом
$rspn="&rspn=1";
}//if ($ll && $spn)
//запрашивать будем в JSON формате
$urlAddress = "http://geocode-maps.yandex.ru/1.x/?format=json&plng=ru&results=1&kind=house".$ll.$spn.$rspn.$geocode.$apiKey;
if (($html = urlGetContents($urlAddress,1)) === false) {
print "Адрес <b>".$urlAddress."</b> в данный момент недоступен";
}else{
//загрузилось нормально
$file = json_decode($html['body'],true); //декодируем ответ в массив
//эхо для отладки
//echo '<p>found='.$file["response"]["GeoObjectCollection"]["metaDataProperty"]["GeocoderResponseMetaData"]["found"];
//echo ' *** pos='.$file["response"]["GeoObjectCollection"]["featureMember"][0]["GeoObject"]["Point"]["pos"].'</p>';
if ($file["response"]["GeoObjectCollection"]["metaDataProperty"]["GeocoderResponseMetaData"]["found"]>0){
$place=explode(" ",$file["response"]["GeoObjectCollection"]["featureMember"][0]["GeoObject"]["Point"]["pos"]);
$lat=intval($place[1] * 1000000);$lon=intval($place[0] * 1000000);//мне нужны были координаты в целых числах
CIBlockElement::SetPropertyValues($item["ID"], $item["IBLOCK_ID"], array("YLAT"=>$lat),"YLAT");
CIBlockElement::SetPropertyValues($item["ID"], $item["IBLOCK_ID"], array("YLON"=>$lon),"YLON");
}//found>0
}//if
}//if ($city = GetIBlockElement($item["PROPERTY_CITY_VALUE"]))
}//if ($item["PROPERTY_ADDR_VALUE"])
}//while
}//if ($elements->SelectedRowsCount()>0)
//echo $element["NAME"];
}//if(CModule::IncludeModule('iblock'))
?>
Пробовал еще геокодер Гугла, но он оказался послабее Яндекса (адреса все в России). В условиях использования геокодера от Google прочитал, что использовать его можно только в целях отображения результатов его работы на картах Google. Хотя не нашел такого текста о геокодере Яндекса, думаю у него скорее всего такие же условия (поправьте, если кто знает точно). Поэтому добавил в своем проекте ссылки на соотв. участки Яндекс карт, хотя для проекта достаточно было просто координат.
Группы на сайте создаются не только сотрудниками «1С-Битрикс», но и партнерами компании. Поэтому мнения участников групп могут не совпадать с позицией компании «1С-Битрикс».