PHP:mysqli INSERT INTO 语句不起作用 [duplicate]

PHP: mysqli INSERT INTO statement is not working [duplicate]

提问人:nergal darski 提问时间:12/1/2019 最后编辑:GBouffardnergal darski 更新时间:12/3/2019 访问量:65

问:

我的注册 php 代码不会将值插入数据库。我尝试了不同的方法,但仍然不起作用。代码如下:

数据库连接:

<?php $link=mysqli_connect("localhost", "root", "");
  mysqli_select_db($link, "dataadventurers");
 ?>

我的注册表PHP代码:

<?php
include "connection.php"; ?>
            <?php
              if(isset($_POST['submit1'])){
                  $firstname = $_POST['first_name'];
                  $lastname = $_POST['last_name'];
                  $middle = $_POST['middle_initial'];
                  $idnum = $_POST['id_number'];
                  $email = $_POST['email_add'];
                  $pass = $_POST['password'];
                  $bday = $_POST['birthdate'];
                  $course = $_POST['course'];
                  $year = $_POST['year'];


                  mysqli_query($link, "insert into member_registration values('', '$firstname', '$lastname'
                  , '$middle', '$idnum', '$email', '$pass', '$bday', '$course', '$year')");


           ?>
php mysql mysqli 插入

评论

1赞 Dharman 12/1/2019
您的代码容易受到 SQL 注入的攻击。您应该使用预准备语句。
2赞 Juakali92 12/1/2019
请不要让它以当前状态存在。看看如何使用准备好的语句以及密码哈希。切勿将用户直接输入到带有某种清理的表格中
2赞 David 12/1/2019
除了上面提到的安全问题外,SQL注入也是一个非常常见的错误来源。简单地说......您不控制您执行的 SQL 代码。它可以是任何东西。当它失败时,至少你应该检查该SQL代码是什么,它是否是你所期望的,检查从数据库中获取错误。mysqli_error($link)

答:

0赞 Will Jones 12/1/2019 #1

欢迎来到 StackOverflow。

首先,您的代码容易受到 SQL 注入的攻击。这是一个重大缺陷,但值得庆幸的是,这是一个很容易修复的缺陷。重要的是,不要将其留给 SQL 注入,即使这仅供您使用。如果其他人设法访问它,它将确保您的数据安全,并让您养成良好的习惯。

其次,您的代码不起作用,因为您没有指定要插入到哪些列中。

以您的示例为基础,这是一个工作版本。

不要使用这个,它是易受攻击的代码

<?php 
    $link=mysqli_connect("localhost", "root", "");
    mysqli_select_db($link, "dataadventurers");
 ?>


<?php
    include "connection.php"; 
?>
<?php
    if(isset($_POST['submit1'])){
        $firstname = $_POST['first_name'];
        $lastname = $_POST['last_name'];
        $middle = $_POST['middle_initial'];
        $idnum = $_POST['id_number'];
        $email = $_POST['email_add'];
        $pass = $_POST['password'];
        $bday = $_POST['birthdate'];
        $course = $_POST['course'];
        $year = $_POST['year'];

        //If someone passes 2019'); drop table member_registration; -- for example as the year parameter, MySQL interprets the query string as two separate queries. One to insert a record and the second to drop the table and will execute both

        mysqli_query($link, "insert into member_registration (firstname, lastname, middle, idnum, email, pass, bday, course, year) values( '$firstname', '$lastname', '$middle', '$idnum', '$email', '$pass', '$bday', '$course', '$year')");;

    }
?>

更安全的变体

我有几个基于PDO的SQL便利函数,我经常使用。

他们从存储在可公开访问的文件夹结构之外的 ini 文件中获取其凭据。

该过程以关联数组的形式返回结果,返回受影响的行数。GetDataUpdateData

Ini 文件示例

host=localhost
dbname=dataadventurers
username=user
password=pass

便利功能

/*Put credential ini file path here*/
    $credentialFile = "..."; 

   function GetData($sql, $params = null, $paramtypes = null){
        //Get database connection details
        $credentialsArray = parse_ini_file($credentialFile);
        //Create PDO Instance 
        $db = new PDO('mysql:host='.$credentialsArray['host'].';dbname='.$credentialsArray['dbname'].';charset=utf8mb4', $credentialsArray['username'], $credentialsArray['password'], array(PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
        if(is_null($params)){ //If no parameters supplied, execute the query as is
            $stmt = $db->query($sql);
            $results = $stmt->fetchAll(PDO::FETCH_ASSOC);
        }
        else{
            if(count($params) <> count($paramtypes)){ //Check that the parameter count and type count are the same
                throw new InvalidArgumentException;
            }
            $stmt = $db->prepare($sql); //Prepare the statement
            for($i=0; $i<count($params); $i++){ //Bind the parameters
                $stmt->bindValue($i+1, $params[$i], $paramtypes[$i]);
            }
            $stmt->execute(); //Execute query
            $results = $stmt->fetchAll(PDO::FETCH_ASSOC); //Return the results as an associative array
        }
        return $results;        
    }

    function UpdateData($sql, $params){
        //Get database connection details
        $credentialsArray = parse_ini_file($credentialFile);
        //Create PDO Instance 
        $db = new PDO('mysql:host='.$credentialsArray['host'].';dbname='.$credentialsArray['dbname'].';charset=utf8mb4', $credentialsArray['username'], $credentialsArray['password'], array(PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
        try{
            $stmt = $db->prepare($sql); //Prepare the statement
            is_null($params){ //If there aren't any parameters to bind...
                $stmt->execute(); //...execute statement as is
            }
            else{
                $stmt->execute($params); //otherwise execute with the supplied parameters
            }
            $results = $stmt->rowCount(); //Return the rowcount
            return $results;
        }
        catch(PDOException $ex){ //Catch any PDO Exceptions
            return $ex->getMessage(); //Return the exception message
        }
    }

用法

用法很简单。选择数据时,传递一个 SQL 字符串、一个包含任何参数的数组和一个包含参数类型的数组。这些数组的长度必须相同。

更新/插入/删除数据时,请传递一个 SQL 字符串和一个包含参数的数组。没有参数类型要求。UpdateData

//GetData with no parameters
$results = GetData('select * from member_registration', [], []);

//GetData with one parameter of type String.
$results2 = GetData('select * from member_registration where firstname = ?', ['David'], [PDO::PARAM_STR]);

//Your insert example
$parameters = [
    $firstname, 
    $lastname, 
    $middle, 
    $idnum, 
    $email, 
    $pass, 
    $bday, 
    $course, 
    $year
];

$rowsAffected = UpdateData('insert into member_registration (firstname, lastname, middle, idnum, email, pass, bday, course, year) values(?, ?, ?, ?, ?, ?, ?, ?, ?)', $parameters);

最后的思考

您需要将数据库中的字段替换为列名。如果任何字段是自动生成的,例如自动递增的 ID 字段,请省略该字段,以便其正常工作。

其中一个参数称为 $pass。如果您将密码存储在数据库中,请始终以加密形式存储它们,最好使用 bCrypt。这个 StackOverflow 答案解释了原因/方式。

评论

0赞 Your Common Sense 12/1/2019
我确实理解你提供帮助的愿望,但这让你的回答过于宽泛和不一致。最后,它由一个疯狂的猜测、一段不安全的代码和一组可疑的函数组成。考虑写一个专注于某个问题的答案(以防你能说出某个问题是什么)
0赞 Dharman 12/2/2019
您的用法示例没有说明如何创建您创建的此类的实例或如何调用私有方法。为什么要在几行简单的PDO代码上使用如此复杂的功能?如果这些功能实际上提供了一些切实的好处并且不那么混乱,那么它们可能是一个好主意。总的来说,建议是好的,但是在阅读了您的答案后,我仍然不知道最初的问题是什么。
0赞 Will Jones 12/3/2019
对不起,我已从函数定义中删除了 Private Static 修饰符。这将教会我校对我的答案。我看不出我的答案太宽泛或不一致。我承认第一部分附带了猜测的元素,但恕我直言,这是一个合理的假设。如果您阅读有关 SQL 注入的信息,就会发现那里有一些不安全的示例;原因是它教你避免什么。请解释为什么您认为这些功能有问题?可能有更简单的方法,但是我发现这些方法对各种场景都很有用,因此我在这里分享了它们
0赞 Dharman 12/6/2019
如果您希望我们看到这些消息,请使用@WillJones ping 我们。否则,我们可能永远不会看到您的回复。
0赞 Dharman 12/6/2019
几乎没有什么值得怀疑的。1.每次调用此函数时,您似乎都在打开一个新连接。2. 你抛出异常;这已经由 PDO 完成。3. 您使用 4.在一个地方使用,在另一个地方使用bind-in-execute。rowCount()bindValue