Ndodheni ne: Guidat / MySQL / PHP
Motor Kerkimi me PHP dhe MySQL (Full Text Search)

Motor Kërkimi me PHP dhe MySQL (Full Text Search)

Nga më 23 July 2010 në MySQL, PHP me 7 Komente

Në këtë guidë do ju tregoj si të ndërtoni një motor kërkimi plotësisht funksional me PHP dhe MySQL, duke përdorur FULLTEXT SEARCH. Përveç kërkimit në databazë, do ju mësoj si të kodoni një korrigues fjalësh dhe veçimin e fjalëve kyçe në përmbajtje.

  • Shkarko Kodin
  • Shiko Demon

Si mund ta kuptoni shumë mirë nga titulli, në këtë guidë do ju tregoj si të ndërtoni një motor kërkimi për faqen tuaj duke përdorur PHP dhe MySQL. Që mos ta kuptoni keq pa filluar, po flas për një motor kërkimi që kërkon në databazën e faqes tuaj, jo online si Google. Ideja e realizimit të kësaj guide më erdhi nga një kërkesë e dikujt në forum dhe duke menduar se mund ti interesojë shumë të tjerëve, ja ku jemi :)

Çfarë është dhe çfarë bën ky motor kërkimi?

Fusha e kërkimit, renditjes së rezultateve dhe paraqitjes së tyre në një formë të lexueshme dhe informative është mjaft komplekse, për të thënë minimumin. Të jem i sinqert, motori që kam realizuar për këtë guidë është relativisht i mirë, por s’është në asnjë sektor të tij as afër perfektes. Kjo kuptohet sepse po flasim për një kod të shkruar brenda pak ditëve në kohën e lirë, për të cilin s’kam bërë kërkime të thelluara dhe s’kam punësuar një ekip të tërë. Prandaj mos e merrni si referencë absolute asnjë nga kodet që do ju tregoj më pas dhe nëse mendoni ta përdorni për një mjedis real, kini parasysh që çdo gjë në të mund të përmirësohet. Qëllimi i kësaj guide është t’ju tregoj si ndërtohet skeleti i një motori kërkimi, i cili mund të zgjerohet lehtësisht më pas.

Po ju them që është relativisht i mirë për arsyet më poshtë:

  • Përdor Full Text Search, një teknikë kërkimi e implementuar në MySQL.
  • I rendit rezultatet në bazë të rezultatit që MySQL kthen.
  • Përdor operatorë Boolean për kërkime më specifike.
  • Ofron një fjalor shumë të vogël (i cili mund të zgjerohet) për të sugjeruar fjalë të gabuara.
  • I “ndriçon” (i bën bold) fjalët e gjetura nga kërkimi në tituj dhe përmbajtje.

Ato që ofron janë baza e një motori kërkimi dhe nga testet e mia, funksionojnë mirë. Megjithatë, mund të shtohen shumë gjëra për ta bërë akoma më spektakolar. Disa ide:

  • Mund të përmirësohet renditja duke krijuar një algoritëm personal.
  • Fjalori mund të zgjerohet duke përfshirë shumë më tepër fjalë. Futja e të gjithë fjalorit të gjuhës Shqipe do ishte çmenduri, por mund të shtohen fjalët më të kërkuara ose terma specifike për faqen.
  • Fjalori ruhet në një vektor, por jam i sigurt që ka zgjidhje me efikase për një fjalor me dhjetëra mijëra fjalë.
  • Algoritmi i sugjerimit ka vend për përmirësim.
  • Mund ti shtohet sugjerim kërkimi në kohë reale. Ka të tillë të gatshëm të shkruajtur në Javascript.

Për ta mbyllur intron, do ndërtojmë një motor që ka disa opsione interesante e që me siguri do i shërbejnë programuesëve që nuk e kanë prekur këtë fushë. Do i shërbejë patjetër edhe atyre që duan një motor kërkimi të thjeshtë për faqen e tyre, të cilët mund ta implementojnë fare lehtë. Le t’i bëjmë duart pis me kod tani, sepse fjalët vështirë se i shërbejnë dikujt :)

Krijimi i databazës

Ndoshta ndryshe nga çfarë imagjinoni, kodi për të ndërtuar këtë motor nuk është as i gjatë e as tepër i komplikuar. Do shini në vijim që do përdor vetëm një query, disa vektorë dhe manipulim i çmendur (sepse është në përgjithësi) tekstesh. Asgjë super-fantastike që kërkon 1000 rreshta kod. Por si fillim na duhet të ndërtojmë databazën. Krijoni një databazë të re që përmban këto fusha:

id – int(11)
titulli – tinytext
permbajtja – text

