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

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.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow