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

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.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow