Получение координат полигона очерчивающего районы Вологодской области

Ну или собственно легко адаптировать под любую область.

Одной и задач явилось отрисовывание контуров районов Вологодской области на карте. Для этого нужно знать координаты точек полигона очерчивающего районы. Через API Яндекс.Карты возможно получить только полигоны областей, а не районов. Поэтому было принято решение вытянуть координаты точек из OpenStreetMap. Из нюансов:

  1. Обязательно нужно указывать UserAgent — иначе сервис забанит
  2. Ограничение — 1 запрос в секунду. Именно поэтому координаты «складируем» в файлы для последующего использования, а не вытягиваем «на лету»
  3. Координаты в OpenStreetMap хранятся «наоборот», а не как в Яндексе, поэтому сразу «переворачиваем»
<?php

 function GetAreaPolygon($region,$area,$filename){

            $address= urlencode($region.",".$area);
            $rul="https://nominatim.openstreetmap.org/search?q=".$address."&format=json&polygon_geojson=1&limit=2";
            var_dump($rul);
            $ch = curl_init($rul);
            $config['useragent'] = 'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0';
            curl_setopt($ch, CURLOPT_USERAGENT, $config['useragent']);
            curl_setopt($ch, CURLOPT_REFERER, 'https://укмцукму.ru/');
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
            $res_curl=curl_exec($ch);
            $res=json_decode($res_curl);
            if ($res!=null){
                $geo=$res[0]->geojson->coordinates;
                // переворачиваем координаты..
                foreach ($geo as &$coors) {
                    foreach ($coors as &$coor) {
                        $tmp=$coor[0];
                        $coor[0]=$coor[1];
                        $coor[1]=$tmp;
                    };
                };
                file_put_contents($filename,json_encode($geo));
            };
            sleep(2); //делаем паузу, чтоб не забанили
 }

    GetAreaPolygon("Вологодская область","Вологодский район","1.json");
    GetAreaPolygon("Вологодская область","Бабаевский район","2.json");
    GetAreaPolygon("Вологодская область","Бабушкинский район","3.json");
    GetAreaPolygon("Вологодская область","Белозерский район","4.json");
    GetAreaPolygon("Вологодская область","Вашкинский район","5.json");
    GetAreaPolygon("Вологодская область","Великоустюгский район","6.json");
    GetAreaPolygon("Вологодская область","Верховажский район","7.json");
    GetAreaPolygon("Вологодская область","Вожегодский район","8.json");
    GetAreaPolygon("Вологодская область","Вытегорский район","9.json");
    GetAreaPolygon("Вологодская область","Грязовецкий район","10.json");
    GetAreaPolygon("Вологодская область","Кадуйский район","11.json");
    GetAreaPolygon("Вологодская область","Кирилловский район","12.json");
    GetAreaPolygon("Вологодская область","Кичменгско-Городецкий район","13.json");
    GetAreaPolygon("Вологодская область","Междуреченский район","14.json");
    GetAreaPolygon("Вологодская область","Никольский район","15.json");
    GetAreaPolygon("Вологодская область","Нюксенский район","16.json");
    GetAreaPolygon("Вологодская область","Сокольский район","17.json");
    GetAreaPolygon("Вологодская область","Сямженский район","18.json");
    GetAreaPolygon("Вологодская область","Тарногский район","19.json");
    GetAreaPolygon("Вологодская область","Тотемский район","20.json");
    GetAreaPolygon("Вологодская область","Усть-Кубинский район","21.json");
    GetAreaPolygon("Вологодская область","Устюженский район","22.json");
    GetAreaPolygon("Вологодская область","Харовский район","23.json");
    GetAreaPolygon("Вологодская область","Чагодощенский район","24.json");
    GetAreaPolygon("Вологодская область","Череповецкий район","25.json");
    GetAreaPolygon("Вологодская область","Шекснинский район","26.json");

?>

Сохранив файлы, отрисуем районы на карте:

<script src="https://api-maps.yandex.ru/2.1/?lang=RU_ru&apikey=<?=$config->api_map?>" type="text/javascript"></script>    

<div id="map"></div>

