0

I have this Ajax call:

$('#directory_select_form').submit(function(e) {
        $('#loader').show();
        $('#order_number_submit_btn').prop('disabled', true);
        e.preventDefault();
       $.ajax({
           url: 'includes/confirmation_emails/process_directory_request.php',
           type: 'POST',
           dataType: 'json',
           data: $(this).serialize(),
           success: function(data) {
               console.log(data);
               $('#loader').hide();
               $('#order_number_submit_btn').prop('disabled', false);
           },
           error: function(jqXHR, textStatus, errorThrown) {
               $('#loader').hide();
               $('#order_number_submit_btn').prop('disabled', false);
           }
       })
    });

process_directory_request.php contains a shell_exec command:

<?php

$selected_directory = $_POST['selected']; //<-- This will be used later. Hard coded for now
$order_number = $_POST['orderId']; //<-- This will be used later. Hard coded for now.


$command = shell_exec('ssh remoteServer grep -o "Order Number 1234567" /mnt/tank/TECH/"MySQL\\ Data\\ Archives"/path/to/the/file');

echo json_encode($command);

It's crashing because for some reason it is going into an infinite loop. If I run the command from the command line, it does as it's supposed to.

I cannot use this answer because of the ssh at the beginning. I'm running commands remotely.

What is causing this infinite loop? I don't understand. I'm printing the ajax response data to the console, and it's the same line over and over and over.

Edit Here is the output in my dev console, but it's actually many many times over:

/mnt/tank/TECH/MySQL Data Archives/path/to/the/file:Order
/mnt/tank/TECH/MySQL Data Archives/path/to/the/file:Order
/mnt/tank/TECH/MySQL Data Archives/path/to/the/file:Order
/mnt/tank/TECH/MySQL Data Archives/path/to/the/file:Order
/mnt/tank/TECH/MySQL Data Archives/path/to/the/file:Order
/mnt/tank/TECH/MySQL Data Archives/path/to/the/file:Order
/mnt/tank/TECH/MySQL Data Archives/path/to/the/file:Order
/mnt/tank/TECH/MySQL Data Archives/path/to/the/file:Order
/mnt/tank/TECH/MySQL Data Archives/path/to/the/file:Order
/mnt/tank/TECH/MySQL Data Archives/path/to/the/file:Order
/mnt/tank/TECH/MySQL Data Archives/path/to/the/file:Order
/mnt/tank/TECH/MySQL Data Archives/path/to/the/file:Order
/mnt/tank/TECH/MySQL Data Archives/path/to/the/file:Order
/mnt/tank/TECH/MySQL Data Archives/path/to/the/file:Order
/mnt/tank/TECH/MySQL Data Archives/path/to/the/file:Order
/mnt/tank/TECH/MySQL Data Archives/path/to/the/file:Order
/mnt/tank/TECH/MySQL Data Archives/path/to/the/file:Order
/mnt/tank/TECH/MySQL Data Archives/path/to/the/file:Order
miken32
  • 42,008
  • 16
  • 111
  • 154
DevOpsSauce
  • 1,319
  • 1
  • 20
  • 52
  • I don't see any loop here, infinite or otherwise. Do you mean that your AJAX request is being repeatedly triggered? Something else? – David Nov 13 '19 at 20:43
  • I don't know exactly how many times, but it's crashing my script because it's running out of memory. The output is the expected result, but over and over and over and over. – DevOpsSauce Nov 13 '19 at 20:47
  • Can you clarify exactly what's being repeated here? In your browser's debugging tools, is the AJAX request being made repeatedly? Is each instance of that request what you expect? When you debug, is this `submit` event handler being triggered repeatedly? Please elaborate. – David Nov 13 '19 at 20:52
  • Yes, I will edit my question to show some of the output. Gimme a min. – DevOpsSauce Nov 13 '19 at 20:53
  • 1
    It's not an infinite loop. It's a quoting problem, it's just matching the word `Order` not the whole string `Order Number 1234567`. So you're getting all the lines in the file that contain that word, instead of just the specified number. – Barmar Nov 13 '19 at 21:26
  • @Barmar You're correct! I just used the order number and I got two results. I'm gonna go work on formatting that command properly. Thank you for the help! – DevOpsSauce Nov 13 '19 at 21:31

2 Answers2

1

It's not an infinite loop, it's just more output than you were expecting.

The problem is that the quotes are not being sent to the remote server. ssh simply concatenates all the arguments into a single command, so the remote command is:

grep -o Order Number 1234567 /mnt/tank/TECH/MySQL\ Data\ Archives/path/to/the/file

It's just searching for the word Order, and treating Number and 1234567 as files to search.

You need to escape the double quotes so they'll be sent literally.

$command = shell_exec('ssh remoteServer grep -o \\"Order Number 1234567\\" /mnt/tank/TECH/\\"MySQL Data Archives\\"/path/to/the/file');

Also, you don't need to use both double quotes and escaped spaces in the directory name with spaces.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • I can confirm this. I ran `ps -ef | grep "grep"` while that script was running and it was showing "Order Number 1234567" over and over without quotes. I will gladly accept your answer. Thank you. So it was just a syntax error. – DevOpsSauce Nov 13 '19 at 21:38
  • 1
    I would rather recommend use of [escapeshellarg](https://www.php.net/manual/en/function.escapeshellarg.php) to do this, instead of manually trying to escape things. – miken32 Nov 13 '19 at 21:40
  • Thank you for the suggestion @miken32. I will look into that. :-) – DevOpsSauce Nov 13 '19 at 21:42
  • I'm not sure that would help in this case, because it needs an additional level of escaping. @miken32 – Barmar Nov 13 '19 at 21:42
0

Barmar correctly points out the problem is with your unescaped values. Here's how I would solve the problem:

<?php

$selected_directory = escapeshellarg("/mnt/tank/TECH/MySQL Data Archives/$_POST[selected]");
$order_number = escapeshellarg("Order Number $_POST[orderId]");

$grep_cmd = escapeshellarg("grep -o $order_number $selected_directory");

$output = shell_exec("ssh remoteServer $grep_cmd);

header("Content-Type: application/json");
echo json_encode($output);

We are double escaping the arguments so that they pass through the SSH call unscathed.

miken32
  • 42,008
  • 16
  • 111
  • 154