E mira është ta mbushni databazën me informacione, përkundrazi do kërkojmë në boshllëk. Ose bëni copy-paste disa artikuj, ose përdorni databazën e atashuar me skedarët e guidës (në fillim të artikullit; butoni “Shkarko Kodin”). Ju këshilloj të merrni databazën e atashuar sepse fjalori i sugjerimeve (prej 11 fjalësh) është “optimizuar” për të.

Hapi tjetër është të krijoni indekset FULL TEXT në databazën e sapo krijuar. Vetëm duke i krijuar këto indekse do i tregoni MySQL se fushat në fjalë duhet janë të kërkueshme, pëndryshe query që do krijojmë më pas do dështojë. Keni 2 mundësi për krijimin e këtyre indekseve të mallkuar:

1) Duke përdorur një query si më poshtë:

 MySQL |  Kopjo Kodin |? 
1
ALTER TABLE artikujt ADD FULLTEXT(titulli, permbajtja);

Problemi i vetëm është se duhet të keni privilegjet e duhura për të kryer këtë query, gjë që kam përshtypjen se hostet shared nuk e lejojnë (më korrigjoni nëse jam gabim). Sidoqoftë provojeni dhe shkurtojini vetes punë, sepse metoda e dytë është pak më e gjatë.

2) Duke përdorur PHPMyAdmin. Për fat të keq krijimi i indekseve duket i lehtë në pamje të parë, sepse ofrohet një buton i dedikuar direkt në krah të kolonave, por nuk është nëse po krijoni më shumë se 1 indeks. Shikoni foton e mëposhtme që ju tregon hapat e duhura.

Indeksi Fulltext ne PHPMyAdmin

Shtimi i Indeksit FULLTEXT në PHPMyAdmin – Hapi 1

Indeksi Fulltext ne PHPMyAdmin

Shtimi i Indeksit FULLTEXT në PHPMyAdmin – Hapi 2

Shpresoj mos t’ju dalin probleme në këtë fazë, por besoj se fotot që ju dhashë ja u lehtësojnë punën. Me të krijuar edhe indekset, po fillojmë të shkruajm kodin.

Të shkruajmë kodin

Fillon edhe pjesa e vështirë e guidës, prandaj dua vëmendjen tuaj. Do mundohem t’ju shpjegoj çdo rresht një për një që mos t’ju shpëtojë asgjë pa kuptuar, por nëse e keni mendjen tek filmi i bukur që po jepet në TV, sigurisht që s’do kuptoni gjë. Vëmendje! :)

Gjëja e parë është kodi HTML, një formë e thjeshtë më një input dhe një buton.

 HTML |  Kopjo Kodin |? 
1
<form>
2
     <input type="text" name="kerkimi" value="<?php echo $_GET['kerkimi']; ?>" />
3
     <button type="submit"> Kerko </button>
4
</form>

Më thjeshtë se kaq s’bëhet. Forma është GET (vlera default) sepse dua që kërkimi të jetë i aksesueshëm nga URL-ja. Në këtë mënyrë mund të bëhet edhe bookmark, ose mund të dërgohet një query direkt nga një link apo çfarëdo qoftë. Thjeshtë është ide e mirë që kërkimi të jetë GET dhe jo POST. Vini re që kam shkruajtur edhe një kod PHP aty brenda atributit “value” të inputit. Ai kod bën që në fushën e kërkimit të dalë fjala e kërkuar dhe mos të rri bosh pasi të jetë dërguar forma. Thjeshtë një printim i variablës GET që mban kërkimin.

Poshtë kodit HTML do fillojmë ti japim jetë motorit tonë të kërkimit. E nisim me:

 PHP |  Kopjo Kodin |? 
1
<?php
2
if(isset($_GET['kerkimi'])){
3
     //ketu vijon pjesa tjeter e kodit
4
}
5
?>

Komentin brenda e kam shkruajtur dhe do vazhdoj ta bëj në vijim që ta kuptoni se ku vendosen kodet që vijnë më pas. Çfarë kam bërë është kontrollimi nëse është krijuar variabla GET ‘kerkimi’, pra është kërkuar. Funksioni isset() kontrollon nëse variabla është krijuar dhe kthen TRUE nëse po, FALSE nëse jo.

 PHP |  Kopjo Kodin |? 
1
<?php
2
include('funksionet.php');
3
$lidhja = mysql_connect('localhost', 'root', '');
4
mysql_select_db('test');
5
$kerkimi = mysql_real_escape_string($_GET['kerkimi']);
6
?>

