Zoeken…


Invoering

De mysqli interface is een verbetering (dit betekent "MySQL Improvement extension") van de mysql interface, die in versie 5.5 is verouderd en in versie 7.0 is verwijderd. De mysqli-extensie, of zoals het soms wordt genoemd, de verbeterde MySQL-extensie, werd ontwikkeld om te profiteren van nieuwe functies in MySQL-systeemversies 4.1.3 en nieuwer. De mysqli-extensie is inbegrepen bij PHP-versies 5 en hoger.

Opmerkingen

Kenmerken

De mysqli-interface heeft een aantal voordelen, de belangrijkste verbeteringen ten opzichte van de mysql-extensie zijn:

  • Objectgeoriënteerde interface
  • Ondersteuning voor voorbereide verklaringen
  • Ondersteuning voor meerdere verklaringen
  • Ondersteuning voor transacties
  • Verbeterde debugging-mogelijkheden
  • Ingebouwde serverondersteuning

Het beschikt over een dubbele interface : de oudere, procedurele stijl en een nieuwe, object-georiënteerde programmeerstijl (OOP) . De verouderde mysql had alleen een procedurele interface, dus de objectgeoriënteerde stijl heeft vaak de voorkeur. De nieuwe stijl is echter ook gunstig vanwege de kracht van OOP.

alternatieven

Een alternatief voor de mysqli interface voor toegang tot databases is de nieuwere PHP Data Objects (PDO) -interface. Dit biedt alleen programmering in OOP-stijl en heeft toegang tot meer dan alleen databases van het type MySQL.

MySQLi connect

Object georiënteerde stijl

Connecteer met de server

$conn = new mysqli("localhost","my_user","my_password");

Stel de standaarddatabase in: $conn->select_db("my_db");

Maak verbinding met de database

$conn = new mysqli("localhost","my_user","my_password","my_db");

Procedurele stijl

Connecteer met de server

$conn = mysqli_connect("localhost","my_user","my_password");

Stel de standaarddatabase in: mysqli_select_db($conn, "my_db");

Maak verbinding met de database

$conn = mysqli_connect("localhost","my_user","my_password","my_db");

Controleer de databaseverbinding

Object georiënteerde stijl

if ($conn->connect_errno > 0) {
    trigger_error($db->connect_error);
} // else: successfully connected

Procedurele stijl

if (!$conn) {
   trigger_error(mysqli_connect_error());
} // else: successfully connected

MySQLi-zoekopdracht

De query gebruikt een geldige SQL-tekenreeks en voert deze rechtstreeks uit op de databaseverbinding $conn

Object georiënteerde stijl

$result = $conn->query("SELECT * FROM `people`");

Procedurele stijl

$result = mysqli_query($conn, "SELECT * FROM `people`");

VOORZICHTIGHEID

Een veel voorkomend probleem is dat mensen de query gewoon uitvoeren en verwachten dat deze werkt (dwz een object mysqli_stmt retourneert ). Aangezien deze functie slechts een string vereist, bouwt u eerst de query zelf. Als er helemaal geen fouten in de SQL zijn, mislukt de MySQL-compiler, waarna deze functie false retourneert .

$result = $conn->query('SELECT * FROM non_existent_table'); // This query will fail
$row = $result->fetch_assoc();

De bovenstaande code genereert een E_FATAL fout omdat $result false is en geen object.

PHP Fatale fout: aanroep naar een lidfunctie fetch_assoc () op een niet-object

De procedurefout is vergelijkbaar, maar niet fataal, omdat we alleen de verwachtingen van de functie overtreden.

$row = mysqli_fetch_assoc($result); // same query as previous

Je krijgt het volgende bericht van PHP

mysqli_fetch_array () verwacht dat parameter 1 mysqli_result is, boolean gegeven

U kunt dit voorkomen door eerst een test te doen

if($result) $row = mysqli_fetch_assoc($result);

Loop door MySQLi-resultaten

PHP maakt het gemakkelijk om gegevens uit uw resultaten te halen en er met een while instructie overheen te lopen. Als het de volgende rij niet haalt, keert het false terug en eindigt je lus. Deze voorbeelden werken met

Object georiënteerde stijl

while($row = $result->fetch_assoc()) {
    var_dump($row);
}

Procedurele stijl

while($row = mysqli_fetch_assoc($result)) {
    var_dump($row);
}

Om exacte informatie uit de resultaten te krijgen, kunnen we gebruiken:

while ($row = $result->fetch_assoc()) {
    echo 'Name and surname: '.$row['name'].' '.$row['surname'].'<br>';
    echo 'Age: '.$row['age'].'<br>'; // Prints info from 'age' column
}

