Biorąc pod uwagę tablicę identyfikatorów $galleries = array(1,2,5)
, chcę mieć zapytanie SQL, które wykorzystuje wartości tablicy w jej klauzuli WHERE, takie jak:
SELECT *
FROM galleries
WHERE id = /* values of array $galleries... eg. (1 || 2 || 5) */
Jak mogę wygenerować ten ciąg zapytania do użycia z MySQL?
Odpowiedzi:
źródło
$galleries
należy zweryfikować przed tą instrukcją! Przygotowane instrukcje nie obsługują tablic AFAIK, więc jeśli przyzwyczaisz się do wiązania zmiennych, możesz tutaj łatwo wprowadzić SQL.$galleries
miał następującą wartość:array('1); SELECT password FROM users;/*')
. Jeśli tego nie zrobisz, zapytanie zostanie odczytaneSELECT * FROM galleries WHERE id IN (1); SELECT password FROM users;/*)
. Zmień nazwy tabeli i kolumny na coś, co masz w bazie danych i spróbuj tego zapytania, sprawdź wyniki. Jako wynik znajdziesz listę haseł, a nie listę galerii. W zależności od sposobu wyprowadzania danych lub tego, co robi skrypt z tablicą nieoczekiwanych danych, dane te mogą zostać wyświetlone w widoku publicznym ... ouch.$galleries
co podano w pytaniu, a ty wykorzystujesz go przy użyciu wspomnianej „podatności na wstrzyknięcie sql”. Jeśli nie możesz - płacisz mi 200 USD. Co ty na to?Korzystanie z PDO: [1]
Korzystanie z MySQLi [2]
Wyjaśnienie:
Użyj
IN()
operatora SQL , aby sprawdzić, czy wartość istnieje na danej liście.Ogólnie wygląda to tak:
Możemy zbudować wyrażenie do umieszczenia wewnątrz
()
naszej tablicy. Zauważ, że w nawiasie musi znajdować się co najmniej jedna wartość, inaczej MySQL zwróci błąd; oznacza to upewnienie się, że nasza tablica wejściowa ma co najmniej jedną wartość. Aby zapobiec atakom typu SQL injection, najpierw wygeneruj?
dla każdego elementu wejściowego, aby utworzyć sparametryzowane zapytanie. Tutaj zakładam, że tablica zawierająca twoje identyfikatory nazywa się$ids
:Podana tablica wejściowa trzech elementów
$select
będzie wyglądać następująco:Ponownie zauważ, że
?
dla każdego elementu w tablicy wejściowej znajduje się znak . Następnie użyjemy PDO lub MySQLi do przygotowania i wykonania zapytania, jak wspomniano powyżej.Używanie
IN()
operatora z ciągami znakówŁatwo jest zmieniać ciągi znaków i liczby całkowite ze względu na związane parametry. W przypadku ChNP zmiana nie jest wymagana; dla MySQLi zmień
str_repeat('i',
na,str_repeat('s',
jeśli chcesz sprawdzić ciągi.[1]: Pominąłem sprawdzanie błędów pod kątem zwięzłości. Musisz sprawdzić typowe błędy dla każdej metody bazy danych (lub ustawić sterownik DB tak, aby generował wyjątki).
[2]: Wymaga PHP 5.6 lub wyższej. Znowu pominąłem pewne sprawdzanie błędów pod kątem zwięzłości.
źródło
$statement->bind_param(str_repeat('i', count($ids)), ...$ids);
, to...
jest rozszerzenie identyfikatora z tablicy do wielu parametrów. Jeśli masz na myśliexpr IN (value,...)
to oznacza to, że może być więcej wartości npWHERE id IN (1, 3, 4)
. Musi być tylko jeden....
: wiki.php.net/rfc/argument_unpackingints:
smyczki:
źródło
Zakładając, że wcześniej odpowiednio odkażysz swoje dane wejściowe ...
Następnie dostosuj zapytanie:
Podaj wartości odpowiednio w zależności od zestawu danych.
źródło
Posługiwać się:
Działa prosta
for each
pętla.Sposób Flaviusa / AvatarKava jest lepszy, ale upewnij się, że żadna z wartości tablicy nie zawiera przecinków.
źródło
Jako odpowiedź Flaviusa Stefa możesz
intval()
się upewnić, że wszystkieid
są wartościami int:źródło
Dla MySQLi z funkcją Escape:
W przypadku PDO z przygotowanym wyciągiem:
źródło
Powinniśmy zająć się lukami w iniekcji SQL i pustym stanem . Zajmę się obydwoma jak poniżej.
Dla czystego tablicy numerycznej użyciu odpowiedniego mianowicie konwersji typu
intval
lubfloatval
lubdoubleval
nad każdym elementem. Dla typów ciągów,mysqli_real_escape_string()
które można również zastosować do wartości liczbowych, jeśli chcesz. MySQL dopuszcza zarówno liczby, jak i warianty dat jako ciąg znaków .Aby odpowiednio uniknąć wartości przed przekazaniem do zapytania, utwórz funkcję podobną do:
Taka funkcja najprawdopodobniej byłaby już dostępna w twojej aplikacji, a może już ją stworzyłeś.
Wyczyść tablicę ciągów, np .:
Tablica numeryczna może być zdezynfekowana za pomocą
intval
lubfloatval
lubdoubleval
zamiast tego odpowiednio:Następnie w końcu zbuduj warunek zapytania
lub
Ponieważ tablica może być czasami pusta,
$galleries = array();
należy zauważyć, żeIN ()
nie zezwala na pustą listę. Można również użyćOR
zamiast tego, ale problem pozostaje. Tak więc powyższa kontrolacount($values)
ma zapewnić to samo.I dodaj go do końcowego zapytania:
źródło
$query = 'SELECT * FROM galleries WHERE ' . (count($gallaries) ? "id IN ('" . implode("', '", array_map('escape', $gallaries)) . "')" : 0);
Bezpieczniej
źródło
Biblioteka SafeMySQL płk Shrapnela dla PHP zawiera sparametryzowane symbole zastępcze w sparametryzowanych zapytaniach i zawiera kilka wygodnych symboli zastępczych do pracy z tablicami. Symbol
?a
zastępczy rozwija tablicę do rozdzielonej przecinkami listy ciągów znaków *.Na przykład:
* Zauważ, że ponieważ MySQL wykonuje automatyczny przymus typu, nie ma znaczenia, że SafeMySQL skonwertuje powyższe identyfikatory na ciągi - nadal otrzymasz poprawny wynik.
źródło
Możemy użyć tej klauzuli „WHERE id IN”, jeśli odpowiednio przefiltrujemy tablicę wejściową. Coś takiego:
Podobnie jak w poniższym przykładzie:
Tj. Teraz powinieneś bezpiecznie używać
$query = "SELECT * FROM galleries WHERE id IN ({$galleryIds})";
źródło
Możesz mieć stolik
texts
(T_ID (int), T_TEXT (text))
i stoliktest
(id (int), var (varchar(255)))
W
insert into test values (1, '1,2,3') ;
następujących wierszy wyjściowe będzie z tekstami stole, gdzieT_ID IN (1,2,3)
:W ten sposób możesz zarządzać prostą relacją bazy danych n2m bez dodatkowej tabeli i używając tylko SQL bez potrzeby używania PHP lub innego języka programowania.
źródło
Więcej przykładu:
źródło
Oprócz użycia zapytania IN masz do tego dwie opcje, ponieważ w zapytaniu IN istnieje ryzyko podatności na iniekcję SQL. Możesz użyć pętli, aby uzyskać dokładne dane, lub możesz użyć zapytania z literą OR
źródło
Bezpieczny sposób bez PDO:
(array)$ids
Rzuć$ids
zmienną na tablicęarray_map
Przekształć wszystkie wartości tablic na liczby całkowitearray_unique
Usuń powtarzające się wartościarray_filter
Usuń wartości zeroweimplode
Połącz wszystkie wartości z wyborem INźródło
Ponieważ oryginalne pytanie dotyczy tablicy liczb i używam tablicy ciągów, nie mogłem sprawić, by podane przykłady działały.
Odkryłem, że każdy ciąg musi być zamknięty w pojedynczych cudzysłowach, aby pracować z
IN()
funkcją.Oto moje rozwiązanie
Jak widać, pierwsza funkcja otacza każdą zmienną tablicową,
single quotes (\')
a następnie wszczepia tablicę.UWAGA:
$status
nie zawiera pojedynczych cudzysłowów w instrukcji SQL.Prawdopodobnie jest lepszy sposób dodawania cytatów, ale to działa.
źródło
$filter = "'" . implode("','",$status) . "'";
'
wewnątrz ciągu? Wrażliwość na SQL Injection. Użyj PDO :: quote lub mysqli_real_escape_string.Poniżej znajduje się metoda, której użyłem, używając PDO z nazwanymi symbolami zastępczymi dla innych danych. Aby pokonać iniekcję SQL, filtruję tablicę, aby zaakceptować tylko wartości, które są liczbami całkowitymi, i odrzucam wszystkie inne.
źródło
Podstawowe metody zapobiegania wstrzykiwaniu SQL:
Użycie przygotowanych instrukcji i sparametryzowanych zapytań jest uważane za lepszą praktykę, ale jeśli wybierzesz metodę znaków specjalnych, możesz wypróbować mój przykład poniżej.
Możesz wygenerować zapytania,
array_map
dodając pojedynczy cytat do każdego z elementów w$galleries
:Wygenerowany $ sql var będzie:
źródło