2017-01-17 10 views
2

In dem Versuch Code zu rejuvenate schrieb ich vor mehr als 14 Jahren. Ich bin gekommen, um zu sehen, dass das schöne kleine Setup, das ich damals geschrieben habe, ... an bestimmten Stellen fehlte, nämlich die Handhabung von Benutzereingaben.PHP/MySQL bessere Benutzersuche

Lektion: Unterschätzen Sie nie Benutzer Fähigkeit, Müll, Tippfehler und Betrüger vorbei Ihre Validatoren zu injizieren.

Der alte Weg erreicht die kritische Masse, da sich jetzt 470 Elemente in einem SELECT-Dropdown befinden. Ich möchte diesen Teil des Prozesses neu erfinden, damit ich mir keine Sorgen machen muss, dass es einen Bruchpunkt erreicht.

Die Idee besteht also darin, eine unscharfe Suchmethode zu entwickeln, so dass nach Eingabe der Suchzeichenfolge durch die Schreibkraft fünf Datenelemente überprüft werden, die alle in derselben Zeile liegen.

Ich muss den Namen überprüfen, der mit dem Stage-Namen, zwei ebenfalls bekannten Namen sowie deren rechtmäßigen Namen und als letzte Prüfung mit einem soundex() - Index anhand ihres Stage-Namens (dies fängt a wenige Rechtschreibfehler verpasst sonst)

Ich habe einen komplizierten Block von Code versucht, um diese Dinge zu überprüfen (und es funktioniert nicht, meistens, weil ich denke, dass ich die Vergleiche zu streng codiert) als Teil einer Do/While-Schleife .

In der folgenden Zeile würde var $Rin den vom Benutzer angegebenen Namen enthalten.

$setr = mysql_query("SELECT ID,StageName,AKA1,AKA2,LegalName,SoundEx FROM performers"); 
IF ($R = mysql_fetch_array($setr)) { 
    do { 
     $RT = substr(trim($Rin), 5); 
     $RT1 = substr($R[1], 5); 
     $RT2 = substr($R[2], 5); 
     $RT3 = substr($R[3], 5); 
     $RT4 = substr($R[4], 5); 
     $RTx = soundex($RT); 
     IF ($RT == $RT1) { 
      $RHits[] = $R[0]; 
     } 
     IF ($RT == $RT2) { 
      $RHits[] = $R[0]; 
     } 
     IF ($RT == $RT3) { 
      $RHits[] = $R[0]; 
     } 
     IF ($RT == $RT4) { 
      $RHits[] = $R[0]; 
     } 
     IF ($RTx == $R[5]) { 
      $RHits[] = $R[0]; 
     } 
    } while ($R = mysql_fetch_array($setr)); 
} 

Die Idee ist, dass ich ein Array der ID # 's der Nähe von Hits bauen werde, die ich in einem ausgewählten Drop-Down-bevölkern werden, die nur hoffentlich weniger Treffer, dass die gesamte Tabelle hat. Dies bedeutet, dass Sie nach einer Ergebnismenge aus dem Inhalt dieses Arrays suchen müssen, um den Namen des Performers im Dropdown-Feld SELECT anzuzeigen und die ID # als Wert für diese Auswahl zu übergeben.

Das ist, wenn ich das Problem "Ich brauche ein Array in meinem WHERE-Klausel" Hit, und nachdem ich diese Antwort gefunden habe, beginne ich zu vermuten, dass ich aufgrund der unten stehenden Nr. 2 Pech habe. Also habe ich nach alternativen Suchmethoden gesucht und bin mir nicht sicher, ob ich irgendwo anders als verwirrt bin.

Gibt es also eine bessere Möglichkeit, eine einzelne Tabelle für sechs Felder zu scannen, fünf gegen Benutzereingaben zu prüfen und die sechste für die Anzeige in einer Teilmenge der ursprünglichen Tabelle zu notieren?

Denkprozess:

gegen die gesamte Tabelle, pro Datensatz, test $ Rin gegen diese Tests in dieser Reihenfolge:

