Ricerca…


introduzione

L' interfaccia mysqli è un miglioramento (si intende "estensione MySQL Improvement") dell'interfaccia mysql , che è stata deprecata nella versione 5.5 e rimossa nella versione 7.0. L'estensione mysqli, o come è a volte nota, l'estensione migliorata di MySQL, è stata sviluppata per sfruttare le nuove funzionalità presenti nelle versioni 4.1.3 e successive dei sistemi MySQL. L'estensione mysqli è inclusa con le versioni di PHP 5 e successive.

Osservazioni

Caratteristiche

L'interfaccia mysqli ha una serie di vantaggi, i miglioramenti chiave sull'estensione mysql sono:

  • Interfaccia orientata agli oggetti
  • Supporto per le dichiarazioni preparate
  • Supporto per più dichiarazioni
  • Supporto per le transazioni
  • Funzionalità di debug migliorate
  • Supporto del server integrato

È dotato di una doppia interfaccia : il vecchio stile procedurale e un nuovo stile di programmazione orientata agli oggetti (OOP) . Il mysql deprecato aveva solo un'interfaccia procedurale, quindi lo stile orientato agli oggetti è spesso preferito. Tuttavia, il nuovo stile è anche favorevole a causa del potere di OOP.

alternative

Un'alternativa all'interfaccia mysqli per accedere ai database è la più mysqli interfaccia PHP Data Objects (PDO) . Questo include solo la programmazione in stile OOP e può accedere a più di soli database di tipo MySQL.

Connetti MySQLi

Stile orientato agli oggetti

Connetti al server

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

Imposta il database predefinito: $conn->select_db("my_db");

Connetti al database

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

Stile procedurale

Connetti al server

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

Imposta il database predefinito: mysqli_select_db($conn, "my_db");

Connetti al database

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

Verifica connessione al database

Stile orientato agli oggetti

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

Stile procedurale

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

Query MySQLi

La funzione query accetta una stringa SQL valida e la esegue direttamente contro la connessione al database $conn

Stile orientato agli oggetti

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

Stile procedurale

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

ATTENZIONE

Un problema comune qui è che le persone semplicemente eseguono la query e si aspettano che funzioni (ovvero restituiscono un oggetto mysqli_stmt ). Poiché questa funzione richiede solo una stringa, stai costruendo la query prima tu stesso. Se ci sono errori nell'SQL, il compilatore MySQL fallirà, a questo punto questa funzione restituirà false .

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

Il codice sopra genererà un errore E_FATAL perché $result è false e non un oggetto.

Errore fatale PHP: chiama a una funzione membro fetch_assoc () su un non oggetto

L'errore procedurale è simile, ma non fatale, perché stiamo solo violando le aspettative della funzione.

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

Otterrete il seguente messaggio da PHP

mysqli_fetch_array () si aspetta che il parametro 1 sia mysqli_result, dato booleano

Puoi evitarlo facendo prima un test

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

Passa attraverso i risultati MySQLi

PHP semplifica l'acquisizione dei dati dai risultati e il looping su di esso con un comando while . Quando non riesce a ottenere la riga successiva, restituisce false e il ciclo termina. Questi esempi funzionano con

Stile orientato agli oggetti

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

Stile procedurale

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

Per ottenere informazioni esatte dai risultati, possiamo usare:

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

Chiudere la connessione

Quando abbiamo finito di interrogare il database, si consiglia di chiudere la connessione per liberare risorse.

Stile orientato agli oggetti

$conn->close();

Stile procedurale

mysqli_close($conn);

Nota : la connessione al server verrà chiusa non appena termina l'esecuzione dello script, a meno che non venga chiusa in precedenza chiamando esplicitamente la funzione di connessione chiusa.

Caso d'uso: se il nostro script ha una buona quantità di elaborazione da eseguire dopo aver recuperato il risultato e ha recuperato il set di risultati completo, dobbiamo assolutamente chiudere la connessione. Se non lo fossimo, c'è una possibilità che il server MySQL raggiunga il limite di connessione quando il server Web è in uso intensivo.

Dichiarazioni preparate in MySQLi

Leggere la sezione Prevenzione dell'iniezione SQL con query parametrizzate per una discussione completa sul perché le istruzioni preparate consentono di proteggere le istruzioni SQL dagli attacchi SQL Injection

La variabile $conn qui è un oggetto MySQLi. Vedi esempio di connessione MySQLi per maggiori dettagli.

Per entrambi gli esempi, assumiamo che $sql sia

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

Il ? rappresenta i valori che forniremo in seguito. Si prega di notare che non abbiamo bisogno di quotazioni per i segnaposto, indipendentemente dal tipo. Possiamo anche fornire solo segnaposto nelle parti di dati della query, ovvero SET , VALUES e WHERE . Non è possibile utilizzare segnaposto nelle parti SELECT o FROM .

Stile orientato agli oggetti

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

Stile procedurale

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

Il primo parametro di $stmt->bind_param o il secondo parametro di mysqli_stmt_bind_param è determinato dal tipo di dati del parametro corrispondente nella query SQL:

Parametro Tipo di dati del parametro associato
i numero intero
d Doppio
s stringa
b macchia

