Simpele php / sql search
Wat ik probeer is om een simpele zoek functie te maken voor een bepaalde tabel in de database.
Met hier en daar wat zoeken op internet heb ik nu dit
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<form action="" method="POST">
<input name="s" value="<?php echo $term; ?>"/>
<input type="submit" value="zoeken" name="submit"/>
</form>
<?php
if(isset($_POST["submit"])){
$term = $_POST['s'];
$term = htmlspecialchars($term);
$term = mysqli_real_escape_string($term);
$raw_results = mysqli_query("SELECT * FROM info WHERE ('place' LIKE '%".$term."%')");
if(mysqli_num_rows($raw_results) > 0){
while($results = mysqli_fetch_array($raw_results)){
echo "<p><h3>".$results['place']."</h3></p>";
}
}else{
echo "No results";
}
}
?>
<input name="s" value="<?php echo $term; ?>"/>
<input type="submit" value="zoeken" name="submit"/>
</form>
<?php
if(isset($_POST["submit"])){
$term = $_POST['s'];
$term = htmlspecialchars($term);
$term = mysqli_real_escape_string($term);
$raw_results = mysqli_query("SELECT * FROM info WHERE ('place' LIKE '%".$term."%')");
if(mysqli_num_rows($raw_results) > 0){
while($results = mysqli_fetch_array($raw_results)){
echo "<p><h3>".$results['place']."</h3></p>";
}
}else{
echo "No results";
}
}
?>
in de database heb ik 2 records gemaakt in de kolom place heb ik "Amsterdam en Eindhoven".
Als ik een van beide invul blijf ik toch nog 'No results' krijgen
Het lijkt mij beter om zoekfunctionaliteit via GET te laten verlopen.
En htmlspecialchars() lijkt mij niet nodig, tenzij alles in je database ook ge-htmlspecialchars()d is, wat mij geen goede zaak lijkt als dat aan de orde is...
Het functioneert nu :) inderdaad zonder de quotes maar ik zag ook een foutje in SQL staan.
Waarom zou jij kiezen om de GET methode te gebruiken i.p.v. POST?
Dan heb ik nog een vraag betreft SQL, ik zoek nu in 2 kolommen namelijk 'place' en 'location'
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
$min_length = 3;
$term = $_POST["s"];
if(strlen($term) >= $min_length){
$raw_results = mysqli_query($conn, "SELECT * FROM info WHERE place LIKE '%$term%' OR location LIKE '%$term%'");
if(mysqli_num_rows($raw_results) > 0){
while($results = mysqli_fetch_array($raw_results)){
echo "<p>".$results['location']."<h3>".$results['place']."</h3></p>";
}
}else{
echo "No results";
}
}
?>
$min_length = 3;
$term = $_POST["s"];
if(strlen($term) >= $min_length){
$raw_results = mysqli_query($conn, "SELECT * FROM info WHERE place LIKE '%$term%' OR location LIKE '%$term%'");
if(mysqli_num_rows($raw_results) > 0){
while($results = mysqli_fetch_array($raw_results)){
echo "<p>".$results['location']."<h3>".$results['place']."</h3></p>";
}
}else{
echo "No results";
}
}
?>
In de kolom location staan bijvoorbeeld de waarde 'Amsterdam' Eindhoven, Utrecht'
in de kolom location staan de waarde 'Park, station, markt'
Als ik zoek op alles afzonderlijk krijg ik altijd netjes resultaat. Maar hoe maak ik de juiste query als ik bijvoorbeeld zoek op 'Park amsterdam'.
Nu krijg ik geen resultaat terug.
Moet ik dan php explode gebruiken om elke woord apart te behandelen en vervolgens met een foreach de query uitvoeren?
Met GET krijg je niet steeds een bevestiging van je browser als je een formulier opnieuw verzendt. Bij POST juist wel. En je kan ook handig een directe link maken naar je zoekopdracht.
Zoek naar beide velden zo :
Code (php)
1
select titel, artiest from platen where concat(titel, ' ' , artiest) = 'Tapestry Carole King'
Voor 'Tapestry Carole King' kan ook de POST of GET variabelen gebruiken.
@Adoptive het nadeel daarvan is volgorde/exacte match. Als er ook maar iets verkeerd is ingevuld of ingevuld in de verkeerde volgorde heb je geen match.
Als je niet wilt dat er ruimte is voor het maken van dit soort fouten zorg dan dat deze fouten niet gemaakt kunnen worden door het niet af te laten hangen van datgene wat een gebruiker kan invullen maar laat deze kiezen uit vaste waarden (dropdown, checkbox, radio of zelfs autocompletes). Die waarden hebben dan in ieder geval potentieel om nog iets op te leveren.
Gewijzigd op 04/05/2019 00:49:56 door Thomas van den Heuvel
Bryan De Baar op 03/05/2019 19:57:41:
Moet ik dan php explode gebruiken om elke woord apart te behandelen en vervolgens met een foreach de query uitvoeren?
Ja.
Wat wil je: zoeken op "park" en "amsterdam".
Hoe doe je dat in SQL: where place like "%park%" and place like "%amsterdam%"
Hoe kneed je dat in PHP:
Code (php)
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
<?php
$where = [];
if($q = trim($_GET['q'] ?? null)){ //of zoiets in ieder geval q = 'park amsterdam'
$words = preg_split('/\\s+/',$q); //splitsen op white-space = alle losse woorden
foreach($words as $word)
$where[] = "place like '%" . mysqli_real_escape_string($conn,$word) . "%'";
}
$sql = 'select * from info' . ($where ? ' where ' . implode(' and ',$where) : '');
//enz
?>
$where = [];
if($q = trim($_GET['q'] ?? null)){ //of zoiets in ieder geval q = 'park amsterdam'
$words = preg_split('/\\s+/',$q); //splitsen op white-space = alle losse woorden
foreach($words as $word)
$where[] = "place like '%" . mysqli_real_escape_string($conn,$word) . "%'";
}
$sql = 'select * from info' . ($where ? ' where ' . implode(' and ',$where) : '');
//enz
?>
Splitsen met preg_split ipv explode heeft als voordeel dat meerdere spaties, tabs, enz allemaal verdwijnen. Evt. zou je zelfs preg_split('/\\W+/',$q) kunnen doen = splitsen op alle karakters die geen letter of cijfer zijn (of underscore). Bij "park amsterdam-west" zoek je dan dus op "park", "amsterdam", en "west".
2019-05-04 14:00: Nog wat lopen klungelen aan de PHP code. Je kunt er natuurlijk ook voor kiezen om bij een lege $where helemaal niks te doen (of een melding te geven "geef een locatie op").
Gewijzigd op 04/05/2019 14:11:05 door Rob Doemaarwat
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
$words = preg_split('/\\s+/',$_GET["s"]);
foreach($words as $word){
$raw_results = mysqli_query($conn, "SELECT * FROM info WHERE place LIKE '%$word%' OR location LIKE '%$word%'");
}
if(mysqli_num_rows($raw_results) > 0){
while($results = mysqli_fetch_array($raw_results)){
echo "<p>".$results['location']."<h3>".$results['place']."</h3></p>";
}
}else{
echo "No results";
}
?>
$words = preg_split('/\\s+/',$_GET["s"]);
foreach($words as $word){
$raw_results = mysqli_query($conn, "SELECT * FROM info WHERE place LIKE '%$word%' OR location LIKE '%$word%'");
}
if(mysqli_num_rows($raw_results) > 0){
while($results = mysqli_fetch_array($raw_results)){
echo "<p>".$results['location']."<h3>".$results['place']."</h3></p>";
}
}else{
echo "No results";
}
?>
Daarnaast: SQL input escapen (SQL-injectie), HTML output escapen.
Gewijzigd op 04/05/2019 20:03:23 door Rob Doemaarwat
- Locatie
- Plaats
Ik neem aan dat hij zo een soort data heeft:
plaats locatie
Amsterdam Park, Station
Maastricht Station, Mc Donalds
Eindhoven Gemeentehuis
Utrecht Mc Donalds
En zoekt op:
Amsterdam -> resultaat = Plaats: Amsterdam Locatie: Park, Station
Maastricht Mc Donalds -> resultaat = Plaats Maastricht Locatie: Mc Donalds
Mc Donalds -> resultaat = Plaats: Maastricht, Utrecht Locatie: Mc Donalds
Loop je dan niet alle keywoorden maar ook niet de kolommen?
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
<?php
$where = [];
if($q = trim($_GET['q'] ?? null)){ //of zoiets in ieder geval q = 'park amsterdam'
$words = preg_split('/\\s+/',$q); //splitsen op white-space = alle losse woorden
foreach($words as $word){
$word = mysqli_real_escape_string($conn,$word);
$where[] = "(place like '%$word%' or location like '%$word%')";
}
}
$sql = 'select * from info' . ($where ? "\nwhere " . implode("\n and ",$where) : '');
//enz
?>
$where = [];
if($q = trim($_GET['q'] ?? null)){ //of zoiets in ieder geval q = 'park amsterdam'
$words = preg_split('/\\s+/',$q); //splitsen op white-space = alle losse woorden
foreach($words as $word){
$word = mysqli_real_escape_string($conn,$word);
$where[] = "(place like '%$word%' or location like '%$word%')";
}
}
$sql = 'select * from info' . ($where ? "\nwhere " . implode("\n and ",$where) : '');
//enz
?>
Zoeken op "park amsterdam" levert nu $sql =
Code (php)
1
2
3
2
3
select * from info
where (place like '%park%' or location like '%park%')
and (place like '%amsterdam%' or location like '%amsterdam%')
where (place like '%park%' or location like '%park%')
and (place like '%amsterdam%' or location like '%amsterdam%')
Gewijzigd op 04/05/2019 21:35:21 door Rob Doemaarwat
Dit werkt inderdaad zoals ik het had gedacht:)
Maar ik zie dat je shorthand code hebt gebruikt waarmee ik helemaal niet mee bekend ben. Zou je misschien kunnen uitleggen wat er in het script gebeurd bij de shorthands?
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
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
<?php
$q = $_GET['q'] ?? null;
//dit is hetzelfde als:
if(isset($_GET['q'])) $q = $_GET['q'];
else $q = null;
//maar ik had er dan nog een trim() omheen
preg_split('/\\s+/',$q)
/*
/\\s+/ is een regular expression
/ / is de afbakening (ander karakter kan ook, dit wordt veel gebruikt -
bijvoorbeeld in javascript)
\\s dit "matcht" een white-space karakter (spatie, tab, enz); dubbele \\ omdat er
dan een enkele overblijft (escapen); een enkele \ gaat vaak goed, maar kan soms
fout gaan, daarom doe ik uit gewoonte altijd \\
+ 1 of meer matches (dus niet nul)
deze hele riedel splitst de $q dus op witruimte; 'aa bb cc' wordt dus gesplitst
in ['aa','bb','cc'], waar je met explode(' ',$q) -> ['aa','','','bb','','','','cc']
zou krijgen (merk op dat ik vooraf al een trim() heb gedaan om van white-space aan
begin en eind af te komen).
*/
$sql = 'select * from info' . ($where ? "\nwhere " . implode("\n and ",$where) : '');
//dit is hetzelfde als:
$sql = 'select * from info';
if($where) $sql .= "\nwhere " . implode("\n and ",$where);
else $sql .= ''; //maar dit is niet echt noodzakelijk / voegt niks toe
?>
$q = $_GET['q'] ?? null;
//dit is hetzelfde als:
if(isset($_GET['q'])) $q = $_GET['q'];
else $q = null;
//maar ik had er dan nog een trim() omheen
preg_split('/\\s+/',$q)
/*
/\\s+/ is een regular expression
/ / is de afbakening (ander karakter kan ook, dit wordt veel gebruikt -
bijvoorbeeld in javascript)
\\s dit "matcht" een white-space karakter (spatie, tab, enz); dubbele \\ omdat er
dan een enkele overblijft (escapen); een enkele \ gaat vaak goed, maar kan soms
fout gaan, daarom doe ik uit gewoonte altijd \\
+ 1 of meer matches (dus niet nul)
deze hele riedel splitst de $q dus op witruimte; 'aa bb cc' wordt dus gesplitst
in ['aa','bb','cc'], waar je met explode(' ',$q) -> ['aa','','','bb','','','','cc']
zou krijgen (merk op dat ik vooraf al een trim() heb gedaan om van white-space aan
begin en eind af te komen).
*/
$sql = 'select * from info' . ($where ? "\nwhere " . implode("\n and ",$where) : '');
//dit is hetzelfde als:
$sql = 'select * from info';
if($where) $sql .= "\nwhere " . implode("\n and ",$where);
else $sql .= ''; //maar dit is niet echt noodzakelijk / voegt niks toe
?>
Het scheelt dus meestal wat type werk, of een extra regel.
Zie https://php.net/ternary#language.operators.comparison.ternary
Gewijzigd op 05/05/2019 19:34:15 door Rob Doemaarwat