为什么我的while循环似乎总是错误的

时间:2018-12-30 18:15:05

标签: php mysql

我一直试图使我的php代码显示我的mysql数据库中的条目。从某种意义上讲,我想使其自动化,因为我不需要手动打印表格,而是可以根据对数来打印表格,但是它不能按预期工作。

我尝试了不同的设置表格的方法,但是它们都不起作用,我最想得到的是从表格中打印一个条目,并在其后吐出错误。

$base = $_POST["base"];
$connection = mysqli_connect("localhost","login","pass") or die("Impossible to connect to the database!");
$db = mysqli_select_db($connection, "database")or die("Impossible to download the database!");
$sql = "SELECT * FROM $base";
$mysqli_result = mysqli_query($connection, $sql);
$sql2 = "SHOW COLUMNS FROM $base";
$set1 = mysqli_query($connection, $sql2);
$colu = array();
while($db = mysqli_fetch_row($set1)){
  $colu[] = $db[0]; }
$columns=implode("<br/>",$colu);
echo "<TABLE BORDER=1>";
echo "<TR><TH>$colu[0]</TH><TH>$colu[1]</TH><TH>$colu[2]</TH><TH>$colu[3]</TH><TH>$colu[4]</TH><TH>$colu[5]</TH></TR>";
while ($row = mysqli_fetch_array($set1)) {
$colu[0] = $row["echo $colu[0]"];
$colu[1] = $row["echo $colu[1]"];
$colu[2] = $row["echo $colu[2]"];
$colu[3] = $row["echo $colu[3]"];
$colu[4] = $row["echo $colu[4]"];
$colu[5] = $row["echo $colu[5]"];
echo "<TR><TD>$colu[0]</TD><TD>$colu[1]</TD><TD>$colu[2]</TD><TD>$colu[3]</TD><TD>$colu[4]</TD><TD>$colu[5]</TD></TR>";}

echo "</TABLE>";
mysqli_free_result($mysqli_result);
mysqli_close($connection); ?>

$ _ POST [$ base];部分有效,我想这个问题在while循环中,因为它一次也不会完成,而我却迷失了为什么它不起作用的原因。

2 个答案:

答案 0 :(得分:0)

我在您的脚本中看到了一些问题。如果要获取列标题和表主体的内容,则使用错误的结果集。

// next line make it possible to do sql insertion, and what if $base has no input?
$base = $_POST["base"];
// the die will never be reached
$connection = mysqli_connect("localhost","login","pass") or die("Impossible to connect to the database!");
$db = mysqli_select_db($connection, "database")or die("Impossible to download the database!");
// where is this query for?
$sql = "SELECT * FROM $base";
// where is this result being used
$mysqli_result = mysqli_query($connection, $sql);

$sql2 = "SHOW COLUMNS FROM $base";
$set1 = mysqli_query($connection, $sql2);
$colu = [];
// what if the table order chages? Best to use mysqli_fetch_assoc
while($db = mysqli_fetch_row($set1)){
    $colu[] = $db[0]; 
}
// where do you use $comumns?
$columns = implode("<br/>", $colu);

echo "<TABLE BORDER=1>";
echo "<TR><TH>$colu[0]</TH><TH>$colu[1]</TH><TH>$colu[2]</TH><TH>$colu[3]</TH><TH>$colu[4]</TH><TH>$colu[5]</TH></TR>";
// you already fetched all record from set1
while ($row = mysqli_fetch_array($set1)) {
    $colu[0] = $row["echo $colu[0]"];
    $colu[1] = $row["echo $colu[1]"];
    $colu[2] = $row["echo $colu[2]"];
    $colu[3] = $row["echo $colu[3]"];
    $colu[4] = $row["echo $colu[4]"];
    $colu[5] = $row["echo $colu[5]"];
    echo "<TR><TD>$colu[0]</TD><TD>$colu[1]</TD><TD>$colu[2]</TD><TD>$colu[3]</TD><TD>$colu[4]</TD><TD>$colu[5]</TD></TR>";
}

echo "</TABLE>";
mysqli_free_result($mysqli_result);
mysqli_close($connection); ?>

答案 1 :(得分:0)

您当前遇到的最大问题是:

$base = $_POST["base"]
$sql = "SELECT * FROM $base";
$sql2 = "SHOW COLUMNS FROM $base";

