php – 2个准备好的语句,2个存储过程,1个mysqli连接

前端之家收集整理的这篇文章主要介绍了php – 2个准备好的语句,2个存储过程,1个mysqli连接前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
问题

如何使用预准备语句(或另一种对sql注入同样安全的查询方法)在同一mysqli连接中调用两个MySQL存储过程,而不会出现以下错误

Warning: Packets out of order. Expected 1 received 61. Packet size=7 in /...
Warning: MysqLi::prepare(): MysqL server has gone away in /...

tutorialspoint代码连接到网上

故事

我正在使用MysqL数据库制作PHP后端.我想从一个查询中得到两个结果:每周摘要列表,以及所有周的摘要.

┌───────┬────────────┬────────────┬─────
|  Week |    Sales   | Commission | ...
├───────┼────────────┼────────────┼─────
| week1 |  $7,912.12 |    $923.41 | ...
| week2 |  $6,423.48 |    $824.87 | ...
| week3 |  $8,180.67 |    $634.04 | ...
|  ...  |    ...     |    ...     | ...
├───────┼────────────┼────────────┼─────
| total | $67,012.23 |  $7,532.58 | ...
| avg   |  $7,012.54 |    $787.38 | ...
└───────┴────────────┴────────────┴─────

我曾经只将每周摘要存储在数据库表中,并使用存储过程来获取所有每周摘要摘要.在我的PHP代码中,我只选择了周表中的所有行,然后调用了getWeeksSummary存储过程.

现在我必须能够过滤每周摘要中的数据.我用存储过程getWeeks()替换了一个简单的SELECT … FROM周来计算所有的每周摘要.

$weeksSummary = new stdClass();

if ($stmt = $MysqLi->prepare('CALL getWeeks(?,?,?);')) {
    $stmt->bind_param('sss',$a,$b,$c);
    $stmt->execute();
    $stmt->bind_result($week,$sales,$commission,...);
    $weeksSummary->weeks = [];
    while($stmt->fetch())
    {
        $week = new stdClass();
        $week->week = $week;
        $week->sales = $sales;
        $week->commission = $commission;
        ...
        $weeksSummary->weeks[] = $week;
    }
    $stmt->free_result();
    $stmt->close();
}

if ($stmt = $MysqLi->prepare('CALL getWeeksSummary(?,$c);
    $stmt->execute();
    $stmt->bind_result($avgSales,$totSales,$avgCommission,$totCommission ...);
    $stmt->fetch();
    $weeksSummary->summary = new stdClass();
    $weeksSummary->summary->avgSales = $avgSales;
    $weeksSummary->summary->totSales = $totSales;
    $weeksSummary->summary->avgCommission = $avgCommission;
    $weeksSummary->summary->totCommission = $totCommission;
    ...
    $stmt->free_result();
    $stmt->close();
}

echo json_encode($weeksSummary);

当第一个准备好的声明是SELECT周,销售,佣金,…… FROM周WHERE a =?,b =?,c = ?;而不是CALL getWeeks(?,?,?);.现在我收到这些错误

Warning: Packets out of order. Expected 1 received 61. Packet size=7 in /...
Warning: MysqLi::prepare(): MysqL server has gone away in /...

尝试

1)失败:我为第二个查询使用了新的语句对象$stmt2.同样的错误.

2)成功:我关闭MysqLi连接并在第二个语句之前打开了一个新连接.与其自己的预处理语句的第二个MysqLi连接运行正常,但连接到数据库代码保持完全独立,因此这并没有真正帮助.

3)失败:出于好奇,我回到原来的工作代码并重新排序语句,将存储过程语句放在SELECT语句之前.同样的错误.所以MysqLi连接在存储过程之前的查询很好,但是在存储过程之后不喜欢任何东西.

4)失败:我尝试使用$MysqLi-> next_result();在第一次声明之后.同样的错误.但是,如果我使用query()而不是prepare()来调用存储过程,则next_result()确实允许两个存储过程运行.我想使用预备语句,因为它们有助于防止sql注入.

不良潜在的解决方

A):我可以将它分成两个后端调用,但是当数据刷新时,前端的摘要将不同步.

B):我可以将它们加入到一个MysqL存储过程中,然后在PHP中将它们分开,但我也需要将它们分开,所以相同的代码会有两次.

C):我可以停止使用预准备语句,但我不知道任何其他方法来避免sql注入.

救命

有什么建议?

好吧,我将尝试回答问题标题,假设在第一个语句中不是常规查询,而是调用了两个上述存储过程之一.

调用存储过程之后,您始终必须移动每个存储过程返回的其他空结果集:

$MysqLi->next_result();

此外,在第一次准备函数调用后,在获取数据后添加一个额外的fetch():

$stmt->fetch();
$stmt->free_result();

因为你必须“释放”在服务器端等待的结果集.它可以通过多种方式完成,但最简单的方法是再次调用fetch(),或者更严格地说,你必须调用fetch()直到它返回FALSE,表明结果集中没有剩下的行.当你在while循环中调用fetch()时,你正在静默地在其他片段中这样做,但是在这里,只需要获取一行,你必须明确地调用它.

还有另一种方式,更方便:使用get_result()(如果可用),它将立即解决您的所有问题.而不是你现在拥有的冗长而多风的代码,实际上只需要四行:

$stmt = $MysqLi->prepare('CALL getWeeksSummary(?,?)');
$stmt->bind_param('sss',$c);
$stmt->execute();
$weeksSummary = $stmt->get_result()->fetch_object();

get_result()将释放该等待结果集,同时允许您使用fetch_object()方法,这将允许您只在一行中获取结果对象.

猜你在找的PHP相关文章