• Jetzt anmelden. Es dauert nur 2 Minuten und ist kostenlos!

Suchfunktion - mehrere Wörter - splitten

Tobi44

Mitglied
Hallo,

ich habe eine Suchfunktion, mit der User nach Einträgen in einer Datenbank suchen können.

Geben sie "test" ein, erhalten sie alle DB-Einträge, die das Wort "test" enthalten.
Geben sie "test hallo" ein, erhalten sie nichts, da "test hallo" in diesem Zusammenhang nicht existiert.

Nun kann es ja sein, dass ein DB-Eintrag die Wörter "hallo" und "test" enthält, aber halt nicht hintereinander, wie es der User eingibt. Dennoch soll er den DB-Eintrag als Treffer angezeigt bekommen.

Für die DB-Abfrage verwende ich:
Code:
SELECT * FROM table WHERE title LIKE '%".$search."%' OR text LIKE '%".$search."%'
$search ist die Eingabe des Users.

So hatte ich den Gedanken, die Eingabe vom Benutzer, also den String, in einzelne Wörter zu splitten, das Leerzeichen trennt die Wörter:
Code:
$searchwords = preg_split('/[\s]+/', $search);

Und die Wörter dann in ein Array zu setzen:
Code:
foreach($searchwords as $searchword)

Und in der SQL-Abfrage dann $search durch $searchword zu ersetzen.
Nach meinen Tests funktioniert das sogar, was mich selbst durchaus erstaunt, da ich nun wirklich kaum was von PHP verstehe.

Nun meine Frage: Ist diese Methode "sicher", also funktioniert das wirklich so oder sollte ich das lieber anders lösen? Wie würdet Ihr das machen?
 
Werbung:
Ja, da hast Du schon den richtigen Weg gefunden. Auch wenn es funktioniert könnte es für dich evtl. interessant sein, welches SQL-Statement darüber zusammengesetzt wird. Lass dir das mal ausgeben bevor Du es ausführst, dann kannst Du evtl. auch die Funktionsweise besser nachvollziehen.
 
