Zoeken in de database

We gaan nu onze posts pagina uitbreiden met een zoekveld. Boven alle posts maken we een zoekveld waarbij we kunnen gaan zoeken op posts die voldoen aan de voorwaarde die we in het zoekveld intypen.

 

Omdat we bij zoeken niets invoeren/wijzigen in de database versturen we het formulier met een method="get". Het formulier krijgt één input veld van het type="text". Voor de button heb je twee mogelijkheden.

<input type="submit" value="Zoek" class="border b-gray-600 rounded py-1 px-2 hover:bg-gray-100 cursor-pointer">

of

<button class="border b-gray-600 rounded py-1 px-2 hover:bg-gray-100 cursor-pointer">Zoek</button>

De opmaak van de button (class) mag jij zelf bepalen.

 

Opgave J1.1

 

Voeg aan views/posts.view.php onder <h1> tag een formulier toe

Eigenschappen formulier:

 

Voor de button kan je gebruiken maken van de volgende tailwindcss class:
class="border border-1 rounded-md px-2 py-1 hover:bg-gray-100 cursor-pointer"

Gebruik voor het input veld tailwindcss class:
class="border border-1 rounded-md px-2 py-1"

 

Uitwerking:

/app/views/posts.view.php

 

Zoeken in database

We willen nu gaan zoeken in de posts tabel met de meegestuurd waarde uit het zoekveld. Een mogelijke query zou er zo uit kunnen zien:

"SELECT * FROM posts WHERE title LIKE '%zoek%' OR content LIKE '%zoek%'"

In dit geval zou het meegestuurde zoekveld de waar 'zoek' bevatten.

We willen dus voor 'zoek' de meegestuurde waarde invullen, dat kan op een aantal manieren.

"SELECT * FROM posts WHERE title LIKE '%".$request->q."%' OR content LIKE '%".$request->q."%'"

Hierboven vullen we letterlijk tussen de %% tekens hetgeen we hebben meegestuurd in het zoekveld.
Dit heeft echter een groot risico.

SQL-injecties

SQL-injecties zijn een veelvoorkomend beveiligingsrisico in webapplicaties waarbij een aanvaller kwaadaardige SQL-code invoert in een invoerveld. Deze code wordt vervolgens door de server uitgevoerd, waardoor de aanvaller ongewenste toegang kan krijgen tot de database.

Hoe werkt een SQL-injectie?

In bovenstaande query zou je het volgende kunnen doen. Stel je verstuurt het formulier met q= ';DROP DATABASE code_wizard;SELECT * FROM posts WHERE content LIKE '
Wanneer de query dan wordt uitgevoerd. Wordt er eerst een select-query gedaan en daarna wordt de database verwijderd. Voor DROP DATABASE kan natuurlijk ook een INSERT INTO users ... worden gedaan etc.

Dit is iets wat we zeker willen voorkomen.

Hoe voorkom je SQL-injecties?

Wij kunnen SQL-injects voorkomen door in de query parameters op te nemen die we later een waarde geven. Deze parameters worden net als bij de htmlspecialchars() methode veilig ingevoerd.

We hebben hiervoor twee manieren

Optie 1 door het gebruik van vraagtekens

$posts = $db->query("SELECT * FROM posts WHERE title LIKE ? OR content LIKE ?", [
    "%$request->q%",
    "%$request->q%",
])->fetchAll();

Omdat er twee vraagtekens in de query staan moeten we ook twee parameters meegeven

Optie 2 door het gebruik van parameters

$posts = $db->query("SELECT * FROM posts WHERE title LIKE :q OR content LIKE :q", [
    'q' => "%$request->q%"
])->fetchAll();

Omdat :q twee keer hetzelfde is hoeft deze maar één keer als parameter meegestuurd te worden.

Samengevat

$db->query(param1, param2)->fetchAll()
param1 is de query
param2 is een array met parameters

Query met één resultaat

$db->query("SELECT.. ",[
    $request->param1
])->fetch();

gebruiken we de fetch() methode

Query met meerdere resultaten

$db->query("SELECT.. ",[
    $request->param1
])->fetchAll();

gebruiken we de fetchAll() methode

 

Opgave J1.2 - Afhandeling zoekveld

 

Nu gaan we aan het werk in controllers/posts.php

Stap 1
Maak een variabele $db met type Database()

Stap 2
Controleer of er iets is verstuurd: if( $_GET['q']??false ){
Of met het Request object if( $request->q??false ){
??false geeft de variabele de waarde false als deze niet bestaat.

Stap 3
Doe een query en stop het resultaat in $posts (kijk af bij de CheatSheet)

Stap 4
Gebruik view posts en geef variabele $posts mee.

 

Uitwerking

/app/controllers/posts.php