通过PDO将&符插入SQL表

时间:2017-07-19 13:24:25

标签: php sql pdo insert sql-injection

我目前能够使用下面的.php将数据插入到SQL数据库中,但是如果数据包含&符号,则会将其视为PHP语句,并且“&”符号不会插入到数据库中。

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

  

从6月25日起存档所有spl和inp   c:\ versionone \ dbcheck_1000 \ inbound_1000 \ DESPATCH \&   c:\ versionone \ dbcheck_1000 \ inbound_1000 \ DESPATCH \完成c:\ Despatch   归档

这就是写在桌子上的内容:

  

从6月25日起存档所有spl和inp   C:\ VersionOne的\ dbcheck_1000 \ inbound_1000 \寄发\

数据库架构

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;

1 个答案:

答案 0 :(得分:0)

注意:我使用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));
}