L'elenco dei parametri deve essere nell'ordine fornito nella query. In questo esempio si indica che il primo parametro ( column_2 = ? ) È stringa e il secondo parametro ( column_3 > ? ) È intero.

Per il recupero dei dati, vedere Come ottenere dati da una dichiarazione preparata

Strings di evasione

L'escaping delle stringhe è un metodo più vecchio ( e meno sicuro ) di protezione dei dati per l'inserimento in una query. Funziona usando la funzione MySQL mysql_real_escape_string () per elaborare e disinfettare i dati (in altre parole, PHP non sta eseguendo l'escape). L'API MySQLi fornisce accesso diretto a questa funzione

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

A questo punto, hai una stringa che MySQL considera sicura per l'uso in una query diretta

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

Quindi, perché questo non è sicuro quanto le dichiarazioni preparate ? Ci sono modi per ingannare MySQL per produrre una stringa che considera sicura. Considera il seguente esempio

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

1 OR 1=1 non rappresenta i dati che MySQL sfuggirà, ma questo rappresenta ancora l'iniezione SQL. Ci sono anche altri esempi che rappresentano luoghi in cui restituisce dati non sicuri. Il problema è che la funzione di escape di MySQL è progettata per rendere i dati conformi alla sintassi SQL . NON è progettato per garantire che MySQL non possa confondere i dati utente per le istruzioni SQL .

MySQLi Inserisci ID

Recupera l'ultimo ID generato da una query INSERT su una tabella con una colonna AUTO_INCREMENT .

Stile orientato agli oggetti

$id = $conn->insert_id;

Stile procedurale

$id = mysqli_insert_id($conn);

Restituisce zero se non vi era alcuna query precedente sulla connessione o se la query non ha aggiornato un valore AUTO_INCREMENT.

Inserisci ID durante l'aggiornamento delle righe

Normalmente un'istruzione UPDATE non restituisce un ID di inserimento, poiché un ID AUTO_INCREMENT viene restituito solo quando una nuova riga è stata salvata (o inserita). Un modo per aggiornare il nuovo ID è utilizzare la sintassi INSERT ... ON DUPLICATE KEY UPDATE per l'aggiornamento.

Installazione per gli esempi da seguire:

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

Il caso di IODKU che esegue un "aggiornamento" e LAST_INSERT_ID() recupera l' id rilevante:

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

Il caso in cui IODKU esegue un "inserimento" e LAST_INSERT_ID() recupera il nuovo 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)

Contenuto della tabella risultante:

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

Debug di SQL in MySQLi

Quindi la tua query è fallita (vedi Connetti a MySQLi per come abbiamo creato $conn )

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

Come possiamo scoprire cos'è successo? $result è false quindi non è di aiuto. Per fortuna il $conn connect $conn può dirci cosa ci ha detto MySQL sull'errore

trigger_error($conn->error);

o procedurale

trigger_error(mysqli_error($conn));

Dovresti ottenere un errore simile a

La tabella 'my_db.non_existent_table' non esiste

Come ottenere i dati da una dichiarazione preparata

Dichiarazioni preparate

Vedi le istruzioni preparate in MySQLi per come preparare ed eseguire una query.

Legame dei risultati

Stile orientato agli oggetti

$stmt->bind_result($forename);

Stile procedurale

mysqli_stmt_bind_result($stmt, $forename);

Il problema con l'utilizzo di bind_result è che richiede l'istruzione per specificare le colonne che verranno utilizzate. Ciò significa che, per il funzionamento di cui sopra, la query deve essere simile a SELECT forename FROM users . Per includere più colonne, aggiungili semplicemente come parametri alla funzione bind_result (e assicurati di aggiungerli alla query SQL).

In entrambi i casi, stiamo assegnando il forename colonna a $forename variabile. Queste funzioni accettano tutti gli argomenti delle colonne che vuoi assegnare. L'assegnazione viene eseguita una sola volta, poiché la funzione si lega per riferimento.

Possiamo quindi eseguire il loop come segue:

Stile orientato agli oggetti

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

Stile procedurale

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

Lo svantaggio di questo è che devi assegnare un sacco di variabili contemporaneamente. Ciò rende difficile tenere traccia delle grandi domande. Se hai installato MySQL Native Driver ( mysqlnd ) , tutto ciò che devi fare è usare get_result .

Stile orientato agli oggetti

$result = $stmt->get_result();

Stile procedurale

$result = mysqli_stmt_get_result($stmt);

Questo è molto più facile da lavorare perché ora stiamo ottenendo un oggetto mysqli_result . Questo è lo stesso oggetto restituito da mysqli_query . Ciò significa che puoi utilizzare un ciclo di risultati regolare per ottenere i tuoi dati.


Cosa succede se non riesco a installare mysqlnd ?

Se questo è il caso, allora @Sophivorus ti copre questa incredibile risposta .

Questa funzione può eseguire l'attività di get_result senza che sia installata sul server. Semplicemente scorre i risultati e crea un array associativo

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

Possiamo quindi utilizzare la funzione per ottenere risultati come questo, proprio come se stessimo usando 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>';
}

Avrà lo stesso risultato come se si stesse utilizzando il driver mysqlnd , ma non deve essere installato. Questo è molto utile se non riesci a installare il driver sul tuo sistema. Basta implementare questa soluzione.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow