过滤器不起作用(根据参数执行不同的PHP查询)

时间:2016-04-10 00:11:51

标签: php mysql post sql-like

我正在尝试实施过滤器,以帮助用户优化搜索其他用户。这是我的搜索参数的图像,只是为了向您提供我将很快传达的图形表示:

enter image description here

有三个过滤器:

  1. 性别
  2. 年龄
  3. 研究中的相似性
  4. 默认情况下,我想传达系统上的所有用户。因此,当用户进入library(lattice) data(mtcars) xyplot(mpg~wt,data=mtcars,groups=factor(am,labels=c("A","M")), pch=20,auto.key=list(columns=2),type=c("p","g")) 时,将显示每个用户,然后,当应用过滤器时,相应地细化结果。

    并非所有三个参数都必须完成才能开始搜索,例如,用户只需搜索女性用户,就应该在搜索点击时显示所有女性用户。

    我尝试为每个方案实施不同的查询,但始终显示所有用户。如果我指定我想搜索女性然后点击搜索,它将什么都不做,仍然向我显示所有用户。

    另外,我正在努力使用users.php参数。它的工作方式是在一个名为similarity in studies的表中,我存储有关用户正在学习的内容的数据,用户可以选择不提供此信息,因此在我的表中学习也可能是空的。

    我希望它工作的方式是查看登录用户正在学习的内容,然后找到与其他人生物相匹配的单词。例如,我目前以Conor身份登录,Conor正在学习计算机科学。理想情况下,将运行一个算法,从user_bio表中搜索其他用户,并返回其生物中user_biocomputer的所有用户。我很确定这涉及science条款,但我以前从未使用它,所以我无法确定。

    这是我目前的做法:

    LIKE

    摘要,我需要的是:

    1. // processing filters $refined_gender = htmlentities (strip_tags(@$_POST['gender'])); $age_from = htmlentities (strip_tags(@$_POST['age_from'])); $age_to = htmlentities (strip_tags(@$_POST['age_to'])); $studying = htmlentities (strip_tags(@$_POST['studying'])); $get_all_users = mysqli_query ($connect, "SELECT * FROM users" ); mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); if (isset($_POST['submit'])){ // if gender parameter is used ... if ($refined_gender){ $gender_statement = mysqli_prepare ($connect, "SELECT * FROM users WHERE gender = ?"); mysqli_stmt_bind_param($gender_statement, "s", $refined_gender); mysqli_stmt_execute ($gender_statement); mysqli_stmt_close($gender_statement); } // if studying parameter used... if ($studying) { // see explanation below... } // if gender and age parameter used... if ($refined_gender && $age_from && $age_to){ $gen_and_age_statement = mysqli_prepare ($connect, "SELECT * FROM users WHERE gender = ? AND age BETWEEN ? AND ?"); mysqli_stmt_bind_param($gen_and_age_statement, "sss", $refined_gender, $age_from, $age_to); mysqli_stmt_execute ($gen_and_age_statement); mysqli_stmt_close($gen_and_age_statement); } } 上默认执行的SELECT * FROM users查询。这将显示系统中的所有用户。
    2. 适用于任何过滤器。并非所有过滤器都需要应用于获得结果,用户可以搜索女性并单击搜索,加载系统中的所有女性用户。
    3. 我需要根据已应用的过滤器来更改查询。因此,如果用户搜索了男性用户,并且未选择其他两个选项,则查询将为users.php

4 个答案:

答案 0 :(得分:1)

而不是这段代码:

 htmlentities (strip_tags(@$_POST['gender']));

你应该验证它,如下:

 $gender = filter_input(INPUT_POST, 'gender', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => '/^[mf]$/i']]);
 $ageFrom = filter_input(INPUT_POST, 'age_from', FILTER_VALIDATE_INT, [ 'default' => 1, 'min_range' => 1, 'max_range' => 100]);
 $ageTo = filter_input(INPUT_POST, 'age_to', FILTER_VALIDATE_INT, [ 'default' => 1, 'min_range' => 1, 'max_range' => 100]);
 $studying = filter_input(INPUT_POST, 'gender', FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => '/^(similar|different|same)$/i']]);

