使用prepare语句在数据库中搜索数据

时间:2019-02-06 02:49:04

标签: php html

一个简单的问题:),我之所以这样写是因为有人说我的代码容易受到mysql注入的影响,这是学习Web编程中准备好的语句的必要条件,以避免任何用户将恶意数据或语句放入数据库中。我有一个搜索功能,可以从数据库中搜索数据,如果您输入像这样的字符串“ torres”,那么我将搜索torres,但是如果您仅输入“ tor”,它将不会在其中搜索包含“ tor”的数据。他们的名字..我在使用准备好的语句时不知道正确的格式,如果您有建议,我很乐意采用:)

    <?php
if (isset($_POST['search'])) {

    $box = $_POST['box'];
    $box = preg_replace("#[^0-9a-z]#i","",$box);
    $grade =$_POST['grade'];
    $section = $_POST['section'];
    $strand = $_POST['strand'];




      $sql = "SELECT * FROM student WHERE fname LIKE ? or lname LIKE ? or mname LIKE ? or grade = ? or track = ? or section = ?";
        $stmt = mysqli_stmt_init($conn);
        if (!mysqli_stmt_prepare($stmt, $sql)){
            echo "SQL FAILED";
        }
        else {
            //bind the parameter place holder
            mysqli_stmt_bind_param($stmt, "ssssss",$box, $box, $box, $grade, $strand, $section);
            mysqli_stmt_execute($stmt);
            $result = mysqli_stmt_get_result($stmt);

            while($row = mysqli_fetch_assoc($result))
        {
            echo "<tr>";
            echo "<td>".$row['lname']."</td>";
            echo "<td>".$row['fname']."</td>";
            echo "<td>".$row['mname']."</td>";
            echo "<td>".$row['grade']."</td>";
            echo "<td>".$row['track']."</td>";
            echo "<td>".$row['section']."</td>";
       echo "</tr>";
        }

        }

1 个答案:

答案 0 :(得分:1)

根据要求:

  

@ArtisticPhoenix我显然更喜欢国王的方式[复合全文索引]。这应该是显示示例/解释的主要答案。

首先创建一个包含所有三个字段的全文本索引(这在PHPmyAdmin中,使用图像进行解释要容易一些)

enter image description here

然后执行以下查询:

#PDO version SELECT * FROM `temp` WHERE MATCH(fname,mname,lname)AGAINST(:fullname IN BOOLEAN MODE)
#MySqli version SELECT * FROM `temp` WHERE MATCH(fname,mname,lname)AGAINST(? IN BOOLEAN MODE)
SELECT * FROM `temp` WHERE MATCH(fname,mname,lname)AGAINST('edward' IN BOOLEAN MODE)

enter image description here

这似乎很简单,但是有些事情需要全文了解Min char count,即3(我认为)小于未搜索的最小字符数。这可以更改,但是需要修复数据库并重新启动MySql。

停用词,例如andthe等。也可以在my.cnf中进行配置。

标点符号被忽略。这对名字来说似乎没什么大不了,但是想起带连字符的姓氏。

通常,我将单词min减为2,并将停用词指向一个空文件(禁用它们)。

语法匹配非常不同,它非常强大,但是在全文之外并没有真正使用。一个示例是:这是通配符*,并且您使用'"'双引号来进行完全词组匹配'"match exactly"',而+逻辑并且,例如word+ word+(默认为or),-与之不匹配,等等...如果我没记错的话,几年前我曾使用过一堆,但不必使用它最近。

例如,对部分单词进行“开头为”

SELECT * FROM `temp` WHERE MATCH(fname,mname,lname)AGAINST('edwar*' IN BOOLEAN MODE)

相同结果匹配一行。明显的好处是可以同时搜索所有3个字段,但是全文语法本身也可能非常有用。

有关更多信息:

https://dev.mysql.com/doc/refman/8.0/en/fulltext-boolean.html

PS。我可能会补充说,在查询中使用OR确实会导致性能下降,我尽力将简单的OR替换为UNION,因为在很大程度上,性能很差表。从逻辑上讲,数据库优化器必须重新扫描整个表以查找OR,与AND不同的是,数据库优化器可以使用上一个表达式的结果来减少下一个表达式的数据集(这就是我的理解方式) 。我可以说使用OR与UNION的性能差异非常明显。

对于复合全文索引,而不是分别在每个字段上执行OR,这是正确的。默认情况下,全文本速度更快,但这种方式甚至更快。

要修复当前查询(出于完整性考虑)

您需要所谓的独占或类似的内容:

SELECT * FROM student WHERE ( fname LIKE ? OR lname LIKE ? OR mname LIKE ? ) AND grade = ? AND track = ? AND section = ?

这是将OR组合在一起,以便将它们作为一个表达式求值到“下一级”(括号之外)。基本上是操作顺​​序。用英语,您必须至少匹配这些列fnamelnamemname中的1个,并且还必须匹配所有其余列,才能获得返回给定行的结果。

  • 如果您使用所有OR(如现在一样)并且任何单个字段都匹配,则查询将返回为true并带有匹配项。您现在正在经历哪种行为。

  • 如果仅将名称字段之外的所有内容更改为AND,则基本上删除括号

赞:

 #this is wrong don't use it.
 SELECT * FROM student WHERE fname LIKE ? OR lname LIKE ? OR mname LIKE ? AND grade = ? AND track = ? AND section = ?

然后,您必须以这种方式进行匹配。

 (grade AND track AND section AND mname) OR lname OR fname 

因此,如果姓氏或名字匹配,则无论其他字段如何,您都将获得结果。但是您会发现mname字段必须与所有其他字段匹配才能得到结果(但是您不太可能会注意到这一点)。因为,似乎只有mname是匹配项时,查询才能按照您的要求进行。

我希望这是有道理的。最好将WHERE子句视为一个IF条件,并且应用相同的逻辑规则。

干杯!