nwood21
nwood21

Reputation: 322

PHP Form Loop Passing Variables to $_POST When Input Names Aren't Static

In the form below I'm creating a loop but I need unique input name(s). The name "api_key" and name "delete_button" need to be something like "api_key_0" "api_key_1", etc. and delete_button_1, delete_button_2, etc. How do I get unique names in the loop? Second part: How do I get variables inside of the $_POST that are the correct input names created in the loop? I need to pass the correct variables names to the $_POST for each delete button and api key.

<?php // Delete API code. 
        if(isset($_POST['delete_button'])) {
            $delete_api_key = $_POST['api_key'];
            if ($mysqli->query("DELETE FROM api_keys WHERE api_key = '$delete_api_key'")) {
             echo "API Key Successfully Deleted.";      
            }
             else {
                echo "Error:" . $mysqli->error;
                    }
            }
    ?>

Form Part:

<?php
if ($api_cnt >= 1) {

    $list_api_keys = $mysqli->query("SELECT api_key, user FROM api_keys WHERE user = 'testuser'");
?>


<form method= "post" action ="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">
<table>
<tr>
<th>API Keys</th>
</tr>
<?php
    while($row = mysqli_fetch_row($list_api_keys)) {

?>
<tr>
<td><input name = "api_key" type = "hidden" value="<?php echo $row[0]; ?>"><?php echo $row[0]; ?></td> 
<td><input type = "submit" name = "delete_button"  value = "Delete"></td>
</tr>
<?php
    }
?>
</form>
</table>
<?php
$mysqli->close();
}
?>

Upvotes: 0

Views: 156

Answers (3)

AbraCadaver
AbraCadaver

Reputation: 79014

To do it like this you really need multiple forms each with its own data and submit button. Only one can be submitted. I left out some HTML to keep it short:

<?php while($row = mysqli_fetch_row($list_api_keys)) { ?>
<form method= "post" action ="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">
<table>
<tr>
<td><input name = "api_key" type = "hidden" value="<?php echo $row[0]; ?>"></td> 
<td><input type = "submit" name = "delete_button"  value = "Delete"></td>
</tr>
</table>
</form>
<?php } ?>

Then just get it as only one was submitted:

if(isset($_POST['delete_button'])) {
    $delete_api_key = $_POST['api_key'];
}

Or you could do one form and assign the submit button as an array with the id as the key:

<form method= "post" action ="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>">
<table>
<?php while($row = mysqli_fetch_row($list_api_keys)) { ?>
<tr>
<td><input type = "submit" name = "delete_button[<?php echo $row[0]; ?>]"  value = "Delete"></td>
</tr>
<?php } ?>
</table>
</form>

Then just get the key:

if(isset($_POST['delete_button'])) {
    $delete_api_key = key($_POST['delete_button']);
}

Upvotes: 1

Kinglish
Kinglish

Reputation: 23664

There are more elegant ways than this - for instance, provide checkmarks for each and have a single delete button, or use ajax, but with the approach you started, I would recommend individual form tags for each iteration.

<?php
  while($row = mysqli_fetch_row($list_api_keys)) {
?>
<tr>
<form method='post' action='deleteme.php'>
<td><input name="api_key" type="hidden" value="<?php echo $row[0]; ?>"><?php echo $row[0]; ?></td> 
<td><input type="submit" value="Delete"></td>
</tr>
</form>
<?php
    }
?>

Here's an ajax approach First, make sure the surrounding form tag prevents submits:

<form onsubmit='return false'>

then

<?php
  while($row = mysqli_fetch_row($list_api_keys)) {
?>
<tr data-key="<?php echo $row[0]; ?>">
<td><?php echo $row[0]; ?></td> 
<td><button onclick='del(this);' > Delete</button></td>
</tr>
<?php
    }
?>

with the script to facilitate the ajax and subsequent row deletion:

function del(el) {
let key = $(el).closest('tr').attr('data-key');
$.ajax({
  url: "delete.php",
  method: 'post',
  data: { api_key: key}
}).done(function(response) {
  if (response.indexOf('Error:') === -1)  $(el).closest('tr').remove();
  else alert("There was an error - " + response);
});
}

In your PHP, use prepared statements to protect yourself and your data

$stmt = $mysqli->prepare("DELETE FROM api_keys WHERE api_key = ? LIMIT 1");
$stmt->bind_param("s", $_POST['api_key']);
$deleted = $stmt->execute();

if ($deleted) {
  echo "API Key Successfully Deleted.";      
}

Upvotes: 0

M. Eriksson
M. Eriksson

Reputation: 13645

If you're only going to send one pair at the time, an easier solution would be to create different forms instead (one per table row). Then only the relevant inputs will be sent and always have the same names.

<?php while($row = mysqli_fetch_row($list_api_keys)): ?>
    <tr>
    <td>
        <form method="post" action="">
            <input name="api_key" type="hidden" value="<?= $row[0]; ?>" /><?php echo $row[0]; ?>
    </td>
    <td>
            <input type="submit" name="delete_button" value="Delete" />
        </form>
    </td>
    </tr>
<?php endwhile ?>

Side note: Leaving the action in the form empty will make the form submit to the current page, so it's the same as adding htmlspecialchars($_SERVER["PHP_SELF"]). Also adding the form tag between <table> and <tr> will generate invalid HTML (the same for adding it between <tr> and <td>) which is why I've added it inside the <td>'s.

You can read more about that under "permitted content" for table and for tr

Upvotes: 2

Related Questions