geavanceerd zoeken
ik ben bezig met het maken van een script om geavanceerd te kunnen zoeken.
er zijn drie kolommen: titel, jaar en vol_naam (dit zijn dus ook drie invoervelden in het formulier)
Als je alle drie de formulierenvelden invuld en dan uitvoert dan werkt de zoekfunctie.
Maar als je alleen op titel zoekt en de andere twee velden niet invuld dan krijg ik de foutmelding: Warning: mysqli_fetch_assoc() expects parameter 1 to be mysqli_result, boolean given.
ik heb geprobeerd dit op te lossen door een nieuwe case te maken en met een multiquery maar dit werkt dus ook niet.
mijn vraag is: hoe kun je, als je alleen het titel veld invuld dat je dan alleen op titel zoekt en de andere velden 'negeert'?
de code is:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
if(isset($_POST['zoeken'])){
$zoekwoord = $_POST['zoekwoord'];
$beginjaar = $_POST['beginjaar'];
$eindjaar = $_POST['eindjaar'];
if(isset($_POST['criteria'])){
$select1 = $_POST['criteria'];
$bijdrager = $_POST['bijdrager'];
switch ($select1) {
case 'titel':
$bijdr_id = $_SESSION['bijdr_id'];
echo $bijdr_id;
$sql = "SELECT f.titel, f.jaar, b.vol_naam FROM tblfoto_info f, tblbijdrager b WHERE (b.bijdr_id = f.bijdr_id OR titel LIKE '%" . $zoekwoord . "%' OR jaar BETWEEN $beginjaar AND $eindjaar) AND b.bijdr_id = $bijdr_id";
$result = mysqli_query($conn, $sql);
while($row = mysqli_fetch_assoc($result)) {
$titel = $row['titel'];
$jaar = $row['jaar'];
$bijdrager = $row['vol_naam'];
// $info = $row['info'];
echo "<ul>";
echo "<li> $titel</li>";
echo "<li>$jaar</li>";
echo "<li>$bijdrager</li>";
//echo "<li>$info</li>";
echo "</ul>";
}
break;
}}}
$zoekwoord = $_POST['zoekwoord'];
$beginjaar = $_POST['beginjaar'];
$eindjaar = $_POST['eindjaar'];
if(isset($_POST['criteria'])){
$select1 = $_POST['criteria'];
$bijdrager = $_POST['bijdrager'];
switch ($select1) {
case 'titel':
$bijdr_id = $_SESSION['bijdr_id'];
echo $bijdr_id;
$sql = "SELECT f.titel, f.jaar, b.vol_naam FROM tblfoto_info f, tblbijdrager b WHERE (b.bijdr_id = f.bijdr_id OR titel LIKE '%" . $zoekwoord . "%' OR jaar BETWEEN $beginjaar AND $eindjaar) AND b.bijdr_id = $bijdr_id";
$result = mysqli_query($conn, $sql);
while($row = mysqli_fetch_assoc($result)) {
$titel = $row['titel'];
$jaar = $row['jaar'];
$bijdrager = $row['vol_naam'];
// $info = $row['info'];
echo "<ul>";
echo "<li> $titel</li>";
echo "<li>$jaar</li>";
echo "<li>$bijdrager</li>";
//echo "<li>$info</li>";
echo "</ul>";
}
break;
}}}
Waar is de foutafhandeling voor de query? De reden is eenvoudig genoeg, als je beginjaar en eindjaar niet invult krijg je een query die niet klopt.
ok, maar hoe kun je dit het beste afhandelen?
Gewijzigd op 22/10/2017 14:25:17 door Ben van Velzen
Als je enkel een beginjaar invult zul je dus bijvoorbeeld moeten kijken vanaf dat jaar, als je enkel een eindjaar invult zul je moeten kijken tot (en met of tot en zonder) dat jaar. Als je beide invult zul je hiertussen moeten zoeken.
De vorm van je uiteindelijke query hangt dus direct af van de al dan niet ingevulde velden.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
// initialisatie
$titel = null;
$beginjaar = null;
$eindjaar = null;
/* overschrijf de variabelen met de POST variabelen, bijvoorbeeld: */
if(isset($_POST['titel'] && !is_empty($_POST['titel'])) {
$titel = $_POST['titel'];
}
// en zo het zelfde voor beginjaar en eindjaar
$sql = 'SELECT * FROM tabel';
$whereParts = array();
if($titel !== null) {
$whereParts[] = "titel LIKE '%" . $titel . "%'";
}
if($beginjaar !== null) {
$whereParts[] = "jaar >= $beginjaar";
}
if($eindjaar !== null) {
$whereParts[] = "jaar <= $eindjaar";
}
if(count($whereParts)) {
$sql . = ' WHERE ' . implode(' AND ', $whereParts);
}
$result = mysqli($conn, $sql);
// ...
?>
// initialisatie
$titel = null;
$beginjaar = null;
$eindjaar = null;
/* overschrijf de variabelen met de POST variabelen, bijvoorbeeld: */
if(isset($_POST['titel'] && !is_empty($_POST['titel'])) {
$titel = $_POST['titel'];
}
// en zo het zelfde voor beginjaar en eindjaar
$sql = 'SELECT * FROM tabel';
$whereParts = array();
if($titel !== null) {
$whereParts[] = "titel LIKE '%" . $titel . "%'";
}
if($beginjaar !== null) {
$whereParts[] = "jaar >= $beginjaar";
}
if($eindjaar !== null) {
$whereParts[] = "jaar <= $eindjaar";
}
if(count($whereParts)) {
$sql . = ' WHERE ' . implode(' AND ', $whereParts);
}
$result = mysqli($conn, $sql);
// ...
?>
Wat je dus in feite hebt is dus een SQL-string met afwisselend SQL en (USER) DATA van buitenaf:
Het is heel erg belangrijk dat de DATA in de SQL-query niet geïnterpreteerd kan worden als SQL-code. Hiermee zou iemand effectief de werking van de query kunnen aanpassen die in het meest vervelende geval lijdt tot manipulatie of diefstal van gevoelige informatie. Dit (DATA die als SQL geïnterpreteerd wordt) staat beter bekend als SQL-injectie.
Wat je hier enerzijds tegen zou kunnen doen is je invoer filteren: jaartallen zouden numeriek moeten zijn.
Maar wat misschien nog veel belangrijker is is het escapen (en daarmee onschadelijk maken) van uitvoer. Hiermee zorg je ervoor dat DATA niet als SQL geïnterpreteerd kan worden en hierdoor is SQL-injectie niet meer mogelijk.
Je escaped uitvoer (USER DATA) door middel van het toepassen van de escaping-functie real_escape_string() IN COMBINATIE MET het quoten (voorzien van quotes) van de ge-escapete string. Het een is NIET VEILIG zonder het ander.
Wat je moet begrijpen is dat real_escape_string() enkel speciale karakters (die een speciale betekenis binnen SQL hebben) onschadelijk maakt. real_escape_string() is dus geen wondermiddel. Het volgende stuk tekst (dit zou dus een ingevoegd stuk DATA kunnen zijn) bevat informatie die een speciale betekenis in SQL heeft, maar die verder ongemoeid wordt gelaten door real_escape_string():
Dit zou catastrofale gevolgen kunnen hebben die (bijvoorbeeld) securitychecks bypassen. Zorg dus dat je ALTIJD quotes om de ge-escapete DATA-passages zet.
Wees dus altijd zeer voorzichtig wanneer je USER DATA gebruikt en een goede gewoonte is om deze NOOIT te vertrouwen.
Gewijzigd op 23/10/2017 00:17:48 door Thomas van den Heuvel
Ik heb een vraag over de real_escape_string().
Als je OR 1=1 uitvoert in een form veld, heb je dus een sql injectie, ook maak je gebruik van real_escape_string().
Maar als je nu gebruik maakt van prepared statement, is dit dan wel waterdicht?
zie http://php.net/manual/en/mysqli-stmt.bind-result.php
Hoe kun je dan het beste beschermen tegen sql-injecties?
Quote:
Als je OR 1=1 uitvoert in een form veld, heb je dus een sql injectie, ook maak je gebruik van real_escape_string().
Nee, dat is niet wat ik zeg. Wat ik bedoel is dat je real_escape_string() altijd moet gebruiken in combinatie met quotes. Alleen deze combinatie is veilig. Enkel (enkele) quotes om invoer zetten is niet veilig. Enkel real_escape_string() gebruiken is niet veilig. Alleen de combinatie.
Quote:
Maar als je nu gebruik maakt van prepared statement, is dit dan wel waterdicht?
Geen enkel verkeerd gebruik van een methode is veilig :). Als je bijvoorbeeld de DATA nog steeds concateneert in een string in een opzet waarbij je prepared statements zou gebruiken ben je nog steeds nat (dit is dus een verkeerd gebruik). Daarnaast is -in ieder geval in MySQLi- het gebruik van prepared statements nogal omslachtig. Ik gebruik dit in ieder geval niet, teveel moeite om data uit de database op te hoesten. Tenzij je wellicht een wrapper schrijft die je het leven wat aangenamer kan maken. Nee, met enige discipline kun je best zonder prepared statements.
Quote:
Hoe kun je dan het beste beschermen tegen sql-injecties?
Je kunt je het beste wapenen tegen SQL-injectie door de principes die dit mogelijk maken te begrijpen, en hier vervolgens op te acteren. In mijn vorige bericht doe ik beide uit de doeken.
Daarnaast moet je in alles wat je doet je bewust zijn van input (stel jezelf de vraag: kan ik deze DATA vertrouwen (spoiler: het antwoord is bijna altijd NEE, zelfs als de data in je database zit, als je deze weer uitleest zou je deze nog steeds niet moeten vertrouwen want deze is afkomstig uit een externe bron)) en output.
Input zou je altijd moeten filteren als deze aan een bepaald formaat zou moeten voldoen en output zou je altijd moeten escapen binnen de context (HTML, SQL et cetera) waarin je werkt, tenzij je hier een speciale -en gedocumenteerde- reden voor hebt om dit niet te doen. Kort gezegd is dit de aloude vuistregel filter input, escape output. In alles wat je doet.
Daarbij moet gezegd worden dat (een correcte werking van) escaping-functionaliteit (direct) afhankelijk is van de gebruikte character encoding. Dus zorg ook dat je daar kaas van gegeten hebt. Want There Ain't No Such Thing As Plain Text.
Gewijzigd op 23/10/2017 14:55:32 door Thomas van den Heuvel