【问题标题】:PHP MySQL Variable Filter - "AND" Acting Like "OR"PHP MySQL 变量过滤器 - “AND”表现得像“OR”
【发布时间】:2015-07-10 10:37:53
【问题描述】:

有没有更简单的方法来使用url变量过滤mysql结果?我编写了以下代码,它在一定程度上有效,我知道必须有一个更简单的方法,但我不确定从哪里开始。我宁愿更换这个,因为它只工作了一半。

$start=0;
$limit=3;

if(isset($_GET['pg']))
{
$pg=$_GET['pg'];
$start=($pg-1)*$limit;
}
else { 
$pg = 1;
}
$sql = mysql_query($query);
if(isset($_GET['signage'])) {
    $result = mysqli_query($conn,"SELECT * FROM pilotOperators WHERE signage='1' LIMIT $start, $limit");
}
elseif(isset($_GET['certifications'])) {
    $certification = $_GET['certifications'];
    $result = mysqli_query($conn,"SELECT * FROM pilotOperators WHERE certifications='$certification' LIMIT $start, $limit");
}
elseif(isset($_GET['state'])) {
    $state = $_GET['state'];
    $result = mysqli_query($conn,"SELECT * FROM pilotOperators WHERE state='$state' LIMIT $start, $limit");
}
elseif(isset($_GET['certifications'], $_GET['signage'])) {
    $certification = $_GET['certifications'];
    $signage = $_GET['signage'];
    $result = mysqli_query($conn,"SELECT * FROM pilotOperators WHERE signage='$signage' AND certifications='$certification' LIMIT $start, $limit");
}
elseif(isset($_GET['certifications'], $_GET['signage'], $_GET['state'])) {
    $certification = $_GET['certifications'];
    $signage = $_GET['signage'];
    $state = $_GET['state'];
    $result = mysqli_query($conn,"SELECT * FROM pilotOperators WHERE signage='$signage' AND certifications='$certification' AND state='$state' LIMIT $start, $limit");
}
else {
    $result = mysqli_query($conn,"SELECT * FROM pilotOperators LIMIT $start, $limit");
}
while($row = mysqli_fetch_array($result))
{
echo "\n <table border='0' class='resultTable' width='75%'> \n";
echo "<tr> \n";
echo "<td width='120px'>ID: </td> \n";
echo "<td>" . $row['id'] . "</td> \n";
echo "</tr> \n";
echo "<tr> \n";
echo "<td>Name: </td> \n";
echo "<td>" . $row['name'] . "</td> \n";
echo "</tr> \n";
echo "<tr> \n";
echo "<td>Phone: </td> \n";
echo "<td>" . $row['phone'] . "</td> \n";
echo "</tr> \n";
echo "<tr> \n";
echo "<td>Alt. Phone: </td> \n";
echo "<td>" . $row['alt_phone'] . "</td> \n";
echo "</tr> \n";
echo "<tr> \n";
echo "<td>Fax: </td> \n";
echo "<td>" . $row['fax'] . "</td> \n";
echo "</tr> \n";
echo "<tr> \n";
echo "<td>Email: </td> \n";
echo "<td>" . $row['email'] . "</td> \n";
echo "</tr> \n";
echo "<tr> \n";
echo "<td>Website: </td> \n";
echo "<td><a href='" . $row['website'] . "' target='_blank'>" .  $row['website'] . "</a></td> \n";
echo "</tr> \n";
echo "<tr> \n";
echo "<td>City: </td> \n";
echo "<td>" . $row['city'] . "</td> \n";
echo "</tr> \n";
echo "<tr> \n";
echo "<td>State: </td> \n";
echo "<td>" . $row['state'] . "</td> \n";
echo "</tr> \n";
echo "<tr> \n";
echo "<td>Certifications: </td> \n";
echo "<td>" . $row['certifications'] . "</td> \n";
echo "</tr> \n";
echo "<tr> \n";
echo "<td>Top Sign: </td> \n";
echo "<td>";
if($row['signage'] = 1) {
 echo "Has Top Sign";
}
else {
 echo "Top Sign Not Listed";
}
echo "</td> \n";
echo "</tr> \n";
echo "</table> \n\n";
}
$rows = mysqli_num_rows(mysqli_query($conn, "SELECT * FROM pilotOperators"));
$total=ceil($rows/$limit);
echo "<div id='paginationLinks'> \n";
if($pg>1)
{
echo "<a href='?pg=".($pg-1)."' class='paginationButton'>PREVIOUS</a> \n";
}
if($pg!=$total)
{
echo "<a href='?pg=".($pg+1)."' class='paginationButton'>NEXT</a> \n";
}

