使用PDO预处理语句将空变量插入MySQL

时间:2017-09-01 03:11:12

标签: php mysql pdo

我正在撞墙,试图弄清楚为什么这个PDO准备好的声明不起作用。我唯一可以得出的结论是,如果一个变量是空的,那么INSERT就会失败,但这很令人困惑,因为我之前必须完成这一千次而没有问题。

这是我的代码。所有变量都是从POST变量设置的,因此如果用户没有提供这些数据,其中一些变量可能是空白的。

$stmt = $db->prepare("INSERT INTO students
    (id, classid, userid, firstname, surname, form, gender)
    VALUES ('', :classid, :userid, :firstname, :surname, :form, :gender)");

    $stmt->execute(array(':userid' => $userid, ':classid' => $classid, ':firstname' => $firstname, ':surname' => $surname, ':form' => $form, ':gender' => $gender));

如果变量为空,有没有办法告诉它插入一个空字段?

编辑:要明确,这不是一个新的陈述。我之前一直在使用毫无准备的MySQLi进行INSERT,并且刚刚将这些代码更新到PDO。

编辑2:我的架构:

id  int(11) NO  PRI     auto_increment  
encryption  int(1)  NO              
classid int(11) NO              
googleclassroom varchar(50) NO              
userid  varchar(50) NO              
firstname   varchar(100)    NO              
surname varchar(100)    NO              
form    varchar(10) NO              
gender  varchar(10) NO              
colour_code varchar(10) NO              
col1    varchar(50) NO              
col2    varchar(50) NO              
col3    varchar(50) NO              
col4    varchar(50) NO              
col5    varchar(50) NO              
col6    varchar(50) NO              
col7    varchar(50) NO              
timestamp   datetime    NO  

4 个答案:

答案 0 :(得分:1)

您可以查看以下内容:

  1. 允许所有列接受NULL
  2. 如果id是主键,请将其从查询中删除。您可以将其设置为AUTO_INCREMENT
  3. 编辑:

    由于id是您架构中的主键,因此您无法设置''。此外,似乎每个列都不允许接受NULL,并且因为用户没有提供值,$form之类的变量可能未定义或为NULL,因此您的INSERT语句不会执行。

    编辑2:

    尝试找出确切的错误。无论是SQL还是PHP。

    您可以使用link

    设置显示错误

答案 1 :(得分:1)

我认为您遇到的问题是由于您的数据绑定为bindParam()。根据PHP doc's。

  

将PHP变量绑定到相应的命名或问号   占位符在用于准备的SQL语句中   言。

所以我建议改用bindValue()。解释为什么我要回到PHP手册。

  

与PDOStatement :: bindValue()不同,该变量被绑定为引用   并且只会在PDOStatement :: execute()的时候进行评估   调用。

所以我的回答是,

$stmt = $db->prepare("INSERT INTO students
    (classid, userid, firstname, surname, form, gender)
    VALUES (:classid, :userid, :firstname, :surname, :form, :gender)");

$stmt->bindValue(':classid',$classid);//If this is a must enter or not entered by user then you can use bindParam()
$stmt->bindValue(':userid',$userid);//This as well if this is a must enter then you can use bindParam()
if($firstname == "" || $firstname == NULL){
$stmt->bindValue(':firstname', NULL, PDO::PARAM_INT);//_NULL seems to give issues
}else{
$stmt->bindParam(':firstname', $firstname);
}
$stmt->bindValue(':surname',$surname);
$stmt->bindValue(':form',$form);
$stmt->bindValue(':gender',$gender);

$stmt->execute();

答案 2 :(得分:1)

罗布,这不是你问题的答案!我读了你的评论,我只想告诉你如何正确使用错误报告,准备好的陈述和异常处理。

如果您愿意,可以在OOP或程序功能中构建代码。但这个结构与此无关。

我的建议:请务必阅读您正在使用的函数的文档。特别是返回的值。通过这种方式,您将了解如何正确处理所有可能的容易出错的情况。关于PDO,这是必须的步骤; - )

祝你好运!

<?php

/*
 * Set error reporting level and display the errors on screen.
 * --------------------------------------------------------------
 * DON'T DISPLAY ERRORS ON PRODUCTION, DO IT ONLY ON DEVELOPMENT!
 * --------------------------------------------------------------
 */
error_reporting(E_ALL);
ini_set('display_errors', 1);

try {
    /*
     * Create a PDO instance as db connection.
     */

    // Create PDO instance.
    $connection = new PDO(
            'mysql:host=localhost;port=3306;dbname=yourDb;charset=utf8'
            , 'yourDbUsername'
            , 'yourDbPassword'
    );

    // Assign driver options.
    $connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE);
    $connection->setAttribute(PDO::ATTR_PERSISTENT, TRUE);

    /*
     * Prepare and validate the sql statement.
     * 
     * --------------------------------------------------------------------------------
     * If the database server cannot successfully prepare the statement, PDO::prepare() 
     * returns FALSE or emits PDOException (depending on error handling settings).
     * --------------------------------------------------------------------------------
     */
    $sql = 'INSERT INTO students (
                classid,
                userid,
                firstname,
                surname,
                form,
                gender
            ) VALUES (
                :classid,
                :userid,
                :firstname,
                :surname,
                :form,
                :gender
            )';

    $statement = $connection->prepare($sql);

    if (!$statement) {
        throw new UnexpectedValueException('The sql statement could not be prepared!');
    }

    /*
     * Bind the input parameters to the prepared statement.
     * 
     * -----------------------------------------------------------------------------------
     * Unlike PDOStatement::bindValue(), when using PDOStatement::bindParam() the variable 
     * is bound as a reference and will only be evaluated at the time that 
     * PDOStatement::execute() is called.
     * -----------------------------------------------------------------------------------
     */

    $bindings = array(
        ':classid' => $classid,
        ':userid' => $userid,
        ':firstname' => $firstname,
        ':surname' => $surname,
        ':form' => $form,
        ':gender' => $gender,
    );

    foreach ($bindings as $key => $value) {
        $bound = $statement->bindValue(
                getInputParameterName($key)
                , $value
                , getInputParameterDataType($value)
        );

        if (!$bound) {
            throw new UnexpectedValueException('An input parameter could not be bound!');
        }
    }

    /*
     * Execute the prepared statement.
     * 
     * ------------------------------------------------------------------
     * PDOStatement::execute returns TRUE on success or FALSE on failure.
     * ------------------------------------------------------------------
     */
    $executed = $statement->execute();

    if (!$executed) {
        throw new UnexpectedValueException('The prepared statement could not be executed!');
    }

    /*
     * Get last insert id.
     */
    $lastInsertId = $connection->lastInsertId();

    if (!isset($lastInsertId)) {
        throw new UnexpectedValueException('The last insert id could not be read!');
    }

    /*
     * Close connection.
     */
    $connection = NULL;

    /*
     * Print results.
     */
    echo 'Provided data successfully added with the id: ' . $lastInsertId;
} catch (PDOException $pdoException) {
    echo $pdoException->getMessage();
    exit();
} catch (Exception $exception) {
    echo $exception->getMessage();
    exit();
}

