PHP
PHP MySQLi
Recherche…
Introduction
L' interface mysqli
est une amélioration (cela signifie "extension d'amélioration MySQL") de l'interface mysql
, qui est devenue obsolète dans la version 5.5 et qui est supprimée dans la version 7.0. L'extension mysqli, ou, comme on l'appelle parfois, l'extension améliorée de MySQL, a été développée pour tirer parti des nouvelles fonctionnalités des versions 4.1.3 et ultérieures des systèmes MySQL. L'extension mysqli est incluse dans les versions 5 et supérieures de PHP.
Remarques
Caractéristiques
L'interface mysqli présente un certain nombre d'avantages, les principales améliorations par rapport à l'extension mysql étant:
- Interface orientée objet
- Prise en charge des déclarations préparées
- Prise en charge de plusieurs déclarations
- Prise en charge des transactions
- Fonctions de débogage améliorées
- Prise en charge de serveur intégré
Il comporte une double interface : l'ancien style procédural et un nouveau style de programmation orientée objet (OOP) . Le mysql
obsolète n'avait qu'une interface procédurale, de sorte que le style orienté objet est souvent préféré. Cependant, le nouveau style est également favorable en raison de la puissance de la POO.
Des alternatives
Une alternative à l'interface mysqli
pour accéder aux bases de données est l'interface plus récente de PHP Data Objects (PDO) . Cela ne comprend que la programmation de type OOP et peut accéder à plus de bases de données que MySQL.
MySQLi connect
Style orienté objet
Connecter au serveur
$conn = new mysqli("localhost","my_user","my_password");
Définissez la base de données par défaut: $conn->select_db("my_db");
Se connecter à la base de données
$conn = new mysqli("localhost","my_user","my_password","my_db");
Style procédural
Connecter au serveur
$conn = mysqli_connect("localhost","my_user","my_password");
Définissez la base de données par défaut: mysqli_select_db($conn, "my_db");
Se connecter à la base de données
$conn = mysqli_connect("localhost","my_user","my_password","my_db");
Vérifier la connexion à la base de données
Style orienté objet
if ($conn->connect_errno > 0) {
trigger_error($db->connect_error);
} // else: successfully connected
Style procédural
if (!$conn) {
trigger_error(mysqli_connect_error());
} // else: successfully connected
Requête MySQLi
La fonction de query
prend une chaîne SQL valide et l'exécute directement contre la connexion à la base de données $conn
Style orienté objet
$result = $conn->query("SELECT * FROM `people`");
Style procédural
$result = mysqli_query($conn, "SELECT * FROM `people`");
MISE EN GARDE
Un problème courant ici est que les gens vont simplement exécuter la requête et s’attendre à ce qu’elle fonctionne (c.-à-d. Retourner un objet mysqli_stmt ). Puisque cette fonction ne prend qu'une chaîne, vous construisez d'abord la requête vous-même. S'il y a des erreurs dans le SQL, le compilateur MySQL échouera, à quel point cette fonction renverra false
.
$result = $conn->query('SELECT * FROM non_existent_table'); // This query will fail
$row = $result->fetch_assoc();
Le code ci-dessus générera une erreur E_FATAL
car $result
est false
et non un objet.
Erreur fatale PHP: appel à une fonction membre fetch_assoc () sur un non-objet
L'erreur procédurale est similaire, mais pas fatale, car nous ne faisons que violer les attentes de la fonction.
$row = mysqli_fetch_assoc($result); // same query as previous
Vous recevrez le message suivant de PHP
mysqli_fetch_array () s'attend à ce que le paramètre 1 soit mysqli_result, booléen donné
Vous pouvez éviter cela en faisant d'abord un test
if($result) $row = mysqli_fetch_assoc($result);
Boucle sur les résultats de MySQLi
PHP facilite l'obtention de données à partir de vos résultats et la boucle en utilisant une instruction while
. Quand il ne parvient pas à obtenir la ligne suivante, il retourne false
et votre boucle se termine. Ces exemples fonctionnent avec
- mysqli_fetch_assoc - Tableau associatif avec des noms de colonnes comme clés
- mysqli_fetch_object - Objet
stdClass
avec des noms de colonne en tant que variables - mysqli_fetch_array - Tableau associatif ET numérique (peut utiliser des arguments pour obtenir l'un ou l'autre)
- mysqli_fetch_row - Tableau numérique
Style orienté objet
while($row = $result->fetch_assoc()) {
var_dump($row);
}
Style procédural
while($row = mysqli_fetch_assoc($result)) {
var_dump($row);
}
Pour obtenir des informations exactes à partir des résultats, nous pouvons utiliser:
while ($row = $result->fetch_assoc()) {
echo 'Name and surname: '.$row['name'].' '.$row['surname'].'<br>';
echo 'Age: '.$row['age'].'<br>'; // Prints info from 'age' column
}
Fermer la connexion
Lorsque nous avons fini d'interroger la base de données, il est recommandé de fermer la connexion pour libérer des ressources.
Style orienté objet
$conn->close();
Style procédural
mysqli_close($conn);
Remarque : La connexion au serveur sera fermée dès que l'exécution du script se terminera, sauf si elle est fermée plus tôt en appelant explicitement la fonction de connexion fermée.
Cas d'utilisation: Si notre script a un traitement assez important à effectuer après avoir récupéré le résultat et qu'il a récupéré le jeu de résultats complet, nous devons définitivement fermer la connexion. Si nous ne le faisions pas, le serveur MySQL atteindrait sa limite de connexion lorsque le serveur Web est fortement utilisé.
Préparations des déclarations dans MySQLi
Veuillez lire Prévention de l'injection SQL avec des requêtes paramétrées pour une analyse complète des raisons pour lesquelles les instructions préparées vous aident à sécuriser vos instructions SQL contre les attaques par injection SQL.
La variable $conn
est un objet MySQLi. Voir l' exemple de connexion MySQLi pour plus de détails.
Pour les deux exemples, nous supposons que $sql
est
$sql = "SELECT column_1
FROM table
WHERE column_2 = ?
AND column_3 > ?";
Le ?
représente les valeurs que nous fournirons plus tard. Veuillez noter que nous n'avons pas besoin de devis pour les espaces réservés, quel que soit le type. Nous pouvons également fournir uniquement des espaces réservés dans les parties de données de la requête, ce qui signifie SET
, VALUES
et WHERE
. Vous ne pouvez pas utiliser d'espaces réservés dans les parties SELECT
ou FROM
.
Style orienté objet
if ($stmt = $conn->prepare($sql)) {
$stmt->bind_param("si", $column_2_value, $column_3_value);
$stmt->execute();
$stmt->bind_result($column_1);
$stmt->fetch();
//Now use variable $column_1 one as if it were any other PHP variable
$stmt->close();
}
Style procédural
if ($stmt = mysqli_prepare($conn, $sql)) {
mysqli_stmt_bind_param($stmt, "si", $column_2_value, $column_3_value);
mysqli_stmt_execute($stmt);
// Fetch data here
mysqli_stmt_close($stmt);
}
Le premier paramètre de $stmt->bind_param
ou le second paramètre de mysqli_stmt_bind_param
est déterminé par le type de données du paramètre correspondant dans la requête SQL:
Paramètre | Type de données du paramètre lié |
---|---|
i | entier |
d | double |
s | chaîne |
b | goutte |
Votre liste de paramètres doit être dans l'ordre indiqué dans votre requête. Dans cet exemple, si
signifie que le premier paramètre ( column_2 = ?
) Est une chaîne et le second paramètre ( column_3 > ?
) Est un entier.
Pour récupérer des données, voir Comment obtenir des données à partir d'une instruction préparée
Cordes échappant
Échapper aux chaînes est une méthode plus ancienne ( et moins sécurisée ) de sécurisation des données à insérer dans une requête. Cela fonctionne en utilisant la fonction mysql_real_escape_string () de MySQL pour traiter et assainir les données (en d'autres termes, PHP ne fait pas de fuite). L'API MySQLi fournit un accès direct à cette fonction
$escaped = $conn->real_escape_string($_GET['var']);
// OR
$escaped = mysqli_real_escape_string($conn, $_GET['var']);
A ce stade, vous avez une chaîne que MySQL considère comme sûre pour une utilisation dans une requête directe.
$sql = 'SELECT * FROM users WHERE username = "' . $escaped . '"';
$result = $conn->query($sql);
Alors, pourquoi n'est-ce pas aussi sûr que les déclarations préparées ? Il existe des moyens de piéger MySQL pour produire une chaîne considérée comme sûre. Considérons l'exemple suivant
$id = mysqli_real_escape_string("1 OR 1=1");
$sql = 'SELECT * FROM table WHERE id = ' . $id;
1 OR 1=1
ne représente pas les données que MySQL échappera, mais cela représente toujours l’injection SQL. Il existe également d' autres exemples qui représentent des endroits où des données non sécurisées sont renvoyées. Le problème est que la fonction d'échappement de MySQL est conçue pour que les données soient conformes à la syntaxe SQL . Il n'est PAS conçu pour garantir que MySQL ne puisse pas confondre les données utilisateur avec les instructions SQL .
MySQLi Insert ID
Récupère le dernier ID généré par une requête INSERT
sur une table avec une colonne AUTO_INCREMENT .
Style orienté objet
$id = $conn->insert_id;
Style procédural
$id = mysqli_insert_id($conn);
Retourne zéro s'il n'y a pas eu de requête précédente sur la connexion ou si la requête n'a pas mis à jour une valeur AUTO_INCREMENT.
Insérer un identifiant lors de la mise à jour des lignes
Normalement, une instruction UPDATE
ne renvoie pas d'ID d'insertion, car un identifiant AUTO_INCREMENT
n'est renvoyé que lorsqu'une nouvelle ligne a été enregistrée (ou insérée). Une façon de mettre à jour le nouvel identifiant consiste à utiliser la syntaxe INSERT ... ON DUPLICATE KEY UPDATE
pour la mise à jour.
Configuration des exemples à suivre:
CREATE TABLE iodku (
id INT AUTO_INCREMENT NOT NULL,
name VARCHAR(99) NOT NULL,
misc INT NOT NULL,
PRIMARY KEY(id),
UNIQUE(name)
) ENGINE=InnoDB;
INSERT INTO iodku (name, misc)
VALUES
('Leslie', 123),
('Sally', 456);
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
+----+--------+------+
| id | name | misc |
+----+--------+------+
| 1 | Leslie | 123 |
| 2 | Sally | 456 |
+----+--------+------+
Le cas où IODKU effectue une "mise à jour" et LAST_INSERT_ID()
récupère l' id
correspondant:
$sql = "INSERT INTO iodku (name, misc)
VALUES
('Sally', 3333) -- should update
ON DUPLICATE KEY UPDATE -- `name` will trigger "duplicate key"
id = LAST_INSERT_ID(id),
misc = VALUES(misc)";
$conn->query($sql);
$id = $conn->insert_id; -- picking up existing value (2)
Le cas où IODKU effectue un "insert" et LAST_INSERT_ID()
récupère le nouvel id
:
$sql = "INSERT INTO iodku (name, misc)
VALUES
('Dana', 789) -- Should insert
ON DUPLICATE KEY UPDATE
id = LAST_INSERT_ID(id),
misc = VALUES(misc);
$conn->query($sql);
$id = $conn->insert_id; -- picking up new value (3)
Contenu de la table résultant:
SELECT * FROM iodku;
+----+--------+------+
| id | name | misc |
+----+--------+------+
| 1 | Leslie | 123 |
| 2 | Sally | 3333 | -- IODKU changed this
| 3 | Dana | 789 | -- IODKU added this
+----+--------+------+
Débogage de SQL dans MySQLi
Donc, votre requête a échoué (voir MySQLi connect pour savoir comment nous avons fait $conn
)
$result = $conn->query('SELECT * FROM non_existent_table'); // This query will fail
Comment pouvons-nous savoir ce qui s'est passé? $result
est false
, ce n'est pas utile. Heureusement, le $conn
connect peut nous dire ce que MySQL nous a dit à propos de l'échec
trigger_error($conn->error);
ou procédural
trigger_error(mysqli_error($conn));
Vous devriez avoir une erreur similaire à
La table 'my_db.non_existent_table' n'existe pas
Comment obtenir des données à partir d'une déclaration préparée
Déclarations préparées
Voir les instructions préparées dans MySQLi pour savoir comment préparer et exécuter une requête.
Liaison des résultats
Style orienté objet
$stmt->bind_result($forename);
Style procédural
mysqli_stmt_bind_result($stmt, $forename);
Le problème avec l'utilisation de bind_result
est qu'il nécessite l'instruction pour spécifier les colonnes qui seront utilisées. Cela signifie que pour que ce qui précède fonctionne, la requête doit avoir ressemblé à ce nom SELECT forename FROM users
. Pour inclure plus de colonnes, ajoutez-les simplement en tant que paramètres à la fonction bind_result
(et assurez-vous de les ajouter à la requête SQL).
Dans les deux cas, nous attribuons la forename
colonne à $forename
variable. Ces fonctions prennent autant d’arguments que les colonnes que vous souhaitez attribuer. L'affectation est effectuée une seule fois, car la fonction est liée par référence.
On peut alors boucler comme suit:
Style orienté objet
while ($stmt->fetch())
echo "$forename<br />";
Style procédural
while (mysqli_stmt_fetch($stmt))
echo "$forename<br />";
L'inconvénient est que vous devez attribuer beaucoup de variables à la fois. Cela rend difficile le suivi des requêtes volumineuses. Si MySQL Native Driver ( mysqlnd
) est installé, il vous suffit d'utiliser get_result .
Style orienté objet
$result = $stmt->get_result();
Style procédural
$result = mysqli_stmt_get_result($stmt);
Ceci est beaucoup plus facile à utiliser car maintenant nous obtenons un objet mysqli_result . C'est le même objet que mysqli_query renvoie . Cela signifie que vous pouvez utiliser une boucle de résultat régulière pour obtenir vos données.
Et si je ne peux pas installer mysqlnd
?
Si tel est le cas, @Sophivorus vous a couvert avec cette réponse incroyable .
Cette fonction peut effectuer la tâche de get_result
sans être installée sur le serveur. Il parcourt simplement les résultats et construit un tableau associatif
function get_result(\mysqli_stmt $statement)
{
$result = array();
$statement->store_result();
for ($i = 0; $i < $statement->num_rows; $i++)
{
$metadata = $statement->result_metadata();
$params = array();
while ($field = $metadata->fetch_field())
{
$params[] = &$result[$i][$field->name];
}
call_user_func_array(array($statement, 'bind_result'), $params);
$statement->fetch();
}
return $result;
}
Nous pouvons alors utiliser la fonction pour obtenir des résultats comme celui-ci, comme si nous mysqli_fetch_assoc()
<?php
$query = $mysqli->prepare("SELECT * FROM users WHERE forename LIKE ?");
$condition = "J%";
$query->bind_param("s", $condition);
$query->execute();
$result = get_result($query);
while ($row = array_shift($result)) {
echo $row["id"] . ' - ' . $row["forename"] . ' ' . $row["surname"] . '<br>';
}
Il aura le même résultat que si vous utilisiez le pilote mysqlnd
, sauf qu'il ne doit pas être installé. Ceci est très utile si vous ne parvenez pas à installer ce pilote sur votre système. Il suffit de mettre en œuvre cette solution.