PHP - MySQLi 处理查询两次或错误

Posted

技术标签:

【中文标题】PHP - MySQLi 处理查询两次或错误【英文标题】:PHP - MySQLi is processing a query twice or wrong 【发布时间】:2015-09-18 10:49:09 【问题描述】:

我有一个非常奇怪的错误,我完全不明白。 我有以下 php 脚本,它有两种行为方式。

此脚本外壳将新用户添加到 mysql 数据库。我想要做的是检查用户名是否已经在数据库中。如果是,请设置一个用于决定如何进行的变量。 如果我执行这段代码,这一行

if(strcmp($row["username"], $addUser_name) == 0)

已执行(或更好地跳入),但我 100% 确定,在执行此行之前,该名称不(或不应该)存在于数据库中。现在,即使 $errorName 设置为 1 并且正在打印测试,我想添加到我的数据库中的数据集也出现在我的数据库中,但最后一部分开始于

if(!isset($errorName))

不执行。我一遍又一遍地用简单的 echo 语句检查它。

为了查看我的数据集,我删除了这部分的评论

while ($row = mysqli_fetch_assoc($allUserNames))

    echo $row["username"]."\n";

这部分正在正确执行

if(!isset($errorName))

但我在我的数据库中找到了两次数据集。

我完全不明白,为什么 scipt 会这样做。我尝试了很多不同的事情,但我不知道我做错了什么。

<?php
    include "auth/auth1.php";
    include "functions/connectToDB.php";
    include "functions/test_input_XSS.php";

    if(isset($_GET["startCheck"])) //TODO Mache auch GET noch POST
    
        //Sollte niemals true sein! Passiert nur, wenn man Unsinn macht
        if(strcmp($_GET["addUser_pw"], $_GET["addUser_pwRepeat"]) !== 0)  die; 

        $servername     = "localhost";
        $databasename   = "X";
        $mysqluser      = "X";
        $mysqlpass      = "X";
        $addUser_name   = $_GET["addUser_name"];

        $connection = connectToDB($servername, $mysqluser, $mysqlpass, $databasename);

        if(mysqli_connect_errno())
        
            printf("Connect failed!");
            die();
        

        $query_getAllUserNames = "SELECT username FROM user;";
        $allUserNames = mysqli_query($connection, $query_getAllUserNames);

        /*while ($row = mysqli_fetch_assoc($allUserNames))
        
            echo $row["username"]."\n";
        */

        while ($row = mysqli_fetch_assoc($allUserNames))
        
            if(strcmp($row["username"], $addUser_name) == 0)
            
                $errorName = 1;
                echo "test";
            
        

        if(!isset($errorName))
        
            $username = test_input_for_XSS($_GET["addUser_name"]);
            $password = hash("sha256", $_GET["addUser_pw"]);
            $permission = test_input_for_XSS($_GET["addUser_permission"]);

            $query_addUser = "INSERT INTO user (username, passwordhash, permissionlevel) VALUES ('".$username."', '".$password."', '".$permission."');";

            $addUserSuccess = mysqli_query($connection, $query_addUser);

            if($addUserSuccess !== 1)
            
                $hostname = $_SERVER['HTTP_HOST'];
                $path = dirname($_SERVER['PHP_SELF']);
                echo"Success";
                //header("Location: http://".$hostname.($path == "/" ? "" : $path)."/userManagment.php?added=".$username."");
            
            else
            
                echo "ANNOYING_ERROR";
            
        

        //Tidy up
        mysqli_free_result($allUserNames);
        mysqli_close($connection);
    
?>

