PHP Les 04: Veilig gegevens verwerken

Doelstelling les:

  • Bewustwording SQL injection

  • Kennismaken met prepared statements

  • Filterfunctie op basis van dropdown

Voorbereiding (studenten)

  • Huiswerk vorige les natuurlijk
  • Lees uit de reader paragraaf Prepared statements gebruiken van hoofdstuk Veilig gegevens verwerken
  • Bekijk video's van CodeCourse op OnderwijsOnline:
    • 23-CodeCourse-PDO-Fetch types.mp4
    • 24-CodeCourse-PDO-Fetching all results.mp4
    • 25-CodeCourse-PDO-Prepared Statements.mp4

Lesplan

  • Huiswerk bespreken
    • Componisten weergeven
    • Prepared statements

Queries dynamisch maken

In deze les gaan we muziekstukken (uit de tabel Stuk) filteren op basis van genre (niet niveaucode want die is vaak NULL).

In de vorige les zijn we al bezig gegaan met data uit de database halen als de query vast staat. Nu gaan we bezig met een aanpassing op de query op basis van een gebruikers actie.

Stap 1: URL-filter toepassen

We gaan gebruik van van query-parameters (bijv. http://localhost:8080/muziekstukken.php?genrenaam=jazz)

Daarvoor gebruiken we de $_GET superglobal.

  1. Maak eerst de query in SQL Managament Studio.

  2. Plak query in php-code

    ❗️ Let op, in de PHP moet je de single qoutes ' escapen met \'. Het is ook mogelijk om dubbele qoutes " te gebruiken, maar dan zet je de deur weer open voor het per ongeluk uitvullen van variabelen (en dus voor sql injection).

  3. Vervang jazz met pop en toon effect.

  4. Nu gaan we de query-parameters gebruiken zoals:

    pop :

    http://localhost:8080/muziekstukken.php?genrenaam=pop

    jazz :

    http://localhost:8080/muziekstukken.php?genrenaam=jazz

    Dit kunnen we doen door direct met $_GET de query aan te passen, maar daar zitten nogal grote gevolgen aan. Want dan zetten we de deur open voor SQL-injection

Intermezzo: SQL-injection

De docent zal laten zien en vertellen wat de gevaren van SQL-injection zijn.

Stap 2: Query-parameters maar veilig met prepared statements

Nu gaan we prepared statements gebruiken. Zie ook het onderdeel in de H7. Veilig gegevens verwerken: Prepared Statements Gebruiken

Kort gezegd zijn prepared statements:

  • voorbereidde queries, m.a.w. een query met placeholders
  • Vaker te gebruiken, maar vooral een wapen tegen code injection
Recept voor prepared statements:
  1. Maak query met placeholders:

    SELECT .... FROM .... WHERE kolom = :kolom (en :kolom is de placeholder)

  2. Laat query door database voorbereiden: $data = $db->prepare($sql)

  3. Laat query uitvoeren met waardes voor de placeholders: $data->execute(..waarden..)

  4. Haal data op (fetch)

Stap 3: Dropdown menu met alle genres

Bovenaan de pagina gaan we nu een dropdown menu maken met behulp van:

  • het <form> element met een
  • <select> die verschillende <option>-elementen.

Denk goed na over welke "action" en "method" het formulier moet hebben.

Aan de hand van de <option> die gekozen is kun je nu de query draaien.

De query SELECT genrenaam FROM Genre voer je nu uit met behulp van de data die het formulier teruggeeft.

Bij de eerste aanroep krijg je een warning, die eerst even negeren. Speel wat met de pagina (selecteer af en toe een ander genre).

Stap 4: Warning weghalen met isset

Poets de warning weg door te controleren of genrenaam is meegegeven, anders een default waarde:

if(isset($_GET['genrenaam']))
{
    $genrenaam = $_GET['genrenaam'];
}
else
{
    $genrenaam = 'jazz'; // of een ander genre als default
}

Stap 5: Gegevens uit dropdown uit de database halen

De dropdown is nu hardcoded gevuld, maar die gegevens staan ook in de database. Als er nu een nieuw genre bij komt, dan moet je ook de html aanpassen. Dat gaan we dus met een query doen.

  1. Voer eerst in SQL Management de query INSERT INTO Genre(genrenaam) VALUES ('blues') uit en laat zien dat die blues dus niet in de dropdown terecht komt.

  2. Maak een functie getGenreSelectBox die de select box genereert.

  3. Voeg nu nog een genre toe in SSMS:

    INSERT INTO Genre(genrenaam)
    VALUES ('tranentrekker')
    

Nu kun je met het formulier dus stukken vinden op basis van de verschillende genres.

Stap 6: Voeg een nieuw muziekstuk toe

Voeg een nieuw stuk toe, bijvoorbeeld:

INSERT INTO stuk (stuknr, componistId, titel, genrenaam, jaartal)  
VALUES (100, 10, 'Kneiterfalse', 'tranentrekker', 2021)`

Korte samenvatting

De docent zal het uiteindelijke formulier demonstreren en nog meer voorbeelden hiervan bespreken.

Welke voorbeelden kun je zelf bedenken?

Huiswerk

  1. (verplicht) Nieuwe pagina maken met alle stukken, filter maken op basis van componistid (in de dropdown de naam zichtbaar, componistid is value)

  2. (uitdaging, optioneel) in het formulier met de dropdown wordt de selectie niet bewaard, maar steeds op de eerste gezet. Een option als selected markeren doe je door selected op te nemen, bijv. <option value="klassiek" selected>klassiek</option>. Geef de functie getGenreSelectBox() een argument $selection wat het geselecteerde genre is. dus:

    function getGenreSelectBox($selection)
    {
        // Toevoegen: geef het geselecteerde genre `selected`
    
        $db = maakVerbinding();
        $sql = 'select genrenaam 
                from Genre';
        $data = $db->query($sql);
    
        $selectbox = '<select id="genrenaam" name="genrenaam">';
        foreach($data as $rij)
        {
            $genrenaam = $rij['genrenaam'];
            $selectbox .= "<option value=\"$genrenaam\">$genrenaam</option>";
        }
        $selectbox .= '</select>';
    
        return $selectbox;
    }
    
  3. Voorbereiding volgende les