Question

i am using safemysql class for parametrized queries https://github.com/colshrapnel/safemysql. Usualy, when preparing a query, it goes like this:

$entries = $db->getAll("SELECT * FROM table WHERE age = ?i AND name = ?s ",$age,$name);

This kind of queries where i know in advance the total number of parametres to be parsed are pretty straight fwd but it seems i am stacked at queries where I do not know how many parametres I will be using - eg. a search form:

What I would like to do, is parametrize the folowing query:

if($_POST['nameparts']){

    $parts = explode(' ',$_POST['nameparts']);

    foreach((array)$parts as $part){

        $q .= " AND ( `name` LIKE '%".$part."%' OR `firstname` LIKE '%".$part."%' ) ";

    }

    if($_POST['age'])
        $q .= " AND `age` = '".$_POST['age']."' ";

    $entries = $dbs->getAll("SELECT * FROM table WHERE 1 = 1 ".$q." ");

Any suggestions?

Was it helpful?

Solution 2

As with any other SQL query with user-supplied data, to handle this in a truly safe way (or rather to push off the work where it belongs), use placeholders.

Yup, let's start with that goal and not lose sight of it - if the query text contains [user-supplied] data then the code is in violation of one of safemysql's (and safe SQL usage) tenants and the following is not necessarily true anymore!

[safemysql is] safe because every dynamic query part [or "bit of user data"] goes into query via placeholder.

The solution is then to build the query text with placeholders and the data array dynamically - but separately. At no time is the DQL (SQL syntax) and the data mixed. It is this separation (and the guarantee of the lower levels) that guarantees that there is no SQL Injection when this approach is followed.

$data = array();
$q = "SELECT * FROM table WHERE 1 = 1 ";
if($_POST['nameparts']){
    $parts = explode(' ',$_POST['nameparts']);
    foreach((array)$parts as $part){            
        $q .= " AND (`name` LIKE ?s OR `firstname` LIKE ?s )";
        $data[] = '%' . $part . '%'; // add one for each replacement
        $data[] = '%' . $part . '%';
    }
    if($_POST['age']) {
        $q .= " AND `age` = ?i ";
        $data[] = $_POST['age'];
    }
}

And now we have the query text with placeholders and an array of the data to bind. Yippee, we are almost there! Now, create the array that will be passed and invoke the method supplying an array for the parameters.

$params = array($q);
$params = array_merge($params, $data);

$entries = call_user_func_array(array($dbs, 'getAll'), $params);

And, finished!

OTHER TIPS

It doesn't look like safemysql supports variable number of placeholders (otherwise you could build array of parameters in parallel with your query). But you can use methods like escapeString(...). It'll give you the same level of safety, but not so elegant. For example:

$q .= " AND `age` = ".$dbs->escapeInt($_POST['age')]." ";
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top