Hi,

Considering many new developers don't use a database abstraction, and instead 
copy/paste mysqli_query() examples.

I'm just wondering, is there a way we can make it easier to use parameterised 
queries?

Some initial thoughts below.

Craig






Take this semi-complex case, in that it's looking for an undefined number of 
users:

<?php

    $sql = 'SELECT id, name FROM user WHERE id IN (' . implode(', ', $ids) . 
')';

    $result = mysqli_query($db, $sql);

    while ($row = mysqli_fetch_assoc($result)) {
        print_r($row);
    }

?>

This is flawed, especially if those $ids come from untrusted data, but it's not 
obvious.

I'm only aware of mysqli_stmt_bind_param() being able to do parameterised 
queries via mysqli.

I abstracted that function away many years ago, and a recent question reminded 
me of its, well, difficult way of working:

<?php

    $in_sql = implode(',', array_fill(0, count($ids), '?'));

    $sql = 'SELECT id, name FROM user WHERE id IN (' . $in_sql . ')';

    if ($statement = $db->prepare($sql)) {

        $params = [str_repeat('i', count($ids))];
        foreach ($ids as $key => $value) {
            $params[] = &$ids[$key]; // Must be a reference, not ideal.
        }
        call_user_func_array(array($statement, 'bind_param'), $params);

        $statement->execute();

        $result = $statement->get_result();

        while ($row = mysqli_fetch_assoc($result)) {
            print_r($row);
        }

    }

?>

I'm wondering, could mysqli_stmt_execute() be updated to take the parameters in 
a developer friendly way?

<?php

    $in_sql = implode(',', array_fill(0, count($ids), '?'));

    // $in_sql = substr(str_repeat('?,', count($ids)), 0, -1); // Any better 
ideas?

    $sql = 'SELECT id, name FROM user WHERE id IN (' . $in_sql . ')';

    if ($statement = $db->prepare($sql)) {

        $statement->execute($ids);

        while ($row = mysqli_fetch_assoc($statement->result)) {
            print_r($row);
        }

    }

?>

This approach doesn't take types, which might be possible to make optional ('s' 
kind of works for most things); or maybe...

<?php
    $statement->execute($ids, str_repeat('i', count($ids)));
?>

Personally I'm not sold on that idea.

So maybe the parameters could work with an array that includes types:

<?php

    $statement->execute([
            ['i', 1],
            ['s', 'example'],
            ['b', $blob],
        ]);

?>

It is a slightly odd array structure, but it's fairly easy to work with, 
especially if your SQL string is being built up dynamically...

<?php

    $parameters = [];
    $parameters[] = ['i', 1];
    $parameters[] = ['s', 'example'];

    if (true) {
        $parameters[] = ['b', $blob];
    }

?>

And I wonder if $statement->get_result() could be provided via a 
`$statement->result` property, so it could be used directly by 
mysqli_fetch_assoc().

Thoughts?

Reply via email to