PHP
PHP MySQLi
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
- mysqli_fetch_assoc - Array associativo con nomi di colonne come chiavi
- mysqli_fetch_object -
stdClass
oggetto con i nomi delle colonne come variabili - mysqli_fetch_array - Array associativo e numerico (può usare gli argomenti per ottenere uno o l'altro)
- mysqli_fetch_row - Array numerico
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.