Rreshti i parë përfshin një skedar të jashtëm që e kam përdorur për funksionet. Përmbajtjen e tij do ta shohim në fund. Rreshti i dytë dhe i tretë bëjnë respektivisht lidhjen me serverin e databazës dhe zgjedhjen e tabelës së duhur. Unë e kam koduar motorin në një server lokal, prandaj janë ato të dhëna, por vendosni të dhënat e serverit tuaj (lokal apo jo). Sintaksa është: mysql_connect(‘hosti’, ‘username’, ‘fjalekalimi’) dhe mysql_select_db(‘emri_i_tabeles’). Rreshti i katërt e pastron tekstin e kërkimit nga karaktere që mund të thyejnë një query. Mos përdorimi i këtij funksioni është rezultat i një pjese të mirë të SQL Injections. Pjesa tjetër është rezultat i përdorimit të numrave (int) si ID apo çfarëdo qofshin në query dhe mos sigurimi që vlerat e hyrjes janë vërtetë numerike.

 PHP |  Kopjo Kodin |? 
1
<?php
2
if(strlen($kerkimi) > 3){
3
     //ketu vijon pjesa tjeter e kodit
4
} else{
5
     echo '<p>Fjalët që dëshironi të kërkoni duhet të përmbajnë 3 ose më shumë karaktere.</p>';
6
}
7
?>

Me këtë kod kontrollojmë nëse numri i karaktereve të futura për kërkim është më shumë se 3 (pra 4 e sipër) dhe printojmë një mesazh nëse jo. Funksioni strlen() kthen numrin e karaktereve të tekstit. Në fakt ky është limitim i MySQL dhe jo një zgjedhje e imja, e cila i limiton kërkimet në 4+ karaktere. Mund të ndryshohet ky limit përmes variablës së sitemit ft_min_word_len (në my.ini – Windows, my.conf – Linux), gjë që në shared hosts duhet të jetë e pamundur.

 PHP |  Kopjo Kodin |? 
1
<?php
2
echo gjejGabimin($kerkimi);
3
?>

Kodi thërret një funksion të përcaktuar në skedarin e jashtëm (funksionet.php) që thërrita më parë dhe përmbajtjen e tij do ja u tregoj në fund. Ajo që ky funksion bën është krahasimi i fjalës me fjalorin dhe sugjeron fjalën e duhur nëse ajo është gabim.

 PHP |  Kopjo Kodin |? 
1
<?php
2
$rezultatet = mysql_query("SELECT titulli, permbajtja, MATCH(titulli, permbajtja) AGAINST ('$kerkimi*' IN BOOLEAN MODE) AS renditja
3
                           FROM kerkim_artikujt
4
                           WHERE MATCH(titulli, permbajtja) AGAINST ('$kerkimi*' IN BOOLEAN MODE)
5
                           ORDER BY renditja DESC");
6
?>

Si ju thashë, kam përdorur vetëm një query për të bërë kërkimin dhe kjo më sipër është e vetmja. Duket pak e frikshme në sytë e një fillestari, por ju siguroj që nuk është. Po ja u shpjegoj me detaje meqë është edhe një pjesë e rëndësishme e kësaj guide.

Pjesa “SELECT titulli, permbajtja, … FROM kerkim_artikujt WHERE … ORDER BY …”, pa i marrë parasysh ç’farë ka në vend të pikave duhet të jetë e njohur për të gjithë ata që janë marrë sado pak me MySQL (ose çdo databazë SQL). Pra kemi zgjedhur (SELECT) fushat e përcaktuara në tabelën “kerkim_artikujt” (FROM) që plotësojnë një kusht (WHERE) dhe i rendisim sipas një kushti tjetër (ORDER). Kjo është ABC-ja e një query në MySQL. Nëse nuk jeni marrë asnjëherë me MySQL, lexoni 2 guidat e mia këtu në Feniksi: Bazat e MySQL me PHP 1 dhe 2.

Pjesa “WHERE MATCH(titulli, permbajtja) AGAINST (‘$kerkimi*’ IN BOOLEAN MODE)” është ajo që e vë në jetë kërkimin Full Text. Nuk kam çfarë t’ju them tjetër përveç se kjo është sintaksa, ku në MATCH() vendosen kolonat që doni të kërkoni (atyre që i vendosëm indeksin FULLTEXT në fillim të guidës) dhe ne AGAINST() vendoset teksti që do të kërkohet. Në këtë rast teksti ndodhet brenda variablës $kerkimi. Vini re që i kam shtuar një yll (*) në fund të variablës kërkimi. Nuk është e detyrueshme, por do ju japë rezultate më të sakta. Ylli instrukton se fjala që po kërkojmë mund të jetë e pjesshme dhe duhen kërkuar edhe fjalë të ngjashme me të, psh: “kerk*” kerkon edhe për “kerkime”, “kerkimet”, etj. Normalisht MySQL i kërkon automatikisht këto fjalë, por nga testet e mia rezultatet ishin më të sakta kur përfshiva yllin. Gjithashtu më duhet t’ju them se ylli funksionon si duhet kur vendoset para çdo fjale të kërkuara, ndërsa në rastin tonë vendoset në fund të fjalëve. Duheshin shkruar disa rreshta të tjerë kod PHP për ta bërë këtë, por u tregova dembel :)

Pjesa “IN BOOLEAN MODE” aktivizon përdorimin e operatorëve në kërkim. Operatorët janë: + (fjala duhet të jetë patjetër në rezultate, psh: html +php), – (fjala nuk duhet të jetë në rezultatet, psh: html -php), hapësira (pa operator, fjalët janë opsionale: psh: html php), etj. Shikoni manualin e MySQL për BOOLEAN MODE për listën e operatorëve të ofruar dhe funksionimin e detajuar të tyre.

Besoj e keni vënë re që e kam përsëritur 2 herë pjesën MATCH() AGAINST(), një herë në WHERE dhe një herë në SELECT. Arsyeja është se kjo frazë përcakton pikë për rreshtat e kthyer. Pikët vendosen nga MySQL në bazë të cilësisë së rezultateve në krahasim më kërkimin dhe sa më të larta pikët, aq më relevant (se di fjalën në Shqip) rezultati. E kam përfshirë në SELECT duke i kaluar pikët në një variabël “renditja” dhe në fund i rendis rreshtat me ORDER BY sipas kësaj variable, në rend zbritës (nga më e larta tek më e vogla). Me këtë kod të thjeshtë kemi rezultate që kanë kuptim.

Kjo ishte query e zbërthyer në copëza dhe e shpjeguar. Për shumë sintaksa mund të jetë e re, por nuk ju duhet asgjë tjetër përveç se të mbani mend (apo ta rigjeni në këtë guidë) pjesën MATCH() AGAINST(). Të tjerat janë fjalë kyçe normale të MySQL.

 PHP |  Kopjo Kodin |? 
1
<?php
2
if(mysql_num_rows($rezultatet) > 0){
3
     //ketu vijon pjesa tjeter e kodit
4
} else{
5
     echo '<p>Nga kërkimi nuk u gjet asnjë rezultat. Provoni të përdorni fjalë më të përgjithshme dhe sigurohuni që i keni shqiptuar si duhet.</p>';
6
}
7
?>

Funksioni mysql_num_rows() tregon numrin e rreshtave të kthyer nga query. Nëse numri i rreshtave është më i madh se 0, atëherë kemi të paktën një rezultat për të shfaqur. Nëse është 0, atëherë s’kemi rezultate dhe tregojmë mesazhin.

 PHP |  Kopjo Kodin |? 
1
<?php
2
while($vlerat = mysql_fetch_array($rezultatet)){
3
     echo '<div>';
4
     echo shfaqTitullin($vlerat['titulli'], $kerkimi);
5
     echo shfaqPermbajtjen($vlerat['permbajtja'], $kerkimi);
6
     echo '</div>';
7
}
8
?>

Brenda në loop-ën while() kam shkruar një shprehje që i kalon vlerat e kthyera në variablën $vlerat rresht për rresht. Loop-a egzekutohet deri sa mos të ketë asnjë rresht të kthyer. Funksioni mysql_fetch_array() i transformon rreshtat e kthyer në një vektor të asociuar, ku emrat e kolonave ruhen si çelësa të vektorit. Brenda loop-ës while kam shkruar kod HTML (praktikë e keqe por ç’ti bëja) për të krijuar një <div> më klasën “rezultatet”, që ta stiloj me CSS më pas. Dy rreshtat e tjerë janë thirrje të funksioneve për të “ndriçuar” në tituj dhe përmbajtje fjalët kyçe të kërkuara. Ky ishte edhe fragmenti i fundit para se të kaloj në ilustrimin e 3 funksioneve në skedarin “funksionet.php”.

Tre funksionet që kam përdorur janë opsionale dhe nuk luajnë rol në vetë kërkimin, prandaj mund të mos i përdorni. Sidoqoftë, shfaqja e rezultateve do jetë më interesante me përdorimin e tyre. Duke qenë se do zgjatej shumë guida nëse do i shpjegoja rresht për rresht dhe kryesisht kam përdorur funksione për manipulim tekstesh, do ju shpjegoj me pak fjalë teorinë mbrapa këtyre funksioneve dhe do ju tregoj kodin e komentuar. S’duhet ta keni të vështirë ti kuptoni edhe kështu.

Funksionet

