PHP PHP MySQL Suchfunktion

Pfandfinder

Lieutenant
Registriert
Nov. 2020
Beiträge
654
ich habe einen Blog den ich quasi selbst programmiert hab, kein wordpress oder so, ich habe da auch eine Suchfunktion die in der Datenbank so die Eingabe durchsucht :

PHP:
$pdo->prepare('SELECT * FROM blog WHERE title LIKE "%'.$suchbegriff.'%" OR title LIKE "%'.str_replace(' ', '-', $suchbegriff).'%" OR title LIKE "%'.str_replace('-', ' ', $suchbegriff).'%" OR title LIKE "%'.str_replace(' ', '', $suchbegriff).'%" OR content LIKE "%'.$suchbegriff.'%" OR content LIKE "%'.str_replace(' ', '-', $suchbegriff).'%" OR content LIKE "%'.str_replace('-', ' ', $suchbegriff).'%" OR content LIKE "%'.str_replace(' ', '-', $suchbegriff).'%" OR content LIKE "%'.str_replace('-', ' ', $suchbegriff).'%" OR content LIKE "%'.str_replace(' ', '', $suchbegriff).'%"');

das funktioniert soweit auch ganz gut bei einzelnen Worten, aber sucht man z.B. "Windows Passwort", weil es im Beitrag um Windows Passwort reset geht aber die worte nicht hintereinander geschrieben kommen, kommt das Ergebnis natürlich nicht. wie kann ich die Suche verbessern ? gibts irgendwo guten Code den man nutzen kann ?

Ich dachte da auch an sowas:

PHP:
WHERE content LIKE "%Windows%" AND content LIKE "%Passwort%" AND content LIKE "%reset%"

sodass ich die einzelnen Wörter der suche trenne und durch eine Schleife jage und dann diese AND-Abfragen raus kommt. wie kann ich das umsetzen ?
 
Zuletzt bearbeitet:
das stichwort für deine recherche ist "volltextsuche". myql hat da schon was eingebaut, alternativ gibt es dafür extra programme wie lucene oder elasticsearch.
 
  • Gefällt mir
Reaktionen: goonie
Ich muss hier mal den Security-Zeigefinger erheben.

Du nutzt ein Prepared Statement, das ist der richtige Anfang. Falls aber vergessen werden sollte z. B. $suchbegriff per PDO::quote() o. Ä. zu escapen, könnte der User beispielweise nach BOOM!"; DROP TABLE blog -- suchen und deine Tabelle wäre gelöscht. Klassische SQL Injection.

Ein Prepare Statement sollte immer statisch sein und Platzhalter für Variablen enthalten. Die Variablen können mit PDOStatement::bindValue() oder PDOStatement::bindParam() übergeben werden.

Beispiel:
PHP:
$statement = $pdo->prepare('SELECT * FROM blog WHERE title LIKE :suchbegriff');
$statement->bindValue(':suchbegriff', "%{$suchbegriff}%");
 
  • Gefällt mir
Reaktionen: Gonzo28, spoic, Murray B. und eine weitere Person
Grundlegende Regel: Niemals ein leading wildcard einsetzen! Dann kann keinerlei Index genutzt werden -> sehr langsam.
FullText von Mysql ist mittlerweile recht brauchbar geworden, solange du nicht noch mysql5.6 oder älter einsetzt.
Wenn du aber auf Performance angewiesen bist, kommst du um Drittsysteme nicht drum rum.
 
  • Gefällt mir
Reaktionen: Pfandfinder und Murray B.
@goonie Manchmal möchte man nicht nach ganzen Wörtern suchen, dann ist weder ein Fulltext Index noch ein statischer Präfix hilfreich
. Um LIKE '%searchterm%' kommt man dann nicht herum. Ich würde das aber im Einzelfall checken, SQL Server kommt da beispielsweise auch mit großen Tabellen mit >1M rows gut zurecht.
 
floq0r schrieb:
auch mit großen Tabellen mit >1M rows gut zurecht.
Damit kommt jedes DBMS zurecht... halt nicht schnell.
Eine Suche mit "%$x%" ist immer Mist, wenn man dafür keine dafür ausgelegten Techniken nutzt (und nein, "like" meine ich damit nicht).

FTS ist eine Alternative für 0815 Abfragen. Aber grundsätzlich sollte man sich die richtigen Alternativen anschauen, statt sich mit solchen Behelfslösungen rumzuschlagen. Diesen Lernprozess hab ich auf Arbeit auch durch. FTS funktioniert bei 1-2M (halbwegs), aber nicht mehr bei 30M wenn man nicht 1sec+ Antwortzeiten will.
 
Zuletzt bearbeitet:
Je nach gewünschter Mächtigkeit der Volltextsuche kommt man um lucene oder elastic search nicht vorbei. Grade sowas wie fuzzy search und "dir you mean" support sind für User Gold Wert
 
1.) Als schnelle praktikable Lösung für kleine Projekte kann folgendes schon reichen:

Code:
// mach aus "hallo welt" => "%hallo%welt%"
$likePattern = '%' + implode('%', explode(' ', $search)) + '%';

Schwachpunkte:
  • Sehr langsam
  • Der User kann selbst % eingeben
  • Doppelte Leerzeichen werden durch auch durch %% ersetzt (was zwar funktioniert, aber overhead ist)
  • und vieles mehr
2.) Wenn du es halbwegs richtig machen willst, wie schon gesagt wurde: MySQL Volltext (mit MATCH AGAINST)

3.) Wenn du es richtig machen willst, nutze einen Lucene Index bzw. eine ElasticSearch API

4.) Als letzte Alternative könntest du mit PHP auch noch einen JavaScript-Fulltext-Index generieren
und den beim Seitenaufruf mit ausliefern: https://github.com/nextapps-de/flexsearch
Aber das ist vermutlich je nach Datenmenge einfach zu langsam oder beim Ausliefern zu groß.
 
  • Gefällt mir
Reaktionen: Murray B.
Zurück
Oben