Реализация PHP объекта карты для геоданных

Раздел: Геоданные -> Маппинг и карты

Объекты карты в PHP: подходы и реализация

Наиболее эффективным решением для работы с объектами карты в PHP является использование специализированной библиотеки geoPHP, которая предоставляет удобный интерфейс для создания географических объектов (точка, линия, полигон) и их сериализации в популярные форматы (GeoJSON, WKT, KML).


// Установка через Composer
composer require phayes/geophp

// Использование
require_once 'vendor/autoload.php';

use GeoPHP\GeoPHP;
use GeoPHP\Geometry\Point;

$point = new Point(37.7749, -122.4194); // Долгота, широта
echo $point->toGeoJSON();
   

Maps php id (карты идентификаторов в php)

Пояснение: Point принимает координаты (долгота, широта). Метод toGeoJSON() возвращает JSON-представление.

Типичные ошибки:

  • Неправильный порядок координат (многие сервисы ожидают широта, долгота, но geoPHP использует долготу первой).
  • Отсутствие установки SRID (пространственной системы координат) - по умолчанию используется WGS84 (EPSG:4326), что обычно корректно.

Как создать простой объект карты без внешних зависимостей?


class MapPoint {
    public float $lat;
    public float $lng;
    public function __construct(float $lat, float $lng) {
        $this->lat = $lat;
        $this->lng = $lng;
    }
    public function toArray(): array {
        return ['lat' => $this->lat, 'lng' => $this->lng];
    }
}

$point = new MapPoint(55.751244, 37.618423);
echo json_encode($point->toArray());
   

Php map object (объект карты в php)

Этот класс позволяет хранить координаты и преобразовывать их в JSON. Минусы: отсутствие методов для работы с дистанциями, пересечениями.

Проблемы: необходимо самостоятельно реализовывать валидацию координат (проверка диапазонов), нет поддержки пространственных операций.

Как передать данные о карте из PHP в JavaScript (Leaflet)?

В PHP формируется массив точек или GeoJSON, который встраивается в HTML как переменная JavaScript.


$points = [
    ['lat' => 55.751244, 'lng' => 37.618423, 'name' => 'Москва'],
    ['lat' => 59.934280, 'lng' => 30.335099, 'name' => 'Санкт-Петербург']
];
?>

   

Использование JSON_HEX_TAG и JSON_HEX_AMP предотвращает XSS-атаки. Проблемы: при большом объеме данных страница грузится долго.

Ошибки: незаэкранированные кавычки, отсутствие проверки на null, неверный порядок координат для Leaflet (широта, долгота).

Как хранить и извлекать географические объекты из MySQL?

MySQL поддерживает пространственные типы POINT, LINESTRING, POLYGON. Извлечение происходит через функцию ST_AsText или ST_AsGeoJSON.


// Получение точки в WKT
$stmt = $pdo->query("SELECT ST_AsText(location) FROM places WHERE id = 1");
$row = $stmt->fetch();
$wkt = $row['ST_AsText(location)']; // например "POINT(37.618423 55.751244)"
   

Далее WKT можно разобрать с помощью geoPHP или регулярных выражений. Проблемы: различия в порядке координат (MySQL хранит X, Y как долгота, широта).

Распространенные проблемы: игнорирование SRID, неправильное преобразование между форматами.

Как преобразовать массив PHP в GeoJSON коллекцию?


$features = [];
foreach ($points as $p) {
    $features[] = [
        'type' => 'Feature',
        'geometry' => ['type' => 'Point', 'coordinates' => [$p['lng'], $p['lat']]],
        'properties' => ['name' => $p['name']]
    ];
}
$geojson = ['type' => 'FeatureCollection', 'features' => $features];
echo json_encode($geojson, JSON_PRETTY_PRINT);
?>
   

GeoJSON стандартизирует обмен данными. Проблема: сложность структуры, возможны ошибки в порядке координат.

Типичные ошибки: использование широты вместо долготы в координатах GeoJSON (должна быть [долгота, широта]), отсутствие обязательного поля 'type'.