$ Rin -> stagename
$ Rin -> AKA1
$ Rin -> AKA2
$ Rin -> Namensrecht
soundex ($ Rin) -> soundEx

, wo ein Treffer bei einer der fünf Operationen die ID # zu einem Ergebnis-Array hinzufügt, das verwendet wird, um die Ergebnisse von 470 Darstellern auf eine vernünftige Liste herunterzuschränken, aus der sie auswählen können.

Festlegungen:

1) Wie schon geschrieben, ich weiß, dass das ein SQL-Injection-Angriff anfällig ist.

2) Server läuft PHP 4.4.9 und MySQL 4.0.27-Standard, ich kann es nicht aktualisieren. Ich muss beweisen, dass es funktioniert, bevor Geld ausgegeben wird.

3) Dies ist Hobby-Zeug, nicht mein Job.

4) Die Interpreten verwenden häufig nicht englische Namen oder Elemente in ihren Namen, was zu Tippfehlern und Verdoppelungen durch die Schreibkräfte geführt hat.

Ich habe eine Menge mysqli und PDO Antworten für diese Art von Sache gefunden, und ich sehe eine Menge Dinge, die nur die Hälfte sinnvoll sind (wie Link # 4 unten). Ich arbeite daran, mich über diese Dinge auf dem Laufenden zu halten, während ich versuche zu reparieren, was kaputt geht.

Orte sah bereits:

  1. PHP mysql using an array in WHERE clause
  2. PHP/MySQL small-scale fuzzy search
  3. MySQL SubString Fuzzy Search
  4. Sophisticated Name Lookup
+0

Die ersten Dinge zuerst, "mysql_ *" sind jetzt deeperated. Verwenden Sie stattdessen "mysqli_ *" -Funktionen. :) – Ronald

+0

Ist MySQL auf PHP v4.4.9 verfügbar? –

+1

