Générer dynamiquement des chaînes de définition de type pour les instructions préparées
P粉031492081
P粉031492081 2024-02-03 21:09:39
0
1
359

J'écris un script qui charge essentiellement les données d'une API dans une base de données MySQL locale. Ces valeurs changent en fonction de ce que renvoie l'API.

Jusqu'à présent, tout fonctionne bien jusqu'à ce que j'essaie d'insérer des lignes dans la base de données MySQL. Plus précisément, je sais que je suis censé utiliser des instructions préparées, mais j'ai des problèmes lorsque j'essaie de lier des variables à des instructions préparées. Lorsque j'essaie d'exécuter le code suivant, j'obtiens :

PHP Warning:  mysqli_stmt::bind_param(): Number of elements in type definition string doesn't match number of bind variables in /opt/awn2sql/functions.php on line 212

Voici le code en question :

$readingValues = array_values($read); //array of just the values in the original array
array_push($readingValues, $devicemac); //add the MAC address of the device that recorded the reading to the array
    
$columns = implode(", ",$readingTypes); //create a string of column names to build the SQL query
    
$valuesCount = count($readingValues); //get a count of the values to fill an array with placeholders
$stmt_placeholders = implode(',',array_fill(0,$valuesCount,'?')); //fill an array with placeholders (i.e. ?,?,?) - see above
$stmt_param = null; //$stmt_param will hold the type definitions string for binding the 
    
foreach ($readingValues as $param) { //iterate through each value in the $readingValues array, get the type, and add it to the type definitions string
    if (gettype($param) == 'integer')
    {
        $stmt_param = $stmt_param.'i';
    }
    else if (gettype($param) == 'double')
    {
        $stmt_param = $stmt_param.'d';
    }               
    else if (gettype($param) == 'string')
    {
    $stmt_param = $stmt_param.'s';
    }
    else if (gettype($param) == 'blob')
    {
        $stmt_param = $stmt_param.'b';
    }
    else
    {
        echo "Invalid data type!";
    }
}

$val_insert_query = "INSERT INTO ".$config['mysql_db'].".readings (".$columns.") VALUES (".$stmt_placeholders.");"; //Template for the query
    
$stmt=$mysqli->prepare($val_insert_query); //Prepares the template for the query for binding, prepared statement becomes $stmt

echo ($stmt_param." (".strlen($stmt_param).")\n"); //for debugging, echo the type definiton string and get its length (which should match the number of values)

echo (count($readingValues)); //count the number of values, which should match the number of elements in the type defintion string
    
$stmt->bind_param($stmt_param, $readingValues); //Binding
    
$stmt->execute(); //execute the statement

J'admets librement que je suis un peu novice dans ce domaine, donc je suis ouvert à toute suggestion sur la façon de mieux le faire. Pour ce que ça vaut, il n'y a jamais de contribution directe de l'utilisateur, donc je suis relativement indifférent aux problèmes de sécurité, si cela a une incidence sur la meilleure façon de résoudre ce problème.

Merci d'avance !

P粉031492081
P粉031492081

répondre à tous(1)
P粉702946921

bind_param() Accepte en fait les arguments variables, pas les arguments de tableau. Mais le PHP moderne a une syntaxe pour convertir un tableau en plusieurs arguments scalaires :

$stmt->bind_param($stmt_param, ...$readingValues); //Binding

Cela équivaut à passer des éléments de tableau en tant qu'arguments séparés :

$stmt->bind_param($stmt_param, $readingValues[0], $readingValues[1],
    $readingValues[2], etc.);

Mais c'est gênant si vous ne savez pas combien d'éléments il y a dans le tableau.


Pour information, je préfère utiliser PDO au lieu de mysqli. Vous n'avez rien à lier, passez simplement le tableau de valeurs comme argument à execute() :

$stmt=$pdo->prepare($val_insert_query); 

$stmt->execute( $readingValues );

Je trouve l'AOP plus facile. La raison d'utiliser mysqli est si vous avez beaucoup de code hérité du milieu des années 2000 qui doit être peaufiné. Si vous débutez, il n'y a pas de code existant. Alors autant adopter le PDO dans un premier temps.

Il existe un bon tutoriel PDO : https://phpdelusions.net/pdo/

Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal