Kötegelt feldolgozás AJAX és PHP segítségével

Sokszor előfordul, hogy olyan nagy mennyiségű információt kell feldolgoznunk PHP-val ami már nem fér bele az olykor nagyon szűkös futási időkeretbe. Ekkor praktikus szétbontani a feladatott több részfeladatra és ezeket a részfeladatokat egymás után végrehajtani. A célom az volt, hogy készítsek egy icipici kis AJAX-os példarendszert a probléma megoldására. Lássuk mi kell ehhez.

Először is szükségünk lesz egy jófajta JavaScript keretrendszerre, hogy ne kelljen feltalálnunk a meleg vizet. Én a JQuery-t választottam, mivel azt jól ismerem és használom már régóta. Lesz két fájlunk. Az egyik ami mutatja, hogy éppen hol tartunk és tartalmazza a kliens oldali programrészeket. A másik lesz a tulajdonképpeni PHP, ami a feldolgozást végzi.

Nézzük az első fájlt, melyet nevezzünk index.html-nek

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  2. <html>
  3. <head>
  4. <meta http-equiv="content-type" content="text/html; charset=utf-8">
  5. <title>Kötegelt feldolgozó</title>
  6. <script type="text/javascript" src="jquery.js"></script>
  7. <script type="text/javascript">
  8. /* itt lesz az AJAX-os JavaScript kódunk */
  9. </script>
  10. <style>
  11. #slider { margin: 30px; border: 1px solid black; }
  12. #slider div { height: 20px; background-color: blue; width: 0px; }
  13. #messages p { margin: 0; padding: 0; border-bottom: 1px dotted black; }
  14. </style>
  15. </head>
  16. <body>
  17. <div id="slider">
  18. <div>
  19. </div>
  20. </div>
  21. <div id="slider_info">
  22. </div>
  23. <div id="messages">
  24. </div>
  25. </body>
  26. </html>

Mint látható három div elem van. Az első mutatja meg nekünk grafikusan, hogy éppen hol tartunk. Maga a div egy egyszerű kis téglalap ami rendelkezik egy szép elegáns fekete kerettel. Ebben van egy kék hátterű másik div, mely a csíkot fogja húzni. Kezdeti mérete nulla, hisz még nem tartunk sehol sem.
A második, slider_info azonosítójú div fogja tartalmazni azt a szöveges információt, hogy éppen hol tartunk és mennyi van még hátra.
A harmadik div elembe pedig a PHP-től jövő üzeneteket foguk megjeleníteni. Itt láthatjuk, hogy mi az amit sikerült és mi az amit nem sikerült megtennie a scriptünknek.
Nézzük a JavaScriptet!

  1. $.getJSON("send.php?id=0", feldolg);
  2. function feldolg(json){
  3. $('#slider_info').html(json.szam + ' / ' + json.ossz);
  4. hossz = $('#slider').width();
  5. $('#slider div').width(hossz * json.szam / json.ossz);
  6. $('#messages').append('<p>'+ json.message +'</p>');
  7. if(json.szam < json.ossz){
  8. $.getJSON("send.php?id="+ json.szam, feldolg);
  9. }else{
  10. $('#slider div').css('background-color','green');
  11. }
  12. }

Természetesen a működéshez szükségünk lesz még a JQuery függvény könyvtárra is. Nézzük a kódot részletesen.
  1. $('#slider_info').html(json.szam + ' / ' + json.ossz);

Itt annyit csinálunk, hogy beírjuk az információs div-be, hogy éppen hol tartunk és mennyi az összes feldolgozandó rekord. Felhívnám a figyelmet itt és most, hogy ez egy olyan mintakód, mely pusztán a működés bemutatására szolgál. Nincs benne semmifajta hibakezelés. Nem vizsgáljuk, hogy sikerült-e a lekérés, jött-e egyáltalán adat és ha jött az megfelelő-e.
  1. hossz = $('#slider').width();
  2. $('#slider div').width(hossz * json.szam / json.ossz);

Beállítjuk a kék sáv szélességét. A számítás egyszerű. A befoglaló div hosszát annyi részre osztjuk ahány feldolgozandó rekordunk lesz, majd ezt a számot megszorozzuk azzal a számmal, mely jelzi mennyi adatot dogloztunk már fel. A műveletek fordított sorrendje egy rég elfeledett a gépi kódú programozást idéző egész számos aritmetika nyomait idézi.
  1. $('#messages').append('<p>'+ json.message +'</p>');

Kiíratjuk a kapott üzenetet. A friss üzeneteket mindig a többi végére szúrjuk be.

  1. if(json.szam < json.ossz){
  2. $.getJSON("send.php?id="+ json.szam, feldolg);
  3. }else{
  4. $('#slider div').css('background-color','green');
  5. }

Amennyiben nem végeztünk, újra elindítjuk ezt a szép asszinkron folyamatot. Ha már minden elemet feldolgoztunk, akkor szép zöldre állítjuk a csíkot, hogy tudjuk a feldolgozás befejeződött.

Végezetül nézzük a PHP fájlt.

  1. <?
  2. include('dbconnect.php');
  3. $limit = 10;
  4. $sql = "SELECT * FROM tabla ...";
  5. $csql = "SELECT COUNT(*) as db FROM tabla ...";
  6. $ossz = $db['db'];
  7. $res = mysql_query($sql. ' LIMIT '. (int)$_GET['id'] .','. (int)$limit);
  8. $id = (int) $_GET['id'] + $limit;
  9. if ($id > $ossz) {$id = $ossz;}
  10. $message = '';
  11. while($row = mysql_fetch_assoc($res)){
  12. // itt csináljuk azt amit csinálunk
  13. // az eredményt beletesszük a $message változóba
  14. }
  15. print "{ szam : $szam, ossz : $ossz, message : '$message'}";