<script>
 ymaps.ready(init);
 
 function GetAreaPolygon(region,area,filename,fillcolor){
    var url = "https://eуцкацукаc/areas/"+filename;
    $.getJSON(url, {})
    .then(function (data) {    
        var p = new ymaps.Polygon(
            data,
            {
              hintContent: area   
            },
            {
                fillColor: fillcolor,
                strokeColor: '#0000FF',
                opacity: 0.2,
                strokeWidth: 2,
                strokeStyle: 'shortdash'
            }                            
            );
    myMap.geoObjects.add(p);                                                        
    });     
 }
 
 function init () {
    latitude=59.2084992;
    longitude=39.8491648;

    myMap = new ymaps.Map('map', {
        center: [latitude, longitude], 
        controls: ['routeButtonControl','geolocationControl'],
        zoom: 7,
    }, {
        searchControlProvider: 'yandex#search',
        geoObjectBalloonAutoPan: false,
        geoObjectBalloonPanelMaxMapArea: Infinity,
        balloonPanelMaxMapArea: Infinity // балун-всегда панель - проблема с наложением надписи "Открыть на яндекс картах", из-за динамической загрузки
    });
    GetAreaPolygon("Вологодская область","Вологодский район","1.json","#FF0000");
    GetAreaPolygon("Вологодская область","Бабаевский район","2.json","#dcec3c");
    GetAreaPolygon("Вологодская область","Бабушкинский район","3.json","#3c9cec");
    GetAreaPolygon("Вологодская область","Белозерский район","4.json","#ec813c");
    GetAreaPolygon("Вологодская область","Вашкинский район","5.json","#ca5784");
    GetAreaPolygon("Вологодская область","Великоустюгский район","6.json","#57cab2");
    GetAreaPolygon("Вологодская область","Верховажский район","7.json","#467623");
    GetAreaPolygon("Вологодская область","Вожегодский район","8.json","#764923");
    GetAreaPolygon("Вологодская область","Вытегорский район","9.json","#236c76");
    GetAreaPolygon("Вологодская область","Грязовецкий район","10.json","#3eb9ca");
    GetAreaPolygon("Вологодская область","Кадуйский район","11.json","#4fca3e");
    GetAreaPolygon("Вологодская область","Кирилловский район","12.json","#cab13e");
    GetAreaPolygon("Вологодская область","Кичменгско-Городецкий район","13.json","#e47694");
    GetAreaPolygon("Вологодская область","Междуреченский район","14.json","#e176e4");
    GetAreaPolygon("Вологодская область","Никольский район","15.json","#7694e4");
    GetAreaPolygon("Вологодская область","Нюксенский район","16.json","#76e4e4");
    GetAreaPolygon("Вологодская область","Сокольский район","17.json","#76e4af");
    GetAreaPolygon("Вологодская область","Сямженский район","18.json","#80e476");
    GetAreaPolygon("Вологодская область","Тарногский район","19.json","#b2e476");
    GetAreaPolygon("Вологодская область","Тотемский район","20.json","#e4a576");
    GetAreaPolygon("Вологодская область","Усть-Кубинский район","21.json","#e48676");
    GetAreaPolygon("Вологодская область","Устюженский район","22.json","#e4768a");
    GetAreaPolygon("Вологодская область","Харовский район","23.json","#d776e4");
    GetAreaPolygon("Вологодская область","Чагодощенский район","24.json","#a876e4");
    GetAreaPolygon("Вологодская область","Череповецкий район","25.json","#76dae4");
    GetAreaPolygon("Вологодская область","Шекснинский район","26.json","#FF0000");
    
    
};

</script> 

Получение геокординат по адресу

Задача: получить координаты по известному адресу

Решение: воспользуемся API Яндекс.Карты по геокодированию. К сожалению бесплатная версия ограничена 1000 запросов в сутки. Но это обходимо возможностью «растягивать» во времени заполнение БД


            $address= urlencode($maddress->address);
            $rul="https://geocode-maps.yandex.ru/1.x/?geocode=".$address."&format=json&results=1&apikey=".$api_map;
            var_dump($rul);
            $ch = curl_init($rul);        
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json')); 
            $res_curl=json_decode(curl_exec($ch));            
            if ($res_curl!=null){
                if (isset($res_curl->response->GeoObjectCollection->featureMember[0]->GeoObject->Point->pos)){
                 $coors=$res_curl->response->GeoObjectCollection->featureMember[0]->GeoObject->Point->pos;     
                 $coors= explode(" ",$coors);
                 var_dump($coors);
                }              
            };            

OTP авторизация

Суть в чём: для каждого пользователя хранится некий OTP ключ (соль), на основании которого генерируется некий код, который в один момент времени (плюс-минус 30 секунд) будет одинаковый с ключём сгенерированным сторонним приложением. Естественно этому стороннему приложению сначала необходимо передать ключ.

Соответственно если код сгенерированный при проверке одинаков с ключем сгенерированным приложением, можно считать что идентификация успешно пройдена.

OTP авторизация обычно используется как «дополнительная», т.е. в качестве реализации двухфакторной авторизации.

Соберём класс для генерации кода на основании токена:

class TOTP {

 const keyRegeneration  = 30; // Время действия ключа
 const otpLength  = 6; // длина кода OTP