/**
 * Get the name of an input parameter by its key in the bindings array.
 *  
 * @param int|string $key The key of the input parameter in the bindings array.
 * @return int|string The name of the input parameter.
 */
function getInputParameterName($key) {
    return is_int($key) ? ($key + 1) : (':' . ltrim($key, ':'));
}

/**
 * Get the PDO::PARAM_* constant, e.g the data type of an input parameter, by its value.
 *  
 * @param mixed $value Value of the input parameter.
 * @return int The PDO::PARAM_* constant.
 */
function getInputParameterDataType($value) {
    $dataType = PDO::PARAM_STR;
    if (is_int($value)) {
        $dataType = PDO::PARAM_INT;
    } elseif (is_bool($value)) {
        $dataType = PDO::PARAM_BOOL;
    }
    return $dataType;
}

答案 3 :(得分:0)

感谢您的所有意见和解答。几个不同的用户建议允许NULL值; @sand建议我将这些列的默认值设置为NULL。它工作

我仍然感到困惑的是这几个月如何快乐地工作(使用毫无准备的MySQLi声明),但拒绝接受PDO声明中的这些INSERT。

无论如何,答案(所有归功于@Sand,@ Anshuman和@Lawrence)都是将默认列值设置为NULL ,然后它不关心变量是否为空