Bind variables for the parameter markers in the SQL statement that was
passed to mysqli_prepare().

Note:

If data size of a variable exceeds max. allowed packet size
(max_allowed_packet), you have to specify b in
types and use
mysqli_stmt_send_long_data() to send the data in packets.

Note:

Care must be taken when using mysqli_stmt_bind_param() in conjunction
with call_user_func_array(). Note that mysqli_stmt_bind_param()
requires parameters to be passed by reference, whereas call_user_func_array()
can accept as a parameter a list of variables that can represent references or values.

User Contributed Notes 39 notes

There are some things to note when working with mysqli::bind_param() and array-elements.
Re-assigning an array will break any references, no matter if the keys are identical.
You have to explicitly reassign every single value in an array, for the references to be kept.
Best shown in an example:
<?php
function getData() {
return array(
0=>array(
"name"=>"test_0",
"email"=>"test_0@example.com"
),
1=>array(
"name"=>"test_1",
"email"=>"test_1@example.com"
)
);
}
$db = new mysqli("localhost","root","","tests");
$sql = "INSERT INTO `user` SET `name`=?,`email`=?";
$res = $db->prepare($sql);
// If you bind array-elements to a prepared statement, the array has to be declared first with the used keys:
$arr = array("name"=>"","email"=>"");
$res->bind_param("ss",$arr['name'],$arr['email']);
//So far the introduction...

/*
Example 1 (wont work as expected, creates two empty entries)
Re-assigning the array in the while()-head generates a new array, whereas references from bind_param stick to the old array
*/
foreach( getData() as $arr ) {
$res->execute();
}

Coming to the problem calling mysqli::bind_param() with a dynamic number of arguments via call_user_func_array() with PHP Version 5.3+, there's another workaround besides using an extra function to build the references for the array-elements.
You can use Reflection to call mysqli::bind_param(). When using PHP 5.3+ this saves you about 20-40% Speed compared to passing the array to your own reference-builder-function.
Example:
<?php
$db = new mysqli("localhost","root","","tests");
$res = $db->prepare("INSERT INTO test SET foo=?,bar=?");
$refArr = array("si","hello",42);
$ref = new ReflectionClass('mysqli_stmt');
$method = $ref->getMethod("bind_param");
$method->invokeArgs($res,$refArr);
$res->execute();
?>

2) Though PHP numbers cannot be reliably cast to (int) if larger than PHP_INT_MAX, behind the scenes, the value will be converted anyway to at most long long depending on the size. This means that keeping in mind precision limits and avoiding manually casting the variable to (int) first, you can still use the 'i' binding type for larger numbers. i.e.:

3) You can default to 's' for most parameter arguments in most cases. The value will then be automatically cast to string on the back-end before being passed to the Mysql engine. Mysql will then perform its own conversions with values it receives from PHP on execute. This allows you to bind not only to larger numbers without concern for precision, but also to objects as long as that object has a '__toString' method.

This auto-string casting behavior greatly improves things like datetime handling. For example: if you extended DateTime class to add a __toString method which outputs the datetime format expected by Mysql, you can just bind to that DateTime_Extended object using type 's'. i.e.:

You can bind to variables with NULL values, and on update and insert queries, the corresponding field will be updated to NULL no matter what bind string type you associated it with. But, for parameters meant for the WHERE clause (ie where field = ?), the query will have no effect and produce no results.

When comparing a value against NULL, the MYSQL syntax is either "value IS NULL" or "value IS NOT NULL". So, you can't pass in something like "WHERE (value = ?)" and expect this to work using a null value parameter.

I was searching for a class which supports multiple calls to bind_param, because I have scenarios where I build huge SQL statements over different functions with variable numbers of parameters. But I didn't found one. So I have just written up this little piece of code I would like to share with you. There is enough room to optimize these classes, but it shows the general idea. And for me it works. In mbind_param_do() it seems to depend from the PHP version if makeValuesReferenced() must be used or if $params can be used directly. In my case I have to use it.

The cool thing about this solution: You don't have to care about a lot if you are using my mbind_ functions or not. You may also use default bind_param and the execute will still work.

It is believed that if one has specified 'b' in $types, the corresponding variable should be set to null, and one has to use mysqli_stmt::send_long_data() or mysqli_stmt_send_long_data() to send the blob, otherwise the blob value would be treated as empty.

