【发布时间】:2015-12-22 18:50:47
【问题描述】:
问题
如何使用准备好的语句(或另一种对 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 代码中,我只是选择了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 连接对于查询before 存储过程很好,但不喜欢任何after 存储过程。
4) 失败: 我尝试将$mysqli->next_result(); 放在第一条语句之后。同样的错误。但是,如果我使用query() 而不是prepare() 调用存储过程,next_result() 确实允许两个存储过程运行。不过我想使用准备好的语句,因为它们有助于防止 SQL 注入。
不受欢迎的潜在解决方案
A):我可以将它分成两个对后端的调用,但是当数据刷新时,前端的摘要会不同步。
B): 我可以将它们加入一个 MySQL 存储过程,然后在 PHP 中将它们分开,但我也需要将它们分开,所以相同的代码将是有两次。
C):我可以停止使用准备好的语句,但我不知道有什么其他方法可以避免 SQL 注入。
帮助
有什么建议吗?
【问题讨论】:
-
您的问题的答案一般是下一个结果()。要获得特定代码中某些拼写错误的帮助,您必须创建一个完整的、功能齐全的示例并将其发布在此处。根据问题正文中不断编辑的某些草图,无法回答。
-
阅读php.net entry for
next_result()似乎暗示它与multi_query()一起使用,而没有提及prepare() -
虽然有人建议在comments of the php.net article for
prepare()中使用next_result(),但我尝试使用相同的代码时却没有用。 -
我把所有的代码都放到tutorialspoint上,可以查看、修改和执行
标签: php mysql stored-procedures mysqli prepared-statement