Je suis novice dans l'utilisation d'instructions préparées dans mysql avec php. J'ai besoin d'aide pour créer une instruction préparée pour récupérer des colonnes.
J'ai besoin d'obtenir des informations de différentes colonnes. Actuellement, pour un fichier de test, j'utilise l'instruction complètement non sécurisée SQL:
$qry = "SELECT * FROM mytable where userid='{$_GET['userid']}' AND category='{$_GET['category']}'ORDER BY id DESC"
$result = mysql_query($qry) or die(mysql_error());
Quelqu'un peut-il m'aider à créer une instruction secure mysql en utilisant les paramètres d’entrée (comme ci-dessus) préparés?
BONUS: Les déclarations préparées sont supposées augmenter également la vitesse. La vitesse globale augmentera-t-elle si je n'utilise qu'une déclaration préparée trois ou quatre fois par page?
Voici un exemple utilisant mysqli (object-syntax - assez facile à traduire en syntaxe de fonction si vous le souhaitez):
$db = new mysqli("Host","user","pw","database");
$stmt = $db->prepare("SELECT * FROM mytable where userid=? AND category=? ORDER BY id DESC");
$stmt->bind_param('ii', intval($_GET['userid']), intval($_GET['category']));
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($column1, $column2, $column3);
while($stmt->fetch())
{
echo "col1=$column1, col2=$column2, col3=$column3 \n";
}
$stmt->close();
De plus, si vous voulez un moyen simple de récupérer des tableaux associatifs (à utiliser avec SELECT *) au lieu de spécifier exactement les variables auxquelles vous souhaitez vous connecter, voici une fonction pratique:
function stmt_bind_assoc (&$stmt, &$out) {
$data = mysqli_stmt_result_metadata($stmt);
$fields = array();
$out = array();
$fields[0] = $stmt;
$count = 1;
while($field = mysqli_fetch_field($data)) {
$fields[$count] = &$out[$field->name];
$count++;
}
call_user_func_array(mysqli_stmt_bind_result, $fields);
}
Pour l'utiliser, il suffit de l'invoquer au lieu d'appeler bind_result:
$stmt->store_result();
$resultrow = array();
stmt_bind_assoc($stmt, $resultrow);
while($stmt->fetch())
{
print_r($resultrow);
}
Vous pouvez écrire ceci à la place:
$qry = "SELECT * FROM mytable where userid='";
$qry.= mysql_real_escape_string($_GET['userid'])."' AND category='";
$qry.= mysql_real_escape_string($_GET['category'])."' ORDER BY id DESC";
Mais pour utiliser des instructions préparées, il vaut mieux utiliser une bibliothèque générique, comme PDO
<?php
/* Execute a prepared statement by passing an array of values */
$sth = $dbh->prepare('SELECT * FROM mytable where userid=? and category=?
order by id DESC');
$sth->execute(array($_GET['userid'],$_GET['category']));
//Consider a while and $sth->fetch() to fetch rows one by one
$allRows = $sth->fetchAll();
?>
Ou, en utilisant mysqli
<?php
$link = mysqli_connect("localhost", "my_user", "my_password", "world");
/* check connection */
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
$category = $_GET['category'];
$userid = $_GET['userid'];
/* create a prepared statement */
if ($stmt = mysqli_prepare($link, 'SELECT col1, col2 FROM mytable where
userid=? and category=? order by id DESC')) {
/* bind parameters for markers */
/* Assumes userid is integer and category is string */
mysqli_stmt_bind_param($stmt, "is", $userid, $category);
/* execute query */
mysqli_stmt_execute($stmt);
/* bind result variables */
mysqli_stmt_bind_result($stmt, $col1, $col2);
/* fetch value */
mysqli_stmt_fetch($stmt);
/* Alternative, use a while:
while (mysqli_stmt_fetch($stmt)) {
// use $col1 and $col2
}
*/
/* use $col1 and $col2 */
echo "COL1: $col1 COL2: $col2\n";
/* close statement */
mysqli_stmt_close($stmt);
}
/* close connection */
mysqli_close($link);
?>
Je suis d'accord avec plusieurs autres réponses:
ext/mysql
de PHP ne prend pas en charge les instructions SQL paramétrées.mysql_real_escape_string()
peut également être efficace si vous l'utilisez correctement, mais le code est plus détaillé.Vous devez également noter que vous devez toujours faire attention à l'injection SQL même si vous utilisez des paramètres de requête, car ceux-ci ne remplacent que les valeurs littérales des requêtes SQL. Si vous construisez des requêtes SQL de manière dynamique et utilisez des variables PHP pour le nom de la table, le nom de la colonne ou toute autre partie de la syntaxe SQL, ni les paramètres de requête ni mysql_real_escape_string()
ne vous aident dans ce cas. Par exemple:
$query = "SELECT * FROM $the_table ORDER BY $some_column";
En ce qui concerne la performance:
Il existe même des cas où une requête préparée nuit - performance. Par exemple, dans le cas suivant, l'optimiseur ne peut pas supposer qu'il peut utiliser un index pour la recherche, car il doit assumer la valeur du paramètre might begin avec un caractère générique:
SELECT * FROM mytable WHERE textfield LIKE ?
La sécurité avec MySQL dans PHP (ou tout autre langage) est un sujet largement débattu. Voici quelques endroits où vous pouvez trouver de bons conseils:
Les deux éléments les plus importants à mon avis sont:
mysql_real_escape_string()
de PHP (ou quelque chose de similaire).Si vous utilisez mysqli - ce qui me semble la meilleure solution - je vous recommande fortement de télécharger une copie de la classe codesense_mysqli .
C'est une petite classe soignée qui cache et cache la plupart des difficultés accumulées lors de l'utilisation de mysqli brut, de telle sorte que l'utilisation d'instructions préparées ne prend qu'une ligne ou deux de plus sur l'ancienne interface mysql/php
Les instructions préparées ne sont pas prises en charge par l'ancienne interface Mysql/PHP. Vous aurez besoin de PDO ou mysqli . Mais si vous voulez simplement substituer des espaces réservés, consultez ce commentaire sur la page de manuel de php mysql_query.
Assez tard, mais cela pourrait aider quelqu'un:
/**
* Execute query method. Executes a user defined query
*
* @param string $query the query statement
* @param array(Indexed) $col_vars the column variables to replace parameters. The count value should equal the number of supplied parameters
*
* Note: Use parameters in the query then supply the respective replacement variables in the second method parameter. e.g. 'SELECT COUNT(*) as count FROM foo WHERE bar = ?'
*
* @return array
*/
function read_sql($query, $col_vars=null) {
$conn = new mysqli('hostname', 'username', 'user_pass', 'dbname');
$types = $variables = array();
if (isset($col_vars)) {
for ($x=0; $x<count($col_vars); $x++) {
switch (gettype($col_vars[$x])) {
case 'integer':
array_Push($types, 'i');
break;
case 'double':
array_Push($types, 'd');
break;
default:
array_Push($types, 's');
}
array_Push($variables, $col_vars[$x]);
}
$types = implode('', $types);
$sql = $conn->prepare($query);
$sql -> bind_param($types, ...$variables);
$sql -> execute();
$results = $sql -> get_result();
$sql -> close();
}else {
$results = $conn->query($query) or die('Error: '.$conn->error);
}
if ($results -> num_rows > 0) {
while ($row = $results->fetch_assoc()) {
$result[] = $row;
}
return $result;
}else {
return null;
}
}
Vous pouvez ensuite invoquer la fonction comme suit:
read_sql('SELECT * FROM mytable where userid = ? AND category = ? ORDER BY id DESC', array($_GET['userid'], $_GET['category']));