通过 PDO 将 & 号插入 SQL 表

Posted

技术标签:

【中文标题】通过 PDO 将 & 号插入 SQL 表【英文标题】:Inserting ampersand into SQL table through PDO 【发布时间】:2017-12-24 19:26:07 【问题描述】:

我目前可以使用下面的 .php 将数据插入 SQL DB,但是如果数据包含一个 & 符号,它会将其视为 PHP 语句,并且 & 符号不会插入到数据库中。

比如我在work_carried_out字段中输入的数据是:

从 6 月 25 日起存档所有 spl 和 inp 来自 c:\versionone\dbcheck_1000\inbound_1000\DESPATCH\ & c:\versionone\dbcheck_1000\inbound_1000\DESPATCH\done 到 c:\Despatch 存档

这是写入表格的内容:

从 6 月 25 日起存档所有 spl 和 inp 来自 c:\versionone\dbcheck_1000\inbound_1000\DESPATCH\

数据库架构

CREATE TABLE [dbo].[server_log_entries](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [start_date_time] [varchar](100) NOT NULL,
    [finish_date_time] [varchar](100) NOT NULL,
    [server_name] [varchar](50) NOT NULL,
    [carried_out_by] [varchar](50) NOT NULL,
    [verified_by] [varchar](50) NOT NULL,
    [authorised_by] [varchar](50) NULL,
    [work_carried_out] [varchar](max) NULL,
    [work_verified] [varchar](max) NULL,
    [change_reason] [varchar](max) NULL,
    [perceived_impact] [varchar](max) NULL,
    [rollback_process] [varchar](max) NULL,
 CONSTRAINT [PK_server_log_entries] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

代码

// Get the form fields and remove whitespace
var_dump($_POST);

$datetime = trim($_POST["datetime"]);
$servername = trim($_POST["servername"]);
$carriedoutby = trim($_POST["carriedoutby"]);
$workverifiedby = trim($_POST["workverifiedby"]);
$authorisedby = trim($_POST["authorisedby"]);
$workcarriedout = trim($_POST["workcarriedout"]);
$howverified = trim($_POST["howverified"]);
$reason = trim($_POST["reason"]);
$impact = trim($_POST["impact"]);
$rollback = trim($_POST["rollback"]);


try 
    $db = new PDO(DB_DSN, DB_USERNAME, DB_PASSWORD);
 catch (PDOException $e) 
    echo 'Connection failed: ' . $e->getMessage();



// Insert data into SQL table
$stmt = $db->prepare("INSERT INTO [dbo].[server_log_entries] (date_time, server_name, carried_out_by, verified_by, authorised_by, work_carried_out, work_verified, change_reason, perceived_impact, rollback_process)
                 values (:datetime,:servername,:carriedoutby,:workverifiedby,:authorisedby,:workcarriedout,:howverified,:reason,:impact,:rollback)");

$stmt->bindParam(':datetime', $datetime, PDO::PARAM_STR);
$stmt->bindParam(':servername', $servername, PDO::PARAM_STR);
$stmt->bindParam(':carriedoutby', $carriedoutby, PDO::PARAM_STR);
$stmt->bindParam(':workverifiedby', $workverifiedby, PDO::PARAM_STR);
$stmt->bindParam(':authorisedby', $authorisedby, PDO::PARAM_STR);
$stmt->bindParam(':workcarriedout', $workcarriedout, PDO::PARAM_STR);
$stmt->bindParam(':howverified', $howverified, PDO::PARAM_STR);
$stmt->bindParam(':reason', $reason, PDO::PARAM_STR);
$stmt->bindParam(':impact', $impact, PDO::PARAM_STR);
$stmt->bindParam(':rollback', $rollback, PDO::PARAM_STR);


$stmt->execute();

$db = null;

【问题讨论】:

“但是,如果数据包含 & 符号,它会将其视为 PHP 语句” - 那是哪个 POST 数组/列?您需要编辑您的帖子以包含它以供将来的用户使用,因为我们中的一些人可能还没有出现在问题中,等待回复。它的架构也是。 嗨@Fred-ii-这是本例中的工作执行列,我输入的信息是“从 6 月 25 日起归档所有来自 c:\versionone\dbcheck_1000\inbound_1000\DESPATCH\ 的 spl 和 inp & c:\versionone\dbcheck_1000\inbound_1000\DESPATCH\done to c:\Despatch Archive”,这是写入表的内容:“从 6 月 25 日起归档所有来自 c:\versionone\dbcheck_1000\inbound_1000\DESPATCH 的 spl 和 inp \" 你能告诉我们表格的架构吗?数据类型/长度等... 您确定问题出在这一端,而不是在发送数据的代码中吗?您的var_dump($_POST) 是否包含正确的数据?它来自表单、服务、应用程序吗? 嗨@MagnusEriksson - 我已将这个示例添加到您的原始帖子中 【参考方案1】:

注意:我使用 mysql 作为 RDBMS。

尽管看起来很奇怪,但问题是——我希望你的情况也是如此——SQL 语句由双引号 (") 分隔。用单引号 (') 替换它们。另外,请考虑如果您遇到反斜杠问题,请申请 PDO::quote

请注意,PDO 异常不仅会在创建连接时发出,还会由其他 PDO 函数(如 PDO::prepare)发出。一般来说,最好检查每个函数的文档,以便找出返回/抛出的值和/或异常。

我做了一个完整的代码,我把它贴在这里;从异常/返回值处理的角度来看,您可能会发现一些有用的东西。您只需更改 DSN 和凭据以适合您的系统。作为个人选择,我使用了bindValue 而不是bindParam

祝你好运!


PDO预处理语句+异常处理:

index.php(主页)

<?php

require_once 'configs.php';
require_once 'functions.php';
require_once 'testFunctions.php';

// Activate error reporting (only on development).
activateErrorReporting();

// Get the form fields and remove whitespace
$datetime = trim($_POST["datetime"]);
$servername = trim($_POST["servername"]);
$carriedoutby = trim($_POST["carriedoutby"]);
$workverifiedby = trim($_POST["workverifiedby"]);
$authorisedby = trim($_POST["authorisedby"]);
$workcarriedout = trim($_POST["workcarriedout"]);
$howverified = trim($_POST["howverified"]);
$reason = trim($_POST["reason"]);
$impact = trim($_POST["impact"]);
$rollback = trim($_POST["rollback"]);

try 
    // Create db connection.
    $connection = createConnection(
            MYSQL_HOST
            , MYSQL_DATABASE
            , MYSQL_USERNAME
            , MYSQL_PASSWORD
            , MYSQL_PORT
            , MYSQL_CHARSET
    );

    // Insert data.
    $lastInsertId = insertData(
            $connection
            , $datetime
            , $servername
            , $carriedoutby
            , $workverifiedby
            , $authorisedby
            , $workcarriedout
            , $howverified
            , $reason
            , $impact
            , $rollback
    );

    // Print data (for testing purposes).
    printData($lastInsertId, TRUE);

    // Fetch all data.
    $fetchedLastInsertedData = fetchData($connection, $lastInsertId);

    // For testing purposes.
    printData($fetchedLastInsertedData, TRUE);

    closeConnection($connection);
 catch (PDOException $pdoException) 
    // On development.
    printData($pdoException, TRUE);

    // On production.
    // echo $pdoException->getMessage();

    exit();
 catch (Exception $exception) 
    // On development.
    printData($exception, TRUE);

    // On production.
    // echo $exception->getMessage();

    exit();

testFunctions.php

<?php

/*
 * ---------------------
 * Test functions
 * ---------------------
 */

/**
 * Insert data.
 * 
 * @param PDO $connection Connection instance.
 * @param type $datetime
 * @param type $servername
 * @param type $carriedoutby
 * @param type $workverifiedby
 * @param type $authorisedby
 * @param type $workcarriedout
 * @param type $howverified
 * @param type $reason
 * @param type $impact
 * @param type $rollback
 * @return integer Last insert id.
 * @throws Exception
 */
function insertData(
        $connection
        , $datetime
        , $servername
        , $carriedoutby
        , $workverifiedby
        , $authorisedby
        , $workcarriedout
        , $howverified
        , $reason
        , $impact
        , $rollback
) 
    // Sql statement.
    $sql = 'INSERT INTO [dbo].[server_log_entries] (
                date_time,
                server_name,
                carried_out_by,
                verified_by,
                authorised_by,
                work_carried_out,
                work_verified,
                change_reason,
                perceived_impact,
                rollback_process
            ) VALUES (
                :datetime,
                :servername,
                :carriedoutby,
                :workverifiedby,
                :authorisedby,
                :workcarriedout,
                :howverified,
                :reason,
                :impact,
                :rollback
            )';

    // Prepare and check sql statement (returns PDO statement).
    $statement = $connection->prepare($sql);
    if (!$statement) 
        throw new Exception('The SQL statement can not be prepared!');
    

    // Bind values to sql statement parameters.
    $statement->bindValue(':datetime', $datetime, getInputParameterDataType($datetime));
    $statement->bindValue(':servername', $servername, getInputParameterDataType($servername));
    $statement->bindValue(':carriedoutby', $carriedoutby, getInputParameterDataType($carriedoutby));
    $statement->bindValue(':workverifiedby', $workverifiedby, getInputParameterDataType($workverifiedby));
    $statement->bindValue(':authorisedby', $authorisedby, getInputParameterDataType($authorisedby));
    $statement->bindValue(':workcarriedout', $workcarriedout, getInputParameterDataType($workcarriedout));
    $statement->bindValue(':howverified', $howverified, getInputParameterDataType($howverified));
    $statement->bindValue(':reason', $reason, getInputParameterDataType($reason));
    $statement->bindValue(':impact', $impact, getInputParameterDataType($impact));
    $statement->bindValue(':rollback', $rollback, getInputParameterDataType($rollback));

    // Execute and check PDO statement.
    if (!$statement->execute()) 
        throw new Exception('The PDO statement can not be executed!');
    

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


/**
 * Fetch data by id.
 * 
 * @param PDO $connection Connection instance.
 * @param integer $id Record id.
 * @return array Fetched data.
 * @throws Exception
 */
function fetchData($connection, $id) 
    // Sql statement.
    $sql = 'SELECT * 
            FROM [dbo].[server_log_entries]
            WHERE id = :id';

    // Prepare and check sql statement (returns PDO statement).
    $statement = $connection->prepare($sql);
    if (!$statement) 
        throw new Exception('The SQL statement can not be prepared!');
    

    // Bind values to sql statement parameters.
    $statement->bindValue(':id', $id, getInputParameterDataType($id));

    // Execute and check PDO statement.
    if (!$statement->execute()) 
        throw new Exception('The PDO statement can not be executed!');
    

    // Fetch data.
    $fetchedData = $statement->fetchAll(PDO::FETCH_ASSOC);
    if ($fetchedData === FALSE) 
        throw new Exception('Fetching data failed!');
    

    return $fetchedData;

configs.php

<?php

/*
 * ----------------
 * Database configs
 * ----------------
 */

define('MYSQL_HOST', '...');
define('MYSQL_PORT', '3306');
define('MYSQL_DATABASE', '...');
define('MYSQL_CHARSET', 'utf8');
define('MYSQL_USERNAME', '...');
define('MYSQL_PASSWORD', '...');

functions.php

<?php

/*
 * ---------------------
 * Data access functions
 * ---------------------
 */

/**
 * Create a new db connection.
 * 
 * @param string $host Host.
 * @param string $dbname Database name.
 * @param string $username Username.
 * @param string $password Password.
 * @param string $port [optional] Port.
 * @param array $charset [optional] Character set.
 * @param array $options [optional] Driver options.
 * @return PDO Db connection.
 */
function createConnection($host, $dbname, $username, $password, $port = '3306', $charset = 'utf8', $options = array(
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_EMULATE_PREPARES => false,
    PDO::ATTR_PERSISTENT => true,
)) 
    $dsn = getDsn($host, $dbname, $port, $charset);
    $connection = new PDO($dsn, $username, $password);
    foreach ($options as $key => $value) 
        $connection->setAttribute($key, $value);
    
    return $connection;


/**
 * Create a mysql DSN string.
 * 
 * @param string $host Host.
 * @param string $dbname Database name.
 * @param string $port [optional] Port.
 * @param array $charset [optional] Character set.
 * @return string DSN string.
 */
function getDsn($host, $dbname, $port = '3306', $charset = 'utf8') 
    $dsn = sprintf('mysql:host=%s;port=%s;dbname=%s;charset=%s'
            , $host
            , $port
            , $dbname
            , $charset
    );
    return $dsn;


/**
 * Close a db connection.
 * 
 * @param PDO $connection Db connection.
 * @return void
 */
function closeConnection($connection) 
    $connection = NULL;


/**
 * Get the data type of a binding value.
 * 
 * @param mixed $value Binding value.
 * @return mixed Data type of the binding value.
 */
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;


/*
 * ---------------
 * Print functions
 * ---------------
 */

/**
 * Print data on screen.
 * 
 * @param mixed $data Data to print.
 * @param bool $preformatted Print preformatted if TRUE, print normal otherwise.
 * @return void
 */
function printData($data, $preformatted = FALSE) 
    if ($preformatted) 
        echo '<pre>' . print_r($data, true) . '</pre>';
     else 
        echo $data;
    


/*
 * -------------------------
 * Error reporting functions
 * -------------------------
 */

/**
 * Toggle error reporting.
 * 
 * @param integer $level Error level.
 * @param bool $displayErrors Display errors if TRUE, hide them otherwise.
 * @return void
 */
function activateErrorReporting($level = E_ALL, $displayErrors = TRUE) 
    error_reporting($level);
    ini_set('display_errors', ($displayErrors ? 1 : 0));

【讨论】:

对于我的问题downvote(d)的用户:请让我知道你downvote的动机,以便我可以相应地更改我的答案。通过这种方式,我们可以共同为本网站的持续改进做出贡献。谢谢。

以上是关于通过 PDO 将 & 号插入 SQL 表的主要内容,如果未能解决你的问题,请参考以下文章

将多个复选框插入 MySQL (PDO)

PDO 将一个简单的数组插入 MySQL 数据库

PDO Prepared在单个查询中插入多行

[PDO如果ID存在,则在更新时插入MySQL

使用 PDO 准备语句插入多行

两个插入,两个表,一个PDO事务,双SQL结果[重复]