2

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

テストされているコード:

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

4 に答える 4

7

これは、エラーメッセージの品質を向上させるだけでなく、結果セットの処理方法も向上させるアプローチです。

$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>" . var_export($rows[$q_key], true) . "</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>";
}

最初のクエリでのエラー:最初のクエリが、指定されたデータベースに存在しないテーブルにアクセスしようとすると、次のようになります。ordersXYZ 配列$rowsは存在せず、var_export()発生せず、次の応答が表示されます。

クエリキー=注文、クエリ= SELECT * FROMordersXYZ WHERE location ='IN' ORDER BY orderNum DESC LIMIT 20、構文エラー=テーブル'[someDB].ordersXYZ'は存在しません

2番目のクエリでのエラー:最初のクエリは成功したが、2番目のクエリが次のような存在しないテーブルにアクセスしようとした場合:inventory2
$rows["Orders"]目的の行データを保持し、var_export()'edされ、$row["Inventory"]存在せず、次の応答が表示されます。

クエリキー=インベントリ、クエリ= SELECT * FROM Inventory2、構文エラー=テーブル'[someDB].inventory2'は存在しません

エラーなし:両方のクエリにエラーがない場合、$rows配列は目的のデータで埋められ、var_export()'edされ、エラー応答はありません。に保存されたクエリデータを使用して、および$rowsから必要なものにアクセスできます。$rows["Orders"]$rows["Inventory"]


注意事項:

  1. 変数宣言と条件付きチェックを同時に行っていることに気付くかもしれません。これによりコードがより簡潔になりますが、一部の開発者はこれを避けたいと考えています。

  2. 私のアプローチimplode()では行にセミコロンを使用しているelseifため、クエリに末尾のセミコロンを追加しないように注意してください。

  3. このクエリのセットは常に結果セットを返します。これは、すべてがSELECTクエリであるためです。クエリの混合コレクションがある場合は、このリンク( https://stackoverflow.com/a/22469722/2943403affect_rows )で役立つ情報を見つけることができます。

  4. mysqli_multi_query()エラーが発生するとすぐにクエリの実行を停止します。「すべての」エラーをキャッチすることを期待している場合は、複数のエラーが発生することはありません。

  5. OPの質問と解決策のように条件付きブレークポイントを記述することはお勧めできません。カスタムブレークポイントは他の状況でも正しく使用できますが、この場合、ブレークポイントはブロックのwhile()ステートメントの内側に配置する必要があります。do()

  6. ゼロ行を返すクエリでは、エラーメッセージは表示されません。ループが開始されない$rowsため、サブ配列は作成されません。while()

  7. この関数を使用することにより、各結果セット行の列をカウントするkey()OPの条件を回避できます。if/elseif場合によっては、反復ごとに条件を実行するとコストが高くなる可能性があるため、これはより適切な方法です。配列ポインタは、各反復$qの終わりに内部で進められることに注意してください。do()これは、phpのマニュアルページにはない追加のテクニックです。key()意図したとおりに機能します。

  8. そしてもちろん、この<div><pre>var_export()...</pre></div>行は作業コードから削除できます。これは純粋にデモンストレーション用です。

  9. このコードブロックの後で変数を再利用するクエリをさらに実行する場合は、残りのデータが干渉しないように、使用されているすべての変数を必ずクリアしてください。例:$mysqli_error=null; // clear errorsreset($q); // reset array pointer

  10. あなた自身の裁量でこのやや漠然とした警告に注意してください: http: //php.net/manual/en/mysqli.use-result.php

クライアント側で多くの処理が実行される場合は、mysqli_use_result()を使用しないでください。これにより、サーバーが拘束され、他のスレッドがデータのフェッチ元のテーブルを更新できなくなります。

  1. 最後に、セキュリティ上の理由から、クエリやクエリエラー情報を公開しないでください。不吉な人にこの種のフィードバックを見せたくない場合があります。同様に重要なのは、クエリをインジェクションハックから常に保護することです。クエリにユーザー提供のデータが含まれている場合は、で使用する前に、データをフィルタリング/サニタイズして終了する必要がありますmysqli_multi_query()。実際、ユーザー入力を処理する場合、より高いレベルのセキュリティを実現するために、データベースの相互作用にmysqliまたはpdoのプリペアドステートメントから離れてmysqli_multi_query()使用することを強くお勧めします。
于 2014-03-18T04:33:14.073 に答える
1

私自身の質問に答えるために、そしてドキュメントが貧弱なので、ここに他の人を助けることを願っている解決策があります。欠けていたのは、最初のクエリでエラーをキャッチする方法です。(myqsqli_multi_queryの隠されたアクションを理解するのは困難です。)

次に、$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);
于 2012-09-02T16:35:43.037 に答える
0

doループでカウンターを追加し、mysqli_next_resultが成功するたびにカウンターをインクリメントします。mysqli_next_resultがfalseを返したら、カウンターも出力します。

于 2012-09-02T05:02:45.200 に答える
0

これは2つのクエリで機能します。

エラーが最初の場合、PHPへの最初のクエリの応答はエラーメッセージであり、2番目のクエリ(これは起動しません)の場合、最初のメッセージをたたきます。

エラーが2番目にある場合、最初の応答が返され、2番目がエラーメッセージを受け取ります。

私は連想配列とnixing配列要素[0]を使用しています。これにより、関連するエラーがある場合にのみ['Error']キーが追加されます。

最後に、私は最高のPHPerではないので、醜いものを修正するのはあなた次第です。

$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) ;
}
于 2016-04-30T01:42:37.937 に答える