【问题标题】:adding extra variable inside fetched data在获取的数据中添加额外的变量
【发布时间】:2020-09-22 17:36:02
【问题描述】:

正如您在下面看到的,我正在获取 idsOfSenders 并执行另一个查询以获取该用户的信息。到目前为止,这工作正常。

但是正如你所看到的,我还有另一个变量$msgDate,我想把它放在每个用户的输出中。我该怎么做?

$recieverId = 33;

$query = "SELECT from_msg, chat_date FROM msg WHERE `to_msg` = '$recieverId' ORDER BY `chat_date` DESC";
$res = mysqli_query($conn, $query);
    while($row = mysqli_fetch_array($res)) {
        $idsOfSenders[] = $row['from_msg'];
        $msgDate[] = $row['chat_date'];
    }

$queryb = "SELECT fullname, username FROM `users` WHERE `id` IN('".implode("','",$idsOfSenders)."')";
$resb = mysqli_query($conn, $queryb);

if($resb->num_rows >0){
    $json=[];
    while(($rowb = $resb->fetch_assoc())) {
        $json[] = $rowb;
    }
    echo json_encode($json);
} else {
    echo "0";
}
case 'gmmn':
//ini_set('display_errors', 1);
//ini_set('display_startup_errors', 1);
//error_reporting(E_ALL);
if(isTheseParametersAvailable(array('i'))){

    if (!$conn) {
        return;
    }

    //$recieverId = str_replace(" ", "", $_POST["i"]);
    $recieverId = 33;

        $sqlCheckMsg = "SELECT from_msg, chat_date, fullname, username FROM msgNew LEFT JOIN users_table on users_table.id = msgNew.from_msg WHERE to_msg = ? ORDER BY `chat_date` DESC";
        $stmt = $conn->prepare($sqlCheckMsg );
        $stmt->bind_param("i",$recieverId);
        $stmt->execute();
        $stmt->store_result();
        $stmt->bind_result($from_msg,$chat_date,$fullname,$username);
        if($stmt->num_rows > 0){
            $rows=[];
            while($stmt->fetch()) {
                $rows[] = array('from_msg'=>$from_msg
                                , 'chat_date'=>$chat_date
                                , 'fullname'=>$fullname
                                , 'username'=>$username);
            }
        } else {
            echo "0";
            return;
        }

        echo json_encode($rows);

}
break;

【问题讨论】:

  • 警告:使用mysqli 时,您应该使用parameterized queriesbind_param 将任何数据添加到您的查询中。 请勿使用字符串插值或连接来完成此操作,因为您创建了一个严重的SQL injection bug切勿$_POST$_GET任何类型的数据直接放入查询中,如果有人试图利用您的错误,这可能是非常有害的。做好,不难修复
  • @tadman 我只是希望你能花 3 秒时间阅读这篇文章的第一行。
  • 你是否知道它不安全并不重要,改变你的代码以使用安全版本是几秒钟的工作,所以如果你足够关心你的代码在 Stackoverflow 上向人们寻求帮助,花几秒钟的时间让你的代码没有巨大的安全漏洞。至于如何获取更多数据:只需在json_encode 之前更新$json 并返回它?此外,如果您要返回 JSON,请不要返回 0,而是返回 {},以便在被使用它的任何东西解析时,内容将始终是正确的对象。
  • 为您的草率代码道歉比修复它需要更多的努力和精力。这些东西非常重要要做到正确,所以当你半途而废一些代码然后给出一个蹩脚的道歉时,它不仅对你有不好的影响,而且对整个程序员都有影响。这个“我稍后会修复它”或“它只是测试代码!1!”态度是为什么SQL Injection Hall of Fame 页面上永远不会缺少条目的原因。立即将其扼杀在萌芽状态。
  • 这个问题解决了吗?它的状态如何?

标签: php mysql sql mysqli


【解决方案1】:

这就是JOIN 派上用场的地方。您对两个查询所做的事情可以一次完成,另外,不需要那种可怕的implode 注入:

SELECT from_msg, chat_date, fullname, username
  FROM msg
  LEFT JOIN users on users.id=msg.from_msg
  WHERE to_msg=? ORDER BY `chat_date` DESC

