【问题标题】:Mistake in my coding, but not sure how to correct it, wonder if anyone can give a hand?我的编码有错误,但不知道如何纠正,不知道是否有人可以帮忙?
【发布时间】:2012-04-16 10:36:22
【问题描述】:

您好,我在 php 中遇到了 foreach 函数的问题...我使用该函数将数组的结果输入到数据库中。例如,如果数组 (3,5,7),系统应在数据库中输入 3 个不同的条目。但是,就我而言,它只创建了 1 个条目,而完全忽略了其他 2 个条目。请问是否有人能发现我的错误?

我创建了一个带有复选框的表单并尝试检索值并为每个值提供一个单独的数组,例如:

<form name="appoptions" id="applicationoptions" method="post" action="s_apply_now.php">
<table width="100%" class="apptable" border="0" cellspacing="0" cellpadding="0">
  <tr>
    <td><input type="checkbox" name="cat[]" value="1" /> CAT 2PG</td>
    <td><input type="checkbox" name="cat[]" value="2" /> CAT 1OR</td>
    <td><input type="checkbox" name="cat[]" value="3" /> CAT 2TT</td>
  </tr>
  <tr>
    <td><input type="checkbox" name="cat[]" value="4" /> CAT 3PG </td>
    <td><input type="checkbox" name="cat[]" value="5" /> CAT 2OR</td>
    <td><input type="checkbox" name="cat[]" value="6" /> CAT 3TT</td>
  </tr>
  <tr>
    <td><input type="checkbox" name="cat[]" value="7" /> CAT 4PG</td>
    <td><input type="checkbox" name="cat[]" value="8" /> CAT 3OR</td>
    <td>&nbsp;</td>
  </tr>
</table>
</form>

点击确认后,将进入处理器页面。在我的处理器页面中,我试图提取该值,但我在一个数组中实现了它:

<?php
session_start();
include'Connections/database.php';
$conn = dbConnect ();
    if (! $conn)
    die("Couldn't connect to MySQL");
    $user = $_SESSION['eid'];
    $query = "select MED  from emp where EID = '$user'";
    $result = mysql_query($query, $conn);
    $row = mysql_fetch_assoc($result);

$med = $row['MED']; 
$user =$_SESSION['eid'];
$class=$_POST['class'];
$cat_arr=$_POST['cat'];


$i = 0; /* for illustrative purposes only */

foreach ($cat_arr as $cat) 
{
    if ($med=='no')
    {

        if (! $conn)
        die("Couldn't connect to My SQL");

        $query = "insert into permit (EID, PTYPE, STATUS) values ('$user,$cat, 'medical')";
        $result = mysql_query($query,$conn);
        header ('Location:medical_question.php');
        $i++;
    }
    else
    {

        if (! $conn)
        die("Couldn't connect to My SQL");
        $query = "insert into permit (EID, PTYPE) values ('$user,$cat)";
        $result = mysql_query($query,$conn);
        $i++;
    }
 }
dbDisconnect($conn);
 ?>

我不确定是否每个都是错误,但我认为它就在那里......

提前致谢。

【问题讨论】:

  • 首先,我不会将数据库连接放入循环中。其次,您是否遇到任何错误,您是否已转储 $cat_arr 以查看其中包含的内容?
  • 有几件事...首先,您不应该在循环中连接和断开数据库。这是不必要的开销。您应该在循环之前连接并在之后断开连接。其次,我们看不到$med 是什么。尝试这样做:var_dump($cat_arr); var_dump($med); 在循环之前查看它包含的内容。
  • @Travesty3 对不起,伙计们...我从来没有包含整个代码...我已经添加了...您介意简要解释一下 car_dump 的用途吗?因为php手册网站不是很清楚……我不太明白。
  • @Hubert: var_dump 基本上会输出一个变量的内容。它非常适合调试目的。如果你var_dump一个数组,它会吐出数组的内容。
  • @Travesty3 哦,谢谢,所以我将var_dump($cat_arr); 添加到$cat_arr=$_POST['cat']; 的下方,或者没有我需要放置的特定位置?

标签: php database arrays foreach


【解决方案1】:

它只插入一次,因为在进行第一次插入后,您将重定向到 medical_question.php。

将此重定向移到 foreach 之外:

header ('Location:medical_question.php');

另外,你也可以将 db connect 移到 foreach 之前。

【讨论】:

  • 好吧,从技术上讲,由于他没有die()exit(),脚本将继续执行。但我同意它应该被移出循环。
  • @Travesty3:标题不会在第一次 foreach 完成后立即重定向吗?
  • 它可以继续,但是一旦浏览器收到Location,它就会断开连接并且脚本将在那个时候停止执行。在这种情况下,这似乎发生在 MySQL 收到下一个插入查询之前,特别是考虑到每次迭代都会创建一个新的数据库连接。
  • 伙计们...对不起我的错误...我的意图是 if ($med=='no') 然后转到 header ('Location:medical_question.php'); 否则转到我尚未创建的 enxt 页面,但这将是告诉用户的页面即许可证申请成功。
  • @MrCode 如果我想将页面设置为转到header ('Location:medical_question.php'); if ($med=='no') 或转到我尚未创建的下一页,但它将是告诉用户许可成功申请的页面为了。我应该把标题放在哪里?
【解决方案2】:

