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

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.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow