Использование фильтрации по формулам Haversine с помощью Mysql и PHP для значения поиска

#php #mysql

#php #mysql

Вопрос:

У меня есть следующий PHP-скрипт, который фильтрует полученное значение ($ r) с данными о местоположении, связанными с использованием формулы haversine, чтобы показывать только значения, которые находятся на определенном расстоянии от полученной точки. По какой-то причине приведенный ниже скрипт не работает, и я не могу сказать, является ли он функционально неправильным или это что-то простое, как синтаксическая ошибка (просматривается посимвольно несколько раз и не видит ничего плохого, но я могу ошибаться)

Полученное значение имеет следующую форму: [search_value]latlong[lat_value]latlong[long_value]

Пример:

Item1latlong26.2616236latlong25.6010943

Сценарий PHP выглядит следующим образом:

 <?php

include('db.php');

$r = strval($_GET['r']);

$parts = explode('latlong', $r);

$term = $parts[0];
$latitude = $parts[1];
$longitude = $parts[2];

$distance = 1;

mysqli_select_db($mysqli,"db");
$search="SELECT *, (((acos(sin((".$latitude."*pi()/180)) * sin(('lat'*pi()/180))   cos((".$latitude."*pi()/180)) * cos(('lat'*pi()/180)) * cos(((".$longitude."- 'lng')*pi()/180)))) * 180/pi()) * 60 * 1.1515) as distance FROM 'table_data' WHERE distance <= ".$distance." AND type = '".$term."'";
$result = mysqli_query($mysqli,$search);

echo "<script type='text/javascript'>";
echo "var map;";
echo "var markers = [];";
echo "var locations = [";

while($row = mysqli_fetch_array($result)) {
     echo "[" . $row['merchant'] . ".info," . $row['merchant'] . ".lat," . $row['merchant'] . ".lng," . $row['merchant'] . ".type," . $row['merchant'] . ".label," . $row['userid'] . "],";
};

echo "];";

echo "</script>";

mysqli_close($mysqli);
 

В приведенном выше ‘lat’ и ‘long’ соответствуют соответствующим столбцам в соответствующей таблице, где хранится список элементов, каждый со своими данными о местоположении.

Любые рекомендации по улучшению приветствуются (я новичок в php), и помощь будет оценена, спасибо!

Комментарии:

1. Вы не можете использовать псевдоним расстояния с помощью WHERE . Либо измените значение на HAVING, либо измените формулу.

2. И обратите внимание, что ваш код открыт для внедрения

3. @Strawberry спасибо! Так что, по сути, замена «ГДЕ» на «НАЛИЧИЕ» разрешит? Все еще планируете включить фильтры php — я предполагаю, что это устранит риск инъекций?

4. Для внедрения требуется только использование подготовленных и связанных запросов

5. Здесь есть и другие проблемы. Но перебирать их немного утомительно

Ответ №1:

Если это полезно, вот хранимая функция для вычисления расстояний на Земле в километрах…

 DELIMITER $

CREATE FUNCTION geo_distance_km(lat1 double, lon1 double, lat2 double, lon2 double) RETURNS double
begin
   declare R int DEFAULT 6372.8;
   declare phi1 double;
   declare phi2 double;
   declare d_phi double;
   declare d_lambda double;
   declare a double;
   declare c double;
   declare d double;
   set phi1 = radians(lat1);
   set phi2 = radians(lat2);
   set d_phi = radians(lat2-lat1);
   set d_lambda = radians(lon2-lon1);
   set a = sin(d_phi/2) * sin(d_phi/2)  
         cos(phi1) * cos(phi2) *
         sin(d_lambda/2) * sin(d_lambda/2);
   set c = 2 * atan2(sqrt(a), sqrt(1-a));
   set d = R * c;
   return d;
end$
DELIMITER ;
 

Пример использования:

 <?php

/*
CREATE TABLE my_table
(id SERIAL PRIMARY KEY
,userid INT NOT NULL
,merchant INT NOT NULL
,latitude DECIMAL(11, 8) NOT NULL
,longitude DECIMAL(11, 8) NOT NULL
,type VARCHAR(12) NOT NULL
);

INSERT INTO my_table VALUES
(1, 100, 1000, 30.45180,31.236083,'Item1'),
(2, 101, 1000, 26.26162,25.601094,'Item1'),
(3, 101, 1001, 30.36100,31.232080,'Item1'),
(4, 102, 1002, 30.45180,31.236083,'Item1'),
(5, 103, 1003, 30.44473,31.241958,'Item1'),
(6, 103, 1003, 26.26150,25.601000,'Item2'),
(7, 103, 1004, 30.45180,31.236083,'Item2');
*/

require('path/to/pdo/connection/stateme.nts');

$r = 'Item1latlong26.2616236latlong25.6010943';

$parts = explode('latlong', $r);

$term = $parts[0];
$latitude = $parts[1];
$longitude = $parts[2];

$distance = 1;

$query="
SELECT merchant
     , userid
     , geo_distance_km(:latitude,:longitude,latitude,longitude) distance
  FROM my_table
 WHERE type = :term
HAVING distance < :distance
   ";

$stmt = $pdo->prepare($query);
$stmt->bindParam(':latitude', $latitude, PDO::PARAM_INT);
$stmt->bindParam(':longitude', $longitude, PDO::PARAM_INT);
$stmt->bindParam(':distance', $distance, PDO::PARAM_INT);
$stmt->bindParam(':term', $term, PDO::PARAM_STR, 12);
$stmt->execute();

$result = $stmt->fetch();

print_r($result);


?>
 

Выводит:

 Array ( [merchant] => 1000 [userid] => 101 [distance] => 0.0004015440080907 )  
 

Комментарии:

1. Это не отвечает на вопрос, это всего лишь еще один подход к функции haversine в PHP

2. @Nick1991 FWIW, я думаю, что это рекомендация по улучшению — то, что вы указали, будет приветствоваться и оценено. Я думаю, это моя ошибка.

3. @Nick1991 В любом случае, я добавил пример использования.

4. Спасибо! Я пропустил это и только сейчас понял, и мне нравится метод — Как я уже упоминал, я новичок в PHP — я хочу попробовать повторить ваш пример, чтобы учиться — я создал ваш пример my_table в виде таблицы, а также добавил точную сохраненную процедуру, которую вы предлагаете для БД в phpmyadminоднако, когда я пытаюсь запустить предложенный вами php-скрипт, я получаю ошибку 500? Не уверен, что там что-то не так, поскольку я этого не вижу, но мне бы очень хотелось извлечь из этого урок (я отвечу на вопрос с конечным результатом, как только это заработает в будущем, ПОЭТОМУ используйте)