使用 While 循环内的多个输入元素和 While 循环外的单个提交按钮更新 MySQL 数据库

Posted

技术标签:

【中文标题】使用 While 循环内的多个输入元素和 While 循环外的单个提交按钮更新 MySQL 数据库【英文标题】:Update MySQL Database With Data From Multiple Input Elements Inside A While Loop, And A Single Submit Button Outside of The While Loop 【发布时间】:2022-01-24 03:50:50 【问题描述】:

我有一个页面在初始上传后从数据库中获取图像,允许用户为图像添加标题和标签。

我已设置while 循环以在一个表单中输出单个图像。每个图像都有两个相关的输入字段。我想做的是,当提交表单时,数据库中的所有信息都会一次性更新(即使相关输入字段中的图像详细信息保持空白/未填写)。

为了实现这一点,我想我可以在while 循环之外设置表单的提交按钮。但是,这并没有按预期工作。它基本上一次更新一张图像,每次我按下提交时(它会更新循环中的最后一张图像)。

如何获取它,以便它在提交时一次性处理 while 循环内所有图像的所有信息?如果我将提交按钮放在循环中,我会为每个图像获得一个按钮,这是我不想要的。

注意:<img/> 源路径我刚刚在下面硬编码以保存添加实现此目的的不同变量,从而希望使代码更简单。

从数据库中获取数据并输出 HMTL 表单

<?php isset($_REQUEST['username']) ? $username = $_REQUEST['username'] : header("Location: login.php"); ?>

<form method="post" enctype="multipart/form-data">

    <?php

        if (isset($_SESSION['logged_in'])) 
            $user_id = $_SESSION['logged_in'];
        

        $stmt = $connection->prepare("SELECT * FROM lj_imageposts WHERE user_id = :user_id");

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

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

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

    ?>

    <div class="upload-details-component">                
        <div class="form-row">
            <img src="/project/images/image.jpg">
        </div>
        <div class="edit-zone">
            <div class="form-row">
                <label for="upload-details-title">Image Title</label>
                <input id="upload-details-title" type="text" name="image-title">
            </div>
            <div class="form-row">
                <label for="upload-details-tags">Comma Separated Image Tags</label>
                <textarea id="upload-details-tags" type="text" name="image-tags"></textarea>
            </div>
            <div class="form-row">
                <input type="hidden" name="username" value="<?php echo $username; ?>">
                <input type="hidden" name="image-filename" value="<?php echo $db_image_filename; ?>">
            </div>
        </div>
    </div>

    <?php  ?>

    <button type="submit" name="upload-submit">COMPLETE UPLOAD</button>
</form>

在提交表单时更新数据库

<?php 

if(isset($_POST['upload-submit'])) 

    $image_title = $_POST['image-title'];
    $image_tags = $_POST['image-tags'];
    $form_filename = $_POST['image-filename']; // value attribute from hidden form element

        try 

            $sql = "UPDATE lj_imageposts SET
            image_title = :image_title,
            image_tags = :image_tags

            WHERE filename = :filename";
                
            $stmt = $connection->prepare($sql);
    
            $stmt->execute([
                ':image_title' => $image_title,
                ':image_tags' => $image_tags,
                ':filename' => $form_filename
            ]);
            
            // This is the URL to this actual page (basically refreshes the page)
            header("Location: upload-details.php?username=$username");

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

        // give values an empty string to avoid an error being thrown before form submission if empty
        $image_title = $image_tags = "";



?>

【问题讨论】:

funfact,跟随 Location:directs 是可选的,对于黑客来说不跟随 Location 重定向是微不足道的。 嗨@Don'tPanic - 是的。我几乎肯定会把它标记为正确的,并在它到期时将赏金分配给你。非常感谢。 【参考方案1】:

如果我正确理解您的问题,您希望将每个图像的所有多个输入条目保存到您的数据库中。

为此,您首先需要将每个输入名称设为一个数组。例如,在您的第一个输入“image-title”中,您需要将其设为“image-title[]”。您还需要将“image-tags”设为“image-tags[]”。

完成后,您将需要在它提交的代码中添加逻辑,以循环每个输入并更新数据库。

所以现在提交脚本上的 $image_title 将是一个值数组。您需要遍历这些并相应地更新数据库。

【讨论】:

我不知道如何遍历这些并更新数据库?【参考方案2】:

您当前方法的问题是 bcs 每组输入使用相同的name,它们相互覆盖。假设您的前端有 3 条记录、3 组表单输入。如果您输入 onetwothreeimage-title 值,则在后端您只会看到 three

您可以自行验证:print_r($_POST);

解决方案是将数据作为数组发送,您只需在输入名称中使用 [] 即可:

<?php while ($row = $stmt->fetch())  ?>
    <input type="text" name="image-title[]">
    <textarea type="text" name="image-tags[]"></textarea>
    <input type="hidden" name="image-filename[]" value="<?php echo $db_image_filename; ?>">
<?php  ?>
<button type="submit" name="upload-submit">COMPLETE UPLOAD</button>

现在您将在后端获得输入数组,例如(再次使用print_r($_POST); 自己查看):

[image-title] => Array
    (
        [0] => First Title
        [1] => 2nd Title
    )