Hechte band

Wanneer we klaar zijn met het doorzoeken van de database, wordt het aanbevolen om de verbinding te verbreken om bronnen vrij te maken.

Object georiënteerde stijl

$conn->close();

Procedurele stijl

mysqli_close($conn);

Opmerking : de verbinding met de server wordt gesloten zodra de uitvoering van het script eindigt, tenzij deze eerder wordt gesloten door de functie nauwe verbinding expliciet aan te roepen.

Gebruikscasus: als ons script na het ophalen van het resultaat een behoorlijke hoeveelheid bewerkingen moet uitvoeren en de volledige resultaatset heeft opgehaald, moeten we absoluut de verbinding sluiten. Als we dat niet zouden doen, bestaat de kans dat de MySQL-server de verbindingslimiet bereikt wanneer de webserver zwaar wordt gebruikt.

Opgestelde verklaringen in MySQLi

Lees SQL-injectie voorkomen met geparametriseerde zoekopdrachten voor een volledige discussie over waarom voorbereide instructies u helpen uw SQL-instructies te beveiligen tegen SQL Injection-aanvallen

De variabele $conn hier is een MySQLi-object. Zie het voorbeeld van MySQLi connect voor meer informatie.

Voor beide voorbeelden nemen we aan dat $sql is

$sql = "SELECT column_1 
    FROM table 
    WHERE column_2 = ? 
        AND column_3 > ?";

De ? vertegenwoordigt de waarden die we later zullen verstrekken. Houd er rekening mee dat we geen offertes nodig hebben voor de tijdelijke aanduidingen, ongeacht het type. We kunnen ook alleen tijdelijke aanduidingen verstrekken in de gegevensgedeelten van de query, wat betekent SET , VALUES en WHERE . U kunt geen tijdelijke aanduidingen gebruiken in de gedeelten SELECT of FROM .

Object georiënteerde stijl

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();
}

Procedurele stijl

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);
}

De eerste parameter van $stmt->bind_param of de tweede parameter van mysqli_stmt_bind_param wordt bepaald door het gegevenstype van de overeenkomstige parameter in de SQL-query:

Parameter Gegevenstype van de gebonden parameter
i geheel getal
d dubbele
s draad
b bobbel

Uw lijst met parameters moet in de volgorde staan die in uw zoekopdracht is opgegeven. In dit voorbeeld betekent si dat de eerste parameter ( column_2 = ? ) String is en de tweede parameter ( column_3 > ? ) Een geheel getal is.

Zie Gegevens ophalen uit een voorbereide verklaring voor het ophalen van gegevens

Ontsnappende snaren

Ontsnappen aan tekenreeksen is een oudere ( en minder veilige ) methode voor het beveiligen van gegevens voor invoeging in een query. Het werkt door de functie mysql_real_escape_string () van MySQL te gebruiken om de gegevens te verwerken en op te schonen ( met andere woorden, PHP doet niet aan de ontsnapping). De MySQLi API biedt directe toegang tot deze functie

$escaped = $conn->real_escape_string($_GET['var']);
// OR
$escaped = mysqli_real_escape_string($conn, $_GET['var']);

Op dit moment hebt u een string die MySQL als veilig beschouwt voor gebruik in een directe query

$sql = 'SELECT * FROM users WHERE username = "' . $escaped . '"';
$result = $conn->query($sql);

Dus waarom is dit niet zo veilig als voorbereide verklaringen ? Er zijn manieren om MySQL te misleiden om een string te produceren die het als veilig beschouwt. Overweeg het volgende voorbeeld

$id = mysqli_real_escape_string("1 OR 1=1");    
$sql = 'SELECT * FROM table WHERE id = ' . $id;

1 OR 1=1 vertegenwoordigt geen gegevens die MySQL zal ontsnappen, maar dit vertegenwoordigt nog steeds SQL-injectie. Er zijn ook andere voorbeelden die plaatsen vertegenwoordigen waar onveilige gegevens worden geretourneerd. Het probleem is dat de ontsnappingsfunctie van MySQL is ontworpen om gegevens te laten voldoen aan de SQL-syntaxis . Het is NIET ontworpen om ervoor te zorgen dat MySQL geen gebruikersgegevens kan verwarren voor SQL-instructies .

MySQLi ID invoegen

Haal de laatste ID op die is gegenereerd door een INSERT query in een tabel met een kolom AUTO_INCREMENT .

Objectgeoriënteerde stijl

$id = $conn->insert_id;

Procedurele stijl

$id = mysqli_insert_id($conn);