我发现您的 PHP 代码存在一些不同的问题:

  1. 您不应在循环中连接/断开 MySQL。这是不必要的开销。相反,请在循环之前连接并在之后断开连接。
  2. 在查询中使用任何用户输入之前,您需要对其进行清理。您的代码容易受到SQL injection 的攻击。
  3. 您还应该将 header('Location:medical_question.php'); 行移到循环之外,并将其更改为 die(header('Location:medical_question.php')); 以阻止脚本的其余部分执行(假设这是您想要发生的情况)。
  4. 您需要修复查询中的单引号:

    insert into permit (EID, PTYPE, STATUS) values ('$user,$cat, 'medical')

    应该是:

    insert into permit (EID, PTYPE, STATUS) values ('$user', '$cat', 'medical')

    对于您的其他查询也是如此。

最后,您的脚本看起来会更类似于以下内容:

$conn = dbConnect();
if (!$conn)
    die("Couldn't connect to MySQL");

$user = mysql_real_escape_string($_SESSION['eid']);
$class = $_POST['class'];
$cat_arr = $_POST['cat'];

foreach ($cat_arr as $cat) 
{
    $cat = mysql_real_escape_string($cat);

    if ($med == 'no')
        $query = "INSERT INTO permit (EID, PTYPE, STATUS) VALUES ('{$user}', '{$cat}', 'medical')";
    else
        $query = "INSERT INTO permit (EID, PTYPE) VALUES ('{$user}', '{$cat}')";

    mysql_query($query);
}

dbDisconnect($conn);

if ($med == 'no')
    $nextPage = "medical_question.php";
else
    $nextPage = "next_page.php";

die(header("Location:{$nextPage}"));

SQL 注入示例:

假设您的查询如下所示:

$user = $_GET["user"];
$cat = $_GET["cat"];
$query = "insert into permit (EID, PTYPE, STATUS) values ('$user', '$cat', 'medical')";

如果我为user 传递这样的值,您的查询会是什么样子:

`'); DROP TABLE permit; /*`

这会将您的查询变成这样:

insert into permit (EID, PTYPE, STATUS) values (''); DROP TABLE permit; /*', 'cat', 'medical')

绝对不是你想要发生的。当您使用mysql_real_escape_string 清理输入时,它将转义单引号字符,并且查询将失败或将插入整个字符串而不是执行。


更新:

如果您确切知道该函数的作用,您要将header 移出循环的原因将更容易理解:

当您调用 PHP header 函数时,您是在告诉 PHP(在服务器端)向浏览器(在客户端)发送一个 HTTP 标头。在 header('Location:...') 的情况下,您发送的 HTTP 标头会导致浏览器重定向到不同的页面并断开与当前 PHP 脚本的连接。

所以这是发生的事件的过程:

  1. PHP 脚本发送 HTTP 标头,根据延迟,浏览器可能需要一些时间才能接收它。
  2. 浏览器解释标头并重定向到您指定的位置,这还会向当前正在执行的 PHP 脚本发送断开连接消息。
  3. 同样,根据延迟,服务器可能需要一些时间才能从浏览器接收断开连接消息。

在 PHP 脚本发送标头和收到断开连接消息之间,脚本仍在执行。在收到断开连接消息之前,无法知道脚本将执行多少代码,因此您根本不能依赖它。这就是为什么您应该在发送标头时die

知道这就是 PHP header 函数的工作原理,您可能希望将其放入循环中的唯一原因是,如果您希望当前脚本根据某些特定条件在循环中间停止执行健康)状况。像这样:

foreach ($vars as $var)
{
    if ($var == "stop")
        die(header("Location:anotherPage.php"));

    // do something as long as $var != "stop"
}

这将循环遍历$var 数组,直到达到"stop" 的值,此时它将向客户端发送重定向标头并停止执行。

与您的示例不同的是(在您编辑之前)您的循环包含一个 if-else 语句,并且在 if else,您进行了标头重定向调用。所以无论如何,它都会在循环的第一次迭代中发送,这是没有意义的。如果这确实是您想要的,那么您将不会使用循环。它只会执行一次,这违背了循环的目的。

对于冗长的回复感到抱歉,但希望您现在对代码中的实际情况有了更好的了解。

【讨论】:

  • 对不起,我对消毒部分有点困惑……你说放 var_dump() 对吗?这是为了清理输入?
  • 不,var_dump 是让您直观地查看和查看数组的内容。要清理您的用户输入,请使用mysql_real_escape_string。阅读 SQL 注入的定义,以更好地了解为什么需要对用户输入进行清理。
  • 明白了!谢谢...我去阅读更多关于 mysql_real_escape_string() 在 php 手册...
  • 哦,我还能再问一件事吗?为什么我们必须在变量周围有 {}?对不起,如果它是一个菜鸟 qns...
  • 好。我继续发布了一个 SQL 注入尝试的示例,以便您认识到风险。方括号 ({}) 不是必需的,我只是发现它们有助于识别字符串中变量名的边界。在这种情况下它可以提供帮助:$variable = "Hello"; $string = "{$variable}_world!";。如果那里没有括号,_world! 部分将连接到变量名,因此这有助于将变量名与字符串的其余部分分开。
【解决方案3】:
  1. 字符串由 '$string'(撇号)标记到 sql 查询中

    $query = "插入许可(EID, PTYPE) 值('$user','$cat')";

  2. 您可以通过正确的连接仅初始化一个 db 对象 ($db),并在需要的地方使用它:请参阅 http://php.net/manuel/en/ref.mysql.php

例如:

    $conn = new mysqli('localhost', 'root', 'pass', 'db');
    if (mysqli_connect_errno()) {
        exit('Connect failed: '. mysqli_connect_error());
    }
    $sql = "INSERT INTO `table` (`id`, `val`) VALUES (1, 'peace'), (2, 'love')";
    if ($conn->query($sql) === TRUE) {
        echo 'Done';
    }
    else {
        echo 'Error: '. $conn->error;
   }
   $conn->close();

这只是一个原始示例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-03
    • 2020-11-20
    • 2016-11-09
    相关资源
    最近更新 更多