这是相应的 html 代码,紧随其后的是同一个文件:

        <?php
            include "home.php";
        ?>

        <section>
            <h3>Einen neuen Benutzer hinzufügen</h3>

            <?php
                if(isset($errorName))
                
                    echo '<p class="warningMessage">Der Nutzername <b>'.$_GET["addUser_name"].'</b> ist bereits vergeben.<br />Bitte wählen Sie einen anderen aus!</p>';
                
            ?>

            <form method="GET" action="addUser.php">
                <table>
                    <tr>
                        <td>Nutzername:</td>
                        <td><input type="text" name="addUser_name" required pattern="\w+" /></td>
                        <td></td>
                        <td class="annotation">z.B.: Vorname</td>
                    </tr>

                    <tr>
                        <td>Passwort:</td>
                        <td><input type="password" name="addUser_pw" required pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).6," title="Passwort muss mindestens 6 Zeichen, Groß- und Kleinbuchstaben, sowie Zahlen enthalten"
                                    onChange="this.setCustomValidity(this.validity.patternMismatch ? '' : ''); if(this.checkValidity()) form.addUser_pwRepeat.pattern = this.value; " /></td>
                        <td></td>
                        <td class="annotation">Muss Groß- und Kleinbuchstaben, Zahlen und mindestens 6 Zeichen enthalten</td>
                    </tr>
                    <tr>
                        <td>Passwort wiederholen:</td>
                        <td><input type="password" name="addUser_pwRepeat" required pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).6," /></td>
                        <td></td>
                        <td class="annotation">Muss identisch sein zum ersten eingegebenen Passwort</td>
                    </tr>
                    <tr>
                        <td>Berechtigungslevel:</td>
                        <td>
                            <input type="radio" name="addUser_permission" value="1" checked />1<br />
                            <input type="radio" name="addUser_permission" value="2" />2
                        </td>
                    </tr>
                </table>
                <input type="hidden" name="startCheck" value="1" />
                <input type="submit" value="Nutzer hinzufügen" class="button" />
            </form>
        </section>
    </body>
</html>

如果我的问题描述得不够清楚,我很乐意提供所需的任何其他信息。

【问题讨论】:

为什么用strcmp()而不是简单的比较$row["username"] == $addUser_name 我从 Java 开始,对于字符串,我们被告知使用方法而不是 == 但我可以更改它,尽管我认为它不会解决我的问题。 *编辑:不,还是同样的问题 为什么要使用 select 查询和 while 循环,而不是使用带有 where 条件的 select 查询。此外,如果动作在同一页面上,请将动作保持为空,action="" mysqli 提供参数化查询,不要从字符串连接构建插入查询。 听起来不错,但是当我想使用它时出现此错误:致命错误:调用未定义的函数 sqlsrv_query() 我按照该网站的说明进行操作:blogs.msdn.com/b/sqlphp/archive/2008/09/30/… 【参考方案1】:

我建议您不要获取所有用户名并通过 PHP 检查是否有相同的用户名。您可以简单地进行这样的查询

$result=$connection->query("SELECT username FROM user WHERE username='".$connection->real_escape_string($addUser_name)."';"); 

然后检查查询是否返回任何行

if($result -> num_rows > 0)

  //the username is already in use

else

  //the username is unique

【讨论】:

我同意 - 但请使用参数,宝贝! 这部分是做什么的:$connection->real_escape_string($addUser_name) 您可以在此处查看有关此功能的详细信息php.net/manual/en/mysqli.real-escape-string.php 很好,这很有效,非常感谢。我从 num_rows 中删除了这个 (),没有它它可以完美运行。你能给我解释一下为什么吗?我真的很想知道为什么我的方法行不通。【参考方案2】:

您正在检查数据库中的所有用户名并在 while 循环中循环它们。

因此,在每次迭代中,当您使用 $errorName 变量时,您将覆盖每个用户名的 $errorName 变量,而范围变量的值是为结果集中的最新用户设置的。

你能做的是,

$query_getAllUserNames = "SELECT count(*) FROM user where username=?"; 

if ($stmt = mysqli_prepare($connection, $query_getAllUserNames)) 
    /* bind parameters for markers */
    mysqli_stmt_bind_param($stmt, "s", $addUser_name);
    /* execute query */
    mysqli_stmt_execute($stmt);
    /* bind result variables */
    mysqli_stmt_bind_result($stmt, $userCount);
    /* fetch value */
    mysqli_stmt_fetch($stmt);
 

if(!isset($userCount) || $userCount == 0) 
    //Create a new user here
    echo "Create new user";
 else 
    //Go with the flow
    echo "User exists";


//rest of your code 

【讨论】:

以上是关于PHP - MySQLi 处理查询两次或错误的主要内容,如果未能解决你的问题,请参考以下文章

PHP & MySQLi - 在下拉列表中显示选定的值两次

initWithNibName 调用了两次或加载了错误的 xib

如何在一个页面上使用一个表单两次或三次?

php mysqli_query 函数似乎运行了两次

如何修改我的T-SQL查询,以便输出基于2个不同时期出现两次或更多次的所有记录?

如何读取 BufferedReader 两次或多次?