Beste forum leden,

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.


<?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>
 
Ik zie dat je hem inderdaad al 'multiple' gemaakt hebt.
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.
Leg uit?

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.
Hi 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? :


<?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>";

									 }
						 }
}
					 ?>
het is trouwens $_GET['country_caught']. Maar waarom zou je dit via GET willen doen, en niet via POST?
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.
Hi Arië,

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?
Ik zou het toch even her-ontwerpen als ik jouw was.
Maak bij voorkeur een stroomdiagram die aangeeft wat er moet gebeuren, en hoe een request plaatsvindt.
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.
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() 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.

Reageren