gpt4 book ai didi

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

转载 作者:可可西里 更新时间:2023-11-01 06:33:00 26 4
gpt4 key购买 nike

问题

如何使用准备好的语句(或其他对 SQL 注入(inject)同样安全的查询方法)在同一个 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 代码中,我只是选择了 week 表中的所有行,然后调用了 getWeeksSummary 存储过程。

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

代码

$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(?,?,?);')) {
$stmt->bind_param('sss', $a, $b, $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 week, sales, commission, ... FROM week 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 注入(inject)。

不良的潜在解决方案

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

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

C): 我可以停止使用准备好的语句,但我不知道还有什么其他方法可以避免 SQL 注入(inject)。

帮助

有什么建议吗?

最佳答案

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

调用存储过程后,您总是必须移动每个存储过程返回的额外空结果集:

$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', $a, $b, $c);
$stmt->execute();
$weeksSummary = $stmt->get_result()->fetch_object();

get_result() 将释放等待的结果集,同时允许您使用 fetch_object() 方法,这将使您仅需获取结果对象一行。

关于php - 2 个准备好的语句,2 个存储过程,1 个 mysqli 连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32773694/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com