Расширенные примеры работы с объектами карты на PHP

1. Создание полигона и проверка вхождения точки

Пример

require_once 'vendor/autoload.php';
use GeoPHP\GeoPHP;
use GeoPHP\Geometry\Point;
use GeoPHP\Geometry\Polygon;
use GeoPHP\Geometry\LineString;

// Создаем полигон (пример территории Москвы внутри МКАД)
$exterior = [
    [37.6, 55.7],
    [37.7, 55.7],
    [37.7, 55.8],
    [37.6, 55.8],
    [37.6, 55.7]
];
$polygon = new Polygon([new LineString($exterior)]);
$pointInside = new Point(37.65, 55.75);
$pointOutside = new Point(38.0, 56.0);

echo "Точка внутри? " . ($polygon->contains($pointInside) ? 'да' : 'нет') . "\n"; // да
echo "Точка снаружи? " . ($polygon->contains($pointOutside) ? 'да' : 'нет');  // нет
    
Точка внутри? да
Точка снаружи? нет
    

Метод contains() использует алгоритм Ray casting, поддерживается для всех геометрий. Важно: корректная ориентация колец (против часовой стрелки).

2. Расчет расстояния между двумя точками (формула гаверсинусов)

Пример

function haversineDistance(float $lat1, float $lng1, float $lat2, float $lng2): float
{
    $earthRadius = 6371; // км
    $dLat = deg2rad($lat2 - $lat1);
    $dLng = deg2rad($lng2 - $lng1);
    $a = sin($dLat/2) * sin($dLat/2) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * sin($dLng/2) * sin($dLng/2);
    $c = 2 * atan2(sqrt($a), sqrt(1-$a));
    return $earthRadius * $c;
}

$distance = haversineDistance(55.751244, 37.618423, 59.934280, 30.335099);
echo "Расстояние между Москвой и Санкт-Петербургом: " . round($distance, 2) . " км";
    
Расстояние между Москвой и Санкт-Петербургом: 634.98 км
    

Формула полезна для быстрого расчета без внешних библиотек, но точность ниже, чем у Vincenty.

3. Импорт данных из MySQL и генерация GeoJSON для отображения на Leaflet

Пример

// Предполагаем таблицу places с полями id, name, location (POINT SRID 4326)
$pdo = new PDO('mysql:host=localhost;dbname=geo', 'user', 'pass');
$stmt = $pdo->query("SELECT id, name, ST_AsGeoJSON(location) AS geojson FROM places");
$features = [];
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    $features[] = [
        'type' => 'Feature',
        'geometry' => json_decode($row['geojson'], true),
        'properties' => [
            'id' => $row['id'],
            'name' => $row['name']
        ]
    ];
}
$collection = ['type' => 'FeatureCollection', 'features' => $features];
file_put_contents('places.geojson', json_encode($collection, JSON_PRETTY_PRINT));
    
// Файл places.geojson будет содержать стандартную GeoJSON коллекцию.
    

ST_AsGeoJSON возвращает строку GeoJSON для каждой геометрии. Преобразование в массив и сборка коллекции.

Проблемы: необходимо убедиться, что в MySQL используется правильный SRID (4326), иначе координаты могут быть интерпретированы неверно.

4. Парсинг GPX файла и извлечение трека

Пример

$gpx = simplexml_load_file('track.gpx');
$points = [];
foreach ($gpx->trk->trkseg->trkpt as $pt) {
    $points[] = [
        'lat' => (float)$pt['lat'],
        'lng' => (float)$pt['lon'],
        'ele' => (float)$pt->ele,
        'time' => (string)$pt->time
    ];
}
echo json_encode($points, JSON_PRETTY_PRINT);
    
[
    {
        "lat": 55.751244,
        "lng": 37.618423,
        "ele": 156,
        "time": "2024-01-15T12:00:00Z"
    },
    ...
]
    

GPX формат широко используется для обмена треками. SimpleXML позволяет легко парсить, но нужно учитывать пространства имен (в примере без неймспейсов).

Объект карты в PHP - comments

En
Php map object (php)