 private static $lut = array( 
  "A" => 0, "B" => 1,"C" => 2, "D" => 3,"E" => 4, "F" => 5,"G" => 6, "H" => 7,"I" => 8, "J" => 9,"K" => 10, "L" => 11,
  "M" => 12, "N" => 13,"O" => 14, "P" => 15,"Q" => 16, "R" => 17,"S" => 18, "T" => 19,"U" => 20, "V" => 21,"W" => 22, "X" => 23,
  "Y" => 24, "Z" => 25,"2" => 26, "3" => 27,"4" => 28, "5" => 29,"6" => 30, "7" => 31
 );


 /**
 * Возвратим текущее время Unix Timestamp округлённое до времени действия ключа
 * @return integer
 **/
 public static function get_timestamp() {
  return floor( (microtime(true) + 10) /self::keyRegeneration);
 }

 /**
 * Перекодируем строку base32 в бинарный вид
 **/
 public static function base32_decode($b32) {
  $b32  = strtoupper($b32);
  if (!preg_match('/^[ABCDEFGHIJKLMNOPQRSTUVWXYZ234567]+$/', $b32, $match))
   throw new Exception('Используются не верные символы в ключе.');
  $l  = strlen($b32);
  $n = 0;
  $j = 0;
  $binary = "";
  for ($i = 0; $i < $l; $i++) {
   $n = $n << 5;     // Move buffer left by 5 to make room
   $n = $n + self::$lut[$b32[$i]];  // Add value into buffer
   $j = $j + 5;    // Keep track of number of bits in buffer
   if ($j >= 8) {
    $j = $j - 8;
    $binary .= chr(($n & (0xFF << $j)) >> $j);
   }
  }
  return $binary;
 }

 /**
 * Вернём текущий код
 * @param binary $key - бинарный ключ
 * @param integer $counter - Timestamp
 * @return string
 **/
 public static function oath_hotp($key, $counter){
    if (strlen($key) < 8)
      throw new Exception('Секретный ключ слишком мал.Он должен быть больше 16 символов');
    $bin_counter = pack('N*', 0) . pack('N*', $counter);  
    $hash  = hash_hmac ('sha1', $bin_counter, $key, true);
    return str_pad(self::oath_truncate($hash), self::otpLength, '0', STR_PAD_LEFT);
 }

 /**
 * Вычленяет OTP из SHA1 hash.
 * @param binary $hash
 * @return integer
 **/
 public static function oath_truncate($hash){
    $offset = ord($hash[19]) & 0xf;
    return (
        ((ord($hash[$offset+0]) & 0x7f) << 24 ) |
        ((ord($hash[$offset+1]) & 0xff) << 16 ) |
        ((ord($hash[$offset+2]) & 0xff) << 8 ) |
        (ord($hash[$offset+3]) & 0xff)
    ) % pow(10, self::otpLength);
 }
}

Использование:

$InitalizationKey = "QWERTYUIOPASDFGH";     // Начальный ключ

$TimeStamp  = TOTP::get_timestamp();
$secretkey   = TOTP::base32_decode($InitalizationKey); // Перекодируем в бинарную строку
$otp         = TOTP::oath_hotp($secretkey, $TimeStamp); // получим текщий токен

echo("Ключ: $InitalizationKey\n");
echo("Timestamp: $TimeStamp\n");
echo("Код OTP: $otp\n");

Для того чтобы руками не вводить в OTP приложение начальный токен, можно генерировать QR код, с текстом вида:

otpauth://totp/мой_сайт:логин?secret=токен&issuer=логин

phpspreadsheet автовысота строки

Задача: для некоторых строк выставить автоматическую высоту

Решение:

    $wSheet->getRowDimension($totalrow)->setRowHeight(-1);  

PHP AMP Websocket: указание произвольных заголовков при рукопожатии

Задача: добавить произвольный заголовок клиенту при рукопожатии с сервером. Например Sec-WebSocket-Protocol

Решение:

use Amp\Delayed;
use Amp\Websocket\Client\Connection;
use Amp\Websocket\Client\Handshake;
use Amp\Websocket\Message;
use function Amp\Websocket\Client\connect;
use Amp\Socket\ClientTlsContext;
use Amp\Socket\ConnectContext;

            Amp\Loop::run(function () use ($wss_url,$ip,$port,$pascket,&$answer,$wait_reseive) {                            
                $tlsc=new ClientTlsContext("");
                $tlw=$tlsc->withoutPeerVerification();
                $connectContext = (new ConnectContext)->withTlsContext($tlw);
                $handshake = (new Handshake("ws://1.18.24.70:$port/virtual_api_1c"))->withHeader('Sec-WebSocket-Protocol', 'virtual');  
                $connection = yield connect($handshake,$connectContext);   
                yield $connection->send($pascket);
                yield $connection->close();
            });  
1 6 7 8 9 10 29