这更简单,更安全。

每个输入都应该正确验证。

避免使用 @

获得值后,可以将它们连接到查询中,如下所示:

$types = '';
$values = [];
$query = 'SELECT * FROM users';
$where = [];

// empty tests for both null (no data in input) and false (invalid data)
if (!empty($gender)) {
    $where[] = 'gender = ?';
    $types .= 's';
    $values[] = &$gender;
}
if (!empty($ageFrom)) {
    $where[] = 'age >= ?';
    $types .= 'i';
    $values = &$ageFrom;
}
if (!empty($ageTo)) {
    $where[] = 'age <= ?';
    $types .= 'i';
    $values = &$ageTo;
}
if (!empty($studying)) {

    $field = 'user_bio';

    // Get the $user_bio value of the current user from the database

    // Change the $user_bio into a regular expression collection of words
    $regexp = '('.str_replace(' ','|',$user_bio).')';

    // Set up the where 
    switch ($studying) {
        case 'same':
            $comparison = '= ?';
            break;
        case 'different':
            $comparison = 'NOT REGEXP (?)';
            break;
        case 'similar':
            $comparison = 'REGEXP (?)';
            break;                
    }
    $where[] = $field.' '.$comparison;
    $types .= 's';
    $values[] = &$user_bio;
}

if (count($where) > 0) {
    $query .= ' WHERE '.implode(' AND ',$where);
}

// new mysqli ( host, 
$mysqli = new mysqli('localhost','root','','stuff');
$stmt = $mysqli->prepare($query);

// This allows you to use a variable number of arguments with the prepared statement
// Note the use of the ampersands on the array assignment, this ensures they are passed by reference
$params = array_merge([$types],$values);
call_user_func_array([$stmt,'bind_param'],$params);

$stmt->execute();

// Bind a variable for each column
$stmt->bind_result($user_name);

while ($stmt->fetch()) {
var_dump($result);
}

答案 1 :(得分:0)

这里我提供代码,以便你如何在一个查询中编写多个过滤器选项..但在这里我没有提到你的第三个过滤器选项学习,因为它关于另一个表而你没有明确提到它它使用外键或关系数据库结构链接到此表。多种过滤器选项如下所示。我添加了数据库连接和逃逸注入的功能......如果你不需要忽略那部分..

function escape($e_string)
{
    global $connect;
    if(!isset($connect))
    {
        // DATABASE CONNECTION QUERY
        $connect = mysqli_connect("servername", "username", "password", "");
        if (!$connect) 
            die("Connection failed: " . mysqli_connect_error());
    }   
    $e_string = trim(utf8_encode($e_string));   
    $e_string = mysqli_real_escape_string($connect,$e_string);
    return $e_string;   
}

// processing filters
$refined_gender = isset($_POST['gender']) ? escape($_POST['gender']) : '';
$age_from       = isset($_POST['age_from']) ? escape($_POST['age_from']) : '';
$age_to         = isset($_POST['age_to']) ? escape($_POST['age_to']) : '';
$studying       = isset($_POST['studying']) ? escape($_POST['studying']) : '';

$query = "SELECT * FROM users WHERE 1=1";

if (isset($_POST['submit'])){

        $addstring1 = $addstring2 = $addstring3 =  $and1 = $and2 = $and3 = "";
        $andcnt =3;

        if($refined_gender != '') 
        $addstring1 = " gender = '$refined_gender'";    

        if($age_from != '') 
        $addstring2 = " age >= '$age_from'";    

        if($age_to != '') 
        $addstring3 = " age <= '$age_to'";    

        for($i=1;$i<=$andcnt;$i++)
        ${"and".$i} =  ${"addstring".$i} != '' ? " AND" : "";

        $query .= $and1.$addstring1.$and2.$addstring2.$and3.$addstring3;

}
$get_all_users = mysqli_query ($connect, $query);
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