Funksioni gjejGabimin(). Ky funksion kontrollon nëse fjalët/fjala e futur në kërkim është e ngjashme me ndonjë fjalë në fjalor dhe shfaq sugjerimin. Supozohet që të jenë kërkuar disa fjalë, prandaj secila fjalë futet në një vektor. Bëj 2 loop-a, njëra në fjalët e kërkuara dhe tjetra në vektorin e fjalorit. Nëse gjej ngjashmëri mbi 60% midis fjalës së kërkuar dhe një fjale në fjalor, atëherë e shtoj si sugjerim. Sugjerimin e zëvendësoj direkt në një variabël që ka marrë fillimisht vlerën e fjalëve të kërkuar. Në fund krahasoj nëse teksti në kërkim është i ndryshëm nga variabla e zëvendësimit, që do të thotë se është gjetur të paktën një fjalë e gabuar. Kodi funksionon për disa fjalë dhe kombinime fjalësh të gabuara e të sakta.

Jam i sigurt që ka metoda më të mira për të ruajtur fjalorin dhe për të krahasuar fjalët me to që mund të kursejnë risurse. Megjithatë, nga testet e mia në një server lokal, rezultatet ishin të kënaqshme. Me një fjalor prej 100.000 fjalësh 10-shifrore të gjeneruara, koha egzekutimit nuk i kalonte 0.3 sekonda. Në kontrast, gjenerimi i 100.000 fjalëve kërkonte mbi 1 sekond. Nëse vektori do ishte mbushur manualisht, koha do ishte e papërfillshme. Përfundimi është që teknika që kam përdorur mund të përdoret shumë mirë dhe të japë rezultate të kënaqshme me fjalorë të mëdhenj me dhjetëra mira fjalë.

 PHP |  Kopjo Kodin |? 
01
<?php
02
function gjejGabimin($kerkimi){
03
     //Krijojme nje vektor qe mban fjalet e fjalorit. Mund te shtoni fjale sa te doni.
04
     $fjalori = array('html', 'css', 'vektor', 'vektoret', 'vektori', 'vektore', 'kod', 'kodi', 'kode', 'kodet', 'php');
05
     //Fjalet e kerkuara i kthejme ne nje vektor qe mban cdo fjale ne nje element. Me str_replace() kam
06
     //fshire karakteret qe sherbejne si operatore per FULLTEXT ne menyre qe mos te dalin si te gabuara
07
     //ne fjalor.
08
     $kerkimiFjalet = explode(' ', str_replace(array('-', '+', '~', '*', '(', ')', '"', '<', '>'), '', $kerkimi));
09
     //Krijojmë një variabel qe permban tekstin e kerkimit.
10
     $rezultati = $kerkimi;
11
     //Bejme loop ne te gjitha fjalet e kerkuara (nese eshte vetem 1, loopa do egzekutohet 1 here)
12
     foreach($kerkimiFjalet as $kerkimiFjala){
13
          //Nese fjala e kerkuar egziston ne fjalor, ndalo egzekutimin dhe kalo ne fjalen tjeter.
14
          //in_array() kontrollon nese nje vlere egziston brenda ne nje vektor, ndersa fjala kyce
15
          //continue; ndalon egzekutimin e loopes egzistuese dhe vazhdon me tjetren.
16
          if(in_array($kerkimiFjala, $fjalori)){ continue; }
17
          //Bejme nje loop tjeter ne te gjitha fjalet e fjalorit
18
          foreach($fjalori as $fjala){
19
               //Krahasojme fjalen e kerkuar me te gjitha fjalet e fjalorit.
20
               //Funksioni similiar_text() krahason fjalet dhe permes variables
21
               //$distanca kthen perqindjen e afersise.
22
               similar_text($kerkimiFjala, $fjala, $distanca);
23
               //Nese afersia eshte me shume se 60%, atehere fjala MUND te jete
24
               //shkruar gabim dhe ndodhet ne fjalor.
25
               if($distanca > 60){
26
                    //Nese ju kujtohet nga siper, variabla $rezultati mban fjalet e kerkuara.
27
                    //Me str_replace() zevendesojme fjalen e gabuar me ate te sakten te gjetur
28
                    //ne fjalor
29
                    $rezultati = str_replace($kerkimiFjala, $fjala, $rezultati);
30
                    //Perfundojme egzekutimin e loop-es dhe kalojme ne nje fjale tjeter
31
                    //nga ato te kerkuarat.
32
                    break;
33
               }
34
          }
35
     }
36
     //Nese teksti i kerkuara eshte i ndryshem nga teksti ne rezultat dhe nese teksti
37
     //ne rezultat eshte i ndryshem nga bosh, atehere kemi gjetur nje gabim ne kerkim.
38
     if($kerkimi != $rezultati && $rezultati != ''){
39
          //Kthejme tekstin me rezultatin e korrigjuar dhe nje lidhje per te kerkuar direkt
40
          //me korrigjimin.
41
          return '<p><b>Donit te thonit <a href="index.php?kerkimi=' . $rezultati . '">' . $rezultati . '</a>?</b></p>';
42
     }
43
}
44
?>

