Dav*_*vid 2 php error-handling mysqli multiple-select-query mysqli-multi-query
使用 SO 上其他地方的示例来更好地捕获“隐藏”错误。虽然下面的代码将捕获并返回错误,但是否可以改进它以报告发生错误的查询?
使用下面的代码,输出是:
Columns: 18
Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'FRO inventory' at line 1
Run Code Online (Sandbox Code Playgroud)
正在测试的代码:
$query = "SELECT * FROM orders WHERE location = 'IN' ORDER BY orderNum DESC LIMIT 20;";
$query .= "SELECT * FRO inventory"; // With error
$ord = array();
$invent = array();
if(mysqli_multi_query($link, $query)) {
do {
// fetch results
if($result = mysqli_store_result($link)) {
echo 'Columns: ' . mysqli_field_count($link) . "<br>";
while($row = mysqli_fetch_assoc($result)) {
if(count($row) > 17)
$orders[] = $row;
elseif(count($row) == 6)
$inv[] = $row;
}
}
if(!mysqli_more_results($link))
break;
if(!mysqli_next_result($link)) {
// report error
echo 'Error: ' . mysqli_error($link);
break;
}
} while(true);
mysqli_free_result($result);
}
Run Code Online (Sandbox Code Playgroud)
这是一种不仅可以提高错误消息质量的方法,还可以改进处理结果集的方式。
$q["Orders"]="SELECT * FROM orders WHERE location = 'IN' ORDER BY orderNum DESC LIMIT 20";
$q["Inventory"]="SELECT * FRO inventory";
if(!$link=mysqli_connect("host","user","pass","db")){
echo "Failed to connect to MySQL: ",mysqli_connect_error();
}elseif(mysqli_multi_query($link,implode(';',$q))){
do{
$q_key=key($q); // current query's key name (Orders or Inventory)
if($result=mysqli_store_result($link)){ // if a result set... SELECTs do
while($row=mysqli_fetch_assoc($result)){ // if one or more rows, iterate all
$rows[$q_key][]=$row;
}
mysqli_free_result($result);
echo "<div><pre>"; // <pre> is for easier array reading
var_export($rows[$q_key]);
echo "</pre></div>";
}
} while(next($q) && mysqli_more_results($link) && mysqli_next_result($link));
}
if($mysqli_error=mysqli_error($link)){ // check & declare variable in same step to avoid duplicate func call
echo "<div style=\"color:red;\">Query Key = ",key($q),", Query = ",current($q),", Syntax Error = $mysqli_error</div>";
}
Run Code Online (Sandbox Code Playgroud)
第一次查询时出错:如果您的第一个查询尝试访问指定数据库中不存在的表,例如:ordersXYZ
Array $rowswill not exist, no var_export()will发生,您将看到以下响应:
查询键 = 订单,查询 = SELECT * FROM ordersXYZ WHERE location='IN' ORDER BY orderNum DESC LIMIT 20,语法错误 = 表 '[someDB].ordersXYZ' 不存在
第二个查询出错:如果您的第一个查询成功,但您的第二个查询尝试访问一个不存在的表,例如:inventory2
$rows["Orders"]将保存所需的行数据并将被var_export()'ed,$row["Inventory"]将不存在,您将看到以下响应:
查询键 = 库存,查询 = SELECT * FROMinventory2,语法错误 = 表 '[someDB].inventory2' 不存在
无错误:如果两个查询都没有错误,您的$rows数组将填充所需的数据并进行var_export()'ed,并且不会有错误响应。通过保存在 中的查询数据$rows,您可以从$rows["Orders"]和访问您想要的内容$rows["Inventory"]。
注意事项:
您可能会注意到我同时进行变量声明和条件检查,这使得代码更加 DRY。
由于我的方法在行implode()上使用分号elseif,因此请确保不要在查询中添加尾随分号。
这组查询总是返回一个结果集,因为都是 SELECT 查询,如果你有一个混合的查询集合affect_rows,你可能会在这个链接(/sf/answers/1572880571/)上找到一些有用的信息。
mysqli_multi_query()一旦出现错误,就会停止运行查询。如果您希望捕获“所有”错误,您会发现永远不会超过一个。
不建议像在 OP 的问题和解决方案中那样编写条件断点。虽然在其他情况下可以正确使用自定义断点,但在这种情况下,断点应while()位于do()块语句的内部。
返回零行的查询不会导致错误消息——它只是不会在其中创建任何子数组,$rows因为while()不会进入循环。
通过使用该key()函数,if/elseif可以避免OP 对每个结果集行中的列进行计数的条件。这是更好的做法,因为在某些情况下,在每次迭代中运行条件可能会变得昂贵。请注意,$q每次do()迭代结束时,数组指针都在内部前进。这是一项在 php 手册页上找不到的附加技术;它允许key()按预期工作。
而且,当然,这些<div><pre>var_export()...</pre></div>行可以从您的工作代码中删除——这纯粹是为了演示。
如果您要在此代码块之后运行更多重用变量的查询,请务必清除所有使用的变量,以免残留数据干扰。例如$mysqli_error=null; // clear errors & reset($q); // reset array pointer。
请自行决定注意这个有点模糊的警告:http : //php.net/manual/en/mysqli.use-result.php:
如果在客户端执行大量处理,则不应使用 mysqli_use_result(),因为这将占用服务器并阻止其他线程更新任何从中获取数据的表。
最后也是最重要的是,出于安全原因,不要公开显示查询或查询错误信息——您不希望阴险的人看到这种反馈。同样重要的是,始终保护您的查询免受注入黑客攻击。如果您的查询包含用户提供的数据,则需要在mysqli_multi_query(). 事实上,在处理用户输入时,我非常强烈的建议是远离mysqli_multi_query()并使用准备好的语句或pdo来进行数据库交互,以获得更高的安全级别。
| 归档时间: |
|
| 查看次数: |
4520 次 |
| 最近记录: |