答案 2 :(得分:0)

这个Html页面:

<form method="POST" action="">
    <input type="radio" name="rbo_gender" value="male">Male
    <input type="radio" name="rbo_gender" value="female">Female
    Age From<select name="agefrom">
        <?php
        for($i=10;$i<50;$i++):
        ?>
        <option value="<?php echo $i?>"><?php echo $i?></option>
        <?php
        endfor;
        ?>
    </select>
    Age To<select name="ageto">
        <?php
        for($i=10;$i<50;$i++):
        ?>
        <option value="<?php echo $i?>"><?php echo $i?></option>
        <?php
        endfor;
        ?>
    </select>
    Studying:
    <input type="radio" name="rbo_type" value="similar">Similar
    <input type="radio" name="rbo_type" value="exact">Exactly same
    <input type="radio" name="rbo_type" value="different">Different
    <input type="submit" name="btnsearch" value="Search">
</form>

这是php部分:

if($_POST["btnsearch"])
{
   if(!empty($_POST["rbo_gender"]))
   {
       $gender = $_POST["rbo_gender"];
       $cond .= " and gender = '".$gender."'";
   }
   if(!empty($_POST["agefrom"]))
   {
       $agefrom = $_POST["agefrom"];
       $cond .= " and age >= '".$agefrom."'";
   }
   if(!empty($_POST["ageto"]))
   {
       $ageto = $_POST["ageto"];
       $cond .= " and age <= '".$ageto."'";
   }
   if(!empty($_POST["rbo_type"]))
   {
       $user_type = $_POST["rbo_type"];
       switch($_POST["rbo_type"])
       {
           case "similar": $cond .= " and user_bio like '%".$ageto."%'";
               break;
           case "exact": $cond .= " and user_bio = '".$ageto."'";
               break;
           case "different":$cond .= " and user_bio ! like '%".$ageto."%'";
               break;       
       }
   }

   $query = "select * from users where 1 ".$cond;
}

请根据mysqli()&amp;更新查询使用bind param。另外,不要使用@尝试使用filter_input,而是使用REGEXP而不是使用{{1}}。我创建了变量以使用bind_param目的。

答案 3 :(得分:0)

(我不确定为什么已经提供的答案不能充分解决您的问题。)

我这样接近它。首先,摆脱第一次查询执行以拉动所有用户。相反,只使用一个查询。

动态准备SQL文本。使用&#34; SELECT ... FROM users&#34;启动语句。 (我们将在最后一步处理附加ORDER BY。

我有条件地检查每个&#34;过滤器&#34;,看看我是否需要在WHERE子句中附加条件。

在SQL开始时,我们将包含一个&#34; WHERE 1 = 1&#34;。

$sql = "SELECT ... FROM users u" 
$sql .= " WHERE 1=1";

&#34; WHERE 1 = 1&#34;基本没用。优化器将抛弃它。我们添加它的原因只是为了让我们的代码以后更容易。我们可以使用&#34;添加我们的下一个过滤器AND condition&#34;,而不用担心这是否是第一个,我们需要使用WHERE而不是AND。

我们将初始化一个字符串和一个数组,以保存我们的绑定类型字符串&#34; sssis&#34;无论它需要什么,以及我们想要传入的值的引用数组。

  $bind_type = "";
  $bind_vals = array();