Funsioni shfaqTitullin(). Ky funksion “ndriçon” fjalët e kërkuara që gjenden në titull. Është një funksionalitet interesant që i jep vizitorit idenë se ku është gjetur fjala/fjalët që ai po kërkon. Duke përdorur sërish vektorë dhe manipulim tekstesh, bëj loop në të gjitha fjalët e kërkuara për të kontrolluar nëse fjala e kërkuar gjendet në titull. Nëse fjala gjendet, marr pozicionin e saj fillestar në tekst. Më pas marr një porcion teksti që mban fjalën dhe e zëvendësoj atë në tekstin origjinal me një klasë të shtuar. Kam shtuar klasë në mënyrë që të stilohet me CSS sipas dëshirës; unë e bëra Bold. Arsyeja që kam shkëputur një porcion nga titulli me fjalën që do të zëvendësohet është se nuk e di madhësinë e gërmave (të mëdha apo të vogla – case) dhe doja ta ruaja. Nëse do e zëvendësoja direkt do ishte më e thjeshtë, por fjalët në titull do ishin me madhësinë e gërmave që do ishte bërë kërkimi.

 PHP |  Kopjo Kodin |? 
01
<?php
02
function shfaqTitullin($titulli, $kerkimi){
03
     //stripslashes() heq slashet (/) e vendosura para ', ", etj.
04
     $titulli = stripslashes($titulli);
05
     //Fjalet e kerkuara i kthejme ne nje vektor qe mban cdo fjale ne nje element. Me str_replace() kam
06
     //fshire karakteret qe sherbejne si operatore per FULLTEXT ne menyre qe mos te pengojne ne kodin ne vijim.
07
     $kerkimi = explode(' ', str_replace(array('-', '+', '~', '*', '(', ')', '"', '<', '>'), '', $kerkimi));
08
     //Bejme nje loop ne te gjitha fjalet e kerkuara.
09
     foreach($kerkimi as $kerkimiFjala){
10
          //Testojme nese ndonje fjale kyce gjendet ne titull. Funksioni stripos() kthen pozicionin qe ndodhet
11
          //fjala e kerkuar ne tekst. Kthen FALSE nese nuk gjendet, prandaj dhe krahasimi i kundert me FALSE.
12
          //Ne ndryshim nga strpos(), stripos() nuk case-insensitive (germat e medha jane njesoj si te voglat).
13
          if(stripos($titulli, $kerkimiFjala) !== FALSE){
14
               //Marrim pozicionin ne titull te fjales se kerkuar.
15
               $fillimi = stripos($titulli, $kerkimiFjala);
16
               //Marrim nje porcion nga titulli qe nis me pozicionin fillestar te fjales se kerkuar dhe
17
               //perfundon na mbarim te saj. substr() merr porcione teksti nga nje tekst tjeter, ndersa
18
               //strlen() kthen gjatesine e fjales.
19
               $porcioni = substr($titulli, $fillimi, strlen($kerkimiFjala));
20
               //Ne titull zevendesojme porcionin (i cili eshte fjala kyce e kerkuar qe ndodhet ne titull)
21
               //me perseri ate porcion, por te rrethuar nga nje <span>. Kete <span> e kam stiluar me CSS
22
               //qe te jete bold. Pra fjalet kyce te kerkuara qe gjenden ne titull behen bold.
23
               $titulli = str_replace($porcioni, '<span>' . $porcioni . '</span>', $titulli);
24
          }
25
     }
26
     //Kthejme titullin. I kam vendosur lidhje meqe normalisht ky titull drejton per tek permbajtja e plote.
27
     return '<a href="#">' . $titulli . '</a><br />';
28
}
29
?>

Funksion shfaqPermbajtjen(). Ky funksion realizon të njëjtën gjë si shfaqTitullin(), vetëm se “ndriçon” fjalët e gjetura në përmbajtje dhe ndryshon pak në kod. Fillimisht kam krijuar një vektor që ka të njëjtët elementë (fjalër) si kërkimi dhe i kam bërë bold të gjitha fjalët. Më pas kam bërë një loop në të gjitha fjalët e kërkuara për të gjetur pozicionin (nëse egziston) të fjalës së kërkuar në përmbajtje. Kam zëvendësuar fjalët e gjetura me ekuivalentin e tyre në bold duke përdorur 2 vektorët, atë të kërkimit dhe atë të zëvendësimit (që është i njëjtë më kërkimin por fjalët janë bold). Në fund kam marrë një porcion nga përmbajtja që fillon nga pozicioni i fjalës së kërkuar deri 1500 karaktere më tutje. Që mos ta mbyll porcionin e marrë në mes të një fjalë, kam gjetur gjithashtu pozicionin e fundit të një hapësire dhe kam marr një porcion tjetër. Për ta përmbledhur, marr një porcion nga përmbajtja që fillon nga fjala e parë e kërkuar që u gjet dhe mbaron në 150 karaktere, duke e mbyllur porcionin në hapësirën e fundit që mos ta lë fjalën në gjysëm.

 PHP |  Kopjo Kodin |? 
