PHP
PHP MySQLi
Sök…
Introduktion
mysqli
gränssnittet är en förbättring (det betyder "MySQL Improvement-förlängning") av mysql
gränssnittet, som avskrivs i version 5.5 och tas bort i version 7.0. Mysqli-förlängningen, eller som det ibland är känt, den förbättrade MySQL-tillägget, utvecklades för att dra nytta av nya funktioner som finns i MySQL-systemversion 4.1.3 och nyare. Mysqli-förlängningen ingår i PHP-versioner 5 och senare.
Anmärkningar
Funktioner
Mysqli-gränssnittet har ett antal fördelar, varvid nyckelförbättringarna jämfört med mysql-förlängningen är:
- Objektorienterat gränssnitt
- Stöd för förberedda uttalanden
- Stöd för flera uttalanden
- Support för transaktioner
- Förbättrade felsökningsmöjligheter
- Inbyggd serverstöd
Den har ett dubbelt gränssnitt : den äldre, procedurmässiga stilen och en ny, objektorienterad programmering (OOP) -stil. Den avskrivna mysql
hade bara ett procedurellt gränssnitt, så den objektorienterade stilen föredras ofta. Men den nya stilen är också gynnsam på grund av kraften i OOP.
alternativ
Ett alternativ till mysqli
gränssnittet för att komma åt databaser är det nyare PHP Data Objects (PDO) -gränssnittet. Den här funktionen har bara programmering i OOP-stil och har åtkomst till mer än bara databaser av MySQL-typ.
MySQLi connect
Objektorienterad stil
Anslut till servern
$conn = new mysqli("localhost","my_user","my_password");
Ställ in standarddatabasen: $conn->select_db("my_db");
Anslut till databasen
$conn = new mysqli("localhost","my_user","my_password","my_db");
Procedurstil
Anslut till servern
$conn = mysqli_connect("localhost","my_user","my_password");
Ställ in standarddatabasen: mysqli_select_db($conn, "my_db");
Anslut till databasen
$conn = mysqli_connect("localhost","my_user","my_password","my_db");
Verifiera databasanslutning
Objektorienterad stil
if ($conn->connect_errno > 0) {
trigger_error($db->connect_error);
} // else: successfully connected
Procedurstil
if (!$conn) {
trigger_error(mysqli_connect_error());
} // else: successfully connected
MySQLi-fråga
query
tar en giltig SQL-sträng och kör den direkt mot databasanslutningen $conn
Objektorienterad stil
$result = $conn->query("SELECT * FROM `people`");
Procedurstil
$result = mysqli_query($conn, "SELECT * FROM `people`");
VARNING
Ett vanligt problem här är att människor helt enkelt kommer att köra frågan och förvänta sig att den ska fungera (dvs. returnera ett mysqli_stmt-objekt ). Eftersom den här funktionen bara tar en sträng bygger du först frågan själv. Om det finns några fel i SQL alls, kommer MySQL-kompilatorn att misslyckas, då kommer denna funktion att returnera false
.
$result = $conn->query('SELECT * FROM non_existent_table'); // This query will fail
$row = $result->fetch_assoc();
Ovanstående kod genererar ett E_FATAL
fel eftersom $result
E_FATAL
är false
och inte ett objekt.
PHP Dödligt fel: Ring till en medlemsfunktion fetch_assoc () på ett icke-objekt
Procedurfelet är liknande, men inte dödligt, eftersom vi bara bryter mot förväntningarna på funktionen.
$row = mysqli_fetch_assoc($result); // same query as previous
Du får följande meddelande från PHP
mysqli_fetch_array () förväntar sig att parameter 1 ska vara mysqli_result, boolean given
Du kan undvika detta genom att göra ett test först
if($result) $row = mysqli_fetch_assoc($result);
Gå igenom MySQLi-resultat
PHP gör det enkelt att hämta data från dina resultat och slinga över den med hjälp av en while
uttalande. När det inte lyckas få nästa rad returnerar det false
och din slinga slutar. Dessa exempel fungerar med
- mysqli_fetch_assoc - Associativ matris med kolumnnamn som nycklar
- mysqli_fetch_object -
stdClass
objekt medstdClass
som variabler - mysqli_fetch_array - Associativ OCH Numerisk matris (kan använda argument för att få det ena eller det andra)
- mysqli_fetch_row - Numerisk matris
Objektorienterad stil
while($row = $result->fetch_assoc()) {
var_dump($row);
}
Procedurstil
while($row = mysqli_fetch_assoc($result)) {
var_dump($row);
}
För att få exakt information från resultaten kan vi använda:
while ($row = $result->fetch_assoc()) {
echo 'Name and surname: '.$row['name'].' '.$row['surname'].'<br>';
echo 'Age: '.$row['age'].'<br>'; // Prints info from 'age' column
}
Stäng anslutningen
När vi är klar med frågan i databasen rekommenderas det att stänga anslutningen för att frigöra resurser.
Objektorienterad stil
$conn->close();
Procedurstil
mysqli_close($conn);
Obs : Anslutningen till servern stängs så snart exekveringen av skriptet upphör, såvida det inte stängs tidigare genom att uttryckligen anropa funktionen för nära anslutning.
Använd fall: Om vårt skript har en hel del bearbetning att utföra efter att ha hämtat resultatet och har hämtat hela resultatuppsättningen, bör vi definitivt stänga anslutningen. Om vi inte skulle göra det finns det en chans att MySQL-servern når sin anslutningsgräns när webbservern är under kraftigt bruk.
Förberedda uttalanden i MySQLi
Vänligen läs Förebygga SQL-injektion med parametriserade frågor för en fullständig diskussion om varför förberedda uttalanden hjälper dig att säkra dina SQL-uttalanden från SQL-injektionsattacker
Variabeln $conn
här är ett MySQLi-objekt. Se exempel på MySQLi connect för mer information.
För båda exemplen antar vi att $sql
är
$sql = "SELECT column_1
FROM table
WHERE column_2 = ?
AND column_3 > ?";
?
representerar de värden vi kommer att tillhandahålla senare. Observera att vi inte behöver offert för platshållarna, oavsett typ. Vi kan också bara ge platshållare i datadelarna i frågan, vilket betyder SET
, VALUES
och WHERE
. Du kan inte använda platshållare i SELECT
eller FROM
delarna.
Objektorienterad stil
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();
}
Procedurstil
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);
}
Den första parametern för $stmt->bind_param
eller den andra parametern för mysqli_stmt_bind_param
bestäms av mysqli_stmt_bind_param
för motsvarande parameter i SQL-frågan:
Parameter | Datatyp för den bundna parametern |
---|---|
i | heltal |
d | dubbel- |
s | sträng |
b | klick |
Din parameterlista måste vara i den ordning som anges i din fråga. I det här exemplet betyder si
den första parametern ( column_2 = ?
) column_2 = ?
sträng och den andra parametern ( column_3 > ?
) column_3 > ?
heltal.
Information om hur du hämtar data finns i Hur man hämtar data från ett förberett uttalande
Rymdsträngar
Rymdsträngar är en äldre ( och mindre säker ) metod för att säkra data för infogning i en fråga. Det fungerar genom att använda MySQL: s funktion mysql_real_escape_string () för att bearbeta och desinficera data (med andra ord, PHP gör inte undkommet). MySQLi API ger direkt tillgång till den här funktionen
$escaped = $conn->real_escape_string($_GET['var']);
// OR
$escaped = mysqli_real_escape_string($conn, $_GET['var']);
Just nu har du en sträng som MySQL anser vara säker att använda i en direktfråga
$sql = 'SELECT * FROM users WHERE username = "' . $escaped . '"';
$result = $conn->query($sql);
Så varför är detta inte lika säkert som förberedda uttalanden ? Det finns sätt att lura MySQL att producera en sträng som den anser vara säker. Tänk på följande exempel
$id = mysqli_real_escape_string("1 OR 1=1");
$sql = 'SELECT * FROM table WHERE id = ' . $id;
1 OR 1=1
representerar inte data som MySQL kommer att fly, men detta representerar fortfarande SQL-injektion. Det finns också andra exempel som representerar platser där det returnerar osäkra data. Problemet är att MySQLs utrymningsfunktion är utformad för att få data att uppfylla SQL-syntax . Det är INTE utformat för att se till att MySQL inte kan förväxla användardata för SQL-instruktioner .
MySQLi Infoga ID
Hämta det senaste ID som genererades av en INSERT
fråga i en tabell med en AUTO_INCREMENT- kolumn.
Objektorienterad stil
$id = $conn->insert_id;
Procedurstil
$id = mysqli_insert_id($conn);
Returnerar noll om det inte fanns någon tidigare fråga på anslutningen eller om frågan inte uppdaterade ett AUTO_INCREMENT-värde.
Infoga id när rader uppdateras
Normalt returnerar inte ett UPDATE
uttalande ett insert-id, eftersom ett AUTO_INCREMENT
id endast returneras när en ny rad har sparats (eller infogats). Ett sätt att uppdatera den nya iden är att använda INSERT ... ON DUPLICATE KEY UPDATE
syntax för uppdatering.
Konfigurera följande exempel:
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 |
+----+--------+------+
Fallet med IODKU som utför en "uppdatering" och LAST_INSERT_ID()
hämtar relevant 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)
Fallet där IODKU utför en "insert" och LAST_INSERT_ID()
hämtar den nya 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)
Resultatet av tabellinnehållet:
SELECT * FROM iodku;
+----+--------+------+
| id | name | misc |
+----+--------+------+
| 1 | Leslie | 123 |
| 2 | Sally | 3333 | -- IODKU changed this
| 3 | Dana | 789 | -- IODKU added this
+----+--------+------+
Debugging SQL i MySQLi
Så din fråga har misslyckats (se MySQLi-anslutning för hur vi skapade $conn
)
$result = $conn->query('SELECT * FROM non_existent_table'); // This query will fail
Hur får vi reda på vad som hände? $result
är false
så det är ingen hjälp. Tack och lov kan connect $conn
berätta vad MySQL berättade om felet
trigger_error($conn->error);
eller processuella
trigger_error(mysqli_error($conn));
Du bör få ett fel som liknar
Tabellen "my_db.non_existent_table" finns inte
Hur man får data från ett förberett uttalande
Förberedda uttalanden
Se Förberedda uttalanden i MySQLi för hur du förbereder och kör en fråga.
Bindning av resultat
Objektorienterad stil
$stmt->bind_result($forename);
Procedurstil
mysqli_stmt_bind_result($stmt, $forename);
Problemet med att använda bind_result
är att det krävs att uttalandet anger de kolumner som ska användas. Detta betyder att frågan måste se ut så här SELECT forename FROM users
. För att inkludera fler kolumner lägg bara till dem som parametrar till bind_result
funktionen (och se till att du lägger till dem i SQL-frågan).
I båda fallen tilldelar vi forename
till variabeln $forename
. Dessa funktioner tar lika många argument som kolumner du vill tilldela. Uppdraget görs bara en gång, eftersom funktionen binds genom referens.
Vi kan sedan slinga på följande sätt:
Objektorienterad stil
while ($stmt->fetch())
echo "$forename<br />";
Procedurstil
while (mysqli_stmt_fetch($stmt))
echo "$forename<br />";
Nackdelen med detta är att du måste tilldela många variabler samtidigt. Detta gör det svårt att hålla reda på stora frågor. Om du har MySQL Native Driver ( mysqlnd
) installerad, behöver du bara använda get_result .
Objektorienterad stil
$result = $stmt->get_result();
Procedurstil
$result = mysqli_stmt_get_result($stmt);
Det här är mycket lättare att arbeta med eftersom vi nu får ett mysqli_result- objekt. Detta är samma objekt som mysqli_query returnerar . Detta innebär att du kan använda en vanlig resultatslinga för att få dina data.
Vad händer om jag inte kan installera mysqlnd
?
Om så är fallet har @Sophivorus du täckt med detta fantastiska svar .
Denna funktion kan utföra uppgiften att get_result
utan att den installeras på servern. Det släpper helt enkelt igenom resultaten och bygger en associerande grupp
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;
}
Vi kan sedan använda funktionen för att få resultat som detta, precis som om vi använder 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>';
}
Den kommer att ha samma utgång som om du använder mysqlnd
drivrutinen, förutom att den inte behöver installeras. Detta är mycket användbart om du inte kan installera nämnda drivrutin på ditt system. Implementera bara den här lösningen.