php 基于通过GET方法传递的参数构建SQL WHERE语句

w80xi6nr  于 2023-02-28  发布在  PHP
关注(0)|答案(2)|浏览(110)

我正在用PHP构建一个搜索页面,使用多个选择选项,并通过GET方法将值从一个页面传递到另一个页面。
但是我被WHERE子句卡住了,在那里未传递的值不会填充我的查询,最终我总是会收到没有找到记录。我尝试了一些方法,详细介绍了一些相关的帖子,如:建议使用SQL WHERE column = everythingWhy would someone use WHERE 1=1 AND in a SQL clause?,其中WHERE column=column(1=1),但正如第一个链接中所述,这不是一个有效的解决方案。
一个建议的工作解决方案是使用IF情况,但如果我考虑我的15个选项和它的所有类型的组合,(当一些被选中,一些被取消选中,'NULL'/any/all值,我立即感到头痛。
因此,我考虑询问是否可以基于传递的参数构建这个WHERE条件并将其应用于查询。

编辑1.

@Flewz我的过滤器看起来像:

通过GET得到这样的结果

]

我的数据库如下所示:

我的where子句是

$stmt = $conn->prepare("SELECT * FROM Mydatabase WHERE mushtype='$mushtype'AND capsurface='$capsurface' AND capform='$capform')

我没有在这里重复所有15个过滤器,这在时间上可能会更多,但你的想法。
所以,用户不需要使用所有的过滤器来识别它的蘑菇,它只会使用需要的一个,但在我的句子中,如果一列没有使用,返回给我一个没有找到记录消息,我想避免这种情况。我愿意接受任何建议。

编辑2.

感谢@Flewz给我这么漂亮的指南,这让我很惊讶,我不需要任何编程技巧就能理解它,并根据我的需要进行调整。**(一切)。我在哪里能够看到发生在每一行的代码,并遵循它,直到最后。我在哪里需要改变一点这个指南在这里:

if($get_var_size == 0){
  // no point in doing anything, 
  // echo error message
  echo 'Please select at least one filtering condition'; // echo 'I am a teapot';
  exit();
}

原因是,我不想返回一个错误消息,如果没有选择,因为这将意味着用户要列出所有可用的记录,这是没有必要的错误。第二节是与上述内容有关,在这里:

// in addition we can check if we have all get params and adjust query
if($get_var_size == count($all_get_keys)){
    // execute
}

因为**if $get_var_size == count($all_get_keys)表示用户填写了所有可能的条件,所以我的查询$sql = 'SELECT * FROM some_table';**不是这个,而是从ELSE分支构建的一个完全定制的查询,所以,我把这个IF分支切掉了,认为它不需要。
到目前为止一切顺利,但我还没有完成,我仍然有一个问题。倒带和总结一下,我有一个索引页与此代码(使用3过滤器为一个较短的代码示例):

<form name="search_form" role="form" method="GET" id="search_form" action="SearchResults.php">
  <?php 
    try {
      $conn = new PDO('sqlite:db/Ciupercomania.db');
      $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
   ?>

<select id="mushtype" name="mushtype" style="width: 30vw;">
  <option value="" selected disabled hidden>Choose</option>
    <?php 
      $stmt = $conn->prepare("SELECT * FROM attributes WHERE attributename='mushtype' ORDER by attributevalueEN ASC");
      $stmt->execute();
      $data = $stmt->fetchAll(PDO::FETCH_ASSOC);
        foreach($data as $row): ?>
  <option value="<?php echo $row['idattributevalue']; ?>"><?php echo $row['attributevalueEN']; ?></option>
        <?php endforeach; ?>
</select>

<select id="capform" name="capform" style="width: 30vw;">
  <option value="" selected disabled hidden>Choose</option>
    <?php 
      $stmt = $conn->prepare("SELECT * FROM attributes WHERE attributename='capform' ORDER by attributevalueEN ASC");
      $stmt->execute();
      $data = $stmt->fetchAll(PDO::FETCH_ASSOC);
        foreach($data as $row): ?>
  <option value="<?php echo $row['idattributevalue']; ?>"><?php echo $row['attributevalueEN']; ?></option>
        <?php endforeach; ?>
</select>

<select id="capsurface" name="capsurface" style="width: 30vw;">
  <option value="" selected disabled hidden>Choose</option>
    <?php 
      $stmt = $conn->prepare("SELECT * FROM attributes WHERE attributename='capsurface' ORDER by attributevalueEN ASC");
      $stmt->execute();
      $data = $stmt->fetchAll(PDO::FETCH_ASSOC);
        foreach($data as $row): ?>
  <option value="<?php echo $row['idattributevalue']; ?>"><?php echo $row['attributevalueEN']; ?></option>
        <?php endforeach; ?>
</select><br><br>

  <?php 
    } catch(PDOException $e) {
    echo "Error: " . $e->getMessage();
    }
    $conn = null;
  ?>

<input type="submit" value="Find Your Mushroom">
</form>

和一个“结果”页面,其中包含

<?php 
  // declaring all parameters I expect to pass through GET method
  $all_get_keys = ['mushtype', 'capform', 'capsurface'];

  // we will use this to make our sql statement
  $get_key_config = [
    'mushtype'    => [
      'db_col'    => 'mushtype',
      'assoc_var' => 'mushtype'
    ], 
    'capform'     => [
      'db_col'    => 'capform',
      'assoc_var' => 'capform'
    ],
    'capsurface'     => [
      'db_col'    => 'capsurface',
      'assoc_var' => 'capsurface'
    ]
  ];

  // for parsed $_GET
  $get_params = [];

  // go over all possible keys
  foreach ($all_get_keys as $key) {
    // if we have it, push to array
    if (isset($_GET[$key])) {
      $get_params[] = [
        'key'   => $key,
        'value' => $_GET[$key]
      ];
    }
  }

  // how many we got
  $get_var_size = count($get_params);

try {
  $conn      =  new PDO('sqlite:db/Ciupercomania.db');
  $conn      -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  $stmt_data = [];
  $sql       = 'SELECT IDmush, genus, species, img1 FROM mushroomdata ';

  // adjusting the query
  if ($get_var_size == 0) {
  } else {
    $sql .= ' WHERE ';

    for ($i = 0; $i < $get_var_size; $i++) {

      // get config for our get key
      $cfg = $get_key_config[$get_params[$i]['key']];

      // append to sql query
      $sql .= $cfg['db_col'] . '=:' . $cfg['assoc_var'];

      // don't forget on variable
      $stmt_data[$cfg['assoc_var']] = $get_params[$i]['value'];

      // don't add AND if its our last
      if ($i < $get_var_size - 1) {
          $sql .= ' AND ';
      }
    }
  }

  $stmt = $conn->prepare($sql);
  $stmt -> execute();
  $data = $stmt->fetchAll(PDO::FETCH_ASSOC);
  echo '<ul class="no-bullets">';
  if ( !empty($data) ) {
    foreach ( $data as $row ){
       echo '<a target="blank" href="Datasheet.php?IDmush='.$row['IDmush'].'">' .
              '<li>'.$row['genus'].'&nbsp;'.$row['species'].'</li>'.
            '</a>';
    }
  } else {
       echo "No records found.";
  }
  echo '</ul>';
} catch(PDOException $e) {
  echo "Error: " . $e->getMessage();
}

// temporary messages
  echo "<pre>"; 
    echo "all-get-keys<br/>"; print_r($all_get_keys); echo '<br/>';
    echo "stmt_data<br/>"; print_r($stmt_data); echo '<br/>';
    echo "sql statement<br/>"; print_r($sql); echo '<br/>';
  echo "</pre>";

$conn = null;
?>

运行此代码并应用一些过滤参数,我再次收到此意外消息未找到记录x1c4d 1x
由于Flewz的帮助,SQL查询被正确构建,并且可以在屏幕截图中看到,我确信是我在执行命令时的错误,但我不知道在哪里。未排序的列表部分也是正确的,我已经在其他页面上使用了它。请帮助我识别我在执行命令时的错误。谢谢。

4xrmg8kj

4xrmg8kj1#

既然你已经更新了你的问题,让我们从一些安全的做法开始。
您使用的是预准备语句,这很好,只是您的方法不对。
因为你使用的是php,我们有一个命名参数选项,见下面的例子。

$sql = 'SELECT name FROM pets WHERE species=:species;';
$stmt = $con->prepare($sql);
$stmt->execute([ 'species' => 'cat' ]);
$err = $stmt->errorInfo();

if($err[0] != '00000'){
    // handle error, code is in $err[2]
}

while($row = $stmt->fetch(PDO::FETCH_ASSOC)){
    // do something
}

WHERE species=:species:species是我们在预准备语句中的变量,我们通过传递一个带键的数组给execute方法来填充它,这是唯一安全的方法。
对于你手头的问题,最容易理解的是大量的if语句。可以用配置对象和一个for循环来完成。
未经测试,可能行不通。

// we need to figure out which GET parameters came trough
$all_get_keys = [ 'mushtype' ];
// we will use this to make our sql statement
$get_key_config = [
    'mushtype'      => [
        'db_col'    => 'mtype',
        'assoc_var' => 'mtype'
    ]
];
// for parsed $_GET
$get_params = [];

// go over all possible keys
foreach($all_get_keys as $key){
    // if we have it, push to array
    if(isset($_GET[$key])){
        $get_params[] = [
            'key'   => $key,
            'value' => $_GET[$key]
        ];
    }
}

// how many we got
$get_var_size = count($get_params);

if($get_var_size == 0){
    // no point in doing anything
    // echo error message
    echo 'I am a teapot';
    exit();
}

$stmt_data = [];
$sql = 'SELECT * FROM some_table';

// in addition we can check if we have all get params and adjust query
if($get_var_size == count($all_get_keys)){
    // execute
}else{
    $sql .= ' WHERE ';

    for($i = 0; $i < $get_var_size; $i++){
        // get config for our get key
        $cfg = $get_key_config[$get_params[$i]['key']];

        // append to sql query
        $sql .= $cfg['db_col'] . '=:' . $cfg['assoc_var'];
        // don't forget on variable
        $stmt_data[$cfg['assoc_var']] = $get_params[$i]['value'];

        // don't add AND if its our last
        if($i < $get_var_size - 1){
            $sql .= ' AND ';
        }
    }

    //execute
}

// check for error
// do data operation

if和for循环之间的唯一区别是config中的选项将被类型化为if语句。

q8l4jmvw

q8l4jmvw2#

WHERE子句是用来过滤数据的,所以如果你不需要过滤(想查看所有记录),完全跳过WHERE子句就行了,它是不需要的。

相关问题