views:

310

answers:

6

Considering that everyone is always worried about User Data (And Rightly So), would it be sufficient to simply loop through each external array when you get it, and apply a mysql_real_escape_string().

I'm curious to if this is a bad idea.

Something like:

function getExternalData($type='GET')
{
    $type = strtoupper($type);
    $data = $_$type;
    foreach($data as $key => $value)
    {
        $clean[$key] = mysql_real_escape_string($value);
    }
    return $clean;
}

That would make all that data safe to use in databases. But, what are the cons of doing it this way?

+1  A: 

Cons:

You might forget there are other types of user input and so, not clean them.
And, of course, The excess loops.
And, I think DB cleaning should be done the latest as possible, just before you enter the data into the DB in your DL.
Cleaning data for presentation should be done just before presenting the data, etc.

That said, until you will try this approach, you will never know, as people usualy tend to disagree with approaches they don't use themselves (see above :-) )

Itay Moav
A: 

i think you're actually looking for array_map(). This removes the need for a loop. And yes, this is acceptable for making requests safe for database.

One thing though, you might want to use $_SERVER['REQUEST_METHOD'] here. (unless you're using it to pass in as the param to this function.)

contagious
+1  A: 

Don't try to sanitize data. Use queries with placeholders. See bobby-tables.com

Andy Lester
+2  A: 

Applying mysql_real_escape_string on all superglobal variables convey the impression that you either want to use them exclusively in MySQL queries or that you have no clue what mysql_real_escape_string is good for.

Gumbo
+1  A: 

The main con is if you have to process the input, for example in order to parse markup, you'll have to unescape the input then not forget to re-escape it. Also, it's quite inefficient. Query placeholders are a very good way to prevent SQL injection.

As for sanitization itself (not only for SQL) you should take a look at the Filter extension, available by default in PHP 5.2 and in PECL for 5.1.

Josh Davis
+1  A: 

I think it's a bad idea to generalize validation and filtering logic. That was the idea behind magic quotes after all, which is now universally condemned.

Besides that, validating field inputs usually involves a lot of specific junk. Generic rules turn out to be a rather small part of validation, especially as apps grow in size and complexity.

It would be a better idea to come up with a mini framework that allows you to handle both generic and specific validation in the same place. Something like this...

class BrokenRules extends Exception {
    protected $errors;
    function __construct($errors) {
        $this->errors = $errors;
    }
    function getErrors() {
        return $this->errors;
    }
}

class Foo {
    protected $db;
    function __construct(PDO $db) {
        $this->db = $db;
    }
    function loadNew() {
        return array('bar' => 'new foo', 'baz' => 5);
    }
    function loadById($id) {
        $stmt = $this->db->prepare('SELECT * FROM foo WHERE id = ?');
        $stmt->bindValue(1, $id, PDO::PARAM::INT);
        $stmt->execute();
        return $stmt->fetch();
    }
    function save($data) {
        return isset($data['id']) ? $this->update($data) : $this->insert($data);
    }
    protected function validateForInsert($data) {
        if ((int)$data['baz'] <= 3) $errors['baz'][] = 'Baz must be greater than 3';
        if (isset($errors)) throw new BrokenRules($errors);
    }
    protected function validateForUpdate($data) {
        // TODO: validateForUpdate
    }
    protected function insert($data) {
        $this->validateForInsert($data);
        $stmt = $this->db->prepare('INSERT INTO foo (x, y) VALUES (?, ?)');
        $stmt->bindValue(1, $data['bar'], PDO::PARAM_STR);
        $stmt->bindValue(2, $data['baz'], PDO::PARAM_INT);
        $stmt->execute();
        return $this->db->lastInsertId();
    }
    protected function update($data) {
        $this->validateForUpdate($data);
        $stmt = $this->db->prepare('UPDATE foo SET x = ?, y = ? WHERE id = ?');
        $stmt->bindValue(1, $data['bar'], PDO::PARAM_STR);
        $stmt->bindValue(2, $data['baz'], PDO::PARAM_INT);
        $stmt->bindValue(3, $data['id'], PDO::PARAM_INT);
        $stmt->execute();
        return $data['id'];
    }
}

try {
    $foo = new Foo($pdo);
    if ($_POST) {
        $id = $foo->save($_POST);
        redirect("edit_foo.php?id=$id");
    } else if (isset($_GET['id'])) {
        $data = $foo->loadById($_GET['id']);
    } else {
        $data = $foo->loadNew();
    }
} catch (BrokenRules $e) {
    $errors = $e->getErrors();
}

include 'templates/foo.php';
bytebrite