01
<?php
02
function shfaqPermbajtjen($permbajtja, $kerkimi){
03
     //Permbajtjes i heqim slashet dhe me strip_tags() i heqim kodet HTML. Zakonisht permbajtja e artikujve
04
     //shkruhet ne editore qe gjenerojne kod HTML dhe ne nuk na sherben per ta shfaqur ne rezultate.
05
     $permbajtja = stripslashes(strip_tags($permbajtja));
06
     //Fjalet e kerkuara i kthejme ne nje vektor qe mban cdo fjale ne nje element. Me str_replace() kam
07
     //fshire karakteret qe sherbejne si operatore per FULLTEXT ne menyre qe mos te pengojne ne kodin ne vijim.
08
     $kerkimi = explode(' ', str_replace(array('-', '+', '~', '*', '(', ')', '&quot;', '<', '>'), '', $kerkimi));
09
     //Krijojme nje vektor qe permban elementet e kerkimit.
10
     $zevendesimi = $kerkimi;
11
     //array_walk() eshte nje funksion qe i vendos cdo elementi te vektorit nje funksion tjeter te shkruar nga programuesi.
12
     //Ajo qe doja te beja ishte qe cdo elementi te vektorit $zevendesimi ti vendos nje element HTML <b>, ne menyre qe te
13
     //shfaqet si bold. Menyra si e kam shkruar eshte pak jo-ortodokse per PHP-ne sepse i ngjan me teper nje kodi Javascript,
14
     //por ne kete rast ishte e pershtatshme. Pra kam krijuar nje funksion anonim direkt brenda array_walk() dhe jo jashte tij e ne
15
     //fund ta therrisja. Vini re para variables $vlera kam vene nje &, i cili e kthen variablen me reference dhe ben qe
16
     //te modifikohen direkt vlerat e vektorit. Nese sdo e vija, nuk do funksiononte.
17
     array_walk($zevendesimi, function(&$vlera, $celesi){
18
          $vlera = '<b>' . $vlera . '</b>';
19
     });
20
     //Bejme nje loop per te gjitha fjalet e kerkuara.
21
     foreach($kerkimi as $kerkimiFjala){
22
          //Variabla $fillimi merr pozicionin fillestar te fjales se kerkuara qe ndodhet ne permbajtje.
23
          $fillimi = stripos($permbajtja, $kerkimiFjala);
24
          //Nese eshte gjetur nje fjale e kerkuar ne permbajtje, e perfundojme loop-en.
25
          if($fillimi !== FALSE){ break; }
26
     }
27
     //Zevendesojme fjalet e kerkuara me ato te zevendesuarat ne permbajtje. Ju kujtoj se fjalet e zevendesuara jane
28
     //egzaktesisht si ato te kerkuarat, vetem se jane bold. Te dy jane vektore me te njejtin numer elementesh prandaj
29
     //kerkimi dhe zevendesimi behet per cdo element. Ashtu si stripos(), str_ireplace() ne krahasim me str_replace()
30
     //eshte case insensitive.
31
     $permbajtja = str_ireplace($kerkimi, $zevendesimi, $permbajtja);
32
     //Nga permbajtja, fillojme nga germa e pare e fjales kyce te gjetur (nese eshte gjetur, perndryshe fillon nga 0)
33
     //dhe marrim nje porcion prej 150 karakteresh.
34
     $permbajtja = substr($permbajtja, $fillimi, 150);
35
     //Per ta mbyllyr porcionin ne nje fjale te plote dhe jo rastesisht, marrim pozicionin e fundit te nje hapesire.
36
     //strrpos() merr pozicionin e fundit, ndersa strpos() merr pozicionin e pare.
37
     $fundi = strrpos($permbajtja, ' ');
38
     //Marrim nje porcion tjeter te permbajtjes qe fillon nga 0 dhe ne pozicionin e fundit te hapesires.
39
     $permbajtja = substr($permbajtja, 0, $fundi) . '...';
40
     //Kthejme permbajtjen.
41
     return $permbajtja;
42
}
43
?>

Përfundimi