这应该显着更快更安全,因为它不涉及在返回数据库之前通过 PHP 进行往返。

注意:确保msgfrom_msg 上被索引,以使JOIN 操作高效。您可以使用EXPLAIN SELECT ...检查查询性能

【讨论】:

  • 好的,谢谢。这是我确实需要知道的。我已经更新了帖子,你可以看看吗?
  • 看起来很合理,使用占位符做得很好。该代码现在是安全的,而且将来不会造成麻烦。调试转义错误非常繁琐。
【解决方案2】:

毫无疑问,您应该使用@tadman 的答案。话虽如此,您遇到的主要问题是单个用户可以向接收者发送任意数量的消息。

假设我是usera,我在一周前、昨天和今天向receiverId 33 发送了消息。有 3 条消息,有 3 个不同的日期。您需要为该用户提供 3 行,以反映 3 条消息。

我不建议您使用以下方法,但它会起作用,具体取决于您如何看待它,通过解决用户可以发送多个带有相关聊天日期的 msg 的事实。此代码将消息存储在一个数组中,并将它们添加到每个用户的获取结果中。您仍然需要处理“chat_date”是一个日期数组而不是像结果集的其余部分那样的单个标量值这一事实。

            $recieverId = 33;

            $query = "SELECT from_msg, chat_date FROM msg WHERE `to_msg` = '$recieverId' ORDER BY `chat_date` DESC";
            $res = mysqli_query($conn, $query);
                while($row = mysqli_fetch_array($res)) {
                    $idsOfSenders[] = $row['from_msg'];
                    //msgDate will be an array of all the dates sent for this member to the other member
                    $msgDate[$row['from_msg']][] = $row['chat_date'];
                }

            $queryb = "SELECT id, fullname, username FROM `users` WHERE `id` IN('".implode("','",$idsOfSenders)."')";
            $resb = mysqli_query($conn, $queryb);

            if($resb->num_rows >0){
                $json=[];
                while(($rowb = $resb->fetch_assoc())) {
                    // Add the array of this user's sent message dates
                    $rowb['msg_date'] = $msgDate[$rowb['id']];
                    // get rid of the users.id column if you don't want it
                    unset($rowb['id']);
                    $json[] = $rowb;
                }
                echo json_encode($json);
            } else {
                echo "0";
            }

这确实假设用户的表主键名为 id。如果不是,则需要更改相关代码以反映用户表主键的名称,该名称存储在msg表的from_msg和to_msg中。

如您所见,这是一个丑陋的 hack。关系数据库会为您解决这个问题。同样,@tadman 的解决方案是可行的方法,但我认为如果我向您展示如何使其工作以及您缺少的东西,它可能会帮助您更好地了解您当前的问题。

更新:既然您实现了@tadman 的查询,我个人不会绑定结果,因为这会导致您在这种情况下使用很多您并不真正关心的变量。这更简单:

                $sqlCheckMsg = "SELECT from_msg, chat_date, fullname, username FROM msgNew LEFT JOIN users_table on users_table.id = msgNew.from_msg WHERE to_msg = ? ORDER BY `chat_date` DESC";
                $stmt = $conn->prepare($sqlCheckMsg );
                $stmt->bind_param("i",$recieverId);
                $stmt->execute();
                $result = $stmt->get_result();
                $rows = array();
                while ($row = $result->fetch_assoc()) {
                    $rows[] = $row;
                }
       
                if (count($rows) > 0) {
                    echo json_encode($rows);
                    return;  
                } else {
                    echo "0";
                    return;
                } 

【讨论】:

  • 您似乎解决了有关未使用参数化查询的投诉并使用了 tadman 的建议。所以我会说干得好!有效吗?
  • 是的,它按我想要的方式工作,并不是我不知道如何使用参数化查询,只是我不知道如何进行我所要求的查询和使用帮助/建议我会以正确的方式构建它。谢谢。
  • 查看我的更新,以获取有关以更简单/更清洁的方式处理结果的建议。否则看起来你做得很好。您当然也应该投票并接受 tadman 的回答。如果我对您有所帮助,请随意支持或不支持我。
猜你喜欢
  • 1970-01-01
  • 2018-07-20
  • 2012-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-20
  • 2021-07-18
  • 1970-01-01
相关资源
最近更新 更多