这是一个巨大的SQL注入漏洞,即使他们仅将一个空字符串传递给它,也很糟糕。例如,这将导致查询错误,并且取决于您在服务器上的设置以及错误报告,您可能会公开很多信息。仅一个示例是堆栈跟踪可能包含数据库密码等。

而不是直接使用用户输入,而是将白名单制作如下:

$tables = ['user', 'user_meta', 'states']; //etc

$base =  !empty($_POST["base"]) && false !== ($index = array_search($_POST["base"], $tables)) ? $tables[$index] : false;

if(!$base) die('Unknown table '.$_POST["base"]);

这样,您仅使用知道其值的数据。

可变重用

除此之外,您的变量名引起了一堆“代码混乱”。如果必须通用变量名,则会发生这种情况。一些例子:

   $db = mysqli_select_db(...)
   while($db = mysqli_fetch_row($set1)){  //overwriting db
     ...
   }
   //....................
   while ($row = mysqli_fetch_array($set1)) {
     $colu[0] = $row["echo $colu[0]"]; //overwriting $colu

最后一个也是错误的,因为行键将类似于:

   $colu[0] = $row["echo name"];

或带有列名的内容。因为您要在下一个循环中重新使用此变量(“变量混淆”),所以它将是$row["echo $colu[0]"];的值,并将其放回去。因此,假设没有echo就是正确的,并且将使用Name作为值。

//loop 1
   $colu[0] = 'name';
   $row['name'] = 'Tom';
   //result 
   $colu[0] = 'Tom'

//loop 2
   $colu[0] = 'Tom';
   $row['Tom']  doesn't exist.
   //result 
   $colu[0] = null; //undefined index warning

光标重用

您还将重用数据库游标$set1并将其循环2次。我不确定MySqli,但是PDO不允许您这样做。这可能是第二个循环失败的原因。我相信第二个应该是$mysqli_result。这有点令人困惑,因为您同时执行了两个查询,然后又一个又一个地循环。而不是执行查询,而是遍历整个查询。然后再做另一个,并循环执行。

相反,您可以执行以下操作:

//you can even query the DB for the table names
$tables = ['user', 'user_meta', 'states']; //etc

$base =  !empty($_POST["base"]) && false !== ($index = array_search($_POST["base"], $tables)) ? $tables[$index] : false;

if(!$base) die('Unknown table '.$_POST["base"]);

$connection = mysqli_connect("localhost","login","pass") or die("Impossible to connect to the database!");
$db = mysqli_select_db($connection, "database")or die("Impossible to download the database!");

//---------query for the columns
$sql = "SHOW COLUMNS FROM `$base`";
$mysqli_result = mysqli_query($connection, $sql);

$columns = [];
while($row = mysqli_fetch_row($mysqli_result)){
    $columns[] = $row[0]; 
}

//---------query for the data
//use the column result in the select part of query, because the column names
//come from the DB they are safe to use.
$sql = "SELECT `".implode('`,`', $columns)."` FROM `$base`"; //reuse sql (no longer needed)

$mysqli_result = mysqli_query($connection, $sql); //reuse results (no longer needed)

//fetch all data as assoc array. because we tied it to the results 
//of the first query, the column names.  We no longer need to map it.
$data = mysqli_fetch_all($mysqli_result, MYSQLI_ASSOC);

///output table and headers

echo "<table>";
   echo "<thead>";
      echo "<tr>";
      //we can just loop over the columns and put them in the table head
      foreach($columns as $key ){
          echo "<th>$key</th>";
      }
      echo "</tr>";
   echo "</thead>";
   echo "<tbody>";

   //loop over each row of data
   foreach($data as $row){
      echo "<tr>";

      //loop over each "correlated" column
      foreach($columns as $key ){
         echo "<td>{$row[$key]}</td>";
      }
      echo "</tr>";  
   }
   echo "</tbody>";
echo "</table>";

奖励:要从数据库中获取表名:

$sql = 'SELECT `TABLE_NAME` FROM `information_schema`.`TABLES` WHERE `TABLE_SCHEMA` LIKE "'.$database.'"';
$mysqli_result = mysqli_query($connection, $sql);
$tables = mysqli_fetch_all($mysqli_result, MYSQLI_NUM);

希望如此。