PHP
PHP MySQLi
Szukaj…
Wprowadzenie
Interfejs mysqli
jest ulepszeniem (oznacza „rozszerzenie MySQL Improvement”) interfejsu mysql
, który został wycofany w wersji 5.5 i został usunięty w wersji 7.0. Rozszerzenie mysqli, lub jak to czasem jest znane, ulepszone rozszerzenie MySQL, zostało opracowane w celu wykorzystania nowych funkcji dostępnych w systemach MySQL w wersji 4.1.3 i nowszych. Rozszerzenie mysqli jest dołączone do PHP w wersji 5 i nowszych.
Uwagi
cechy
Interfejs mysqli ma wiele zalet, a najważniejsze ulepszenia w stosunku do rozszerzenia mysql to:
- Interfejs obiektowy
- Obsługa przygotowanych wyciągów
- Obsługa wielu instrukcji
- Obsługa transakcji
- Ulepszone możliwości debugowania
- Obsługa wbudowanego serwera
Posiada podwójny interfejs : starszy styl proceduralny i nowy styl programowania obiektowego (OOP) . Przestarzały mysql
miał tylko interfejs proceduralny, więc często preferowany jest styl obiektowy. Jednak nowy styl jest również korzystny ze względu na moc OOP.
Alternatywy
Alternatywą dla interfejsu mysqli
do uzyskiwania dostępu do baz danych jest nowszy interfejs PHP Data Objects (PDO) . Funkcja ta obejmuje wyłącznie programowanie w stylu OOP i może uzyskać dostęp do więcej niż tylko baz danych typu MySQL.
Połącz MySQLi
Styl obiektowy
Połączyć się z serwerem
$conn = new mysqli("localhost","my_user","my_password");
Ustaw domyślną bazę danych: $conn->select_db("my_db");
Połącz z bazą danych
$conn = new mysqli("localhost","my_user","my_password","my_db");
Styl proceduralny
Połączyć się z serwerem
$conn = mysqli_connect("localhost","my_user","my_password");
Ustaw domyślną bazę danych: mysqli_select_db($conn, "my_db");
Połącz z bazą danych
$conn = mysqli_connect("localhost","my_user","my_password","my_db");
Sprawdź połączenie z bazą danych
Styl obiektowy
if ($conn->connect_errno > 0) {
trigger_error($db->connect_error);
} // else: successfully connected
Styl proceduralny
if (!$conn) {
trigger_error(mysqli_connect_error());
} // else: successfully connected
Zapytanie MySQLi
Funkcja query
pobiera prawidłowy ciąg SQL i wykonuje go bezpośrednio na połączeniu z bazą danych $conn
Styl obiektowy
$result = $conn->query("SELECT * FROM `people`");
Styl proceduralny
$result = mysqli_query($conn, "SELECT * FROM `people`");
UWAGA
Częstym problemem jest to, że ludzie po prostu wykonają zapytanie i oczekują, że zadziała (tj. Zwróci obiekt mysqli_stmt ). Ponieważ ta funkcja zajmuje tylko ciąg, najpierw sam konstruujesz zapytanie. Jeśli w SQL wystąpią jakiekolwiek błędy, kompilator MySQL zawiedzie, w którym to momencie funkcja zwróci false
.
$result = $conn->query('SELECT * FROM non_existent_table'); // This query will fail
$row = $result->fetch_assoc();
Powyższy kod wygeneruje błąd E_FATAL
ponieważ $result
jest false
, a nie obiekt.
Błąd krytyczny PHP: Wywołanie funkcji członkowskiej fetch_assoc () na obiekcie niebędącym obiektem
Błąd proceduralny jest podobny, ale nie śmiertelny, ponieważ po prostu naruszamy oczekiwania funkcji.
$row = mysqli_fetch_assoc($result); // same query as previous
Otrzymasz następującą wiadomość z PHP
mysqli_fetch_array () oczekuje, że parametr 1 będzie mysqli_result, podano wartość logiczną
Możesz tego uniknąć, wykonując najpierw test
if($result) $row = mysqli_fetch_assoc($result);
Pętla wyników MySQLi
PHP ułatwia pobieranie danych z wyników i przeglądanie ich za pomocą instrukcji while
. Gdy nie uda się pobrać następnego wiersza, zwraca false
, a pętla się kończy. Te przykłady działają z
- mysqli_fetch_assoc - Tablica asocjacyjna z nazwami kolumn jako kluczami
- mysqli_fetch_object - obiekt
stdClass
z nazwami kolumn jako zmiennymi - mysqli_fetch_array - Tablica asocjacyjna ORAZ Tablica numeryczna (można użyć argumentów, aby uzyskać jedną lub drugą)
- mysqli_fetch_row - Tablica liczbowa
Styl obiektowy
while($row = $result->fetch_assoc()) {
var_dump($row);
}
Styl proceduralny
while($row = mysqli_fetch_assoc($result)) {
var_dump($row);
}
Aby uzyskać dokładne informacje z wyników, możemy użyć:
while ($row = $result->fetch_assoc()) {
echo 'Name and surname: '.$row['name'].' '.$row['surname'].'<br>';
echo 'Age: '.$row['age'].'<br>'; // Prints info from 'age' column
}
Zamknij połączenie
Po zakończeniu wysyłania zapytań do bazy danych zaleca się zamknięcie połączenia w celu zwolnienia zasobów.
Styl obiektowy
$conn->close();
Styl proceduralny
mysqli_close($conn);
Uwaga : Połączenie z serwerem zostanie zamknięte, gdy tylko zakończy się wykonywanie skryptu, chyba że zostanie wcześniej zamknięte przez jawne wywołanie funkcji zamknięcia połączenia.
Przypadek użycia: Jeśli nasz skrypt wymaga sporego przetworzenia po pobraniu wyniku i pobrał pełny zestaw wyników, zdecydowanie powinniśmy zamknąć połączenie. Gdybyśmy tego nie robili, istnieje prawdopodobieństwo, że serwer MySQL osiągnie limit połączeń, gdy serwer jest intensywnie wykorzystywany.
Przygotowane instrukcje w MySQLi
Przeczytaj Zapobieganie wstrzykiwaniu SQL za pomocą zapytań parametryzowanych, aby uzyskać pełne omówienie, dlaczego przygotowane instrukcje pomagają zabezpieczyć instrukcje SQL przed atakami SQL Injection
Zmienna $conn
tutaj jest obiektem MySQLi. Aby uzyskać więcej informacji, zobacz przykład połączenia MySQLi .
W obu przykładach zakładamy, że $sql
jest
$sql = "SELECT column_1
FROM table
WHERE column_2 = ?
AND column_3 > ?";
The ?
reprezentuje wartości, które podamy później. Pamiętaj, że nie potrzebujemy cytatów dla symboli zastępczych, niezależnie od typu. Możemy również podać symbole zastępcze w częściach danych zapytania, co oznacza SET
, VALUES
i WHERE
. Nie można używać symboli zastępczych w częściach SELECT
ani FROM
.
Styl obiektowy
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();
}
Styl proceduralny
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);
}
Pierwszy parametr $stmt->bind_param
lub drugi parametr mysqli_stmt_bind_param
jest określony przez typ danych odpowiedniego parametru w zapytaniu SQL:
Parametr | Typ danych związanego parametru |
---|---|
i | liczba całkowita |
d | podwójnie |
s | strunowy |
b | kropelka |
Twoja lista parametrów musi być w kolejności podanej w zapytaniu. W tym przykładzie si
oznacza, że pierwszy parametr ( column_2 = ?
) Jest łańcuchem, a drugi parametr ( column_3 > ?
) Jest liczbą całkowitą.
Aby uzyskać dane, zobacz Jak uzyskać dane z przygotowanej instrukcji
Uciekające struny
Ucieczka ciągów to starsza ( i mniej bezpieczna ) metoda zabezpieczania danych do wstawienia do zapytania. Działa przy użyciu funkcji MySQL mysql_real_escape_string () do przetwarzania i odkażania danych (innymi słowy, PHP nie robi ucieczki). Interfejs API MySQLi zapewnia bezpośredni dostęp do tej funkcji
$escaped = $conn->real_escape_string($_GET['var']);
// OR
$escaped = mysqli_real_escape_string($conn, $_GET['var']);
W tym momencie masz ciąg, który MySQL uważa za bezpieczny do użycia w bezpośrednim zapytaniu
$sql = 'SELECT * FROM users WHERE username = "' . $escaped . '"';
$result = $conn->query($sql);
Dlaczego więc nie jest to tak bezpieczne, jak przygotowane oświadczenia ? Istnieją sposoby na oszukiwanie MySQL w celu utworzenia ciągu, który uważa za bezpieczny. Rozważ następujący przykład
$id = mysqli_real_escape_string("1 OR 1=1");
$sql = 'SELECT * FROM table WHERE id = ' . $id;
1 OR 1=1
nie reprezentuje danych, które ucieknie MySQL, ale nadal oznacza to wstrzyknięcie SQL. Istnieją również inne przykłady, które reprezentują miejsca, w których zwraca niebezpieczne dane. Problem polega na tym, że funkcja ucieczki MySQL ma na celu dostosowanie danych do składni SQL . NIE jest zaprojektowany, aby upewnić się, że MySQL nie może mylić danych użytkownika z instrukcjami SQL .
MySQLi Wstaw identyfikator
Pobierz ostatni identyfikator wygenerowany przez zapytanie INSERT
w tabeli z kolumną AUTO_INCREMENT .
Styl obiektowy
$id = $conn->insert_id;
Styl proceduralny
$id = mysqli_insert_id($conn);
Zwraca zero, jeśli w połączeniu nie było wcześniejszego zapytania lub jeśli zapytanie nie zaktualizowało wartości AUTO_INCREMENT.
Wstaw identyfikator podczas aktualizacji wierszy
Zwykle instrukcja UPDATE
nie zwraca identyfikatora wstawiania, ponieważ identyfikator AUTO_INCREMENT
jest zwracany tylko wtedy, gdy nowy wiersz został zapisany (lub wstawiony). Jednym ze sposobów aktualizowania nowego identyfikatora jest użycie INSERT ... ON DUPLICATE KEY UPDATE
do aktualizacji.
Przygotuj przykłady do naśladowania:
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 |
+----+--------+------+
Przypadek IODKU przeprowadzającego „aktualizację” i LAST_INSERT_ID()
pobierającego odpowiedni 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)
Przypadek, w którym IODKU wykonuje „wstaw”, a LAST_INSERT_ID()
pobiera nowy 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)
Wynikowa zawartość tabeli:
SELECT * FROM iodku;
+----+--------+------+
| id | name | misc |
+----+--------+------+
| 1 | Leslie | 123 |
| 2 | Sally | 3333 | -- IODKU changed this
| 3 | Dana | 789 | -- IODKU added this
+----+--------+------+
Debugowanie SQL w MySQLi
Twoje zapytanie nie powiodło się (zobacz MySQLi connect, aby dowiedzieć się, jak stworzyliśmy $conn
)
$result = $conn->query('SELECT * FROM non_existent_table'); // This query will fail
Jak dowiemy się, co się stało? $result
jest false
więc to nie pomaga. Na szczęście connect $conn
może nam powiedzieć, co MySQL powiedział nam o awarii
trigger_error($conn->error);
lub proceduralne
trigger_error(mysqli_error($conn));
Powinieneś otrzymać błąd podobny do
Tabela „my_db.non_existent_table” nie istnieje
Jak uzyskać dane z przygotowanego wyciągu
Przygotowane wyciągi
Zobacz Przygotowane instrukcje w MySQLi, aby dowiedzieć się, jak przygotować i wykonać zapytanie.
Wiązanie wyników
Styl obiektowy
$stmt->bind_result($forename);
Styl proceduralny
mysqli_stmt_bind_result($stmt, $forename);
Problem z użyciem bind_result
polega na tym, że wymaga instrukcji, aby określić kolumny, które będą używane. Oznacza to, że aby powyższe zadziałało, zapytanie musi wyglądać następująco: SELECT forename FROM users
. Aby dołączyć więcej kolumn, po prostu dodaj je jako parametry do funkcji bind_result
(i upewnij się, że dodajesz je do zapytania SQL).
W obu przypadkach przypisujemy kolumnę forename
do zmiennej $forename
. Funkcje te przyjmują tyle argumentów, ile kolumn, które chcesz przypisać. Przypisanie jest wykonywane tylko raz, ponieważ funkcja wiąże się przez odwołanie.
Następnie możemy zapętlić w następujący sposób:
Styl obiektowy
while ($stmt->fetch())
echo "$forename<br />";
Styl proceduralny
while (mysqli_stmt_fetch($stmt))
echo "$forename<br />";
Wadą tego jest to, że musisz przypisać wiele zmiennych jednocześnie. Utrudnia to śledzenie dużych zapytań. Jeśli masz zainstalowany MySQL Native Driver ( mysqlnd
) , wszystko, co musisz zrobić, to użyć get_result .
Styl obiektowy
$result = $stmt->get_result();
Styl proceduralny
$result = mysqli_stmt_get_result($stmt);
Jest to o wiele łatwiejsze w obsłudze, ponieważ teraz otrzymujemy obiekt mysqli_result . Jest to ten sam obiekt, który zwraca mysqli_query . Oznacza to, że możesz użyć zwykłej pętli wyników, aby uzyskać dane.
Co jeśli nie mogę zainstalować mysqlnd
?
W takim przypadku @Sophivorus udzielił Ci tej niesamowitej odpowiedzi .
Ta funkcja może wykonywać zadanie get_result
bez instalowania go na serwerze. Po prostu zapętla wyniki i buduje tablicę asocjacyjną
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;
}
Możemy wtedy użyć funkcji, aby uzyskać takie wyniki, tak jakbyśmy używali 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>';
}
Będzie miał takie same dane wyjściowe, jakbyś mysqlnd
sterownika mysqlnd
, mysqlnd
że nie musi być zainstalowany. Jest to bardzo przydatne, jeśli nie możesz zainstalować tego sterownika w systemie. Wystarczy wdrożyć to rozwiązanie.