Az első természetesen az, hogy betöltjük az adatbázis kapcsolódásához szükséges részeket, ezt itt nem részletezem. A $limit változóba beállítjuk, hogy egy akció során egyszerre hány rekordot szeretnénk feldolgozni.
  1. <?
  2. include('dbconnect.php');
  3. $limit = 10;

Ezután lekérdezzük, hogy hány rekordunk lesz összesen.
  1. $sql = "SELECT * FROM tabla ...";
  2. $csql = "SELECT COUNT(*) as db FROM tabla ...";
  3. $ossz = $db['db'];

Természetesen az itt látható sql lekérdezés nem egy teljes értékű használható kód, csak egy minta. Az esetek nagy részében elégséges, hogy a rekordok lekérdezésére szolgáló query-ben ($sql) kicseréljük a SELECT és FROM közötti részt a következő kódra: " COUNT(*) as db ". Ne felejtsük el azonban, hogy egy "bonyolultabb" lekérdezésben, ahol pl. GROUP direktívát használunk, vagy egy másik al-lekérdezés eredményét ez nem lesz elég. Ott le kell ülnünk és átgondolnunk, hogy mely lekérdezés fogja a megfelelő eredményt adni. Miután ez megvan lekérdezzük az egyetlen egy rekordot és a kapott eredmény egyetlen egy oszlopát beletöltjük az $ossz változóba.
Ezek után jöhet a megfelelő szelet amit feldolgozunk.
  1. $res = mysql_query($sql. ' LIMIT '. (int)$_GET['id'] .','. (int)$limit);

Látszik, hogy csak egyszerűen hozzárakjuk a LIMIT záradékot a megfelelő paraméterezéssel. A kezdő rekord számát ($_GET['id']) az AJAX-os alkalmazástól kapjuk, ezért ezt típus kényszerítjük, ezzel elkerülve az esetleges felhasználótól érkező trükkös hibákat. A $limit paraméter ugyan a saját kódunkból érkezik, de biztos ami ziher arra is rárakjuk a típuskényszerítést. Erre azért van szükség, mert lehetséges, hogy egy óvatlan pillanatban egy ügyes kis függvénybe helyezzük el ezt a kódot és akkor már nem a mi kódunkból, hanem a felhasználót érkezik majd ez a paraméter is. Mindenképpen érdemes azonban megszokni azt, hogy bármely SQL lekérdezés összerakásánál a változókat vagy escape-eljük, vagy típus kényszerítjük. Ez nem véd meg minket minden esetben az SQL-injection támadások ellen, de az alap hibákat ki tudjuk ezzel küszöbölni.
Ezek után kiderítjük a következő adag kezdő rekordszámát.
  1. $id = (int) $_GET['id'] + $limit;
  2. if ($id > $ossz) {$id = $ossz;}

Amennyiben a lépésszám ($limit) nem osztója az összes elem számának ($ossz) akkor természtesen az utolsó etapban a következő adag kezdő rekordszáma nagyobb lesz mint az összes elem száma. Ebben az esetben beállítjuk az $id-t az utolsó rekord utánra, így jelezzük a JavaScript függvényünknek, hogy véget ért a feldolgozás.
Most következzen kódunk legkidolgozatlanabb része.
  1. $message = '';
  2. while($row = mysql_fetch_assoc($res)){
  3. // itt csináljuk azt amit csinálunk
  4. // az eredményt beletesszük a $message változóba
  5. }

Végigmegyünk az eredmény halmazon és feldolgozzuk. Itt küldhetünk E-mail-t, konvertálhatunk fájlokat, végrehajthatunk bonyolult lekérdezéseket stb.
A végén pedig kiírjuk a válaszunkat.
  1. print "{ szam : $szam, ossz : $ossz, message : '$message'}";

Természetesen ez sem egy tökéletes kód. A legfontosabb, hogy a $message változó nem tartalmazhat soremelést, csak '\n' karakterpárost. Figyelj ezt úgy tudod PHP-ben szöveges változóba beletenni, hogy dupla visszaperjelet használsz! A kódból talán kiderül az is, hogy aposztrófot (') sem túl egészséges használni, azt is csak escape-elve tegyük bele az üzeneteinkben.

Remélem hasznos volt ez a kis szösszenet, egészségetekre.

Szia pp! Erre jártam, és

Szia pp!

Erre jártam, és megláttam ezt a post-ot. Jó kis post, de én arra lennék még kiváncsi, hogy a fenti munkából mennyit lehet megspórolni, ha Drupal-os megoldást készítünk. Másképpen: a Drupal milyen függvénykkel, hook-okkal segíti az ilyen kötelgelt feldolgozást?

Nyitott kapukat döngetsz!

Nyitott kapukat döngetsz! Terveim közt szerepel egy rövidke írás erről magyarul, amint lesz időm megírom. Addig is: A drupal.org-on van egy nagyon jó leírás - igaz angolul - azt tanulmányozd át. Nem hiszem, hogy túlzottan nagy problémát okozna az ott található kód megértése.

pp

Hozzászólás

A mező tartalma nem nyilvános.
  • A webcímek és email címek automatikusan linkekké alakulnak.
  • A sorokat és bekezdéseket a rendszer automatikusan felismeri.
  • You can enable syntax highlighting of source code with the following tags: [code], [blockcode].

További információ a formázási lehetőségekről

Type the characters you see in this picture. (verify using audio)
Type the characters you see in the picture above; if you can't read them, submit the form and a new image will be generated. Not case sensitive.