[image-tags] => Array
    (
        [0] => foo
        [1] => bar
    )

[image-filename] => Array
    (
        [0] => filename
        [1] => another-filename
    )

因此您可以循环遍历它们,一次处理一个:

$sql = "UPDATE lj_imageposts SET
    image_title = :image_title,
    image_tags = :image_tags
    WHERE filename = :filename";
$stmt = $connection->prepare($sql);

foreach ($_POST['image-title'] as $key => $value) 
    $stmt->execute([
        ':image_title' => $_POST['image-title'][$key],
        ':image_tags'  => $_POST['image-tags'][$key],
        ':filename'    => $_POST['image-filename'][$key]
    ]);

请注意,使用文件名作为唯一标识符并不理想 - 这就是 ID 的用途。可能存在非唯一文件名的风险,但您的数据库查询对于诸如(假设您的表有一个主键 idUPDATE ... WHERE id=:id 之类的查询会更有效率。您可以通过将隐藏文件输入替换为隐藏 ID 输入来做到这一点:

<input type="hidden" name="id[]" value="<?php echo $row->id; ?>">

然后当然在后端更新您的查询:

WHERE id = :id
// ...
':id'    => $_POST['id'][$key]

更好的是,您可以在输入name 中使用id 来明确识别值集:

<input type="text" name="image-title[<?php echo $row->id; ?>]">
<textarea type="text" name="image-tags[<?php echo $row->id; ?>]"></textarea>

在这种情况下,您甚至不需要将 id(或 image-filename)作为单独的隐藏输入传递 - 您已经拥有输入名称中的所有 ID。在后端你可以这样做:

$sql = "UPDATE lj_imageposts SET
    image_title = :image_title,
    image_tags = :image_tags
    WHERE id = :id";
$stmt = $connection->prepare($sql);

foreach ($_POST['image-title'] as $id => $value) 
    $stmt->execute([
        ':image_title' => $_POST['image-title'][$id],
        ':image_tags'  => $_POST['image-tags'][$id],
        ':id'          => $id
    ]);

你可以想象这是一个常见的问题,这里还有很多其他的解决方案可以参考:

Multiple inputs with same name through POST in php How to get a form input array into a PHP array HTML/PHP - Form - Input as array

PHP 文档参考:

https://www.php.net/manual/en/faq.html.php#faq.html.arrays

【讨论】:

你是缩写because吗?为什么?【参考方案3】:

首先,在您的问题/代码中,您使用filename 字段作为表lj_imageposts 中记录的唯一标识符。我假设您确定此字段中的值对于您拥有的每个用户都是唯一的。我强烈建议您在表中创建一个唯一的自动增量字段id(以防万一)并使用它。在我的回答中,我将使用id 字段来识别图像。

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

        $db_image_id = $row['id']; // the unique id for this image
        $db_image_filename = htmlspecialchars($row['filename']);
        ...
        ...

其次,当您创建/构建表单时,为您的输入使用一个数组名称,并确保您拥有的每个图像都有一个唯一的输入名称。为此,请替换此名称:

<input id="upload-details-title" type="text" name="image-title">

到这里:

<input id="upload-details-title_<?=$db_image_id;?>" type="text" name="image-title[<?=$db_image_id;?>]">

重要您需要为循环中的每个inputtextarea 执行此操作。

此时,当您提交表单时,您的$_POST 应该如下所示

array(
    'image-title' => array(
        1 => 'First Image Title',
        2 => 'Second Image Title',
        3 => 'Third Image Title',
        ...
        ...
    ),
    'image-tags' => array(
        1 => 'First Image Tags',
        2 => 'Second Image Tags',
        3 => 'Third Image Tags',
        ...
        ...
    ),
    ...
    ...
)

其中 1, 2, 3, ... 是图像的 ID

第三,在你的更新代码中,你需要循环获取你有数据的图片,并一张一张地更新图片:

if(isset($_POST['upload-submit'])) 

    foreach( $_POST['image-title'] as $image_id => $dummy)  // at this point I only need the ID


        $image_title = $_POST['image-title'][$image_id];
        $image_tags = $_POST['image-tags'][$image_id];

        // I don't need this value to identify the record. in this example I'm using `id` field
        //$form_filename = $_POST['image-filename'][$imageId]; // value attribute from hidden form element

        try 

            $sql = "UPDATE lj_imageposts SET
            image_title = :image_title,
            image_tags = :image_tags

            WHERE id = :id";
                
            $stmt = $connection->prepare($sql);
    
            $stmt->execute([
                ':image_title' => $image_title,
                ':image_tags' => $image_tags,
                ':id' => $image_id // using id instead of filename as identifier
            ]);

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

    

    // move the "redirect" header to outside my update loop
    // This is the URL to this actual page (basically refreshes the page)
    header("Location: upload-details.php?username=$username");

    // also, exit to only send the redirect header not anything else
    exit;

【讨论】:

以上是关于使用 While 循环内的多个输入元素和 While 循环外的单个提交按钮更新 MySQL 数据库的主要内容,如果未能解决你的问题,请参考以下文章

while循环 和 运算符

while循环 和 运算符

2022年最新Python大数据之Python基础

C;如果我在 while 循环内的 for 循环中放置一个 break

while循环 和 运算符

Python ❀ while循环