每个过滤器的处理都会很糟糕......但我们可以做到。检查我们是否需要向SQL附加任何内容。如果我们这样做,找出需要添加的内容,包括任何绑定占位符。并将绑定参数的类型(&#34; i&#34;,&#34; s&#34;,无论如何)附加到$ bind_type字符串,并将值(引用)推送到$ bind_vals数组中。

if ( $refined_gender ) {
   // figure out what that SQL text needs to look like
   // append the string to the SQL text
   $sql .= " AND u.gender = ?";

   // append type to string, and push a reference to the value into array 
   $bind_types .= "s";
   $bind_val[] = &$refined_gender;
}

我们的代码会比那更复杂。那只是处理一个平等比较。我们现在只是保持简单,以说明模式。

对于我们可能需要添加的每个过滤器,我们重复相同的事情。检查是否需要,找出我们需要附加到SQL文本的内容,附加到bind_types字符串并将值推送(引用)到bind_vals数组中。

为了解决这个问题,我开始只处理一个条件,并开始工作,以解决问题。当我们添加更多过滤器,并且出现问题时,我知道在哪里寻找问题。 (我知道之前有什么工作。)

当我完成WHERE子句时,我附加了我需要的任何ORDER BY和LIMIT。这可能是有条件的,但最终,我们最终会做这样的事情:

   $sql .= " ORDER BY u.id DESC LIMIT 50";

当我完成所有这些操作后,我得到了一个包含SQL文本的字符串,如下所示:

  SELECT ...
    FROM users u 
   WHERE 1=1
     AND u.gender = ?
     AND u.age_from >= ?
     AND u.age_to   <= ?
   ORDER BY u.id DESC
   LIMIT 50

(在这个例子中,它包含三个绑定占位符。如果我们做得对,

我们将有一个包含三个字符的$ bind_types字符串,例如&#34; SII&#34;

我们将有一个$ bind_vals数组,其中包含对三个值的引用。

现在,我们可以调用mysqli_stmt_prepare。如果我们的SQL中没有错误,我们应该返回一个语句句柄。

$stmt = mysqli_prepare($conn,$sql);

(检查准备工作的回报。)

现在我们只需要绑定参数。这就是mysqli让事情变得有点毛茸茸的地方。如果我们使用PDO(或Perl DBI),则调用&#34;绑定参数/绑定值&#34;会很容易的。那些让我们传递一个绑定值的数组。但不是mysqli。他不会让我们用数组作为参数调用mysqli_stmt_bind_param。

我们需要像这样运行一个函数调用:

mysqli_stmt_bind_param($stmt, $bind_types, &$refined_gender, &$age_from, ... );

我们的问题是我们有一个变量个参数。

有一种解决方法。

我们可以使用call_user_func_array功能。

因为代码使用的是过程样式而不是面向对象的样式,所以预准备语句的句柄是第一个参数,第二个参数是绑定类型字符串,后跟绑定值。绑定值已经在数组中。我们只需要把所有这些都放进一个hugh jass数组中。

array_merge函数似乎是为此而自定义设计的。

 // array_merge(array($stmt), array($bind_types), $bind_vals)

那将返回一个数组。这正是我们调用call_user_func_array函数所需要的。我们不会在其他任何地方需要该阵列(除非我们正在调试,我们要打印出来)。

如果我们的语句中至少有一个绑定占位符,我们只需要调用mysqli_stmt_bind_param。因此,如果我们的$ bind_types字符串为空,我们可以快捷方式。 (我们知道$ bind_types赢了&#34; 0&#34;因为我们的代码从来没有附加&#34; 0&#34 ;.)

 if ($bind_types) {
    call_user_func_array('mysqli_stmt_bind_param', array_merge(array($stmt), array($bind_types), $bind_vals) );
 }

第一个参数(to call_user_func_array)是我们想要执行的函数的名称,第二个参数是我们想要转换成列表的hugh jass数组。

这样做的全部意义在于使它变得动态,我们可以传递一个,两个,三个绑定值。

此时,我们已准备好执行该语句,并获取结果。

同样重要的是要指出:mysqli_stmt_bind_param期望绑定值通过引用传递,而不是通过值传递。这就是为什么我们将引用推送到bind_vals数组中的值。

我不确定你问的是什么问题。

但绝对放弃第一次调用mysqli_query。这将返回users表中的所有行。

使用一个或两个条件,静态SQL和静态绑定类型的方法以及列出绑定值是可行的。

但是当我们得到三个,四个,五个可能的过滤器以及所有可能的组合时,这将是不合适的。

因此,我们采用更动态的方法,动态创建查询,并按原样推送数组上的绑定值。