[PHP] Auto completion erg traag

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • bindsa
  • Registratie: Juli 2009
  • Niet online
Ik heb op mijn site een auto completion script draaien, dit werkt perfect, maar is erg traag. De gegevens waarin wordt gezocht worden eerst d.m.v. PHP in een JavaScript variabele gezet, die variabele wordt vervolgens in een jQuery script geladen die voor het auto completen zorgt. Het probleem van de snelheid zit hem hier denk ik in de page generate time van het PHP script. Is er een manier van caching o.i.d. mogelijk (de user database verandert niet elke minuut)? Of weet iemand een snellere manier?

Hier staan wat gegevens en 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
31
32
33
34
35
36
37
38
39
40
41
42
<?
require_once "dbfunctions.php";
connect();
$query_leerlingen = dbquery("SELECT leerlingnummer, voornaam, tussenvoegsel, achternaam FROM leeromgeving_leerlinggegevens");
$query_personeel = dbquery("SELECT personeelslid, voornaam, tussenvoegsel, achternaam FROM leeromgeving_personeelsgegevens");
disconnect();
print "var gegevens = [ \n";
$i = 0; 
while (list($leerlingnummer, $voornaam, $tussenvoegsel, $achternaam) = mysql_fetch_row($query_leerlingen)) { 
    if(!empty($tussenvoegsel)) {
        $naam = $voornaam . " " . $tussenvoegsel . " " . $achternaam;
    }
    else {
        $naam = $voornaam . " " . $achternaam;
    }
    $id = $leerlingnummer;
    if($i == 0) {
        echo "{ naam: \"$naam\", id: \"$id\" }";
    }
    else {
        echo ", \n { naam: \"$naam\", id: \"$id\" }";
    }
    $i++;
}
while (list($personeelslid, $voornaam, $tussenvoegsel, $achternaam) = mysql_fetch_row($query_personeel)) {
    if(!empty($tussenvoegsel)) {
        $naam = $voornaam . " " . $tussenvoegsel . " " . $achternaam;
    }
    else {
        $naam = $voornaam . " " . $achternaam;
    }
    $id = $personeelslid;
    if($i = 0) {
        echo "{ naam: \"$naam\", id: \"$id\" }";
    }
    else {
        echo ", \n { naam: \"$naam\", id: \"$id\" }";
    }
    $i++;
}
print "]; \n";
?>


Deze code wordt vervolgens in de pagina geladen d.m.v. deze code:
HTML:
1
<script type='text/javascript' src='../includes/search.php'></script>


Het script voor het autocompleten is als volgt (hiervoor wordt de plugin jQuery autocomplete gebruikt):
JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$(function() { 
    $('#delersbox').dialog({modal: true, bgiframe: true, closeOnEscape: true, buttons: {Annuleren: function() {$(this).dialog('close');}}});    
    $('#delersbox').dialog('close');
    $('.sharelinks').click(function() {
        $('#shareform').append("<input type = 'hidden' name = 'file' value = '" + $(this).attr('id') + "'>");
        $('#delersbox').dialog('open');
        $("#autocomplete").autocomplete(gegevens, {
            width: 300,
            multiple: true,
            matchContains: true,
            formatItem: function(row, i, max) {
                return row.naam + " (" + row.id + ")";
            },
            formatMatch: function(row, i, max) {
                return row.id;
            },
            formatResult: function(row) {
                return row.id;
            }
        });
    })
}); 

En tot slot wordt de volgende HTML gebruikt om de auto completion box weer te geven:
HTML:
1
2
3
4
5
6
7
8
9
10
11
<div id = 'delersbox' title = 'Delers toevoegen' style = 'display:none;'>
<form action = '?pageindex=diskspace&action=sharesupdate' id = 'shareform' method = 'post'>
<p>
<textarea id = 'autocomplete' cols = '40' rows = '3' name = 'sharesfield'></textarea>
<br>
</p>
<input type = 'submit' value = 'Voeg delers toe'>
</form>
<ol id="result"></ol>
<br>
</div>

Acties:
  • 0 Henk 'm!

  • Cartman!
  • Registratie: April 2000
  • Niet online