echo "<ul class='page'> \n";
 for($i=1;$i<=$total;$i++)
{
if($i==$pg) { echo "<li class='current'>".$i."</li> \n"; }

else { echo "<li><a href='?id=".$i."'>".$i."</a></li> \n"; }
}
echo "</ul> \n";
echo "</div> \n";
mysqli_close($con);

当我说这段代码有点工作时,请允许我解释一下。当我的网址中有多个变量时(即 ?signage=VALUE&certifications=VALUE),代码的行为就像它有 OR 代替 AND。

像这样:$result = mysqli_query($conn,"SELECT * FROM PilotOperators WHERE signage='$signage' ORcertifications='$certification' LIMIT $start, $limit");

而不是这个:$result = mysqli_query($conn,"SELECT * FROM PilotOperators WHERE signage='$signage' AND certificates='$certification' LIMIT $start, $limit");

如果我的 URL 包含以下 &signage=1&certifications=washington,它不仅向我显示具有这两者的结果,而且向我显示具有华盛顿认证或 signage=1 的人的结果。

我没有太多要传递的变量。应该只有3,但我的方法看起来很复杂。

我可以做些什么来使这更简单,为什么我的 AND 在尝试过滤结果时表现得像 OR。

【问题讨论】:

  • 当你尝试直接对 MySQL 运行这些查询时会发生什么(使用 MySQL 工作台或类似的东西)
  • 变量都是通过checkbox和select选项传递的。除非他们编辑 URL 哈哈,否则不用担心用户输入。不过我会调查一下,因为我还有其他需要验证的表单。
  • The variables are all passed by checkboxes and select options 不代表不能独立于表单提交数据(通过更改网址自动或手动提交)
  • Maximus 完全按照我说的做。它确实过滤了结果,但它基本上忽略了 AND 条件并表现得像他们说“OR”拉取具有部分参数而不是全部参数的结果。

标签: php mysql variables filter


【解决方案1】:

问:我可以做些什么来简化这个过程?

答:您可以执行以下操作,有条件地将谓词附加到 SQL 语句,并推迟运行该语句直到它完全构建。看起来您只需要运行一条 SQL 语句,因此只需调用一次 mysqli_query。填充一个变量以包含填充 SQL 文本,并让 mysqli_query 引用该变量。

注意:任何潜在的不安全值必须正确转义以阻止 SQL 注入漏洞。 (注意在 SQL 文本中包含的 每个 值周围使用 mysqli_real_escape_string 函数。)

例如:

# start of SQL statement
$sql = "SELECT * FROM pilotOperators WHERE 1=1";

# append condition for signage (if required)
if(isset($_GET['signage'])) {
   $sql .= " AND signage='1'";
}

# append condition for certifications (if required)
if(isset($_GET['certifications'])) { 
   $certification = mysqli_real_escape_string($conn,$_GET['certifications']);
   $sql .= " AND certifications='$certification'"
}

# append condition for state (if required)
if(isset($_GET['state'])) {
   $state = mysqli_real_escape_string($conn,$_GET['state']);
   $sql .= " AND state='$state'";
}


# append ORDER BY and LIMIT 
$sql .= " ORDER BY 1,2,3";
$sql .= " LIMIT " . mysqli_real_escape_string($conn,$start) 
            . "," . mysqli_real_escape_string($conn,$limit);

#echo "SQL=" . $sql; // for debugging

$result = mysqli_query($conn,$sql);

我还添加了一个 ORDER BY 子句,因此行将以确定的顺序返回;替换你想要的列的位置引用。

WHERE 1=1 是一个虚拟占位符,它的计算结果始终为 TRUE。这样做的目的是让任何后续谓词都可以添加AND,我们不需要弄清楚这是否是第一个添加的谓词,我们需要使用WHERE而不是@987654328 @。

每个附加部分的前导空格很重要。 (我只是发现将其作为主角处理更容易,而不是记住在末尾添加它,但您可以在每个部分的末尾留出空格)。


问:为什么我的 AND 表现得像 OR?

答:不是,您永远不会得到包含AND 的语句。如果设置了“certifications”,则您正在执行的 SQL 语句仅包含 certifications 列上的谓词。您永远不会到达 elseif 来设置“证书”和“状态”。


跟进

上面的代码有错误,一行中缺少一个分号(语句终止符):

   $sql .= " AND certifications='$certification'" ;
                                                  ^

.= 运算符将右侧的值附加到左侧变量的当前值上。也就是这个说法

$x .= "foo";

和这个语句做同样的事情。

$x = $x . "foo";

变量$certification$state 并不是必需的。您可以删除这两行:

   $state = mysqli_real_escape_string($conn,$_GET['state']);
   $sql .= " AND state='$state'";

并将其替换为:

   $sql .= " AND state='" . mysqli_real_escape_string($conn,$_GET['state']) . "'";

