What is the right way to add a variable where-clau

2019-08-05 15:04发布

问题:

I'm made a database class in php. Now i was testing the update function in it. It returns an syntax error or an unknown column error depending on how the where-clause is formed.

I tried:

'woord = \'uiteindelijk\'' and 'woord = \"uiteindelijk\"' and 
'woord = "uiteindelijk"' and more

I also tried different quotes and backsticks in de functions query but it al gave me the same errors.

My question is what is the right way to form the where-clause is this example if it possible ofcourse. And if not how can i fix it.

part of database.mysqli.php

<?php

class myDB {

    private $mysqli;

    public function __construct() {
        require_once('config.php');

        $this->mysqli = new mysqli(HOST, USERNAME, PASSWORD, DB_NAME);  
        if (mysqli_connect_errno()) {
            printf("Connect failed: %s\n", mysqli_connect_error());
        exit();
        }
    }

    public function close() {
        $this->mysqli->close(); 
    }

    private function check($input) {
        if(is_string($input)) {
            $input = trim($input);
            return $this->mysqli->real_escape_string($input);   
        }       
        elseif(is_int($input)) {
            return $input;
        }
        elseif($input === true || $input === false) {
            return $input;
        }
        else {
            die('invalid input');
        }   
    }
    public function update($table, $data, $where) {
        $table = $this->check($table);
        $where = $this->check($where);
        $result = '';
        if (is_array($data)) {
            $update = array();
            foreach ($data as $key => $val) {
                $key = $this->check($key);
                $val = $this->check($val);  
                $update[] .= $key . '=\'' . $val . '\'';
            }
            $query = 'UPDATE ' . $table . ' SET ' . implode(',', $update) . ' WHERE ' . $where;
            if($this->mysqli->query($query)) {
                $result = 'Last updated row id is: '.$this->mysqli->insert_id;
            } 
            else {
                $result = $this->mysqli->error;
            }
        }   
        return $result;
    }

test.php

<!DOCTYPE HTML>
<html>
<head>
</head>
<body>  

<?php
require_once('database.mysqli.php');
$db = new myDB;
$data = array('woord' => 'gewoontjes', 'lengte' => 10);
$result = $db->update('galgje', $data, 'woord = \'uiteindelijk\'');
echo $result;
$db->close();
?>

</body>
</html>

回答1:

The problem comes from escape_string in your check method. This function is used to escape precise parts inside a statement, you cannot apply it to the where clause as a whole in such a generic way.

If you ever know for sure that your inputs are safe (not containing special characters breaking the sql statement, malicious or not), then simply remove the escaping.

Or if you think that they may contain special characters, for good reasons or to possibly drag a sql injection, then you have to provide a more constrained interface so that you can build the where clause yourself with the appropriate escaping. For example :

public function update($table, $data, $woord) {
    ...
    $where = 'woord = \'' . $this->check($woord) . '\'';
    ...
}

Edit: I know it may sound too much constrained but security comes at a price. For something more flexible, you could have a look at prepared statements. They let you use placeholders, for example WHERE woord = ? AND id < ?, which you can bind to variables with something like :

$stmt->bind_param('si', $woord, $id); // 'si' -> 1:string, 2:integer

In this case, mysqli applies escaping internaly on bound strings, so you don't have to worry about it.

Note that you cannot use a placeholder to replace the whole where clause. WHERE ? with $stmt->bind_param('s', $where); will not work.

Last thing, PDO, an alternative API to access your database in PHP, supports named placeholders (WHERE woord = :woord instead of WHERE woord = ?).