Je kunt inderdaad caching inbouwen (die verwijder je weer als je aanpassingen doet aan de database bijvoorbeeld). Ik begrijp ook niet helemaal wat je insteek is met deze autocomplete nu want je roept voor elke keypress de volledige tabellen elke keer aan. Geen wonder dat dit langzaam is zonder caching.

Overigens nog een paar opmerkingen:
- waarom zo moeilijk doen met al je " echo ", \n { naam: \"$naam\", id: \"$id\" }"; " stukjes? Bouw een array en gooi er json_encode() overheen.
- maak er in je list $leerlingnummer van om daarna $id te benoemen en $leerlingnummer niet te gebruiken, maak er dan meteen $id van

Acties:
  • 0 Henk 'm!

  • 418O2
  • Registratie: November 2001
  • Laatst online: 23:31
Ik zou mijn PHP even profilen, kijken waar de bottleneck zit. Ook even mbv Firebug kijken wat waar gebeurd.

Dan zou je al een stuk verder moeten zijn

Acties:
  • 0 Henk 'm!

  • HuHu
  • Registratie: Maart 2005
  • Niet online
Waarom haal je alle leerling- en personeelsgegevens op voor je autocompletion? Ik kan me voorstellen dat het dan traag wordt als je veel data hebt. Autocompletion gaat om het aanvullen van dingen, dus ik verwacht dan op z'n minst een WHERE voornaam LIKE 'ja%' in je query.

Verder zit er een fout op regel 33, dat moet een == zijn.

Acties:
  • 0 Henk 'm!

  • HuHu
  • Registratie: Maart 2005
  • Niet online
Ow... en besef je wel dat je met zo'n autocompletion je volledige leerlingen- en personeelsdatabase op internet gooit? Ik mag hopen dat er beveiliging op zit, zodat niet iedereen er bij kan?

Acties:
  • 0 Henk 'm!

  • bindsa
  • Registratie: Juli 2009
  • Niet online
Allereerst iedereen bedankt voor het reviewen van mijn code, de fouten zijn er uit en bezig met json_encode().
@huhu: Inloggen is nodig, dus hij is inderdaad beveiligd, zou niet best wezen anders, het gaat trouwens niet om een echt gebruikt systeem, het gaat in dit geval om een PWS, we maken een digitale leeromgeving.

Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Dan nog moet je toch echt wel een where clause met minimum aantal karakters erin stoppen. Een hele tabel leegtrekken moet je eigenlijk nooit willen.

{signature}


Acties:
  • 0 Henk 'm!

  • pasz
  • Registratie: Februari 2000
  • Laatst online: 01-09 23:08
De hele database overtrekken is eerlijk gezegd een beetje een bijzonder ....

Als ik jou was, zou ik de database query pas uitvoeren als iemand wat intoetst. Bij veel auto-completion scriptjes kun je instellen hoeveel karakters een gebruiker moet intypen voordat de database wordt aangesproken. Hetgene wat de gebruiker heeft ingetypt kun je gebruiken in je WHERE-cluase.

Nog een kleine tip : pas op voor SQL-injection.

sorry, zag dat vautlooz een soortgelijk antwoord gaf.

[ Voor 7% gewijzigd door pasz op 21-12-2009 10:42 ]

woei!


Acties:
  • 0 Henk 'm!

  • bindsa
  • Registratie: Juli 2009
  • Niet online
Ik heb het script nu totaal veranderd via GET wordt nu de query string opgegeven en op basis daarvan wordt er data uit de database gehaald. Nog 1 probleempje, het script kijkt nu al wel of er wel ingelogd is, maar ik zou graag willen dat als een ingelogde de directe link naar dit script (=search.php) intikt, hij niets te zien krijgt, weet iemand hou dat zou moeten?

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
<?
session_start();
if($_SESSION['ingelogd'] == 1) {
    $q = htmlspecialchars(nl2br(strip_tags(strtolower($_GET["q"]))));
    if (!$q) return;
    require_once "dbfunctions.php";
    connect();
    $query_leerlingen = dbquery("SELECT leerlingnummer, voornaam, tussenvoegsel, achternaam FROM leeromgeving_leerlinggegevens WHERE leerlingnummer LIKE '%$q%' OR tussenvoegsel LIKE '%$q%' OR achternaam LIKE '%$q%' OR voornaam LIKE '%$q%'");
    $query_personeel = dbquery("SELECT personeelslid, voornaam, tussenvoegsel, achternaam FROM leeromgeving_personeelsgegevens WHERE personeelslid LIKE '%$q%' OR tussenvoegsel LIKE '%$q%' OR achternaam LIKE '%$q%' OR voornaam LIKE '%$q%'");
    disconnect();
    while (list($id, $voornaam, $tussenvoegsel, $achternaam) = mysql_fetch_row($query_leerlingen)) {
       if(!empty($tussenvoegsel)) {
          $naam = $voornaam . " " . $tussenvoegsel . " " . $achternaam;
       }
       else {
          $naam = $voornaam . " " . $achternaam;
       }
       echo "$id|$naam\n";
    }
    while (list($id, $voornaam, $tussenvoegsel, $achternaam) = mysql_fetch_row($query_personeel)) {
       if(!empty($tussenvoegsel)) {
          $naam = $voornaam . " " . $tussenvoegsel . " " . $achternaam;
       }
       else {
          $naam = $voornaam . " " . $achternaam;
       }
       echo "$id|$naam\n";
    }
}
?>

Acties:
  • 0 Henk 'm!

  • KabouterSuper
  • Registratie: September 2005
  • Niet online
ehm, hij geeft toch een lege pagina terug? Of bedoel je dat niet met "niets te zien krijgen"?

When life gives you lemons, start a battery factory


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Op deze manier ben je in ieder geval verkeerd bezig.
PHP:
1
$q = htmlspecialchars(nl2br(strip_tags(strtolower($_GET["q"]))));

Is in ieder geval geen goede manier om escaping voor je query te doen.

Ik zie in ieder geval geen nut voor strip_tags/nl2br/htmlspecialchars, en ik mis het escapen voor database specifieke dingen.

[ Voor 24% gewijzigd door Woy op 21-12-2009 11:47 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • MueR
  • Registratie: Januari 2004
  • Laatst online: 21:34

MueR

Admin Tweakers Discord

is niet lief

Hoe snel zijn de querys uberhaupt? Verder met Woy wbt escapen.

Anyone who gets in between me and my morning coffee should be insecure.


Acties:
  • 0 Henk 'm!

  • bindsa
  • Registratie: Juli 2009
  • Niet online
Weet iemand hoe ik ervoor zorg dat als iemand het script (search.php?q=lol) direct via de browser intikt hij een lege pagina terugkrijgt, zodat dit script alleen werkt als het wordt benaderd vanuit het autocompletion script?

Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
L0calh0st schreef op maandag 21 december 2009 @ 12:24:
Weet iemand hoe ik ervoor zorg dat als iemand het script (search.php?q=lol) direct via de browser intikt hij een lege pagina terugkrijgt, zodat dit script alleen werkt als het wordt benaderd vanuit het autocompletion script?
Waterdicht kun je dat niet krijgen, en ik zie ook niet in waarom je dat zou willen. Je stelt die gegevens immers toch beschikbaar voor de gebruiker, waarom zou je dat dan willen beveiligen.

Echter zou je bijvoorbeeld een extra header in je request toe kunnen voegen bij je script, en daar dan op controleren, maar daar is natuurlijk makkelijk omheen te werken als je zou willen.

Verder zul je gewoon eens moeten gaan profilen als het niet snel genoeg is. Ga eerst eens uitzoeken waar de bottleneck zit, en ga dan kijken hoe je dat specifieke stukje kunt optimaliseren.

Op de manier in je TS, waar je de complete tabel overstuurt, kun je het result natuurlijk gewoon in je cache stoppen, en die direct outputten. Maar als de query niet de bottleneck is, ga je daar niet veel mee opschieten.

[ Voor 22% gewijzigd door Woy op 21-12-2009 12:30 ]

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”

Pagina: 1