0

I have an array like this:

var ids = [8372839402, 8392615782, 3677281302];

Inserted are id values. Based on this ids I have to get for each one some information from the database. Basicly I get data by using following function which is located in db.js:

function getdata(get_command) {
  var request = new XMLHttpRequest();
  var params = params + 'command=' + encodeURIComponent(get_command) + '&';

  console.log(params);

  currentpromise = new Promise(function(resolve, reject) {
    request.open('POST', './php/get_data.php', true);
    request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    request.onreadystatechange = function() {
      if (request.readyState === XMLHttpRequest.DONE) {
        if (request.status === 200) {
          var response = JSON.parse(request.response);
          resolve(response);
        }
        else {
          resolve({error: 'Cant connect!'});
        }
      }
    };
    request.send(params);
  });
}      

And than bascily in my main.js I use this function like this:

var user_id = 'r82h9hfew89hf9983f8d9';
var currentpromise;
var obj = getdata('SELECT username, email FROM users WHERE id=' + user_id);
      currentpromise.then(function(obj) {
        if (obj.data[0] == 'false') {

        }
        else {
           //succesfully go on
        }
      });     

But when I would use this in an array it wouldnt work. Beginning with that I have multiple promises on the var currentpromise or that they get override by calling the getdata function every time in array forEach.
How to fix my problem to loop through the array without errors?

ids.forEach(function(id) {
    var obj = getdata('SELECT name FROM data WHERE id=' + id);
      currentpromise.then(function(obj) {
        if (obj.data[0] == 'false') {

        }
        else {
           //succesfully do next step
           var obj = getdata('SELECT version FROM vers WHERE name=' + obj.data[0]['name']);
           currentpromise.then(function(obj) {
             if (obj.data[0] == 'false') {

             }
             else {
               //succesfully finished with one id
             }
           });  
        }
      });  
});    

I dont think it is so important but here we have the get_data.php:

<?php
include('classes/db.php');

$data = array();
$command = urldecode($_POST['command']);

$result_value = db::query($command);
$data['data'] = $result_value;

// return all our data to an AJAX call
echo json_encode($data, JSON_PRETTY_PRINT);
?>    

EDIT: dp.php

<?php

class db {
  private static function connect() {
    //db inf, username, pwd
    $pdo = new PDO('mysql:host=127.0.0.1;dbname=emergencybase;charset=utf8', 'root', '');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    return $pdo;
  }

  public static function query($query, $params = array()) {
    $statement = self::connect()->prepare($query);
    $statement->execute($params);

    if (explode(' ', $query)[0] == 'SELECT') {
      $data = $statement->fetchAll();
      return $data;
    }
  }
}

Hope someone can help me with this. Thanks in advance.
Filip

Filip Degenhart
  • 631
  • 4
  • 19
  • 1
    `getdata()` doesn't return anything, what do you expect `obj` to be? – Barmar Oct 04 '20 at 10:07
  • 1
    Instead of overwriting an external variable, simply have `get_data` return the created promise. Then use this in your loop: `get_data(...).then(function (reply) { ... });` Or even better, turn the array of ids into an array of promises using `.map`, then pass it to `Promise.all(...)` –  Oct 04 '20 at 10:09
  • 3
    This is a great example of a code prone to sql injection. When someone invoke `getData('DROP DATABASE')` heads will roll. – francisco neto Oct 04 '20 at 10:10
  • @ChrisG Can you write a short answer how this would look like? – Filip Degenhart Oct 04 '20 at 10:11
  • When `getData()` returns a Promise you can take a look at this question to see how to wait in your for loop: https://stackoverflow.com/questions/37576685/using-async-await-with-a-foreach-loop – A_A Oct 04 '20 at 10:12
  • No, because the answer to this is all over the web and this website. –  Oct 04 '20 at 10:12
  • @francisconeto How should I do it than? Please show me a better solution – Filip Degenhart Oct 04 '20 at 10:12
  • As for the injection issue, move the queries to your PHP code and use urls like `get_data.php?param=version` or something along those lines, then use PDO statements to query the DB. –  Oct 04 '20 at 10:13
  • 1
    Just passing the id as arg to `getData()` function (and not the sql command) would be a good start. Using PDO to build the query would be good as well. – francisco neto Oct 04 '20 at 10:14
  • @francisconeto Indeed, and a dropped database might be the least damaging things an attacker may do.. :) – Keith Oct 04 '20 at 10:20
  • @ChrisG I already use PDO. Please have a look at my edit. – Filip Degenhart Oct 04 '20 at 12:00
  • Does this answer your question? [Using async/await with a forEach loop](https://stackoverflow.com/questions/37576685/using-async-await-with-a-foreach-loop) – Liam Oct 13 '20 at 15:00

1 Answers1

2

ForEach is synchronous in nature and you shouldn't use promises or any async code inside forEach loop as it will simply iterate over array without waiting for promise to get fulfilled. You could use for await...of loop instead.

Piyush Rana
  • 631
  • 5
  • 8