但是将其分成两行确实更容易调试和发现错误,很容易添加echovar_dump 进行调试...

   $state = mysqli_real_escape_string($conn,$_GET['state']);
   echo "state=" . $state ;
   var_dump($state);
   $sql .= " AND state='$state'";

【讨论】:

  • 我想我现在明白了一点。所以帮助我更好地理解你的代码?您在上面发布的那个将完全有效,还是我需要为多个变量添加更多 if 语句?我对使用这些类型的东西有点陌生。我注意到您使用 .=(句号等于)。那有什么作用?谢谢。
  • @JesseElser;点等于 (.=) 运算符(在 PHP 中)将右侧指定的值附加到左侧变量的当前值。这:$x .= "foo";$x = $x . "foo"; 做同样的事情
  • 我使用了你的大部分答案。它没有完全工作(认证区域中的某些东西导致了致命错误),但我确实使用了我根据你的修改编写的版本。我非常感谢您的帮助:)
  • @JesseElser:我的示例代码中的一行缺少分号。 $sql .= " AND certifications='$certification'"... 该语句需要以分号结束。
  • 我试图找出问题所在,哈哈,我总是忽略最简单的。我最终复制并粘贴了状态一并将措辞修改回认证。我现在还删除了“订单”,直到我添加时间戳或其他内容,因为我确实计划首先显示更新的结果。
【解决方案2】:

这不是你真正应该做的最好的事情,但就像一个想法:

$query = 'SELECT * FROM pilotOperators ';

$filters = array('signage', 'certifications', 'state');

$where = false;
foreach($filters as $filter) {
     if (isset($_GET[$filter])) {
         $filter_val = mysqli_real_escape_string($_GET[$filter]);
         if (! $where ) {
           $where = true;
           $query .= ' WHERE '.$filter.'= "'.$filter_val.'"';
         } else {
           $query .= ' AND '.$filter.'= "'.$filter_val.'"';  
         }
     }
}

$query .= " LIMIT $start, $limit";

$result = mysqli_query($conn,$query);

EDIT 1忽略过滤器的一些值

$filters = array('signage', 'certifications', 'state');

$filters_ignore_value = array('state'=>'Select State');

$where = false;
foreach($filters as $filter) {
     if (isset($_GET[$filter])) {
         $filter_val = mysqli_real_escape_string($_GET[$filter]);
         if (isset($filters_ignore_value[$filter] && $filters_ignore_value[$filter] == $filter_val) {
             continue;
         }
         if (! $where ) {
           $where = true;
           $query .= ' WHERE '.$filter.'= "'.$filter_val.'"';
         } else {
           $query .= ' AND '.$filter.'= "'.$filter_val.'"';  
         }
     }
}

【讨论】:

  • 当谈到不同的 $query 我有一个问题。它如何结合每一个来构建完整的列表?这就是 .= 的用途(带句号?)
  • 我不明白你的问题。只有一个变量$query.= 只是字符串的连接运算符。所以我只是遍历过滤器数组并检查$_GET中是否存在当前过滤器,如果存在,我检查WHERE子句是否已经启动。如果它还没有启动,我用WHERE filter = filter 启动它,如果它已经启动,我只需用AND filter = filter 在末尾添加新过滤器。那你在问什么?
  • 我的意思是如果 URL 中有多个变量。 ?Variable1=VALUE&Variable2=value
  • 你试过我的解决方案了吗?在我的回答中,我希望开发人员控制接受的过滤器列表:因此它预设在 $filters.xml 中。如果您需要更多 - 您将它们添加到数组中。另一端的用户可以在传入的请求 url 中使用或不使用接受的过滤器,这就是为什么我们需要检查是否isset($_GET[])
  • 是的。没有得到任何结果。我已经尝试了所有 3 个过滤器。
【解决方案3】:

当我的网址中有多个变量时(即 ?signage=VALUE&certifications=VALUE),代码的行为就像它有 OR 代替 AND

以设置signage AND certifications 为例:第一个 if 子句的计算结果为 true,导致无论是否设置了 certifications 都会执行该查询。您可以考虑重新排序 if/elseif。例如:

//check for all
if(isset($_GET['certifications'], $_GET['signage'], $_GET['state'])) {

}elseif (isset($_GET['certifications'], $_GET['signage'])){

}elseif (){

}

或者,如另一个答案中所建议的,通过检查每个必要参数来构建您的查询

【讨论】:

  • 所以基本上要查找的子句越多,就越高。我会试试这个。有没有更简单的方法来完成我正在做的事情?与简单的道路相比,我似乎走的是一条复杂的道路。
  • Is there an easier way to accomplish what I am doing Easy 是相对的,但您可以按照@spencer7593 的建议构建查询
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-11
  • 1970-01-01
  • 1970-01-01
  • 2014-12-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多