Jetzt wird es interessant... Ich verstehe wieder mal nur Bahnhof. :-(
SQL-Statement ist die SQL-Abfrage die ausgeführt wird? Und was soll ich da ausgeben lassen?
 
Werbung:
Ich kenne deinen aktuelle Code ja nicht. Angenommen er sieht momentan so aus:

PHP:
$searchwords = preg_split('/[\s]+/', $search);
$sql_where = "";
foreach($searchwords as $searchword) {
 if( strlen($sql_where) > 0 )$sql_where .= " OR ";
 $sql_where .= "title like '%".mysql_escape_string($searchword)."%'";
}
$sql = "SELECT * FROM table WHERE ".$sql_where;
$result = mysql_query($sql);
...

Dann könntest Du das so zusammengebaute Statement einfach per echo ausgeben lassen. Also:

PHP:
$searchwords = preg_split('/[\s]+/', $search);
$sql_where = "";
foreach($searchwords as $searchword) {
 if( strlen($sql_where) > 0 )$sql_where .= " OR ";
 $sql_where .= "title like '%".mysql_escape_string($searchword)."%'";
}
$sql = "SELECT * FROM table WHERE ".$sql_where;
echo $sql;
$result = mysql_query($sql);
...

Dann siehst Du in der Ausgabe in der Webseite das ausgeführte SQL-Statement stehen. Dieses kannst Du von dir kopieren, dir näher anschauen und auch z.B. im phpmyadmin direkt ausführen.

Mit weiteren echo-Ausgaben könntest Du dir auch den Ablauf des PHP-Scripts näher anschauen. Z.B. so:
PHP:
$searchwords = preg_split('/[\s]+/', $search);
$sql_where = "";
foreach($searchwords as $searchword) {
 if( strlen($sql_where) > 0 )$sql_where .= " OR ";
 echo $searchword;
 $sql_where .= "title like '%".mysql_escape_string($searchword)."%'";
}
$sql = "SELECT * FROM table WHERE ".$sql_where;
echo $sql;
$result = mysql_query($sql);
...

Da ich deinen Quellcode nicht kenne ist das natürlich nur pauschal geraten wie man es machen könnte. Der Knackpunkt für dich ist aber wie gesagt einfach die Ausgabe per echo.
 
Mit der echo Ausgabe habe ich zuvor die Ausgabe des foreach getestet, um zu sehen, ob das funktioniert. Also ob die Suchwörter einzeln im Array stehen.

Was ich momentan komisch finde:
Wenn der User folgendes eingibt: "ifherf hallo test" zeigt er passende Ergebnisse mit "hallo" und "test" in den Spalten an. "ifherf" existiert dabei nirgendwo.
Wenn er aber "hallo test ifherf" eingibt, wird kein Ergebnis gefunden.

Edit: Und wenn ich irgendwas, was es gar nicht in der DB gibt, wie z.B. "12345667 " mit Leerzeichen am Ende eingebe, findet er angeblich alle Einträge! o_O

Anhand Deines geposteten Beispieles muss ich sagen, dass ich hinter dem foreach keine Klammer { habe.

Was Du da schreibst, ist wieder zu hoch für mich. :-D

Bei mir sieht es momentan folgendermaßen aus:
PHP:
$searchwords = preg_split('/[\s]+/', $search);
foreach($searchwords as $searchword)
$suchausgabe = mysql_query("SELECT * FROM table WHERE title LIKE '%".$searchword."%' OR text LIKE '%".$searchword."%' ORDER BY timestamp DESC");
Danach kommt schon die while-Schleife mit der Ausgabe.
 
Zuletzt bearbeitet:
Das Problem an deinem Code ist folgender:

PHP:
$searchwords = preg_split('/[\s]+/', $search);

Splitten vom String, ok, geht in Ordnung.

PHP:
foreach($searchwords as $searchword)

Gehe durch das Array der Wörter, d.h. pro Durchgang 1 Wort.

PHP:
$suchausgabe = mysql_query("SELECT * FROM table WHERE title LIKE '%".$searchword."%' OR text LIKE '%".$searchword."%' ORDER BY timestamp DESC");

Füge dieses eine Wort jeweils in das Statement ein und ermittle die Ergebnisse.

Danach verarbeitest Du somit die Ergebnisse des letzten Statements in einer Schleife.

Praktisches Beispiel:
Man sucht nach "ifherf hallo test". In deinem Code passiert folgendes:

PHP:
$searchwords = preg_split('/[\s]+/', $search);

Ergibt ein Array in $searchwords mit dem Aufbau

Code:
array {
 ifherf,
 hallo,
 test
}

Die foreach-Schleife geht dann durch die einzelnen Einträge dieses Arrays und erzeugt folgende 3 Statements sowie deren Ergebnisse:

PHP:
$suchausgabe = mysql_query("SELECT * FROM table WHERE title LIKE '%ifherf%' OR text LIKE '%ifherf%' ORDER BY timestamp DESC");
$suchausgabe = mysql_query("SELECT * FROM table WHERE title LIKE '%hallo%' OR text LIKE '%hallo%' ORDER BY timestamp DESC");
$suchausgabe = mysql_query("SELECT * FROM table WHERE title LIKE '%test%' OR text LIKE '%test%' ORDER BY timestamp DESC");

Bei jedem Durchlauf der Schleife wird somit $suchausgabe mit dem jeweils neuen Ergebnis überschrieben.

In der while-Schleife danach liest Du somit nur die Ergebnismenge des letzten Statements ein, also:
PHP:
$suchausgabe = mysql_query("SELECT * FROM table WHERE title LIKE '%test%' OR text LIKE '%test%' ORDER BY timestamp DESC");

Das erklärt auch deine merkwürdigen Ergebnisse:
"ifherf hallo test" als Suchbegriff zeigt nur Suchergebnisse für "test" an. Das dort jeweils "hallo" auch vorkommt ist denke ich Zufall.
"hallo test ifherf" als Suchbegriff zeigt keine Suchergebnisse an, da "ifherf" als Wort in keinem Datensatz vorkommt.

Soweit mitgekommen? :-)

Jetzt zu meinem Entwurf ein paar Kommentare. Vorweg:
Ein SQL-Statement ist ebenso nur ein String, wie die Wörter die Du trennst, welcher auch zusammengesetzt werden kann. Wichtig ist dabei lediglich, dass durch das zusammensetzen ein stimmendes (d.h. nicht fehlerhaftes) Statement entsteht.

PHP:
// Splitte den String am Leerzeichen um einzelne Wörter zu ermitteln:
$searchwords = preg_split('/[\s]+/', $search);
// Definiere eine Variable die zum Auffangen der where-Bedingungen des Statements dient
$sql_where = "";
// gehe durch das Array mit den einzelnen Wörtern
foreach($searchwords as $searchword) {
 // prüfe bei jedem Durchlauf, ob in $sql_where bereits etwas steht -> wenn ja, dann muss der String für das SQL-Statement um die SQL-Bedingung OR ergänzt werden
 if( strlen($sql_where) > 0 )$sql_where .= " OR ";
 // ergänze die Variable zum Auffangen der where-Bedingungen um die Prüfung nach diesem einen Wort um das es in diesem Durchlauf der foreach-Schleife geht
 $sql_where .= "title like '%".mysql_escape_string($searchword)."%'";
 // Ende der Schleife
}
// setze das endgültige SQL-Statement zusammen
$sql = "SELECT * FROM table WHERE ".$sql_where;
// führe das zusammengesetzte SQL-Statement aus
$result = mysql_query($sql);
...

Als Ergebnis dieses PHP-Codes hast Du genau eine Ergebnismenge die alle eingegebenen Stichwörter berücksichtigt.

Was man hierbei nicht beachtet (und Du in deinem Code auch nicht drinne hast) ist eine Beschränkung auf eine Anzahl Buchstaben. Wenn jemand nach "a" sucht würde er momentan quasi alle Datensätze finden in denen der Buchstaben a vorkommt. Evtl. solltest Du dich auf eine bestimmte Wortlänge beschränken um die Such auszuführen.
 
Werbung:
Danke für die ausführliche Erklärung. Allerdings überlege ich gerade, wo ich den zweiten Teil für die Suche in der Spalte "text" hinschreibe. Momentan wird nur in der "title"-Spalte gesucht. Finde einfach keine Stelle, wo das hier hingehört!

Wie ich nun mit echo in der Testausgabe sehe, wird ein OR file_title like xxx immer dann neu angefügt, wenn ein weiteres wort eingegeben wurde.

Nochmal edit: Bei dieser Version findet er aber auch Einträge wie "fuhferf hallo" oder "hallo fuhferf" obwohl "fuhferf" nirgendwo vorkommt.


Zu meinem Problem, vielleicht muss ich das so anpassen:
PHP:
$sql_where .= "title like '%".mysql_escape_string($searchword)."%' OR text like '%".mysql_escape_string($searchword)."%'";
Damit funktioniert es.
 
Zuletzt bearbeitet:
Zurück
Oben