简体   繁体   中英

Inserting multiple values into MySQL with PHP

So, I am passing arrays of values that will vary upon use into a method that then inserts them into a database. My problem is the way in which the parameters are bound.

public function insertValues($table, $cols, $values) 
{
    $mysqli = new mysqli(DBHOST, DBUSER, DBPASSWORD, DBDATABASE);

    $colString = implode(', ', $cols); // x, x, x
    $valString = implode(', ', array_fill(0, count($values), '?')); // ?, ?, ?

    $sql = "INSERT INTO $table ($colString) VALUES($valString)";
    if (!$stmt = $mysqli->prepare($sql))
         echo "Prepare failed: (" . $mysqli->errno . ") " . $mysqli->error;

    // THIS IS THE PROBLEM AREA
    foreach ($values as $v)
        if (!$stmt->bind_param('s', $v))
            echo "Binding parameters failed: (" . $stmt->errno . ") " . $stmt->error;

    if (!$stmt->execute())
        echo "Execute failed: (" . $stmt->errno . ") " . $stmt->error;

    $stmt->close();
    $mysqli->close();
}

I need a way to bind all the parameters at once I think, and not one at a time, but I can't figure out a useful way to do this. Any help would be greatly appreciated.

I found the answer for the problem you are looking for on PHP.net ( http://php.net/manual/en/mysqli-stmt.bind-param.php ). I'm pasting it here for convenience, all credit goes to a man going by the email Nick9v ^ät^ hotmail -remove- -dot- com

When dealing with a dynamic number of field values while preparing a statement I find this class useful.

[Editor's note: changed BindParam::add() to accept $value by reference and thereby prevent a warning in newer versions of PHP.]

<?php 
class BindParam{ 
    private $values = array(), $types = ''; 

    public function add( $type, &$value ){ 
        $this->values[] = $value; 
        $this->types .= $type; 
    } 

    public function get(){ 
        return array_merge(array($this->types), $this->values); 
    } 
} 
?> 

Usage is pretty simple. Create an instance and use the add method to populate. When you're ready to execute simply use the get method.

<?php 
$bindParam = new BindParam(); 
$qArray = array(); 

$use_part_1 = 1; 
$use_part_2 = 1; 
$use_part_3 = 1; 

$query = 'SELECT * FROM users WHERE '; 
if($use_part_1){ 
    $qArray[] = 'hair_color = ?'; 
    $bindParam->add('s', 'red'); 
} 
if($use_part_2){ 
    $qArray[] = 'age = ?'; 
    $bindParam->add('i', 25); 
} 
if($use_part_3){ 
    $qArray[] = 'balance = ?'; 
    $bindParam->add('d', 50.00); 
} 

$query .= implode(' OR ', $qArray); 

//call_user_func_array( array($stm, 'bind_param'), $bindParam->get()); 

echo $query . '<br/>'; 
var_dump($bindParam->get()); 
?> 

This gets you the result that looks something like this:

SELECT * FROM users WHERE hair_color = ? OR age = ? OR balance = ? array(4) { [0]=> string(3) "sid" 1 => string(3) "red" [2]=> int(25) [3]=> float(50) }

The code doesn't work because bind_param has to have all of the query parameters in a single call to the function instead of multiple calls for each parameter, also it needs variables passed by reference, so in the foreach call it would always be the same variable with the value that it had in the last iteration of the loop.

The easiest way would be to compose an array with the types and parameters, and then pass it to bind_param with a call to call_user_func_array, for example:

$params = array();
$types = '';

foreach ($values as $k => $v)
{
    $types .= 's';
    $params[] = &$values[$k];
}

$bind_params = array_merge(array($types), $params);

if (!call_user_func_array(array($stmt, 'bind_param'), $bind_params))
    // ...

Note that bind_param expects variables to be passed by reference not by value, otherwise it would be a couple of lines constructing an array with values, instead of the foreach loop.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM