(multiple) output dropdown correct weergeven
Als beginner is het mij gelukt om dropdown menu te maken vanuit een SQL db. Nu zou ik graag zien dat ook meerdere selecties in dit menu te maken zijn. Ook dit is deels gelukt, alleen bij de output wordt slechts 1 gekozen optie weergegeven. Wie kan mij een beetje op weg helpen? Veel dank.
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
<?php
include'dbh.php';
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>TST</title>
<link rel="stylesheet" type="text/css" href="style.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://fonts.googleapis.com/css2?family=Dosis:wght@500&family=Karla:ital@1&family=Nanum+Gothic:wght@700&family=Raleway:wght@300;400&display=swap" rel="stylesheet">
<style>
body{
text-align:center;
background-color: #EEEEEE;
}
.container{
width:1040px;
margin: 0px auto;
overflow: hidden;
background: white;
}
.container header{
width: 1040px;
text-align: center;
margin-top: 10px;
border-bottom: 1.4px solid #a9a9a9;
font-family: 'Karla', sans-serif;
font-size: 30px;
color: #242424;
float: left;
}
div.item{
width: 300px;
height: 220px;
margin-top: 15px;
margin-left: 3.5%;
font-family: sans-serif;
display: inline-block;
font-size: 13px;
float: left;
}
img{
border-radius: 3%;
}
a{
text-decoration:none;
color: inherit;
}
</style>
</head>
<?php
$resultcountry=$conn->query("SELECT DISTINCT country_caught FROM dataset ORDER BY country_caught ASC");
?>
<h1>SEARCH</h1>
<hr/>
<body>
<form id= method="GET" action="" >
<select name="country_caught" multiple >
<?php
while($rows=$resultcountry->fetch_assoc())
{
$country=$rows['country_caught'];
echo "<option style='display:none'>Country</option>
<option value='$country'>$country</option>";
}
?>
</select>
<button type="submit" name="submit-misc-search" >GO!</button>
</form>
<hr/>
<?php
if(isset($_GET['submit-misc-search'])){
$country=$_GET['country_caught'];
$sql1 = "SELECT * FROM dataset WHERE country_caught LIKE '$country' ";
$result1 = mysqli_query($conn, $sql1);
$queryResult1 = mysqli_num_rows($result1);
?>
<body>
<section class="container">
<?php
if($queryResult1 > 0)
echo
"<header>
<p>$country ($queryResult1)</p>
</header>";
{
while($row = mysqli_fetch_assoc($result1)){
echo " <div class='item'>
<a href='medium/".$row['photo_id'].".jpg'><img src='small/".$row['photo_id'].".jpg'</a><br>
</div>";
}
}
}
?>
</section>
</html>
include'dbh.php';
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>TST</title>
<link rel="stylesheet" type="text/css" href="style.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://fonts.googleapis.com/css2?family=Dosis:wght@500&family=Karla:ital@1&family=Nanum+Gothic:wght@700&family=Raleway:wght@300;400&display=swap" rel="stylesheet">
<style>
body{
text-align:center;
background-color: #EEEEEE;
}
.container{
width:1040px;
margin: 0px auto;
overflow: hidden;
background: white;
}
.container header{
width: 1040px;
text-align: center;
margin-top: 10px;
border-bottom: 1.4px solid #a9a9a9;
font-family: 'Karla', sans-serif;
font-size: 30px;
color: #242424;
float: left;
}
div.item{
width: 300px;
height: 220px;
margin-top: 15px;
margin-left: 3.5%;
font-family: sans-serif;
display: inline-block;
font-size: 13px;
float: left;
}
img{
border-radius: 3%;
}
a{
text-decoration:none;
color: inherit;
}
</style>
</head>
<?php
$resultcountry=$conn->query("SELECT DISTINCT country_caught FROM dataset ORDER BY country_caught ASC");
?>
<h1>SEARCH</h1>
<hr/>
<body>
<form id= method="GET" action="" >
<select name="country_caught" multiple >
<?php
while($rows=$resultcountry->fetch_assoc())
{
$country=$rows['country_caught'];
echo "<option style='display:none'>Country</option>
<option value='$country'>$country</option>";
}
?>
</select>
<button type="submit" name="submit-misc-search" >GO!</button>
</form>
<hr/>
<?php
if(isset($_GET['submit-misc-search'])){
$country=$_GET['country_caught'];
$sql1 = "SELECT * FROM dataset WHERE country_caught LIKE '$country' ";
$result1 = mysqli_query($conn, $sql1);
$queryResult1 = mysqli_num_rows($result1);
?>
<body>
<section class="container">
<?php
if($queryResult1 > 0)
echo
"<header>
<p>$country ($queryResult1)</p>
</header>";
{
while($row = mysqli_fetch_assoc($result1)){
echo " <div class='item'>
<a href='medium/".$row['photo_id'].".jpg'><img src='small/".$row['photo_id'].".jpg'</a><br>
</div>";
}
}
}
?>
</section>
</html>
Echter meot je wel eerst aangeven dat de output een array moet worden. Dat kan door twee open-en-sluitende blokhaken achter je de waarde van eht name-attrubute te zetten: name="country_caught[]"
Vervolgens kan je alle gekozen waardes met bijv. foreach() uitlezen uit $_POST['country_caught'] die in feite dus een array is.
Verder wil ik je wel even wijzen dat lijn 88 een SQL-injection heeft. Jijzelf en jan-en-alleman kunnen je query dus manipuleren met onbedoelde en zelfde kwade gevolgen. Dus escape $country even met mysqli_real_escape_string().
Als ik verder nog een tip mag geven: Stap af van genummerde queries. Nu weet je nog wat iets doet, maar als je script groter is, dan moet je dat steeds opzoeken. Iets met $result_country zegt precies wat de result is.
Gewijzigd op 12/10/2020 12:41:18 door - Ariën -
- Ariën - op 12/10/2020 12:40:56:
Dus escape $country even met mysqli_real_escape_string().
Alleen prepared statements beschermen volledig tegen SQL-injectie.
https://www.php.net/manual/en/mysqli.quickstart.prepared-statements.php
mysqli_real_escape_string() werkt even goed.
Vroeger was het wat buggy, maar tegenwoordig werkt het prima, zolang je het goed aanpakt. Prepared statements zijn ook een keuze.
Gewijzigd op 12/10/2020 13:06:07 door - Ariën -
Dank voor je snelle reply! Die tip mbt de name-attribute had ik indd ook gevonden (en geprobeerd), helaas werkte dat voor mij niet. Maar dat komt waarschijnlijk omdat ik het fout doe :-). Het probleem zit hem vooral in de output, dus hoe krijg ik een 'multiple' output. Op dit moment kan ik dus meerdere "country" selecteren, echter hij spuugt dan enkel 1 selectie goed uit. Jouw tip mbt foreach() zou denk ik de oplossing zijn. Als beginner weet ik die echter niet goed te intregreren in onderstaande code, wellicht kan iemand mij helpen? :
Code (php)
Een zoekfunctie via GET laten werken, kan ik goed begrijpen. Maar een formulier om data in te voeren/te bewerken kan prima via POST.
Verder klopt die SQL ook niet. Je hebt een hele bak met geselcteerde country's. Die kan je niet zomaar aan een LIKE query voeren. Die moet je dan stuk per stuk uitlezen en met implode() combineren tot een SELECT... IN () query.
Maar gezien je twee queries uitvoert, dan vraag ik me af of een JOIN niet slimmer is.
Gewijzigd op 12/10/2020 14:27:14 door - Ariën -
Dank voor je snelle reply. De reden voor het GET ipv POST; ik copy paste soms de link zodat iemand anders deze kan openen en dezelfde output ziet. Thanks ook voor je security (SQL injectie) opmerking, daar ga ik zeker wat mee doen.
De huidige code is echt ontstaan vanuit de gedachte dat er 1 "country" geselecteerd wordt. Dat werkte prima.. Maarja, nu kom ik tot het inzicht dat meerdere landen als output ook wel handig is.
Is de huidige code niet met een kleine, intelligente verandering aan te passen, zodat meerdere landen op dezelfde manier worden weergegeven? Of moet ik het echt grondig gaan her ontwerpen?
Maak bij voorkeur een stroomdiagram die aangeeft wat er moet gebeuren, en hoe een request plaatsvindt.
Gewijzigd op 12/10/2020 15:23:09 door - Ariën -
Ad Fundum op 12/10/2020 12:54:52:
Alleen prepared statements beschermen volledig tegen SQL-injectie.
Alleen een juist gebruik van een bepaalde methodiek leidt tot veilige queries. Er zijn nog zat mensen die lappen SQL concateneren in de een query die (ook) gebruik maakt van prepared statements.
- Ariën - op 12/10/2020 13:04:15:
mysqli_real_escape_string() werkt even goed.
Ook deze stelling is niet helemaal juist. In een opzet waarbij je geen gebruik maakt van prepared statements is enkel de combinatie van het gebruik van quotes en real_escape_string() veilig, zoals hier (interne link) staat uitgelegd. real_escape_string() is ook alles behalve een wondermiddel. Het is en blijft belangrijk dat je snapt wat er gebeurt en wat ervoor zorgt dat queries veilig zijn en blijven.
Johan Steel op 12/10/2020 15:16:50:
Is de huidige code niet met een kleine, intelligente verandering aan te passen, zodat meerdere landen op dezelfde manier worden weergegeven? Of moet ik het echt grondig gaan her ontwerpen?
Misschien een lijst van checkboxen voor makkelijkere selectie? Als je verkeerd klikt in een multiselect ben je je selectie kwijt. Of je maakt hier een apart formulier-element voor:
Wat voor oplossing je ook kiest, je hebt dan waarschijnlijk nog steeds een array van waarden. Die zul je op een zodanige manier moeten verwerken in je query zodat al deze landen worden opgepikt. Ik denk dat op dit moment je query misgaat. Voor debugging is het handig om de query eerst op te bouwen in een string, dan kun je deze in afzondering bestuderen. Tegelijkertijd zou je ook na kunnen denken over hoe e.e.a. makkelijker gemaakt kan worden qua interactie/navigatie.
Gewijzigd op 12/10/2020 17:16:51 door Thomas van den Heuvel
Thanks voor de hulp! Het is voor mij als beginneling misschien net iets te lastig om dit voor elkaar te krijgen, maar ik ga een poging wagen. Was eigenlijk wel blij dat het net werkte :-) Maarja, als je dan weer al die mooie mogelijkheden ziet, wil je toch weer meer.
- Ariën - op 12/10/2020 13:04:15:
Leg uit?
mysqli_real_escape_string() werkt even goed.
mysqli_real_escape_string() werkt even goed.
mysqli_real_escape_string() is problematisch.
1. Het is niet veilig als je geen quotes gebruikt. Niet handig voor numerieke kolommen, of wanneer de kolom van datatype verandert, dan zou het voor kunnen komen dat je alle queries langsmoet in je PHP-code, als je alle quotejes al paranoïde bij hebt bijgehouden.
Dat alleen al is een beveiligingsrisico.
2. Het kan verkeerd gaan als je de encoding niet goed hebt ingeregeld voordat je mysqli_real_escape_string() aanroept.
Goed: mysqli_set_charset('utf8', $link);
Fout: mysqli_query("SET NAMES 'utf8'", $link);
Het gaat fout omdat de MySQL API niet wordt ingesteld met de juiste encoding.
3. mysqli_real_escape_string() werkt niet in combinatie met de LIKE-operator. Kan je daarvoor weer het wiel uitvinden.
Prepared statements hebben deze problemen niet, het gaat altijd goed omdat je de variabelen apart meegeeft als functieargumenten. Het beschermt daardoor tegen SQL-injectie.
mysqli_real_escape_string() gaat niet per definitie goed, het beschermt niet per se tegen SQL-injectie, de veiligheid moet dus geborgd door de programmeur.
Daarom: weg met mysqli_real_escape_string(), en altijd prepared statements gebruiken.
Gewijzigd op 13/10/2020 17:34:54 door Ad Fundum
Dit werkt toch prima?
Code (php)
1
2
3
4
2
3
4
<?php
$sql = "SELECT * FROM Customers
WHERE CustomerName LIKE '".mysqli_real_escape_string($conn, $input)."%'";
?>
$sql = "SELECT * FROM Customers
WHERE CustomerName LIKE '".mysqli_real_escape_string($conn, $input)."%'";
?>
Het staat tussen quotes, het heeft niks met LIKE te doen.
Leest alleen een beetje rot met die quotes.
#1 hoe belemmeren quotes het gebruik van numerieke kolommen? je bedoelt het afwezig zijn hiervan? gewoon overal consequent quotes gebruiken en escapen - geen probleem, ook al verandert het datatype. Daarbij, als je de structuur verandert loont het altijd de moeite om code die hierop van toepassing is even langs te lopen? dit zou ik niet blind doen
#2 mja set_charset() is belangrijk, omdat dat bepaalt hoe real_escape_string() werkt; zo zijn de regels van het spel
#3 sja en LIMIT werkt ook niet vlekkeloos in alle gevallen, er zullen altijd uitzonderingen zijn, vind ik niet echt een onoverkomelijk probleem... het is in ieder geval geen reden om een aanpak dan maar helemaal op voorhand af te schrijven
Quote:
Daarom: weg met mysqli_real_escape_string(), en altijd prepared statements gebruiken.
Het probleem ligt niet bij de methoden die veilig zijn, het probleem ligt bij het gebrek aan kennis over deze concepten. Zelfs als je prepared statements gebruikt zou je nog steeds moeten snappen hoe dit werkt en waarom dit veilig is anders gaat dit gewoon op een gegeven moment nog steeds mis, denk aan concatenatie van SQL/variabelen in een prepared statement.
Daarbij, prepared statements in mysqli zijn onwijs clunky, en in PDO wordt standaard een emulatielaag gebruikt, waarbij niet eens de native support voor prepared statements binnen MySQL wordt gebruikt.
Je zou natuurlijk ook niet enkel de nadruk kunnen leggen op de methodiek, maar ook kunnen kijken wat gewoon prettig werkt. Dit vergt dan misschien wat meer discipline, maar het is waarschijnlijk in het gebruik (stukken) makkelijker.
Kies de aanpak die jou het makkelijkste lijkt, begrijp waarom deze veilig is en kies deze ook vooral op grond van valide argumenten want er circuleert een hoop onzin op het internet over wat "veilig" of "beter" zou zijn.
Gewijzigd op 13/10/2020 18:17:27 door Thomas van den Heuvel
Thomas van den Heuvel op 13/10/2020 18:10:39:
Geen enkele methodiek is veilig als de persoon in kwestie niet weet waar 'ie mee bezig is. Misschien word je wat meer tegen jezelf beschermd met prepared statements, maar onwetendheid is nog steeds geen excuus.
Dat is dus het hele punt. Je wordt niet tegen jezelf beschermd. Prepared statements beschermen jou tegen SQL-injectie. mysqli_real_escape_string() doet dat niet, tenzij je zelf altijd enorm oplet.
Daarbij, 'even' langslopen van je code hangt af van hoe effectief je je tijd wilt besteden.
Naarmate het aantal SLOC stijgt, verspil je meer tijd met onnodig langslopen.
Het enige vervelende dat ik had in de tijd dat ik nog aan MySQL vastzat is dat er geen equivalent bestaat voor pg_query_params(). Misschien dat PDO daar iets voor heeft, dat weet ik niet. Maar gelukkig kan je ook zelf een mysqli_query_params() maken. Misschien wel leuk voor bij de PHP Scripts.
Gewijzigd op 14/10/2020 12:41:12 door Ad Fundum
Ad Fundum op 14/10/2020 12:40:35:
Dat is dus het hele punt. Je wordt niet tegen jezelf beschermd. Prepared statements beschermen jou tegen SQL-injectie. mysqli_real_escape_string() doet dat niet, tenzij je zelf altijd enorm oplet.
Dat is dus het hele punt. Je wordt niet tegen jezelf beschermd. Prepared statements beschermen jou tegen SQL-injectie. mysqli_real_escape_string() doet dat niet, tenzij je zelf altijd enorm oplet.
Daarom is het inderdaad de afweging die de programmeur zelf wilt maken. Het is daarom niet dat de escape-functie meteen slecht is.
Als je het vanaf begin af aan consequent op de juiste manier blijft toepassen (quotes, encoding), dan is er niks aan de hand.
Gewijzigd op 14/10/2020 12:55:36 door - Ariën -
Wat er slecht aan is, is dat er vaak van gezegd wordt dat het beschermt tegen SQL-injectie.
En dat doet het niet, dat moet je zelf blijven doen.
Tenzij je gebruikt maakt van prepared statements.
Als (beginnend) programmeur kan je vrij snel op het verkeerde been gezet worden, en dat doet afbreuk de filosofie van PHP als zijnde een pragmatische taal. mysqli_real_escape_string() is niet praktisch, het is eerder onhandig. Om de reden die Thomas noemt: je moet al je code in de gaten blijven houden. Dat mensen dan nog er voor kiezen om mysqli_real_escape_string() te willen blijven gebruiken kan ik echt niet volgen.
Gewijzigd op 14/10/2020 13:18:33 door Ad Fundum
Ad Fundum op 14/10/2020 13:16:59:
mysqli_real_escape_string() is neutraal, het doet precies wat het zegt dat het doet.
Wat er slecht aan is, is dat er vaak van gezegd wordt dat het beschermt tegen SQL-injectie.
En dat doet het niet, dat moet je zelf blijven doen.
Wat er slecht aan is, is dat er vaak van gezegd wordt dat het beschermt tegen SQL-injectie.
En dat doet het niet, dat moet je zelf blijven doen.
Het helpt theoretisch dan voor 50% procent, kan je zeggen. Je moet zelf netjes de quotes in je query toevoegen waar het moet, maar dat is gewoon weer iets wat je zelf moet aanleren als je MySQL gebruikt. Mis je de quotes, dan denkt MySQL dat het om een veld gaat i.p.v. een string, en als het om een input gaat, dan denkt MySQL dat het onderdeel is van een query. Dus daarom alle input in je query netjes escapen.
Quote:
Als (beginnend) programmeur kan je vrij snel op het verkeerde been gezet worden, en dat doet afbreuk de filosofie van PHP als zijnde een pragmatische taal. mysqli_real_escape_string() is niet praktisch, het is eerder onhandig. Om de reden die Thomas noemt: je moet al je code in de gaten blijven houden. Dat mensen dan nog er voor kiezen om mysqli_real_escape_string() te willen blijven gebruiken kan ik echt niet volgen.
Als je meer van de prepared statements bent, dan gebruik je dat. Als je beiden (afzonderlijk van elkaar dan) op de juiste manier toepast, dan is de uitkomst uiteindelijk hetzelfde. Het is een keuze die de programmeur zelf moet maken.
Het is niet zo dat het ene inferieur is vergekelen met het andere.
Een slot in een deur moet je ook op de juiste manier inbouwen. Schroef je hem er niet in vast, dan tik je hem er ook zo uit.
Gewijzigd op 14/10/2020 13:49:06 door - Ariën -
- Ariën - op 14/10/2020 13:41:55:
Een slot in een deur moet je ook op de juiste manier inbouwen. Schroef je hem er niet in vast, dan tik je hem er ook zo uit.
Naar analogie met mysqli_real_escape_string():
Als er dan toch zomaar ineens wordt ingebroken, dan had je van te voren zelf maar zo gis moeten zijn om een slot met kerntrekbeveiliging te gebruiken.
(En een SECU-strip te plaatsen, en een deur met driepuntssluiting te hebben, en je licht aanmoeten houden, en niet op social media moeten zetten dat je een weekje op vakantie was...)
Maar je hebt gelijk: bij goed gebruik kan het goed werken. Als je tijd te veel hebt zou ik zeggen: ga vooral voor mysqli_real_escape_string(), ik hou je niet tegen! :)
Gewijzigd op 14/10/2020 15:14:50 door Ad Fundum
Ad Fundum op 14/10/2020 15:13:06:
Als je tijd te veel hebt zou ik zeggen: ga vooral voor mysqli_real_escape_string(), ik hou je niet tegen! :)
pg_query_params(), en mysqli_bind_params() (net ff als scriptje toegevoegd).
'Doe het goed, doe het nu'.
Helemaal gelijk Thomas, daarom is er ook zoiets als 'Doe het goed, doe het nu'.
Gewijzigd op 14/10/2020 20:22:52 door Ad Fundum