Mit mehreren hundert Optionen und einer Typ-Ahead, würde ich vorschlagen, Daten über Serviceaufruf (AJAX) im Hintergrund nach dem Laden der Seite zu laden, und Typahead mit einem Javascript-Tool, z. [Typaehead-Bibliothek von Twitter] (https://twitter.github.io/typeahead.js/examples/), * besonders * wenn Sie nach mehreren Spalten suchen. – alttag

Antwort

1

ich in den Kommentaren erwähnt, dass eine typeahead Bibliothek Javascript könnte eine gute sein Wahl für dich. Ich habe festgestellt, Twitter Artheahead-Bibliothek und Bloodhound-Engine ziemlich robust. Leider ist die Dokumentation eine bunte Mischung: Solange das, was Sie brauchen, ihren Beispielen sehr ähnlich ist, sind Sie golden, aber bestimmte Details (zB Erläuterungen zu den Tokenizern) fehlen.

In einem der several questions re Typeahead hier auf Stack-Überlauf, @JensAKoch sagt:

ehrlich zu sein, ich denke, twitter auf typeahead.js aufgab. Wir betrachten 13000 Sterne, einen vollständigen Bugtracker ohne Maintainer und eine kaputte Software, letzte Ausgabe 2015. Ich denke, das spricht für sich selbst oder nicht? So ..., versuchen Sie eine der Gabeln: github.com/corejavascript/typeahead.js

Ehrlich gesagt, in einer kurzen Überprüfung der Dokumentation auf der Gabel sieht ein bisschen besser, wenn sonst nichts. Vielleicht möchten Sie es überprüfen.

Server-Side-Code:

Alle der Einsprüche von einer alten Version von PHP anwenden. Ich empfehle dringend, PDO mit PHP 5 neu zu installieren, aber dieses Beispiel verwendet PHP 4 wie gewünscht.

Vollständig ungeprüfter PHP-Code. json_encode() wäre besser, aber es wird nicht angezeigt, bis PHP 5. Ihr Endpunkt wäre so etwas wie:

headers("Content-Type: application/json"); 
$results = mysql_query(
    "SELECT ID,StageName,AKA1,AKA2,LegalName,SoundEx FROM performers" 
); 

$fields = array("ID","StageName","AKA1","AKA2","LegalName","SoundEx"); 

echo "["; 

$first = true; 
while ($row = mysql_fetch_array($results)) { 
    ($first) ? $first = false : echo ','; 

    echo "\n\t,{"; 
    foreach($fields as $f) { 
     echo "\n\t\t\"{$f}\": \"".$row[$f]."\""; 
    } 
    echo "\n\t}"; 
} 
echo "]"; 

clientseitigen Code:

diesem Beispiel wird ein static JSON file als Stub verwendet für alle die Ergebnisse. Wenn Sie davon ausgehen, dass Ihr Ergebnissatz über 1.000 Einträge enthält, sollten Sie sich die remote option of Bloodhound ansehen. Dies würde erfordern, dass Sie einen benutzerdefinierten PHP-Code schreiben, um die Abfrage zu behandeln, aber er würde weitgehend dem Endpunkt ähneln, der alle (oder zumindest Ihre gebräuchlichsten) Daten ablegt.

var actors = new Bloodhound({ 
 
    // Each row is an object, not a single string, so we have to modify the 
 
    // default datum tokenizer. Pass in the list of object fields to be 
 
    // searchable. 
 
    datumTokenizer: Bloodhound.tokenizers.obj.nonword(
 
    'StageName','AKA1','AKA2','LegalName','SoundEx' 
 
), 
 
    queryTokenizer: Bloodhound.tokenizers.whitespace, 
 
    // URL points to a json file that contains an array of actor JSON objects 
 
    // Visit the link to see details 
 
    prefetch: 'https://gist.githubusercontent.com/tag/81e4450de8eca805f436b72e6d7d1274/raw/792b3376f63f89d86e10e78d387109f0ad7903fd/dummy_actors.json' 
 
}); 
 

 
// passing in `null` for the `options` arguments will result in the default 
 
// options being used 
 
$('#prefetch .typeahead').typeahead(
 
    { 
 
     highlight: true 
 
    }, 
 
    { 
 
     name: 'actors', 
 
     source: actors, 
 
     templates: { 
 
     empty: "<div class=\"empty-message\">No matches found.</div>", 
 
     
 
     // This is simply a function that accepts an object. 
 
     // You may wish to consider Handlebars instead. 
 
     suggestion: function(obj) { 
 
      return '<div class="actorItem">' 
 
       + '<span class="itemStageName">'+obj.StageName+"</span>" 
 
       + ', <em>legally</em> <span class="itemLegalName">'+obj.LegalName+"</span>" 
 
     } 
 
     //suggestion: Handlebars.compile('<div><strong>{{value}}</strong> – {{year}}</div>') 
 
     }, 
 
     display: "LegalName" // name of object key to display when selected 
 
     // Instead of display, you can use the 'displayKey' option too: 
 
     // displayKey: function(actor) { 
 
     //  return actor.LegalName; 
 
     // } 
 
});
/* These class names can me specified in the Typeahead options hash. I use the defaults here. */ 
 
    .tt-suggestion { 
 
     border: 1px dotted gray; 
 
     padding: 4px; 
 
     min-width: 100px; 
 
    } 
 
    .tt-cursor { 
 
     background-color: rgb(255,253,189); 
 
    } 
 
    
 
    /* These classes are used in the suggestion template */ 
 
    .itemStageName { 
 
     font-size: 110%; 
 
    } 
 
    .itemLegalName { 
 
     font-size: 110%; 
 
     color: rgb(51,42,206); 
 
    }
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script> 
 
<script src="https://twitter.github.io/typeahead.js/releases/latest/typeahead.bundle.js"></script> 
 

 

 
<p>Type something here. A good search term might be 'C'.</p> 
 
<div id="prefetch"> 
 
    <input class="typeahead" type="text" placeholder="Name"> 
 
</div>

Zur Erleichterung, hier ist die Gist of the client-side code.

+0

Das sieht nach einer brauchbaren Lösung aus. Ich bin nicht so versiert in Javascript wie ich in PHP bin. Ich werde das sicherlich gründlich untersuchen. Vielen Dank. –