Retourneert nul als er geen eerdere query op de verbinding was of als de query de waarde AUTO_INCREMENT niet heeft bijgewerkt.

Voer een ID in bij het bijwerken van rijen

Normaal gesproken retourneert een UPDATE instructie geen invoeg-ID, omdat een AUTO_INCREMENT id alleen wordt geretourneerd wanneer een nieuwe rij is opgeslagen (of ingevoegd). Een manier om updates voor de nieuwe id te maken, is door INSERT ... ON DUPLICATE KEY UPDATE syntaxis te gebruiken voor het bijwerken.

Stel de volgende voorbeelden in:

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 |
+----+--------+------+

Het geval van IODKU die een "update" LAST_INSERT_ID() en LAST_INSERT_ID() die de relevante id LAST_INSERT_ID() :

$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)

Het geval waarin IODKU een "invoeging" uitvoert en LAST_INSERT_ID() haalt de nieuwe 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)

Resulterende tabelinhoud:

SELECT * FROM iodku;
+----+--------+------+
| id | name   | misc |
+----+--------+------+
|  1 | Leslie |  123 |
|  2 | Sally  | 3333 |  -- IODKU changed this
|  3 | Dana   |  789 |  -- IODKU added this
+----+--------+------+

Foutopsporing van SQL in MySQLi

Dus je zoekopdracht is mislukt (zie MySQLi connect voor hoe we $conn hebben gemaakt)

$result = $conn->query('SELECT * FROM non_existent_table'); // This query will fail

Hoe komen we erachter wat er is gebeurd? $result is false dus dat is geen hulp. Gelukkig kan de connect $conn ons vertellen wat MySQL ons heeft verteld over de fout

trigger_error($conn->error);

of procedureel

trigger_error(mysqli_error($conn));

Je zou een fout moeten krijgen die lijkt op

Tabel 'my_db.non_existent_table' bestaat niet

Gegevens ophalen uit een voorbereide verklaring

Opgestelde verklaringen

Zie Voorbereide verklaringen in MySQLi voor het voorbereiden en uitvoeren van een query.

Bindende resultaten

Objectgeoriënteerde stijl

$stmt->bind_result($forename);

Procedurele stijl

mysqli_stmt_bind_result($stmt, $forename);

Het probleem met het gebruik van bind_result is dat het de instructie vereist om de kolommen op te geven die zullen worden gebruikt. Dit betekent dat de bovenstaande opdracht alleen moet werken als de SELECT forename FROM users . Als u meer kolommen wilt opnemen, voegt u ze eenvoudig toe als parameters aan de functie bind_result (en zorgt u ervoor dat u ze toevoegt aan de SQL-query).

In beide gevallen wijzen we de kolom forename aan de variabele $forename . Deze functies hebben evenveel argumenten als kolommen die u wilt toewijzen. De toewijzing wordt slechts eenmaal uitgevoerd, omdat de functie door verwijzing bindt.

We kunnen dan als volgt lussen:

Objectgeoriënteerde stijl

while ($stmt->fetch())
    echo "$forename<br />";

Procedurele stijl

while (mysqli_stmt_fetch($stmt))
    echo "$forename<br />";

Het nadeel hiervan is dat je veel variabelen tegelijk moet toewijzen. Dit maakt het bijhouden van grote zoekopdrachten moeilijk. Als je MySQL Native Driver ( mysqlnd ) hebt geïnstalleerd, hoef je alleen get_result te gebruiken .

Objectgeoriënteerde stijl

$result = $stmt->get_result();

Procedurele stijl

$result = mysqli_stmt_get_result($stmt);

Dit is veel eenvoudiger om mee te werken, omdat we nu een object mysqli_result krijgen. Dit is hetzelfde object dat mysqli_query retourneert . Dit betekent dat u een regelmatige resultatenlus kunt gebruiken om uw gegevens op te halen.


Wat als ik mysqlnd niet kan installeren?

Als dat het geval is, heeft @Sophivorus u gedekt met dit verbazingwekkende antwoord .

Deze functie kan de taak get_result zonder dat deze op de server wordt geïnstalleerd. Het doorloopt eenvoudig de resultaten en bouwt een associatieve array op

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;
}

We kunnen de functie vervolgens gebruiken om dergelijke resultaten te krijgen, net alsof we 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>';
}

Het heeft dezelfde uitvoer als wanneer u het stuurprogramma mysqlnd gebruikt, behalve dat het niet hoeft te worden geïnstalleerd. Dit is erg handig als u het genoemde stuurprogramma niet op uw systeem kunt installeren. Implementeer deze oplossing.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow