Zasady dodawania zmiennej PHP wewnątrz dowolnej instrukcji MySQL są jasne i proste:
- Dowolna zmienna reprezentująca literał danych SQL , (lub w uproszczeniu - ciąg SQL lub liczba) MUSI być dodany za pomocą przygotowanej instrukcji. Bez wyjątków.
- Każda inna część zapytania, taka jak słowo kluczowe SQL, nazwa tabeli lub pola albo operator – należy przefiltrować przez białą listę .
Ponieważ twój przykład obejmuje tylko literały danych, wszystkie zmienne muszą być dodane za pomocą symboli zastępczych (zwanych również parametrami). Aby to zrobić:
- W instrukcji SQL zastąp wszystkie zmienne wypełniaczami
- przygotuj się wynikowe zapytanie
- powiąż zmienne do symboli zastępczych
- wykonaj zapytanie
A oto jak to zrobić ze wszystkimi popularnymi sterownikami baz danych PHP:
Dodawanie literałów danych za pomocą mysql ext
Taki sterownik nie istnieje .
Dodawanie literałów danych za pomocą mysqli
$type = 'testing';
$reporter = "John O'Hara";
$query = "INSERT INTO contents (type, reporter, description)
VALUES(?, ?, 'whatever')";
$stmt = $mysqli->prepare($query);
$stmt->bind_param("ss", $type, $reporter);
$stmt->execute();
Kod jest nieco skomplikowany, ale szczegółowe wyjaśnienie wszystkich tych operatorów można znaleźć w moim artykule Jak uruchomić WSTAW zapytanie za pomocą Mysqli , a także rozwiązanie, które znacznie ułatwia ten proces.
W przypadku zapytania SELECT musisz dodać tylko wywołanie get_result()
metoda, aby uzyskać znajomy mysqli_result
skąd możesz pobrać dane w zwykły sposób:
$reporter = "John O'Hara";
$stmt = $mysqli->prepare("SELECT * FROM users WHERE name=?");
$stmt->bind_param("s", $reporter);
$stmt->execute();
$result = $stmt->get_result();
$row = $result->fetch_assoc(); // or while (...)
Dodawanie literałów danych za pomocą PDO
$type = 'testing';
$reporter = "John O'Hara";
$query = "INSERT INTO contents (type, reporter, description)
VALUES(?, ?, 'whatever')";
$stmt = $pdo->prepare($query);
$stmt->execute([$type, $reporter]);
W PDO możemy połączyć części z bindowaniem i wykonaniem, co jest bardzo wygodne. PDO obsługuje również nazwane symbole zastępcze, które niektórzy uważają za niezwykle wygodne.
Dodawanie słów kluczowych lub identyfikatorów
Czasami musimy dodać zmienną, która reprezentuje inną część zapytania, taką jak słowo kluczowe lub identyfikator (baza danych, tabela lub nazwa pola). To rzadki przypadek, ale lepiej być przygotowanym.
W takim przypadku zmienna musi zostać porównana z listą wartości jasno napisane w twoim skrypcie. Jest to wyjaśnione w moim innym artykule, Dodawanie nazwy pola w klauzuli ORDER BY na podstawie wyboru użytkownika :
Niestety PDO nie ma miejsca na identyfikatory (nazwy tabel i pól), dlatego programista musi je odfiltrować ręcznie. Taki filtr jest często nazywany „białą listą” (gdzie wymieniamy tylko dozwolone wartości) w przeciwieństwie do „czarnej listy”, na której podajemy niedozwolone wartości.
Dlatego musimy wyraźnie wymienić wszystkie możliwe warianty w kodzie PHP, a następnie wybrać z nich.
Oto przykład:
$orderby = $_GET['orderby'] ?: "name"; // set the default value
$allowed = ["name","price","qty"]; // the white list of allowed field names
$key = array_search($orderby, $allowed, true); // see if we have such a name
if ($key === false) {
throw new InvalidArgumentException("Invalid field name");
}
Dokładnie to samo podejście powinno być stosowane dla kierunku,
$direction = $_GET['direction'] ?: "ASC";
$allowed = ["ASC","DESC"];
$key = array_search($direction, $allowed, true);
if ($key === false) {
throw new InvalidArgumentException("Invalid ORDER BY direction");
}
Po takim kodzie oba $direction
i $orderby
zmienne można bezpiecznie umieścić w zapytaniu SQL, ponieważ są one równe jednemu z dozwolonych wariantów lub zostanie zgłoszony błąd.
Ostatnią rzeczą, o której należy wspomnieć o identyfikatorach, muszą być również sformatowane zgodnie z konkretną składnią bazy danych. W przypadku MySQL powinien to być backtick
znaki wokół identyfikatora. Tak więc końcowy ciąg zapytania dla naszego zamówienia według przykładu to
$query = "SELECT * FROM `table` ORDER BY `$orderby` $direction";