Here is the procedural version of a select statement when wanting to use %LIKE% in the query and not an '=':<?phpfunction db_connect(){// set $db as global for access outside functionglobal $db;# Use procedural methods for database connection and manipulation// Connect to Database@$db = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);

$theRecordInTheTableIs = "%".$_POST['theRecordInTheTableIs']."%"; // concat $_POST variable with % on each side for use in prepared statement$theRelatedRecordLooks = "%".$_POST['theRelatedRecordLooks']."%"; // concat $_POST variable with % on each side for use in prepared statement

You can, in fact, use mysqli_bind_parameter to pass a NULL value to the database. simply create a variable and store the NULL value (see the manpage for it) to the variable and bind that. Works great for me anyway.

The first argument 'ss' in $arrParams states, that the two following arguments are of type String. The options are 's' for String, 'i' for Integer, 'd' for Double and 'b' for Blob (sent in packages).

In queries, that do not return a result INSERT, UPDATE, etc. $result->affected_rows and $result->insert_id are available. Connection errors are available in $result->error. Additional error handling would be nice, but is not implemented for now. Play with the wrapper and use print_r on the result ... enjoy!

The name 'iQuery'? Well, it handles mysql*i* - and then I guess it's kind of a tribute to Mr. Jobs ... may he 'rest' in energetic, hungry foolishness =)

==
UPDATE: 08-NOV-2011 07:19

Due to changes in PHP 5.3 I encountered a problem with 'bind_param' in my iQuery function below. The values in the passed array *must* be references. The soloution is this function:

If you specify type "i" (integer), the maximum value it allows you to have is 2^32-1 or 2147483647. So, if you are using UNSIGNED INTEGER or BIGINT in your database, then you are better off using "s" (string) for this.

I think this is a good way to automatically get the types for the binding in as few lines of code as possible. If you bind the array values in the same order as when you used it for this you should not worry about aligning them.

I just came across a very strange behaviour when using bind_param() with a reflection class. I figured I ought to post it here to save anyone else who comes across it from banging their head against their desk for an hour (as I just did).

First, some background: I have a set of classes, one per file format (i.e. CSV, HTML table, etc), which import data from flat files to a temporary table in my database. The class then transforms the data to 3NF.

I'm using a reflection class to pass an array to mysqli->bind_param() because the column counts and types are variable. The code (simplified) I am having issues with is:

<?php

/* Code that loops through the rows and columns in the * flat file and appends the MySQLi 'type' letter to the * $typeString variable and appends the actual value * to the $data array. I left the code out because it's * (probably) not relevant and would bloat the post. */$stmtInsert = $db->prepare('INSERT.....');$typeString = 'ississis';$data = array(1, 'two', 'three', 4, 'five', 'six', 7, 'eight');

Oddly, in one (and only one) case it started throwing "Warning: Parameter 41 to mysqli_stmt::bind_param() expected to be a reference, value given". The reflection class throws an exception. Other import sets using this code work just fine. Parameter 41 is the last parameter. Changing the affected code as follows resolves the issue:

I had to do a more advanced prepare function (A multi-multi values prepared statement)to make things easier for a few situations, so I wrote the following function.

NOTE: This function assumes you have put it into a class that have:$mysqli = A mysqli object

NOTE2: This function currently only supports ints for the values, but you can modify it to support additional types...

To use it:<?php$sql = "SELECT id, code FROM country";$result = $database->fetch_all($sql); // This is just a custom fetch_all function...

if(!$result) { return null; // no results...}

// Re-organize the order of the elements from the resultset, code first then id, just like the sql statement...$pData = array();foreach($result as $row) {$pData[] = array('code'=>$row['code'] + 1,'id'=>$row['id']); //Assign valid php variable names, because this'll be used later on!!!}

$database->mysqli_prepare_exec("UPDATE country SET code=? WHERE id=?", 'ii', $pData);?>

Dont forget that in the query that you are preparing you do NOT need quotes around string values.If you put them there anyway, you will get:mysqli_stmt_bind_param(): Number of variables doesn't match number of parameters in prepared statement

For those learning mysqli::prepare and mysqli_stmt::bind_params for the first time, here is a commented block of code which executes prepared queries and returns data in a similar format to the return values of mysqli_query. I tried to minimize unnecessary classes, objects, or overhead for two reasons:1) facilitate learning2) allow relativity interchangeable use with mysqli_query

My goal is to lower the learning curve for whoever is starting out with these family of functions. I am by no means an expert coder/scripter, so I am sure there are improvements and perhaps a few bugs, but I hope not =)

NOTES to new users! Or programmers like myself who learn the hard way!!!Pay attention to the variables that are given in the function up above. ( string $types , mixed &$var1 [, mixed &$... ] ) . The example shows this too, but I personally didn't get it 'til trying to debug my code.

ITS REQUIRED TO PASS VARIABLES HERE. You can not pass straight data through here.

$stmt->bind('s','Something here'); Will error!!!

Just a clarification as to avoid another night like mine last night and this morning.

I've found that you can't pass NULL values in using mysql_stmt_bind_param. Recently I ran into this problem because I wrote some MySQL routines that would update existing data, but only when the value wasn't NULL.

This will iterate the given list of parameters and replace any null values in the query with an actual null value. You'll want to use the resulting $sQuery to pass to mysqli_prepare(). For that, I use another routine that generates a list of the values (s, i, etc).

To clarify why I pass array values by reference: They aren't being modified, so I don't want copies of them begin made in memory as they may be large. In other languages, this is much more efficient. Not sure if PHP handles passing values on a "copy on edit" basis.. but I'm guessing not.

WOW! Thanks for the code that fixed the issue with mysqli_stmt_bind_param and PHP 5.3+. Worth sharing again for people getting the error message that a reference was expected and a value was provided. Here's a snippet and the whole function that fixed it!

Miguel Hatrick's Statement_Parameter class, as posted in these notes, allows for a relatively painless way of writing secure dynamic SQL. It is secure against SQL injection because we still use bind parameters for any content coming from the user.

For example, the following code constructs an insert statement, but looks at which query string (GET) parameters are present in order to figure out which columns should be included. The ParameterManager.php file is simply Miguel's classes as posted in this discussion.

I wanted to pass the parameters for several queries to a single function to fill them (insert / update having the same fields for example), while at the same time making the types array a bit easier to maintain when you've got a lot of parameters. Here's a simple solution I came up with:

Note that the types will be overwritten after a call to bindParameters to provide a sensible default (otherwise it will be used as the parameter value when you execute the statement), so you need to reinitialize the types if you want to bind it to another statement.

Small correction. This version removes the NULL element from the array, so it doesn't fall on to the next ? when passed to mysql_stmt_bind_param(). Note that $saParams is still passed by reference, but now it is being modified.