Në këtë guidë që shpresoj ka ndihmuar të interesuarit, kemi krijuar nga zero një motor kërkimi që përdor Full Text Search të MySQL për të gjetur rezultatet dhe i kemi manipuluar këto rezultate me PHP për ti shfaqur në mënyrë interesante. Jam i sigurt që e keni ndjekur pa probleme guidën deri pa filluar pjesa e funksioneve, sepse besoj ishte pjesë e thjeshtë për tu kuptuar. Pjesa e funksioneve nga krahu tjetër mund të jetë paksa e vështirë të gëlltitet nga fillestarët, sepse janë gjëra që duan përvojë pune. Nëse nuk i kuptoni, kërkoni në manualin e PHP-së shpjegimet e funksioneve që kam përdorur, sidomos ato të manipulimit të teksteve dhe eksperimentoni me vlerat e kthyera. Asgjë s’është e vështirë nëse i kushtoni kohën e duhur.

Shpresoj vërtetë t’ju hyjë në punë guida dhe ta përdorni këtë motor kërkimi për të mësuar, por pse jo si një zgjidhje për faqen tuaj sepse kodi është i hapur dhe i lirë për përdorim. Nëse zgjidhni opsionin e fundit, do jem kurioz ta shoh të implementuar, prandaj më bëni një zë :)

Mësim të mbarë.

Fadion Dashi

Fadioni është prej shumë vitesh i apasionuar pas internetit dhe punon freelance si dizenjues dhe programues per web. Kur nuk është duke punuar, i pëlqen të shkruajë, të fotografojë, të admirojë koleskionin e tij të aparatëve fotografikë manualë dhe të kalojë kohë të bukur me miqtë.

7 Komente

  1. Banago says:

    Shumë skript interesant, faleminderit! Sa shumë kam për të mësuar :)

  2. Fadion Dashi says:

    Ehh, e kush s’ka shume per te mesuar?! :)

  3. Besnik says:

    Shume interesant ky artikull! Falemnderit.

  4. Lejkre says:

    Shume e Bukur mua me duhet dicka n.q.s eshte e mundur, sepse nuk po ia bej dot. une dua qe te shfaqe me shume info, sepse fjalet e fundit te pershkrimit te asaj fjale nuk me dalin, n.q.s mundeni ne cfar vendi mund ta ndryshoj kodin qe te me shfaqet e gjith pershkrimi.
    Faleminderit! jeni te papare.

  5. Fadion Dashi says:

    Lejkre, nese ke tekste te shkurtra si permbajtje, mund te shfaqesh edhe komplet rreshtin duke zevendesuar:

    echo shfaqPermbajtjen($vlerat['permbajtja'], $kerkimi);

    me

    echo $vlerat['permbajtjen'];

    Nese do te shfaqesh me shume tekst, tek funksioni shfaqPermbajtjen() ke nje rresht:

    $permbajtja = substr($permbajtja, $fillimi, 150);

    Parametri i trete i substr() – pra 150 – eshte numri i karaktereve qe merren dhe mund ta rrisesh. Funksioni shfaqPermbajtjen() nuk eshte perfekt, sepse shkeput nga permbajtja nje tekst qe fillon nga fjala e pare kyce e gjetur dhe mbaron 150 (ose me shume nese do) karaktere me tej. Nese fjala kyce eshte ne fund te fjalise, atehere s’do merret shume teskt, prandaj mund te modifikohet pak qe te merret tekst edhe para fjales kyce.

  6. Lejkre says:

    Pershendetje! flm per pergjigjen edhe qe jeni te gatshem gjithmone per nje pergjigje. ate qe me the une e kam bere prove, edhe si fjase kyqe kur te kerkosh une kam vendosur emer mbiemer tek titulli edhe mne permbajtje kam perdorur vetem ne fillim te fjalis emer mbiemer pastaj vetem pershkrim. edhe ate 150 ia kam rrit por perseri nuk me shfaqet e gjith permbajtja. por une kam edhe nje problem tjeter ne vendin ku shkruajne nje fjale kyqe per te kerkuar me shfaqe ky shkrim ne te
    Notice: Undefined index: kerkimi in C:wampwwwmotor-kerkimi-php-mysqlindex.php on line 14 edhe nuk po munden ta rregulloj, te lutem po munde me jep nje ndihme. Faleminderit.

  7. Fadion Dashi says:

    Rrjeshti 14 eshte pjesa ku krijohet input-i. Duhet ti kesh nderruar emrin (name=”kerkimi”), por nuk e ke reflektuar nderrimin edhe ne printimin e variables GET. Nese inputit ja ke vene emrin psh “search”, tek value i te njejtit input duhet te kesh:

    echo $_GET['search'];

Shkruaj një Koment