#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? Не уверен, что там что-то не так, поскольку я этого не вижу, но мне бы очень хотелось извлечь из этого урок (я отвечу на вопрос с конечным результатом, как только это заработает в будущем, ПОЭТОМУ используйте)