Php 如何使用mysqli\u multi\u查询识别导致错误的查询?

Php 如何使用mysqli\u multi\u查询识别导致错误的查询?,php,mysqli,error-handling,mysqli-multi-query,multiple-select-query,Php,Mysqli,Error Handling,Mysqli Multi Query,Multiple Select Query,使用其他地方的示例,以便更好地捕获“隐藏”错误。虽然下面的代码将捕获并返回一个错误,但是否可以改进此代码以报告发生错误的查询 使用以下代码,输出为: 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 lin

使用其他地方的示例,以便更好地捕获“隐藏”错误。虽然下面的代码将捕获并返回一个错误,但是否可以改进此代码以报告发生错误的查询

使用以下代码,输出为:

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
正在测试的代码:

$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);
}

在do循环中,添加一个计数器,每个成功的mysqli\u next\u结果都会增加计数器。一旦mysqli_next_结果返回false,也输出计数器

为了回答我自己的问题,由于文档很差,这里有一个解决方案,希望能帮助其他人。缺少的是捕获第一个查询错误的方法。myqsqli_multi_查询的隐藏操作很难理解

现在检查$err数组中的条目

$q[1] = "SELECT * FROM orders WHERE location = 'IN' ORDER BY orderNum DESC LIMIT 20";
$q[2] = "SELECT * FROM inventory";
$ord = array();
$invent = array();
$err = array();
$c = 1;

if(mysqli_multi_query($link, implode(';', $q))) {
    do {
        // fetch results
        if($result = mysqli_use_result($link))
            while($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
                if(count($row) > 17)
                    $orders[] = $row;
                elseif(count($row) == 6)
                    $inv[] = $row;
            }
        }
        $c++;
        if(!mysqli_more_results($link))
            break;
        if(!mysqli_next_result($link) || mysqli_errno($link)) {
            // report error
            $err[$c] = mysqli_error($link);
            break;
        }
    } while(true);
    mysqli_free_result($result);
}
else
    $err[$c] = mysqli_error($link);

mysqli_close($link);

这里的方法不仅可以提高错误消息的质量,还可以改进处理结果集的方式

$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>";
}
可以从工作代码中删除行-这纯粹是为了演示

如果要在此代码块之后运行任何重用变量的查询,请确保清除所有已使用的变量,以便剩余数据不会干扰。e、 g.$mysqli_error=null;//清除错误并重置$q;//重置数组指针

请根据您自己的判断,注意这个有点模糊的警告:

如果服务器上有大量处理,则不应使用mysqli_use_result 执行客户端,因为这将占用服务器和 防止其他线程更新数据来自的任何表 被带走

最后也是最重要的一点,出于安全原因,不要公开显示查询或查询错误信息-您不希望邪恶的人看到这种反馈。同样重要的是,始终保护您的查询免受注入黑客攻击。如果您的查询包含用户提供的数据,则在mysqli_multi_查询中使用数据之前,需要对数据进行过滤/清理。事实上,在处理用户输入时,我强烈建议不要使用mysqli_multi_查询,而是将其用于数据库交互,以获得更高级别的安全性


这适用于两个查询

如果错误在第一个查询中,那么对PHP的第一个查询的响应就是错误消息,而对于不会触发的第二个查询,则在第一个查询中会出现一条消息

如果错误在第二个中,则返回第一个的响应,第二个获取错误消息

我正在使用关联数组和尼克松数组元素[0]。 只有存在相关错误时,才会添加['Error']键

最后,我不是最好的PHPer,所以这取决于你修复什么是丑陋的


好评论。这不会捕获第一个查询中的错误。当然,您需要检查所有函数的返回值,这意味着第一个查询的mysqli_multi_query和mysqli_store_result,以及其余所有查询的mysqli_next_result。-向上投票。关于mysqli\u multi\u查询的文档很少。希望你也能把这篇文章发上去。关于mysqli\u multi\u查询的文档很少。希望你也能发布这个目的的count$row?无论如何,不要硬编码这个值?如果$result=mysqli\u使用\u result$link{也…多个\u查询在第一个错误时停止,对吗?它不会继续下一个查询?那么mysqli\u error$link是否会不起作用?@MarcoZen lol这是8年半以前的事了。在那个年龄,我没有使用{}在2020年,mysqli\u multi\u查询仍然没有被广泛使用。
$query_nbr=0;

if (mysqli_multi_query($link,$query ))
{ 
  do
  { 
    unset($field_info) ;            $field_info = array() ;
    unset($field_names) ;           $field_names = array() ;
    unset($values) ;                $values = array(array()) ;

    if ($result = mysqli_store_result($link))
    { 
      $query_nbr += 1 ; 
      $rows_found = mysqli_num_rows($result);
      $fields_returned = mysqli_num_fields($result);
      $field_info = mysqli_fetch_fields($result);

      $field_nbr=0;
      foreach ($field_info as $fieldstuff)
      { $field_nbr +=1 ;
        $field_names[$field_nbr] = $fieldstuff->name ;
      }

      $now = date("D M j G:i:s T Y") ;

      if ($query_nbr == 1)
      { 
        $result_vector1 = array('when'=>$now) ;
        $result_vector1['nrows']=0;
        $result_vector1['nrows']=$rows_found ;
        $result_vector1['nfields']=$fields_returned ;
        $result_vector1['field_names']=$field_names ;
      }
      else 
      { 
        $result_vector2 = array('when2'=>$now) ;
        $result_vector2['nrows2']=0;
        $result_vector2['nrows2']=$rows_found ;
        $result_vector2['nfields2']=$fields_returned ;
        $result_vector2['field_names2']=$field_names ;
      }

      $row_nbr=0 ;
      while ($row = mysqli_fetch_array($result, MYSQLI_BOTH))
      { 
        $row_nbr++ ;
        for ($field_nbr=1;$field_nbr<=$fields_returned;$field_nbr++)
        {
          $values[$row_nbr][$field_names[$field_nbr]]    =$row[$field_nbr-1] ;
        }
      }
      mysqli_free_result($result) ;

      unset($values[0]) ;
      if ($query_nbr == 1)
      {$result_vector1['values']=$values ;}
      else
      {$result_vector2['values2']=$values ;}

    }  // EO if ($result = mysqli_store_result($link))

  } while (mysqli_more_results($link) && mysqli_next_result($link)) ;

}  // EO  if (mysqli_multi_query($link,$query ))
else 
{
  // This will be true if the 1st query failed
  if ($query_nbr == 0)
  { 
    $result_vector1['Error'] = "MySQL Error #:  ".mysqli_errno($link).":  ".mysqli_error($link) ;
    $result_vector2['Error'] = "MySQL Error in first query." ;
  }

}  // EO MySQL

//  Here we only made it through once, on the 2nd query
if ( $query_nbr == 1 && $nqueries == 2  && empty( $result_vector2 ) )
{
  $result_vector2['Error'] = "MySQL Error #:  ".mysqli_errno($link).":  ".mysqli_error($link) ;
}