'Target Individual Form Instance/Counter Inside A PHP While Loop

I have a PDO prepared statement that I use on a single-image page where a user is going to be able to download that specific image. I currently have a counter that increments each time the download button is clicked which updates a counter value in a MySQL database. I'd like to transfer and use the download counter from the single-image page onto an index page that shows multiple images.

Because the form element is inside a while loop when you click the download button, the current functionality updates the counter for all of the images on this page (i.e. everything inside the loop).

Obviously I don't think I can move it outside of the loop because it then won't update anything at all?

How do I get it so the when the download button is clicked for a particular instance of the form, it only updates that specific form elements details?

PHP

<?php

    // get username from URL parameter
    isset($_GET['username']) ? $username = $_GET['username'] : header("Location: index.php");

    // fetch filename details from database
    $stmt = $connection->prepare("SELECT * FROM imageposts WHERE username = :username");
    $stmt->execute([':username' => $username]); 

    while ($row = $stmt->fetch()) {

        $db_image_filename = htmlspecialchars($row['filename']);

        // -- HTML that shows the image file goes here --

        // update counter for number of downloads of an image
        if (isset($_POST['download'])) {
            try {
                $sql = "UPDATE imageposts SET downloads = downloads +1 WHERE filename = :filename";
                $stmt = $connection->prepare($sql);

                $stmt->execute([
                    ':filename' => $db_image_filename
                ]);

            } catch (PDOException $e) {
                echo "Error: " . $e->getMessage();
            }
        }
?>

// download button that updates the counter
<form method="post">
    <button type="submit" name="download">Download</button>
</form>

<?php } ?>


Solution 1:[1]

One way to approach this is to add some PHP outside of your loop, that references a value from a hidden <form> element inside the loop - in this case you have a $db_image_filename value you could use.

<form method="post">
    <button type="submit" name="download">Download</button>
    <input type="hidden" name="hidden-filename" value="<?php echo $db_image_filename; ?>">
</form>

Then reference this value in PHP:

<?php
if (isset($_POST['download'])) {

      // value from hidden form element
      $hidden_filename = $_POST['hidden-filename'];

      try {
           $sql = "UPDATE imageposts SET downloads = downloads +1 WHERE filename = :filename";
           $stmt = $connection->prepare($sql);

           $stmt->execute([
                ':filename' => $hidden_filename
           ]);
           
           header("location: " . $_SERVER['PHP_SELF']);

      } catch (PDOException $e) {
           echo "Error: " . $e->getMessage();
      }
}
?>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 pjk_ok