2

I'm trying to pass to php from javascript elements of an array, for processing, like this:

for(var i=0;i<points.length;++i){
        var xmlhttp = new XMLHttpRequest();
        var distancesObject = null;
        lat = points[i][LAT];
        lng = points[i][LNG];
        xmlhttp.onreadystatechange = function() {
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200){
            if(xmlhttp.response!=null){
                distancesObject = JSON.parse(xmlhttp.response); 
            }
        }       
    };  
        xmlhttp.open("GET", "Distances.php?lat=" + lat + "&lng=" + lng, true);  
        xmlhttp.send();
    }

It should iterate through every elements of the array and return the object, if it exists in the database, yet it returns null, even though i know for sure the first values are stored in the database. It only works if I pass values like points[0], points[1]. The php code is:

<?php
    $latitude = $_GET['lat']; //"47.158857";
    $longitude = $_GET['lng']; // "27.601249"
    $query = "SELECT pharmacyDistance, schoolDistance, restaurantDistance, busStationDistance FROM distances WHERE lat='$latitude' and lng='$longitude'";
    $result = mysqli_query($dbc,$query);
    $count = mysqli_num_rows($result);  
    $row = mysqli_fetch_array($result, MYSQLI_ASSOC);
    $json_array = json_encode($row);
    if($json_array!=null){
        echo $json_array;
    }
    mysqli_close($dbc);
?>

Is there something I'm doing wrong?

DontVoteMeDown
  • 21,122
  • 10
  • 69
  • 105
Dalisay
  • 39
  • 5
  • show what `points` contains... – Yash Parekh Apr 25 '18 at 12:57
  • points[i][LAT] stands for a point latitude, like in my case 47.158857 and points[i][LNG] stands for point longitude - 27.601249 – Dalisay Apr 25 '18 at 13:00
  • I am confused, If you are passing a Lat and Lng presumably gathered from a device like a Phone, how can your database possibly contain all possible distances between any point in the world and any/every Pharmacy in the world? This surely has to be a calculation and you have to look up Pharmacies from something like GoogleMaps – RiggsFolly Apr 25 '18 at 13:02
  • You PHP code is highly vulnerable to [SQL Injection](https://stackoverflow.com/questions/332365/how-does-the-sql-injection-from-the-bobby-tables-xkcd-comic-work), use prepared statements instead (everywhere, not only on this code) – Elias Soares Apr 25 '18 at 13:20

3 Answers3

2

Please don't do that way. Really. Add all array items into your url and perform just one request, where you will query for everything you need and return a list. Handle the list in the response. Something like(from top of my head):

var urlParams = [];

points.forEach(function(point) {
    urlParams.push("lat[]=" + point.LAT + "&lng[]=" + point.LNG);
});

var xmlhttp = new XMLHttpRequest();
var distancesObject = null;

xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == 4 && xmlhttp.status == 200){
        if(xmlhttp.response!=null){
            distancesObject = JSON.parse(xmlhttp.response); 
        }
    }       
};  

xmlhttp.open("GET", "Distances.php?" + urlParams.join("&"), true);  
xmlhttp.send();

In PHP:

$whereClause = "";

for ($i = 0; $i < count($_GET['lat']); $i++) {
    $whereClause.= "(lat='" . $_GET['lat'][$i] . "' and lng='" . $_GET['lng'][$i]. "') and ";
}

$query = "SELECT pharmacyDistance, schoolDistance, restaurantDistance, busStationDistance FROM distances WHERE " . substr($whereClause, 0, (strlen($whereClause) - 4)); // Substr to remove last ' and' from where clause

$result = mysqli_query($dbc,$query);
$count = mysqli_num_rows($result);  
$distances = array();
while($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
    $distances[] = $row;
}

$json_array = json_encode($distances);
if($json_array!=null){
    echo $json_array;
}
mysqli_close($dbc);

Then you'll have a list of your distances as json and just one hit in your database. Also, is not healthy for your app to call an ajax in a for loop, it will open various parallel async requests, a mess.

This is how the query will looks like approximately:

SELECT ... FROM ... WHERE (lat='1' and lng='1') and (lat='2' and lng='2') and ...

I didn't tested those codes and I don't play with PHP for a while, so I hope the code is ok, forgive any typos or syntax errors.

DontVoteMeDown
  • 21,122
  • 10
  • 69
  • 105
  • As the original post, this PHP piece of code is highly vulnerable to [SQL Injection](https://stackoverflow.com/questions/332365/how-does-the-sql-injection-from-the-bobby-tables-xkcd-comic-work). – Elias Soares Apr 25 '18 at 13:20
  • 1
    @EliasSoares sure, that is another thing I leaved aside. The ajax requests was so bad I didn't realized that SQL issue. – DontVoteMeDown Apr 25 '18 at 13:42
  • So, I don't know if i'm asking a stupid question, but how will my query look in php? as I see it(I might me mistaken of course), because $whereClause is in a loop, it will be a concat of all lats and lngs? – Dalisay Apr 25 '18 at 14:38
  • @MadalinaGrigoras look at the updated post. You will have to return the `lat` and `lng` from the request to know in javascript's request callback which row is related to which lat/lng. – DontVoteMeDown Apr 25 '18 at 14:45
  • But that would mean that it will try to select the lines where lat = value and also where lat = anotherValue, right? – Dalisay Apr 25 '18 at 14:58
  • @MadalinaGrigoras yes, you will select multiple lines by the given points, so your javascript will receive a list. You will need to handle that list, that means to perform another *select* over that list(e.g. using [`filter()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)) to use it in your js code. – DontVoteMeDown Apr 25 '18 at 16:09
  • But I modified some lines and now it works, thank you so much @DontVoteMeDown – Dalisay Apr 25 '18 at 16:46
  • @MadalinaGrigoras great! That is the right to do it in my opinion. Cheers. – DontVoteMeDown Apr 25 '18 at 17:12
0

I believe your problem lies with these 2 lines:

lat = points[i][LAT];
lng = points[i][LNG];

Firstly, you have defined them into the global scope. They should be prefixed with the var keyword unless you've already defined these variables above.

Second, [LAT] is trying to use an (I assume unitiated) variable named LAT. The correct syntax for using a string key name is either points[i]['LAT'] or points[i].LAT.

So, updating your code to

var xmlhttp = new XMLHttpRequest();
var distancesObject = null;
var lat = points[i].LAT;
var lng = points[i].LNG;

Should hopefully solve your problem.

Scoots
  • 3,048
  • 2
  • 21
  • 33
0

you're overwriting the object which is handling the connection in the for loop, probably faster than the response can return.

try:

var xmlhttp = [];
    for(var i=0;i<points.length;++i){
            xmlhttp[i] = new XMLHttpRequest();
            var distancesObject = null;
            lat = points[i][LAT];
            lng = points[i][LNG];
            xmlhttp[i].onreadystatechange = function() {
            if (xmlhttp[i].readyState == 4 && xmlhttp[i].status == 200){
                if(xmlhttp[i].response!=null){
                    distancesObject = JSON.parse(xmlhttp.response); 
                }
            }       
        };  
            xmlhttp[i].open("GET", "Distances.php?lat=" + lat + "&lng=" + lng, true);  
            xmlhttp[i].send();
        }
Matthew Knight
  • 631
  • 5
  • 13