PwnageAtPwn
PwnageAtPwn

Reputation: 431

No data supplied for parameters in MySQLi prepared statement

I've been reworking my website from unprotected MySQL queries to mysqli prepared statements and it all went well until I got this: No data supplied for parameters in prepared statement.

if(empty($err)) {
    $pSETQuery  = NULL;
    if(!empty($_POST['password'])) {
        $pSETQuery .= ", password = ?";
    }
    if($session->isSuperuser()) {
        $pSETQuery .= ", usertype = ?";
    }
    if(!($stmt = $database->prepare("UPDATE user SET username = ?, email = ? $pSETQuery WHERE UserId = ?"))) {
        $err[] = "PREPARE FAILED.";
    }
    $stmt->bind_param("s", $_POST['username']);
    $stmt->bind_param("s", $_POST['email']);
    if(!empty($_POST['password'])) {
        $stmt->bind_param("s", $_POST['password']);
    }
    if($session->isSuperuser()) {
        $stmt->bind_param("s", $_POST['usertype']);
    }
    $stmt->bind_param("i", $_POST['userid']);
    if(!$stmt->execute()){
        $err[] = "Execute failed. ERROR: " . $stmt->error;
    }

}

Upvotes: 8

Views: 29745

Answers (4)

Dharman
Dharman

Reputation: 33238

The error you are getting is becauses of these lines:

$stmt->bind_param("s", $_POST['username']);
$stmt->bind_param("s", $_POST['email']);

You should only call bind_param() once and you need to provide the same number of variadic variables as you have placeholders in the SQL. This function is not well designed, which is one of the main reasons people prefer PDO.

To solve the problem you need to dynamically prepare 3 things: placeholders, types and variables to bind. Here is how you could dynamically build such query:

if(empty($err)) {
    $pSETQuery  = '';
    $types = 'sss'; // for the three constant placeholders
    $data = [$_POST['username'], $_POST['email']];
    if(!empty($_POST['password'])) {
        $pSETQuery .= ", password = ?";
        $types .= 's'; //concat one more
        $data[] = $_POST['password'];
    }
    if($session->isSuperuser()) {
        $pSETQuery .= ", usertype = ?";
        $types .= 's'; //concat one more
        $data[] = $_POST['usertype'];
    }
    $data[] = $_POST['userid']; // for UserId
    
    $stmt = $database->prepare("UPDATE user SET username = ?, email = ? $pSETQuery WHERE UserId = ?");
    $stmt->bind_param($types, ...$data);
    $stmt->execute();
}

Upvotes: 9

JoDev
JoDev

Reputation: 6873

I've just found a way to fix the same problem.

It was a value passed to MySQL, which was NULL. Whereas this column can't be NULL in table definition...

Upvotes: -2

ivoputzer
ivoputzer

Reputation: 6469

"No data supplied for parameters in prepared statement" means statement is ok but at least one of the vars you're providing to bind_param is not there as expected! i would print out $_POST and see what's going on and eventually set $pSETQuery = ''; and not to null!

$_POST['username']
$_POST['email']
$_POST['password']
$_POST['usertype']
$_POST['userid'] // this one is the one I would really watch after, how do you tell the userid if the user is not logged ( i assume that from email, passwrod and might be wrong)

Upvotes: -1

Zard
Zard

Reputation: 72

Do you use Zend Framework ? It could be a version problem between Php and Zend. I got the problem with PHP 5.3 + who got the same error on insert or update with Zend framework 1.8.3.

If you are in that case, one of the solutions is to change the connector to the database. Try this, it works for me :

$db = new Zend_Db_Adapter_Pdo_Mysql(array(
    'host'     => '127.0.0.1',
    'username' => 'webuser',
    'password' => 'xxxxxxxx',
    'dbname'   => 'test'
));

Upvotes: 1

Related Questions