PHP
PHP MySQLi
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
- mysqli_fetch_assoc - Associatieve array met kolomnamen als sleutels
- mysqli_fetch_object -
stdClass
object met kolomnamen als variabelen - mysqli_fetch_array - Associatieve EN Numerieke array (kan argumenten gebruiken om het een of het ander te krijgen)
- mysqli_fetch_row - Numerieke array
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.