Aplicatie Pentru Testare Online. Chestionare din Domeniul Transportului Auto
Aplicație pentru testare online. Chestionare din domeniul transportului auto
Introducere
În ultimii ani, mijloacele pentru evaluarea cunoștințelor au evoluat pentru a satisface necesitatea de a evalua o mare masă de cursanți în timp scurt și pentru a urmări mai bine modul cum au învățat. Din acest motiv, testele obiective au câștigat o mai mare importanță în procesul de învățare.
Unii termeni ne permit să ne referim, cu un înțeles mai mult sau mai puțin specific, la utilizarea calculatorului și în particular la sistemele bazate pe Web, la administrarea testelor cursanților (Wikipedia, 2009). De exemplu, termenul de Evaluare asistată de calculator sau Evaluare ajutată de calculator (Computer-Assisted Assessment sau Computer-Aided Assessment (CAA)) se referă în general la utilizarea calculatorului în procesul de evaluare. Termenul Evaluare pe baza calculatorului (Computer-Based Assessment (CBA)), în schimb, se referă mai specific la evaluarea automată a răspunsurilor furnizate de cursanți. Testarea online este administrarea testelor structurate prin internet. În cele din urmă, pentru a ne referi în general la evaluare prin Tehnologia de informații și comunicare (Information and Communications Technology (ICT)), folosim termenul de E- Assessment.
Există mai multe tipuri de întrebări care pot fi utilizate în testele online: cu răspuns la alegere, adevărat/fals, cu mai multe răspunsuri, potrivire, ordonare, completare, etc. Tipul de întrebări cu răspuns la alegere este extrem de popular, deoarece, printre alte avantaje, un număr mare de teste bazate pe el pot fi ușor corectate automat. Mai mult, este posibilă evaluarea calității întrebărilor cu răspunsuri la alegere (denumite de asemenea și elemente), în funcție de termenii de dificultate și capacitate caracteristică, prin modele statistice, cum ar fi Analiza elementelor și Teoria răspunsurilor elementelor ( Item Analysis (IA) și Item Response Theory (IRT)). Elementele cu răspunsuri la alegere sunt compuse dintr-un enunț și o listă de opțiuni. Enunțul este textul care formulează întrebarea. Singura opțiune corectă este denumită cheie, în timp ce opțiunile incorecte sunt denumite distractori (Woodford & Bancroft, 2005).
Tipurile de întrebări pot fi clasificate pe baza tipurilor de stimuli și răspunsuri. Stimulul determină cursanții să-și exprime cunoștințele (de exemplu: schița unui eseu, enunțul unui articol, etc.) Este deschis când cursantul este liber să interpreteze ce i s-a cerut să facă și închis când există unele constrângeri de performanță (lungime, ordonarea conceptelor de prezentat, etc.) Răspunsul este deschis când cursantul este liber să îl elaboreze într-un mod personal, și închis când cursantul trebuie să aleagă răspunsul dintr-o listă de opțiuni. Cele mai multe întrebări incluse în testele online sunt caracterizate de stimuli și răspunsuri închise. Testele care includ doar aceste întrebări sunt denumite teste obiective și au avantajul de a nu fi influențate de efecte distorsionante, cum ar fi hotărâri emoționale și așa mai departe. Ele au, în particular, când sunt bine formulate, avantajul suplimentar de a credita bine verificarea cunoștințelor, înțelegerea și realizarea obiectivelor aplicației. Cu toate acestea, ele nu permit tutorelui să verifice capacitatea de exprimare și abilitatea de a organiza răspunsurile. Mai mult, construirea testului, în special când se folosesc întrebări cu răspunsuri la alegere, poate dura destul de mult.
Testele online ne permit să evaluăm cursanții cu obiective formative și sumative. În cazul celor formative, ele sunt administrate în timpul procesului de învățare, dau informații despre stadiul de învățare al fiecărui cursant și, astfel, permit tutorelui să îl îmbunătățească. În cazul din urmă, în schimb, ele sunt date la sfârșitul procesului de învățare (a unei unități de învățare sau a unui proces de învățare temporar) și sunt utilizate pentru exprimarea unei aprecieri a stadiului de învățare a fiecărui cursant. Pentru o discuție extinsă despre concepte legate de testele obiective, cititorul trebuie să se refere la cartea de Frignani and Bonazza (2003).
Sunt disponibile câteva sisteme software comerciale și Open source pentru gestionarea și administrarea testelor online. În prezent, cele mai multe module software de testare sunt parte a Sistemelor de gestionare a învățării (Learning Management Systems (LMS)). Sistemele de testare online pot fi evaluate din punctul de vedere al suportului unei liste de funcționalități dorite. În continuare, vom descrie aceste funcționalități și vom verifica suportul lor în diferite LMS. Mai mult, vom prezenta stadiul analizei a celor mai recente tehnici propuse pentru testele online în diferite limite ale aplicațiilor, cum ar fi: Testare adaptivă computerizată (Computerized Adaptive Testing (CAT)), generare de întrebări automată, analiza datelor jurnal, m-learning și jocuri educaționale.
Evaluarea online
Evaluarea online este procesul utilizat pentru a măsura anumite aspecte ale informațiilor pentru un scop stabilit în cazul în care evaluarea este realizată prin intermediul unui calculator conectat la o rețea. De cele mai multe ori evaluarea este un tip de testare folosit în scop educațional. Diferite tipuri de testare online conțin elemente de tipul următoarelor componente, în funcție de scopul evaluării: formativ, diagnostic sau sumativ. Două dintre beneficiile sistemului de evaluare online sunt feedback rapid și detaliat precum și flexibilitatea locației de testare și timpul. Sunt multe resurse disponibile ce oferă evaluare online, unele gratuite altele care percep taxe sau necesită un abonament.
Scopul evaluărilor
Evaluările sunt o parte vitală în determinarea rezultatelor cursanților. Ele sunt folosite pentru a determina cunoștințele acumulate de cursanți și pentru a determina dacă ajustările trebuie să fie făcute fie în procesul de predare, fie în procesul de învățare.
Tipuri de evaluare online
Evaluarea online este utilizată în principal pentru a măsura abilitățile cognitive, demonstrând ceea ce a fost învățat după apariția unui anumit eveniment de învățământ, cum ar fi sfârșitul unei unități de învățare sau capitol. La evaluarea abilităților practice sau pentru a demonstra procesul de învățare, care a avut loc pe o perioadă mai lungă de timp, este adesea folosit un portofoliu online. Primul element care trebuie să fie pregătit în predarea unui curs online este evaluarea. Evaluarea este utilizată pentru a determina dacă procesul de învățare este eficient, în ce măsură și în cazul în care sunt necesare modificări.
Lucrul individual
Lucrul individual ajută instructorul sau profesorul să determine progresul cursanților în procesul de învățare. Câteva exemple sunt: exerciții, lucrări, portofolii și examene (cu răspuns la alegere, adevărat/fals, răspunsuri scurte, să completeze spațiile libere, să înceapă/finalizeze un eseu sau potrivire). Pentru ca procesul de evaluare să fie cât mai eficient, instructorul trebuie să folosească metode multiple.
Majoritatea cursanților nu vor finaliza sarcinile dacă nu există o evaluare (motivația) . Această sarcină revine instructorului să sporească motivația cursantului. Un feedback adecvat este cheia unei evaluări, chiar dacă nu există o evaluare notată.
Lucrul în echipă
Studenții sunt adesea solicitați să lucreze în echipă. Acest lucru aduce noi strategii de evaluare. Studenții pot fi evaluați cu ajutorul unui model de proces de învățare în colaborare în care procesul de învățare este condus de studenți și/sau un model de proces de învățare prin cooperare în cazul în care sarcinile sunt atribuite și instructorul este implicat în decizii.
Utilitatea evaluărilor online
Pre-testare – înainte de predarea unei lecții sau concept, un student poate completa un formular online, pentru a determina nivelul său de cunoștințe. Această formă de evaluare ajută la determinarea unei baze, astfel încât, atunci când se realizează o evaluare sumativă sau un post-test, este furnizată o dovadă cantitativă ce arată că procesul de învățare a avut loc.
Evaluarea formativă – este folosită pentru a oferi feedback în timpul procesului de învățare. În situații de evaluare online, întrebările obiective sunt reprezentate, iar feedback-ul este pus la dispoziția studentului, fie în timpul evaluării sau imediat după evaluarea acestuia.
Evaluarea sumativă – oferă un grad de apreciere cantitativ la sfârșitul unei lecții, pentru a stabili dacă obiectivele de învățare au fost îndeplinite.
Testarea pregătitoare – odată cu utilizarea tot mai mare a testării cu miză mare în zona educației, testele de practică online sunt utilizate pentru a da cursanților o îndrumare. Cursanții pot face aceste tipuri de evaluări de mai multe ori pentru a se familiariza cu conținutul și cu formatul evaluării.
Sondaje – Sondarea online poate fi utilizată de instructori pentru a colecta date și pentru a primi feedback privind atitudinile, percepțiile și alte tipuri de informații care pot îmbunătăți instruirea.
Evaluări – Acest tip de sondaje permit intermediarilor să colecteze date și feedback în orice situație unde cursul sau experiența necesită justificare sau îmbunătățire.
Testare de performanță – Utilizatorul arată ce știe și ce poate face. Acest tip de testare este utilizat pentru a arăta experiența tehnologică, înțelegerea lecturii, abilitățile matematice, etc. Această evaluare este de asemenea utilizată pentru a identifica lacunele din învățarea cursantului.
Noile tehnologii, cum ar fi Web, video digital, sunet, animații și interactivitate sunt unelte folosite care pot face proiectarea și implementarea evaluării mai eficientă, oportună și mai sofisticată.
Sistemele de testare online
Sistemele de testare online permit compunerea și administrarea testelor online. Multe dintre ele sunt integrate în LMS-uri. Unele dintre ele sunt proiectate cu scopuri sumative, altele cu scopuri formative, cele mai multe dintre ele cu ambele. Sistemele formative trebuie să includă posibilitatea de inserare a părerii (feedback) tutorului în timpul execuției testului în cazul răspunsului greșit. Sistemele proiectate cu scopuri sumative, în schimb, trebuie să aibă unelte (în particular din motive de securitate) pentru executarea examenelor de laborator cu proctor.
Depozitul de întrebări
Cele mai multe din sistemele de testare online utilizează un depozit de întrebări în care întrebările pot fi inserate și selectate succesiv pentru a compune teste. Selectarea întrebărilor se poate face prin alegerea lor explicită când se construiesc testele sau aleatoriu prin selectarea lor dintr-un set de întrebări care satisfac unele condiții (dificultate, subiect, etc.) în momentul executării testului. Depozitele suportă des inserarea unor tipuri de întrebări și unele suportă definirea de tipuri noi.
În sistemele bazate pe un depozit de întrebări întrebările sunt de obicei organizate după subiect. Printr-o bună organizare a depozitului se poate evita duplicarea întrebării sau inserarea de întrebări foarte similare.
Altă caracteristică dorită este posibilitatea de a compune întrebări cu ajutorul editoarelor avansate care permit utilizarea multimedia și a ecuațiilor.
Suportul dat de standarde
Standardele au fost introduse în e-learning în principal cu obiectul de a îmbunătăți interoperabilitatea dintre sisteme, definită ca și capacitatea lor de a schimba informații. Specificațiile principale introduse în procesul de standardizare definesc formatele schimbate. În particular, un format obișnuit a fost definit pentru schimbarea Obiectelor de învățare (Learning Objects (LO)) și meta-datele lor, pentru a lansa LO-urile produse cu diferite unelte de autorizare pe diferite LMO-uri.
Mai apropiată de testarea online este specificația Interoperabilitatea întrebărilor și testului (Question and Test Interoperability (QTI)), produsă de IMS, care stimulează schimbul de date legate de teste. În particular, ea definește un model de date pentru reprezentarea testeloerii (feedback) tutorului în timpul execuției testului în cazul răspunsului greșit. Sistemele proiectate cu scopuri sumative, în schimb, trebuie să aibă unelte (în particular din motive de securitate) pentru executarea examenelor de laborator cu proctor.
Depozitul de întrebări
Cele mai multe din sistemele de testare online utilizează un depozit de întrebări în care întrebările pot fi inserate și selectate succesiv pentru a compune teste. Selectarea întrebărilor se poate face prin alegerea lor explicită când se construiesc testele sau aleatoriu prin selectarea lor dintr-un set de întrebări care satisfac unele condiții (dificultate, subiect, etc.) în momentul executării testului. Depozitele suportă des inserarea unor tipuri de întrebări și unele suportă definirea de tipuri noi.
În sistemele bazate pe un depozit de întrebări întrebările sunt de obicei organizate după subiect. Printr-o bună organizare a depozitului se poate evita duplicarea întrebării sau inserarea de întrebări foarte similare.
Altă caracteristică dorită este posibilitatea de a compune întrebări cu ajutorul editoarelor avansate care permit utilizarea multimedia și a ecuațiilor.
Suportul dat de standarde
Standardele au fost introduse în e-learning în principal cu obiectul de a îmbunătăți interoperabilitatea dintre sisteme, definită ca și capacitatea lor de a schimba informații. Specificațiile principale introduse în procesul de standardizare definesc formatele schimbate. În particular, un format obișnuit a fost definit pentru schimbarea Obiectelor de învățare (Learning Objects (LO)) și meta-datele lor, pentru a lansa LO-urile produse cu diferite unelte de autorizare pe diferite LMO-uri.
Mai apropiată de testarea online este specificația Interoperabilitatea întrebărilor și testului (Question and Test Interoperability (QTI)), produsă de IMS, care stimulează schimbul de date legate de teste. În particular, ea definește un model de date pentru reprezentarea testelor, întrebărilor și rezultatelor cursanților. Modelul se bazează pe un set de date mare. De aceea, a fost introdusă o specificație care definește setul de date redus, denumită QTI Lite. Mai mult, QTI definește o legătură de date XML și are câteva puncte de extensie, care pot fi utilizate pentru a defini extensiile specializate sau de proprietate a modelului de date.
Altă specificație care privește testarea online este Instrucțiunea gestionată a calculatorului (Computer Managed Instruction (CMI)), care definește un mediu standard în care LO-urile pot fi lansate și pot schimba date cu LMS. Adoptarea acestei specificații este dorită în sistemele de testare online pentru a sprijini urmărirea cursanților în timpul execuției testului.
Adoptarea funcționalităților standard nu este întotdeauna o realizare ușoară, din cauza dificultăților în implementarea specificației, care este de obicei depășită de versiunile noi.
Evaluare, rapoarte și analiza elementelor
Conform tipurilor de întrebări, evaluarea poate fi automată, ca la întrebările la alegere sau necesită intervenția tutorelui, ca în cazul eseurilor scurte. Cele mai avansate sisteme permit tutorelui să revizuiască și, posibil, să modifice notele date de sistem. O anumită flexibilitate este dorită pentru stabilirea strategiei de acordare a notei: unele sisteme sprijină definirea de reguli pentru acordarea notei finale prin atribuirea de diferite ponderi elementelor testului și utilizarea de penalizări sau bonusuri pentru răspunsuri greșite și respectiv corecte.
Sistemele în general permit tutorelui să analizeze rezultatele cursanților, grupului de cursanți prin dedicarea unei secțiuni de raportare special. În particular, această secțiune poate să evalueze îmbunătățirile realizate în timp. Cele mai avansate sisteme permit tutorelui să evalueze calitatea întrebării prin exploatarea modelelor statistice deja citate IA și IRT. Unele studii, cum ar fi cel realizat în (Stage, 1999), le privesc pe amândouă ca fiind eficace și au identificat argumentele pro și contra. Ambele modele sunt bazate pe interpretarea indicatorilor statistici calculați pe rezultatele testului. Cei mai importanți dintre ei sunt indicatorii de dificultate și de discriminare, care reprezintă informațiile despre cât de bine un element discriminează cursanții bine și slab pregătiți.
Analiza sistemelor existente
Analiza unor sisteme de testare online în raport cu sprijinul caracteristicilor menționate anterior au fost realizate: șapte produse din cele mai populare LMS-uri, împreună cu o licență Open source sau comercială, au fost incluse în studiu. Analiza este rezumată în Tabelul 1. Tabelul afișează caracteristicile sprijinite pentru fiecare LMS. Fiecare celulă din tabel raportează caracteristicile suportate pentru fiecare produs și pentru fiecare caracteristică. Pentru elaborare, au fost evaluate următoarele caracteristici:
Tipuri de întrebări: număr de tipuri de întrebări disponibile; suport al tipurilor de întrebări personalizate
Elemente aleatorii: posibilitate de selectare aleatorie a întrebărilor din depozit pentru a compune teste;
Multimedia: suport pentru elementele multimedia în întrebări
Ecuații: suport pentru ecuații în întrebări
Păreri (feedback): posibilitatea ca acei cursanți să primească feedback imediat în timpul testelor de evaluare;
Teste cu proctor: suport de unelte pentru examenele de laborator;
Analiza testului: disponibilitatea de statistici pe teste și întrebări;
Standarde: suport de funcționalități standard pentru testare online (QTI și/sau CMI)
Tabel 1
Suport al celor mai importante funcționalități de testare online în LMS-uri
Tendințele de cercetare principale
Unele caracteristici sunt în prezent subiect de cercetare și sunt prezente rar în sistemele de testare comerciale sau populare. În particular, luăm în considerare următoarele domenii de aplicații, analizate în sub-secțiunile următoare:
Testarea adaptivă computerizată (Computerized Adaptive Testing (CAT));
Generarea de întrebări automate;
Corecția automată a întrebărilor cu răspunsuri deschise;
Testarea adaptivă computerizată
CAT este un caz special de testare bazată pe computer, în care fiecare candidat la examen dă un test unic care este conceput pentru nivelul său de abilitate. În general, estimarea abilității este actualizată după fiecare răspuns și elementul următor este selectat astfel încât să aibă proprietăți optimale în funcție de estimarea nouă (van der Linden & van Krimpen-Stoop, 2003). Adoptarea funcționalităților CAT are argumente pro și contra. Avantajele includ (Triantafillou, 2008):
Posibilitatea pentru cursanții de orice nivel să dea teste: cursanții nu au nevoie să atingă un nivel de cunoștințe suficient înainte de a da teste, deoarece testul este adaptat nivelului lor;
mai mare uniformitate în evaluare comparată cu testele tradiționale, care au o capacitate mare discriminativă doar pentru nivelele medii de cunoștințe.
Mărime a testului redusă: jumătate de întrebările utilizate în testele tradiționale pot fi suficiente pentru a obține rezultate de evaluare semnificative.
Printre avantaje, a fost raportat următorul avantaj (Eggen, 2001): necesitatea de realizare a calibrării elementului preliminar pentru a corecta dificultatea lor și imposibilitatea pentru cursanți de a revizui răspunsurile. Aceasta din urmă se datorează unui truc pe care cursanții îl pot adopta pentru a obține un scor mai mare la un test ușor (în comparație cu nivelul lor de cunoștințe): ei pot da intenționat un răspuns greșit la întrebări și revizuiesc răspunsul ulterior.
Generarea/Corectarea automată a întrebărilor
Generarea de întrebări automată și corectarea automată a întrebărilor cu răspuns deschis are două sectoare de cercetare care au câștigat interesul cercetătorilor în tehnicile Procesare de limbă naturală (Natural Language Processing (NLP)).
Generarea de întrebări automată poate fi realizată într-un mod complet automat sau într-unul semiautomat. Sistemele automate generează elementele, în timp ce cele semiautomate asistă utilizatorul la generarea lor. În general, intervenția umană este oricum necesară pentru verificarea raționalității elementelor înainte de utilizarea lor într-un test.
Un exemplu de generare de întrebări automate este sistemul propus de Mitkov and Ha (2003), care generează elemente cu răspunsuri la alegere prin selectarea propozițiilor de la un text introdus. Textul într-o formă declarativă este transformat în întrebare. Unele cuvinte din textul introdus sunt înlăturate și utilizate ca o opțiune cheie. Distractorii sunt generați prin utilizarea conceptelor semantice apropiați de opțiunea cheie. În experimentul realizat de autori, 43 % din elementele produse au fost eliminate după o verificare manuală a calității lor. Atunci, IA a fost utilizat pentru a evalua diferența calității între elementele generate și celelalte obținute fără utilizarea sistemului. Rezultatele au fost satisfăcătoare, deoarece elementele generate au arătat o capacitate discriminativă mai mare (0,4) decât a celor produse manual (0,25).
Printre sistemele semiautomate, Hoshino & Nakagawa (2008) a propus un proces bazat pe NPL cu scopul de a genera elemente cu răspunsuri la alegere pentru evaluarea cunoștințelor studenților la medicină. Tutorul intervine în procesul de generare a întrebărilor prin alegerea celor mai plauzibili distractori dintre cei sugerați de sistem.
Pentru corecția automată a eseurilor, putem cita sistemul propus de Kakkonen and Sutinen (2004), care utilizează Analiza semantică latentă (Latent Semantic Analysis (LSA)), o tehnică de extragere a informațiilor celor mai cunoscute, pentru a compara similaritatea conceptuală dintre eseuri și pasajele de text selectate care acoperă subiectul specific evaluării eseului. Experimentul lor afișează o corelare bună între notele date de sistem și de un evaluator uman.
Ce își propune aplicația?
Domeniul din care face parte setul de întrebări din această aplicație este cel al transporturilor auto și este destinat, în special, șoferilor profesioniști, managerilor de transport, instructorilor și profesorilor de legislație.
Categoriile din care face parte setul de întrebări sunt:
Atestat șofer CPC – certificatul CPC (curs de pregătire continuă) este destinat posesorilor de permis de conducere ce au obținut categoria D înainte de 10.09.2008, și pentru categoria C înainte de 10.09.2009.
Manager de transport – orice operator de transport rutier este obligat să desemneze cel puțin un manager de transport care conduce permanent și efectiv activitatea de transport rutier.
Certificat ADR – este obligatoriu pentru conducătorii de autovehicule care efectuează transporturi de mărfuri periculoase.
Atestat șofer CPI – certificatul CPI (curs de pregătire continuă) este destinat posesorilor de permis de conducere ce au obținut categoria D după data de 10.09.2008, și pentru categoria C după data de 10.09.2009.
Atestat TAXI – atestatul de taxi conferă unui conducător auto atestat profesional dreptul să efectueze transport în regim taxi sau în regim de închiriere.
Consilieri de siguranță – orice operator de transport marfă periculoasă este obligat să desemneze cel puțin un consilier de siguranță.
Instructori auto – atestatul de instructor auto poate fi obținut de orice absolvent de liceu cu diplomă de bacalaureat și a unui permis de conducere cu o vechime de minim 5 ani în categoria solicitată.
Profesor de legislație – atestatul de profesor de legislație rutieră poate fi obținut de orice absolvent al unei instituții de învățământ superior de lungă durată în specialitatea științe juridice sau tehnice.
Aplicația își propune testarea și evaluarea cunoștințelor cursanților în domeniile descrise anterior în vederea susținerii examenului final, examen ce este susținut online în instituții autorizate de către Autoritatea Rutieră Română (ARR). Setul de întrebări este cel pus la dispoziție publicului de către ARR. De asemenea timpul susținerii unui examen, numărul de întrebări pentru fiecare categorie, numărul minim de întrebări corecte necesar promovării unui examen este standard în conformitate cu cerințele ARR.
Limbaje folosite
HTML
HTML (Hypertext Markup Language) este unul din primele elemente fundamentale ale WWW (World Wide Web), care descrie formatul primar in care documentele sunt distribuite si văzute pe Web. HTML este un limbaj de marcare utilizat în realizarea paginilor web ce pot fi vizualizate cu ajutorul unui browser (sau navigator). Scopul HTML este mai degrabă prezentarea informațiilor – paragrafe, fonturi, tabele etc. – decât descrierea semanticii documentului.
HTML este o formă de marcare orientată către prezentarea documentelor text pe o singura pagină, utilizând un software de redare specializat, numit agent utilizator HTML, cel mai bun exemplu de astfel de software fiind browser-ul web. HTML furnizează mijloacele prin care conținutul unui document poate fi adnotat cu diverse tipuri de metadate și indicații de redare. Indicațiile de redare pot varia de la decorațiuni minore ale textului, cum ar fi specificarea faptului că un anumit cuvânt trebuie subliniat sau că o imagine trebuie introdusă, până la scripturi sofisticate, hărți de imagini și formulare. Metadatele pot include informații despre titlul și autorul documentului, informații structurale despre cum este împărțit documentul în diferite segmente, paragrafe, liste, titluri etc. și informații cruciale care permit ca documentul să poată fi legat de alte documente pentru a forma astfel hyperlink-uri (sau web-ul).
Documentele HTML sunt realizate folosind etichete sau tag-uri și au în general extensia „.htm” sau „.html”. Etichetele pot fi de două feluri, simple cum ar fi <eticheta /> sau compuse din două părți, una de deschidere, <eticheta>, și alta de închidere, </eticheta>. Între cele două componente se pot adăuga alte etichete sau text. Navigatorul web interpretează aceste etichete afișând rezultatul pe ecran. Limbajul HTML nu face deosebire între litere majuscule și minuscule.
Pagina de start a unui domeniu (home) este fișierul „index.html” respectiv „index.htm”. Această pagină se afișează implicit la accesarea unui domeniu.
De exemplu la accesarea domeniului www.domeniu.ro este afișată pagina www.domeniu.ro/index.html.
În general etichetele compuse din doua părți permit utilizarea de atribute care pot avea anumite valori:
<eticheta atribut="valoare"> … </eticheta>
Un document HTML este compus din:
versiunea HTML a documentului
secțiunea head cu etichetele <head> … </head>
secțiunea body cu etichetele <body> … </body> sau <frameset> … </frameset>
Versiunea HTML poate fi:
HTML 4.01 Strict
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
HTML 4.01 Transitional
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
HTML 4.01 Frameset
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
HTML 5
<!DOCTYPE HTML>
CSS (Cascading Style Sheets)
CSS este un limbaj foaie de stil folosit pentru a descrie aspectul și formatarea unui document scris într-un limbaj de marcare. În general este folosit pentru a schimba stilul paginii web și interfețele scrise în HTML si XHTML dar se poate aplica și pentru documente XML, incluzând XML simplu, SVG și XUL. Împreuna cu HTML și JavaScript, CSS este o tehnologie folosită de majoritatea paginilor web pentru a realiza aspectul vizual al acestora.
Stilurile se pot aplica în trei moduri:
stiluri în linie;
stiluri interne;
stiluri externe.
Stilurile în linie se definesc chiar in codul HTML, în interiorul elementului pe care dorim să îl stilizăm cu ajutorul atributului „style”.
Exemplu:
<p style=”color: red;”>Text roșu</p>
Browserul va afișa textul din paragraf de culoare roșie:
Text roșu
Stilurile în linie nu ne permit schimbări rapide, pe mai multe fișiere în același timp, modificările făcându-se pe fiecare element în parte de pe toate paginile.
Stilurile interne se definesc în interiorul fiecărei pagini HTML în cadrul etichetei (tag) <head></head> .
Exemplu:
<head>
<style type=”text/css”>
p: {color: red;}
</style>
</head>
Acest exemplu va schimba culoarea tuturor etichetelor „p” din interiorul unei pagini HTML. Daca dorim modificarea culorii textului pe mai multe pagini HTML, este necesar să copiem codul de mai sus pe fiecare fișier HTML în parte.
Stilurile externe se definesc într-un fișier extern, preferabil cu extensia .css, fișierul atașându-se unuia sau mai multor fișiere HTML cu ajutorul tagului <link> tot în cadrul tagului <head></head>:
Exemplu:
<link rel=”stylesheet” type=”text/css” href=”stil.css” />
În fișierul „stil.css” vom avea codul css:
p:{color: red;}
În exemplul de mai sus, toate tagurile „p” vor avea culoarea textului roșie din toate documentele HTML care includ fișierul „stil.css”.
În concluzie stilurile externe oferă următoarele avantaje:
întreținere mai ușoară;
dimensiuni reduse ale paginilor;
economie de banda internet;
flexibilitate.
JavaScript
Pentru a se construi interfețe intuitive și sofisticate este necesar și un limbaj de scripting la nivel de client. Scripting-ul permite scrierea de cod (mici programe) care rulează în cadrul browserului.
Cel mai cunoscut limbaj de scripting pe parte de client este JavaScript, care este suportat (mau mult sau mai puțin) de aproape orice browser existent. Folosind JavaScript se poate realiza: validarea formularelor, animarea textului și a imaginilor, crearea de meniuri drop-down și a controalelor de navigare, se pot efectua procesări de bază numerice sau asupra textelor și multe altele.
Scripting-ul permite programatorilor să detecteze și să proceseze evenimentele. De exemplu, o pagină care se încarcă, un formular trimis, mișcarea pointer-ului mouse-ului asupra unei imagini sunt toate evenimente, iar script-urile pot fi executate automat de browser atunci cînd aceste evenimente au loc.
Script-urile pot fi incluse în codul HTML sau pot fi stocate în fișiere externe și legate în interiorul codului HTML.
Istoric PHP
PHP-ul, așa cum este cunoscut astăzi, este de fapt succesorul unui produs denumit PHP/FI. Creat în 1994 de Rasmus Lerdorf, prima apariție a PHP a fost un set simplu de binare CGI (Common Gateway Interface) scris în limbajul de programare C. Utilizat în primul rând pentru a urmări vizitele CV-ului lui online, el a denumit suita de scripturi ”Personal Home Page Tools”, referențiate mai frecvent ca „Unelte PHP”. În timp, au fost dorite mai multe funcționalități și Rasmus a rescris Uneltele PHP, producând o mai mare și mai importantă implementare. Acest model a fost capabil de interacțiuni cu baze de date și chiar mai mult a furnizat un cadru de lucru pe care utilizatorii au putut dezvolta aplicații de web simple și dinamice cum ar fi cărțile de oaspeți. În 1995, Rasmus a dat codul sursă al Uneltelor PHP publicului, ceea ce a permis dezvoltatorilor să-l utilizeze așa cum au crezut. Aceasta, de asemenea a permis și încurajat utilizatorii să furnizeze corecții pentru erori de programare (bug-uri) și în general să le rezolve.
În luna septembrie a acelui an, Rasmus a extins PHP și pentru o perioadă scurtă de timp a renunțat la numele PHP. Acum referindu-se la unelte ca FI (denumirea scurtă pentru “Forms Interpreter”), noua implementare include unele dintre funcționalitățile de bază ale PHP așa cum sunt ele cunoscute azi. Avea variabile ca Perl, interpretare automată a variabilelor din formulare și sintaxă încorporată HTML. Sintaxa însăși a fost similară cu cea de Perl, cu toate că era mai limitat, simplu și puțin inconsistent. De fapt, pentru a încorpora codul într-un fișier HTML; dezvoltatorii au trebuit să utilizeze comentarii HTML. Deși această metodă nu a fost bine primită, FI s-a bucurat de creștere și acceptare ca o unealtă CGI – dar nu chiar ca un limbaj. Totuși, aceasta s-a schimbat în luna următoare; în octombrie 1995, Rasmus a lansat o rescriere completă a codului. A adus înapoi denumirea de PHP, denumit acum “Personal Home Page Kit” și a fost prima lansare a ceea ce a fost considerat o interfață de scriptare avansată. Limbajul a fot proiectat pentru a semăna cu structura C, făcându-l mai ușor de adaptat pentru dezvoltatorii familiari cu C, Perl și alte limbaje similare. Deși era limitat doar pentru sisteme UNIX și cele compatibile POSIX, s-a explorat potențialul pentru o implementare Windows NT.
Codul a suferit o nouă transformare completă și în aprilie 1996, combinând numele edițiilor din trecut , Rasmus a introdus PHP/FI. Această implementare de a doua generație a început evoluția PHP de la o suită de unelte într-un limbaj de programare în adevăratul cuvânt. El includea suport pentru bazele de date DBM, mSQL și Postgres95, cookie-uri, suport de funcții definite de utilizator și multe altele. Un fapt interesant despre acesta, totuși, este că a existat doar o singură versiune completă de PHP 2.0. Când el a trecut de starea beta în noiembrie 1997, motorul de interpretare a fost deja rescris în totalitate.
Deși a avut o viață de dezvoltare scurtă, el a continuat să se bucure de o popularitate în creștere în lumea încă tânără a dezvoltatorilor web. În 1997 și 1998, PHP/FI era un limbaj cu câteva mii de utilizatori din lume. Un sondaj Netcraft din mai 1998 indică faptul că aproape 60.000 de domenii au raportat că au antete care conțin PHP, ceea ce indică că serverul gazdă l-a instalat. În ciuda acestor cifre impresionante, maturizarea PHP/FI era totuși limitată, el a fost dezvoltat în primul rând de un singur om, deși au existat mai mulți contribuitori minori.
PHP 3
PHP 3.0 a fost prima versiune care se aseamănă cu PHP-ul așa cum este el astăzi. Găsind PHP/FI 2.0 încă ineficient și fără caracteristici de care aveau nevoie pentru a dezvolta o aplicație eCommerce pe care o dezvoltau pentru un proiect la universitate, Andi Gutmans și Zeev Suraski din Tel Aviv, Israel, au început o rescriere completă a interpretorului de bază în 1997. Într-un efort de a îmbunătăți motorul și de a construi pe baza existentă a PHP/FI, Andi, Rasmus și Zeev au decis să colaboreze pentru a dezvolta un nou limbaj de programare independent. Acest limbaj nou în întregime a fost lansat sub un nume nou, care a înlăturat implicarea utilizării personale limitate pe care îl deținea numele PHP/FI. A fost redenumit simplu PHP, cu semnificația unui acronim recursiv – PHP: Hypertext Preprocessor.
Unul dintre punctele forte ale PHP 3.0 a fost caracteristicile de extensibilitate puternice. În plus, a furnizat utilizatorilor finali o interfață matură pentru baze de date multiple, protocoale, API-uri și ușurința de a extinde limbajul însuși a atras zeci de dezvoltatori care au trimis multe module. Aceasta a fost cheia succesului enorm al PHP. Alte caracteristici cheie introduse în PHP 3.0 au inclus suportul pentru programare orientată pe obiecte și o sintaxă de limbaj mai puternică și mai consistentă.
În iunie 1998, cu mai mulți dezvoltatori noi care s-au alăturat efortului, a fost anunțat PHP 3.0 de Echipa de dezvoltare PHP ca succesor al PHP/FI. Dezvoltarea activă a PHP/FI 2.0, care a încetat în luna noiembrie a anului anterior, a fost oficial închisă. După nouă luni de testare deschisă publicului, când a fost făcut anunțul al lansării oficiale a PHP 3.0, el era deja instalat pe 70.000 de domenii din lume și nu mai era limitat la sisteme de operare compatibile POSIX. O parte relativ mică de domeniile care au raportat PHP ca instalat au fost găzduite de servere care rulau Windows 95, 98, și NT și Macintosh . PHP 3.0 era instalat pe aproximativ 10% din serverele web din internet.
PHP 4
În iarna anului 1998, la scurt timp după lansarea oficială a PHP 3.0, Andi Gutmans și Zeev Suraski au început lucrul la rescrierea nucleului PHP. Obiectivele erau de a îmbunătăți performanța aplicațiilor complexe și de a îmbunătăți modularitatea bazei codului PHP. Astfel de aplicații au fost posibile datorită caracteristicilor noi ale PHP suportând o varietate mare de baze de date și API-uri, dar PHP 3.0 nu a fost proiectat să manipuleze astfel de aplicații complexe eficient.
Noul motor, denumit “Zend Engine” (care este compus din primele lor nume, Zeev și Andi) a îndeplinit cu succes obiectivele și a fost introdus la mijlocul anului 1999. PHP 4.0, bazat pe acest motor și împreună cu foarte multe caracteristici noi, a fost lansat oficial în mai 2000, după aproape doi ani față de predecesorul lui. În plus, PHP 4.0. includea alte caracteristici cheie cum ar fi suport pentru mai multe servere web, sesiuni HTTP, buferizarea ieșirii, metode mai securizate de manipulare pentru ieșirile utilizatorilor și câteva construcții noi ale limbajului.
PHP 5
PHP 5 a fost lansat în iulie 2004 după o lungă dezvoltare și câteva pre-lansări. Se bazează în principal pe motorul Zend Engine 2.0 cu multe caracteristici noi.
Echipa de dezvoltare a PHP include mulți programatori, precum și mulți alții care lucrează la proiecte legate de PHP și de suport, cum ar fi PEAR, PECL și documentații. Mai include o infrastructură de rețea de peste 100 de servere web individuale pe șase din cele șapte continente ale lumii. Deși este o estimare bazată pe statistici din anii anteriori, presupunem că PHP este acum instalat pe zeci sau poate sute de milioane de domenii din lume.
MySQL
MySQL este un limbaj SQL (Structured Query Language) server foarte rapid, robust, multiutilizator și cu interfațare pentru foarte multe alte programe.
MySQL, cel mai popular limbaj de lucru cu baze de date SQL cu sursă deschisă (Open Source SQL database), a fost deținut și sponsorizat de o singură firmă pentru-profit, compania suedeză MySQL AB, deținută în prezent de Oracle Corporation.
MySQL este un sistem de management a bazelor de date. O bază de date este o colecție structurată de date. Poate fi orice de la o simplă listă de cumpărături până la o vastă cantitate de informații în cadrul unei corporații. Pentru a adăuga, accesa și procesa datele stocate într-o bază de date de pe un computer, se poate folosi un sistem de management a bazelor de date cum ar fi MySQL. Atât timp cât computerele sunt foarte bune în manipularea unor mari cantități de date, managementul bazelor de date joacă un rol foarte important în aplicațiile de sine stătătoare sau ca părți componente a altor aplicații.
MySQL este un sistem de management a bazelor de date relaționale. O bază de date relațională stochează datele în tabele diferite și nu într-un singur tabel pentru că acest sistem este mai flexibil și mai rapid. Tabele sunt interconectate prin definire de relații făcând astfel posibilă combinarea de date din diferite tabele în cadrul unei singure interogări.
SQL din cadrul denumirii MySQL derivă de la "Structured Query Language" – limbaj de lucru cu baze de date structurat pe interogări – care este unul dintre cele mai utilizate limbaje pentru accesarea bazelor de date.
MySQL este un limbaj de lucru cu baze de date cu sursă deschisă. Sursa deschisă se referă la faptul că este posibil ca oricine să utilizeze și să modifice sursa și diferitele aplicații dezvoltate de diferiți developeri. Se pot descărca de Internet și se pot modifica după propriile dorințe și necesități fără a plăti nimic. MySQL folosește GPL (GNU General Public License), o licență care specifică ce poți și ce nu poți face cu programul software în diferite situații. Pentru necesitatea de aplicații comerciale se poate cumpăra versiunea comercială cu licență.
Motivația utilizării limbajului MySQL este faptul că oferă rapiditate, performanță și simplitate în utilizare. Chiar de la bun început, MySQL a fost dezvoltat pentru a manipula baze de date mari mult mai rapid decât programele existente la data respectivă pe piață. A fost utilizat cu mare succes de câțiva ani în mediile de producție cu cerințe ridicate. Deși este în continuă dezvoltare, MySQL oferă astăzi un set bogat și foarte util de funcții. Conectivitatea, viteza și securitatea determină MySQL să fie potrivit pentru accesarea bazelor de date pe Internet.
MySQL este un sistem client/server care constă într-o interfațare cu multiple fire de execuție pe serverul SQL (suportă diferite reveniri) și prezintă mai multe programe client și librării, programe administrative și câteva interfețe de programare. MySQL are disponibile foarte multe programe software de interfațare și este foarte probabil să aflați că multe dintre aplicațiile preferate suportă deja interfațare cu limbajul MySQL.
Descrierea aplicației
Apectul paginii (Layout)
Aspectul paginii este împarțit în trei părți distincte:
antet (Header) – parte statică
secțiune (conținut pagini) – parte dinamică
subsol (Footer) – parte statică
Figura 3.1 – Pagina principala a aplicatiei
în header se afla logo-ul aplicației, bara de navigație (meniul principal), formularul de autentificare și legăturile către pagina „creare cont nou” respectiv pagina „recuperare parolă”.
conținutul aplicației se încarcă în funcție de pagina accesată
în footer se află logo-ul, meniul principal detaliat si modulul pentru rețeaua de socializare Facebook
Secțiuni
Pagina de start
Pagina de start (Figura 3.1), conține o prezentare animată realizată cu ajutorul librăriei jQuery și o scurtă descriere a modulelor de testare. În partea de conținut al paginii se derulează fiecare categorie la un interval de timp stabilit in fișierul JavaScript ce afișează informații legate de acea categorie. Fiecare categorie are asociată o pictogramă pe care se poate face click în cazul în care se dorește derularea mai rapidă către acea categorie. Aici este disponibil și un buton ce direcționează către pagina de atestate, numit „Generează chestionar”.
Atestate
În această pagină se află lista cu modulele de testare și subsecțiunile fiecăruia. În această secțiune utilizatorul își alege modulul și examenul pe care dorește să îl susțină.
Figura 3.2 – pagina atestate și selecția unei categorii
Dacă utilizatorul este autentificat, selectarea unui examen va genera o pagină ce afișează informații referitoare la examen cum ar fi: timpul maxim pentru susținerea examenului, punctajul minim și numărul total de întrebări din chestionar, însoțite de butoanele „Începe examen” și „Înapoi”. Butonul „Înapoi” direcționează către pagina anterioară.
Dacă utilizatorul nu este autentificat atunci aplicația va afișa pagina de autentificare.
Legislație
Această secțiune deschide un sub-meniu ce conține legături către pagini de legislație (națională și comunitară). Din aceste pagini se pot descărca fișiere în format PDF ce conțin diverse legi din domeniul transporturilor auto. Fiecare titlu de lege subliniat are un hyperlink ce direcționează către documentul PDF corespunzător ce se poate vizualiza în browser, dacă este instalat plugin-ul Adobe Acrobat Reader sau se poate descărca cu click dreapta pe acel link.
Figura 3.3 – pagina de legislație
Contact
În pagina de contact sunt afișate datele de contact și un formular de contact însoțit de un element de securitate de tip „Captcha”. Dacă datele au fost acceptate atunci un e-mail va fi trimis pe adresa de e-mail prestabilită în aplicație, conținând datele introduse de utilizator în formularul de contact și mesajul acestuia.
Figura 3.4 – Pagina de contact
Cont nou
Pe această pagină este afișat un formular ce conține câmpuri obligatorii și opționale ce se vor completa de către utilizator cu datele specificate în formular. Acest formular este de asemenea însoțit de elementul de securitate de tip „Captcha”. La apăsarea butonului „Creează cont”, se trimit datele către server, sunt analizate iar dacă sunt acceptate, aplicația trimite un e-mail către e-mail-ul introdus de utilizator în acest formular. În acest e-mail sunt scrise informații referitoare la pașii necesari pentru validarea contului. În conținutul e-mail-ului se află și o adresă web generată automat de aplicație pe care utilizatorul trebuie să o acceseze pentru a valida contul. După accesarea adresei de validare, contul este creat iar utilizatorul se poate autentifica în aplicație.
Figura 3.5 – pagina „cont nou”
„Ai uitat parola?”
Această pagină afișează formularul pentru recuperare parola în care se cere adresa de e-mail a utilizatorului și de asemenea codul „captcha”.
Figura 3.6 – pagina pentru recuperare parolă
Pe adresa de e-mail specificată în formular se va trimite o adresă URL pe care utilizatorul trebuie să o acceseze pentru a finaliza procesul de resetare parola. După ce utilizatorul accesează această adresă, aplicația trimite din nou e-mail cu noua parolă. Parola veche nu se poate trimite utilizatorului deoarece se salvează în baza de date criptată MD5. După ce utilizatorul apasă butonul de resetare parolă un mesaj de confirmare va fi afișat iar după o anumită perioadă de timp va fi direcționat către prima pagină.
Figura 3.7 – mesaj pentru confirmarea trimiterii email-ului ce conține
pașii ce trebuie urmați pentru a finaliza procesul de resetare parolă
Meniu adițional
După autentificare, formularul de autentificare va deveni invizibil și va fi înlocuit cu un meniu adițional ce conține legături către pagini specifice tipului de cont. Tipurile de cont sunt de două feluri: „reseller” și sau „utilizator”. Contul de tip „utilizator” este de două feluri, utilizator individual și utilizator ce aparține de un cont de tip „reseller”. Contul de tip „reseller” poate administra doar utilizatorii creați de acesta, având posibilitatea de a adăuga sau șterge utilizatori și de a transfera credite, evident dacă are suficiente credite la rândul său.
Figura 3.8 – meniu disponibil după autentificare
Administrare cursanți
Această pagină este disponibilă doar pentru contul de tip „reseller”. Aici deținătorul contului poate adăuga, șterge sau modifica conturile cursanților. De asemenea se pot vizualiza detaliile cursanților cum ar fi numele și prenumele, numărul total de chestionare, numărul de chestionare disponibile, dacă este activ sau susține examenul în momentul de față. În dreptul fiecărui cursant se află butoanele ce duc către paginile de modificare sau ștergere, pe coloana din tabel numită „Acțiuni”.
Figura 3.9 – pagina listare cursanți
Editare detalii cursant
Pentru adăugare cursant exista buton numit „Adaugă cursant” situat in dreapta sus a listei de cursanți, iar pentru modificare, pe coloana „Acțiuni” se află în dreptul fiecărui cursant două butoane ce au pictograme specifice editării și ștergerii unei înregistrări.
Apăsarea butonului de ștergere din dreptul unui cursant activează o fereastră de tip dialog ce conține un mesaj de avertizare și două butoane, unul pentru confirmare și altul pentru renunțare.
Pe pagina de adăugare sau modificare cont se pot edita numele și prenumele cursantului, numărul de credite ce se doresc a fi transferate către cursant. Creditele sunt transferate din contul celui care administrează în contul cursantului, dacă sunt disponibile. După completarea formularului administratorul are posibilitatea să salveze modificările sau să renunțe având la dispoziție două butoane: „Salvează” și „Renunță”.
Figura 3.10 – pagina modificare cursant
Administrare cont
Aceasta pagină este disponibila tuturor utilizatorilor. Aici se pot modifica detaliile personale mai puțin adresa de e-mail. Utilizatorii creați din contul de tip „reseller” au în loc de adresa de e-mail un ID unic generat de aplicație iar aceștia se pot autentifica cu acel ID și parola date de administrator.
Figura 3.11 – pagina de administrare cont personal
Istoric chestionare
Se poate accesa de pe link-ul „Chestionare” din căsuța din partea dreaptă. În această pagină sunt afișate toate chestionarele realizate de utilizator și rezultatele obținute, având posibilitatea de a vizualiza detaliat toate întrebările chestionarului selectat.
Figura 3.11 – lista chestionarelor rezolvate
„Începe examen” sau rezolvarea unui chestionar
Din pagina de listare categorii din secțiunea „Atestate”, după ce utilizatorul selectează o categorie (mouse hover pe categoria dorită, vezi figura 3.2), o lista de subcategorii va fi vizibilă. Selectarea subcategoriei va direcționa către pagina de detalii specifice domeniului ales.
Figura 3.12 – pagina intermediară de dinaintea începerii rezolvării chestionarului
Apăsând butonul „Începe examen” aplicația va afișa pagina de examinare pe care se află un contor ce reprezintă timpul rămas până la finalizarea examenului, detaliile legate de categorie și subcategorie, numărul întrebării curente, întrebarea și răspunsurile posibile. În acest moment utilizatorul poate începe rezolvarea chestionarului. Răspunsurile pot fi selectate în două moduri, fie prin selectarea unui singur răspuns corect în cazul răspunsurilor ce au „radio button” fie prin selectarea a mai multor răspunsuri corecte în cazul chestionarelor ce permit acest lucru folosind elemente de tip „checkbox”. Utilizatorul are posibilitatea să salveze răspunsul dat, moment în care aplicația va da răspunsul imediat, fără posibilitatea de a mai reveni la acea întrebare decât după finalizarea examenului sau are posibilitatea sa treacă la întrebarea următoare, în cazul în care dorește să răspundă mai târziu. Revenirea la întrebările nerezolvate se poate face fie prin parcurgerea tuturor întrebărilor până la capăt fie accesând direct întrebările marcate cu alb din lista de întrebări. Întrebările marcate cu roșu sau verde sunt întrebări la care s-a acceptat răspunsul și nu pot fi accesate sau modificate, roșu însemnând răspuns greșit iar verde răspuns corect. Utilizatorul are posibilitatea să finalizeze examenul apăsând butonul „Finalizează examenul”. În acest moment întrebările la care nu s-au dat răspuns vor fi marcate cu roșu iar chestionarul este salvat în istoricul de chestionare al utilizatorului și îi este permisă revizuirea chestionarului fără posibilitatea de a mai modifica răspunsurile. La depășirea timpului limita aplicația oprește examenul efectuând aceiași acțiune pe care o realizează butonul „Finalizează examenul”.
Figura 3.13 – pagina de examen, cu examen în curs de desfășurare
Proiectarea aplicației
Baza de date
Baza de date a fost realizata cu ajutorul utilitarului phpMyAdmin, utilitar gratuit scris în PHP ce permite administrarea bazelor de date pe web. phpMyAdmin suportă o gamă larga de operațiuni MySQL cum ar fi gestionarea bazelor de date, tabelelor, coloanelor, relații, indecși, permisiuni etc. Toate acestea pot fi efectuate prin intermediul interfeței de utilizator.
Structura bazei de date
Baza de date are următorul set de tabele:
Sistemul de gestiune al paginilor.
Aplicația are la bază un sistem propriu de gestiune al paginilor. Acesta separă codul sursă în două: cod HTML și cod PHP ce se află în doua directoare distincte.
În directorul „template” sunt situate toate fișierele HTML ale aplicației. Numele fișierelor reprezintă, în mare parte, adresa relativă a paginii accesate din browser fără extensia acestuia (.html). De exemplu utilizatorul doreste sa acceseze pagina de contact ce se află la adresa http://www.examenauto.ro/contact. Aplicația, cu ajutorul modulului de rescriere URL (RewriteEngine) al serverului web, va trimite către server ca parametru valoarea „contact” ce poate fi obținută cu ajutorul PHP folosind variabila „$_GET[‘param1’]”. În acest moment aplicația caută în directorul „template” fișierul „contact.html” și îl va citi dacă există.
În directorul „php” sunt situate toate fișierele PHP legate de fiecare pagina web a aplicației. Ele vor fi accesate în același mod ca cele HTML aplicația căutând fișierul „contact.php” pe care îl va executa daca există.
În concluzie pentru accesarea paginii „contact” aplicația caută fișierele „php/contact.php” respectiv „template/contact.html”, rulează fișierul „contact.php” căruia i se atașează fișierul corespunzător „contact.html”. Conținutul fișierului HTML va fi modificat în timp real în funcție de cerințele stabilite în fișierul PHP, după care se trimite rezultatul către browser. În cazul în care fișierul PHP nu există atunci conținutul fișierului HTML este trimis direct către browser.
Activarea mod-rewrite și fișierul „.htaccess”
Mod-rewrite este un modul din Apache folosit la rescrierea adreselor URL, foarte util pentru îmbunătățirea aspectului acestora, mai ales in cazul site-urilor construite cu PHP.
După cum spune si numele "rewrite", acesta rescrie adresele URL, aspect care ajuta la o mai buna indexare a site-urilor in motoarele de căutare dar și pentru a reține mai ușor adresele URL.
De exemplu avem o adresa URL cu următoarea formă:
http://www.examenauto.ro/?param1=contact
putem rescrie acest URL sub forma:
http://www.examenauto.ro/contact
Pentru aceasta vom folosi următorul set de instrucțiuni scrise în fișierul „.htaccess”:
# activează mod-rewrite
RewriteEngine On
# regula de rescriere URL
RewriteRule ^([a-zA-Z0-9\-]+)$ index.php?param1=$1 [L]
Serverul Apache va interpreta aceasta regula astfel: orice șir de caractere din adresa URL care conține unul sau mai multe caractere din setul de la „a” la „z”, sau de la „A” la „Z” sau de la „0” la „9” sau caracterul „ – ” , datorita parantezelor ”( )” rezultatul va fi copiat în variabila $1. În cazul în care avem mai multe grupuri de paranteze „( )” rezultatul va fi copiat în ordine în variabile de forma $[1 la N], adică dacă vom avea „( ) ( ) ( )” – conținutul primului grup de paranteze va fi copiat în $1, pentru grupul 2 va fi $2 iar grupul 3 va fi $3.
Exemplu de URL rescris cu doi parametri:
http://examenauto.ro/examen/23 – se dorește afișarea întrebării numărul 23 de pe pagina „examen”
Regula va fi:
RewriteRule ^([a-zA-Z0-9\-]+)/([a-zA-Z0-9\-]+)$ index.php?param1=$1¶m2=$2 [L]
Forma adresei trimise către server va fi http://examenauto.ro/?param1=examen¶m2=23
Acest sistem are și un dezavantaj, de exemplu imaginile din pagina ce au URL relativ (<img src=”images/poza1.jpg”>) la accesarea paginii http://examenauto.ro/examen/23, adresa absoluta a imaginii va deveni http://examenauto.ro/examen/images/poza1.jpg, evident serverul nu va găsi imaginea la adresa respectivă deoarece imaginile nu sunt situate în directorul „examen/images/”, imaginea fiind situată la adresa http://examenauto.ro/images/poza1.jpg. Pentru asta vom scrie reguli de rescriere adiționale pentru directoarele pentru care dorim ca rescrierea URL sa facă excepții.
Exemplu:
# rescrie orice URL ce are în componența sa cuvîntul cheie „images/” către directorul # images/
RewriteRule images/(.*) images/$1 [L]
În cazul de mai sus „examen/images/…” va deveni „images/…”
Fișierele de configurare
În fișierul „mysql.php” se află un set de constante ce definesc datele de inițializare și autentificare ale unei conexiuni cu serverul MySQL.
<?php
define ("DB_HOST","localhost",true);
define ("DB_USER","user_mysql",true);
define ("DB_PASS","parola_mysql",true);
define ("DB_NAME","database_name",true);
?>
DB_HOST – adresa de conectare la serverul MySQL, în general este pe mașina locală (localhost)
DB_USER – denumirea utilizatorului care se conectează la serverul MySQL.
DB_PASS – parola asignată utilizatorului.
DB_NAME – denumirea bazei de date care se va utiliza.
Fișierul „main.php” – aici se pot adăuga constante sau variabile globale folosite în aplicație. În cazul de față avem o constantă „INDEX” ce definește adresa URL de bază ce se inserează în general în fața adreselor relative formând astfel adresa URL absoluta a unei poze sau hyperlink.
<?php
define("INDEX",'http://www.examenauto.ro/',true);
?>
Librarii – clase și funcții PHP
Librăria de clasele și funcțiile utilizate în aplicație se află în directorul „libs”. Principalele fișiere din această locație sunt mysql.php, class.tpl.php, funtions.php, router.php, phpQuery și class.phpmailer.php.
Fișierul mysql.php
– reprezintă o clasă denumită „mysql” ce gestionează principalele operațiuni ale lucrului cu baza de date cum ar fi conectarea la serverul MySQL, execuția unui query, deconectarea de la serveryl MySQL, etc.
Exemple de proprietăți ale clasei „mysql”:
function my_connect() {
$this->db_link=mysql_connect(DB_HOST, DB_USER, DB_PASS);
mysql_select_db(DB_NAME,$this->db_link);
mysql_query("SET CHARACTER SET utf8");
mysql_query("SET NAMES utf8");
setlocale(LC_NUMERIC, 'C');
setlocale(LC_ALL,"ro_RO.UTF-8");
}
function my_disconnect() {
mysql_close($this->db_link);
}
function __construct() {
$this->my_connect();
}
function __destruct() {
$this->my_disconnect();
}
Observăm că proprietatea my_connect() este apelată în constructorul clasei iar my_disconnect() în destructorul acesteia. Deci pentru a avea o conexiune deschisă cu serverul MySQL este suficient sa creăm o instanță a clasei:
$my = new mysql();
În acest moment conexiunea este activa iar baza de date este selectată și putem trimite comenzi SQL serverului MySQL. Deconectarea se face în mod automat deoarece serverul PHP apelează destructorul fiecărei instanțe create la terminarea execuției fișierului PHP.
Execuția de comenzi SQL se face cu ajutorul proprietății „sql” din această clasă:
function sql($query, $group_by = '', $single = false, $field='', $last_id = false) {
$this->res = mysql_query($query);
…
if ($group_by == '') {
for ($i = 0; $i < mysql_num_rows($this->res); $i++) {
$tmp[] = mysql_fetch_assoc($this->res);
} else {
…
}
…
return $tmp;
}
În această secvență de cod observăm că rezultatul pe care îl întoarce serverul MySQL este copiat într-o variabilă de tip vector asociativ pe care funcția îl întoarce ca rezultat.
De exemplu dacă se dorește executarea unui query ce selectează un anumit număr de utilizatori ordonați după nume și prenume se va folosi următoarea secvență de instrucțiuni:
$sql = new mysql();
$tmp = $sql->sql(" SELECT `id_user`, `id_parent`, `nume`,`prenume`, `judet`
FROM `users`
ORDER BY `nume`, `prenume`
LIMIT 3
");
echo '<pre>'.print_r($tmp, true).'</pre>';
Folosind funcția print_r putem vedea conținutul variabilei $tmp :
Funcția “sql” are posibilitatea să grupeze înregistrările după un anumit câmp din baza de date, folosind al doilea parametru “$group_by”, valorile acelui câmp fiind cheile variabilei de tip vector asociativ pe care funcția o întoarce.
Exemplu: se dorește să se grupeze utilizatorii după câmpul județ folosind denumirea județului din tabelul de județe.
$tmp = $sql->sql(" SELECT `id_user`,`id_parent`,`nume`,`prenume`,`judete`.`denumire`
FROM `users`
LEFT JOIN `judete` ON `judete`.`id_judet`=`users`.`judet`
WHERE `judet` IN(1,2)
ORDER BY `nume`, `prenume`
LIMIT 4","denumire");
echo '<pre>'.print_r($tmp,true).'</pre>';
Serverul mysql va selecta 4 utilizatori ale căror județe au id 1 și 2, lista rezultată va fi grupată după câmpul „denumire” ce provine din tabelul atașat “judete”. Rezultatul variabilei $tmp va fi un vector pe trei nivele:
Acest tip de vector va putea fi parcurs folosind instrucțiunea „foreach“ :
foreach ($tmp as $cheie => $valoare)
for ($i = 0; $i < count($valoare); $i++)
unde $cheie va reprezenta denumirea județului iar $valoare este conținutul elementului curent, care la rândul său este un vector ce conține elemente ($valoare[$i]) al căror valori sunt tot vectori de tip asociativ ($valoare[$i]["nume"], $valoare[$i]["prenume"], etc.).
Acest mod ne ajută să structurăm datele obținute de la serverul mysql sub forma unui arbore.
Execuția fișierelor PHP atașate paginilor aplicației
class.tpl.php – în acest fișier se află clasa numită „tpl” ce reprezintă sistemul de gestiune al paginilor aplicației. Această clasă include și creează o instanță a clasei mysql descrisă anterior. În capitolul 4.3 – sistemul de gestiune al paginilor, am prezentat o scurtă descriere despre modul cum sunt gestionate fișierele atașate paginilor. Fișierele PHP și HTML sunt procesate în această clasă. Fișierele PHP ce reprezintă codul executabil pe server al fiecărei pagini ale aplicației sunt încărcate folosind funcția „require” după care se execută funcția personalizată din fișierul PHP încărcat folosind funcția call_user_func, deoarece funcția declarată în acest fișier are un nume variabil și este scris în următorul mod:
– dacă numele paginii este de exemplu „contact” fișierul PHP citit va fi „contact.php” iar funcția din interior va avea denumirea „tpl_contact”. Funcția primește ca paramentru instanța clasei ($this). Înainte de a apela funcția „tpl_contact”, se verifică existența funcției folosind instrucțiunea „function_exists”
Exemplu conținut fișier „contact.php”:
<?php
function tpl_contact($tpl) {
…
Instrucțiuni
…
}
?>
Exemplu procesare pagina de contact:
function fetch($id, $tpl_name) {
…
$f=$this->php_dir . $tpl_name . '.php'; //calea completă a fișierului PHP
if ( file_exists ( $f ) ) { //dacă există îl includem
require_once ( $f );
//după includere verificăm dacă există funcția „tpl_” + $tpl_name
if ( function_exists ('tpl_' . str_replace ('-', '_', $tpl_name ) ) ) {
//apelăm funcția „tpl_” + $tpl_name cu parametrul $this
call_user_func ( 'tpl_' . str_replace ('-', '_', $tpl_name ), $this );
}
}
…
}
Exemplul de mai sus reprezintă o secvență de cod din interiorul funcției „fetch” ce realizează deschiderea unui fișier cu numele provenit din parametrul doi al funcției „$tpl_name” la care se inserează calea către directorul de fișiere PHP și se concatenează „.php”. De exmplu dacă „$tpl_name” are valoarea „contact” iar variabila publică „$php_dir” are valoarea „php/” atunci calea va fi „php/contact.php”. Calea către directorul unde sunt localizate fișierele PHP se inițializează după instanțierea clasei „tpl” în variabila publică „php_dir” din interiorul clasei, instanțierea clasei și inițializarea variabilelor publice realizându-se în fișierul de start „index.php”.
Procesarea fișierelor HTML
Fișierele HTML sunt citite și procesate tot în cadrul funției „fetch” cu ajutorul librăriei „phpQuery”, librărie ce reprezintă un set de clase și funcții ce funcționează pe același principiu ca și cunoscuta librărie „jQuery” diferit fiind faptul că phpQuery este scris în limbajul PHP și se executa pe serverul php (server-side) față de „jQuery” care se execută pe mașina clientului (client-side) și este scris în limbajul JavaScript. phpQuery este un CSS3 selector bazat pe DOM (Document Object Model) API ce este derivat din librăria jQuery. Am folosit această librărie pentru o mai bună organizare a codului sursă separând complet codul HTML de cel PHP. Fișierele HTML sunt deschise din interiorul funcției „fetch” folosind phpQuery astfel:
$dom = phpQuery::newDocumentFilePHP ( 'fișier.html' );
Din acest moment avem acces la orice etichetă (tag) HTML folosind funcția gobală a acestei librării numită „pq” ce este echivalentul selectorului „$” din „jQuery”. De exemplu, dacă avem secvența de cod HTML:
<html>
<body>
<div id="main">
<div id="header"></div>
<div id="content"></div>
</div>
</body>
</html>
Se dorește modificarea conținutului etichetelor „div” cu id „main” și „content”. În JavaScript folosind jQuery am fi scris:
$('#main').html('conținut text în eticheta div cu id=”main” ');
$('#content').html('conținut text în eticheta div cu id=”content” ');
Echivalentul PHP folosind phpQuery este:
pq('#main')->html('conținut text în eticheta div cu id=”main” ');
pq('#content')->html('conținut text în eticheta div cu id=”content” ');
Codul rezultat fiind același în ambele variante:
<html>
<body>
<div id="main">
<div id="header">conținut text în eticheta div cu id=”main”</div>
<div id="content"> conținut text în eticheta div cu id=”content”</div>
</div>
</body>
</html>
În JavaScript modificarea se realizează direct in browser, în PHP se afișează codul HTML ce se află în memorie folosind obiectul $dom ce reprezintă instanța clasei phpQuery și proprietatea „html” a acesteia:
echo $dom->html();
Acest lucru nu este necesar deoarece rolul afișării fișierelor HTML procesate revine proprietății „display” din clasa „tpl”. Fișierele HTML procesate sunt salvate într-o listă internă a clasei „tpl” de către proprietatea „fetch” iar la apelarea funcției „display” toată lista este golită și trimisă către browser. Funcția display are ca parametru numele fișierului HTML de pornire, in general este „index.html” din directorul „template”.
Cu ajutorul acestui sistem se pot încărca fișiere întregi, conținutul lor putând fi inserat în etichete din alte fișiere HTML. În exemplul anterior putem insera în loc de text, fișierele „header.html” în eticheta „div” cu id „header” și fișierul „contact.html” în eticheta „div” cu id „content”.
Exemplu:
$tpl->fetch('#header','header');
$tpl->fetch('#content', $page);
echo $tpl->display('index.html');
unde valoarea variabilei $page este numele fișierului fără extensie, în cazul de față „contact”. Dacă în fișierul „index.html” există etichete cu id „header” respectiv „content” atunci conținutul fișierelor „header.html” și „contact.html” vor fi inserate în cele două etichete corespunzător id-ului.
Constructorul clasei „tpl”
În constructorul clasei se fac diferite inițializări necesare funcționării aplicației cum ar fi crearea unei instanțe a clasei „mysql”, variabilele de sistem ce provin din adresa URL ($_GET), numele paginii curente etc.
Exemplu – constructorul clasei „tpl”:
function __construct($params, $page) {
session_start(); //startează sesiune
$this->page = $page; //memorează numele paginii curente
$this->params = $params; //memorează variabilele de tip $_GET provenite din //adresa web URL
$this->doc_array = array(); //lista cu id-urile tagurilor ce urmează a fi alterate
$this->db = new mysql(); //instanțierea clasei mysql
$this->auth = false; //identifică dacă un utilizator este autentificat sau nu
}
Funcțiile ce provin din fișierele PHP atașate paginilor au ca parametru instanța clasei „tpl”. În concluzie, din interiorul acestor funcții avem acces la proprietățile și variabilele clasei instanțiate în fișierul „index.php”. De remarcat este variabila „db” ce conține instanța clasei „mysql” și cu ajutorul căreia putem trimite comenzi către serverul SQL.
Exemplu – comandă SQL executată din interiorul funcției „tpl_contact”:
<?php
function tpl_contact( $tpl ){
…
$tmp = $tpl->db->sql( "SELECT * FROM …” );
…
}
?>
Fișierul router.php
– se ocupă de gestionarea variabilelor provenite din adresa web preluate cu ajutorul variabilei de sistem $_GET. În acest fișier se pot adauga excepții legate de acești parametri cum ar fi, în cazul în care se accesează pagina principală toți parametrii au valoare nulă, deci pagina care trebuie încărcată nu există. În acest caz, dacă $_GET[”param1”] este null atunci $param[0] este inițializat cu valoarea „home”, aplicația accesând în felul acesta fișierul „home.html” respectiv „home.php”. O altă excepție este în cazul paginilor de legislație în care există sub-pagini cum ar fi „legislație/națională” sau „legislație/comunitară”. În această situație valoarea „legislație” din primul parametru nu reprezintă pagina ci o categorie, pagina fiind al doilea parametru.
Exemplu:
<?php
if (isset($_GET['param1']))$params[]=$_GET['param1'];
if (isset($_GET['param2']))$params[]=$_GET['param2'];
if (isset($_GET['param3']))$params[]=$_GET['param3'];
if (isset($_GET['param4']))$params[]=$_GET['param4'];
$page='home'; //setăm pagina initială
if ( isset( $params[0] ) ) {
$page = $params[0];
//dacă $page este ”legislație” atunci $params[1] va fi pagina dorită
if ( isset( $params[1] ) && $page == 'legislatie') $page = $params[1];
}
?>
Diagrama alogritmului de gestiune al paginilor
Figura 4.1
Fișierul de funcții globale – funcțions.php
În acest fișier se află diferite funcții ce pot fi accesate de oriunde în aplicație. Fișierul este încărcat în index.php. Descrierea celor mai importante funcții din această librărie:
Funcția „generate” – realizează generarea unui chestionar sau în cazul în care exisă un examen în desfășurare îl va citi pe acesta. Are ca parametri instanța clasei „tpl” și adresa URL formată din categoria și subcategoria aleasă de utilizator. Această cale se află în baza de date în tabelul „structura” în câmpul numit „url”. Valoarea din acest câmp mai este folosită și pe post de identificator al tipului de chestionar selectat.
Înainte de a se genera un chestionar mai întâi se verifică existența unui chestionar in curs de desfășurare, din tabelul „chestionare”, acest lucru se realizează comparând timpul actual cu cel de terminare al examenului, ce se memorează în baza de date în câmpul „end_time”.
function generate2($tpl,$url) {
$tmp3=$tpl->db->sql("
SELECT * FROM `chestionare`
WHERE `time_end`>'".time()."' AND
`id_user`='".$tpl->user_info['id_user']."'"
);
if (count($tmp3)>0){
//dacă există înregistrare atunci intoarce înregistrarea
return $tmp3[0];
}
…
}
Acest timp se calculează adunând timpul alocat chestionarului cu timpul la care s-a început chestionarul. Timpul alocat chestionarului este dat în minute și este memorat în câmpul „timp_alocat”. Timpul curent, obținut cu funcția PHP „time()”, este dat în secunde, deci se va înmulți cu 60 timpul alocat pentru a fi transformat în secunde.
Cum sunt generate chestionarele?
Din tabelul „structura” se extrage cheia de generare ce se află în câmpul „cheie_generare”, în funcție de câmpul „url” ce reprezintă categoria si subcategoria din care face parte chestionarul ce va fi generat.
$tmp2=$tpl->db->sql("SELECT * FROM `structura` WHERE `url`='".$url."'");
$key=explode(',',$tmp2[0]['cheie_generare']);
Variabila $key va fi un vector ce va conține numărul de întrebări pentru fiecare categorie din care va urma să selectăm întrebările. Categoria este numărul de ordine în vectorul $key[ ] + 1. De exemplu dacă lungimea sa va fi 5 atunci vom avea 5 categorii în ordine (categoria 0, 1, 2, 3, 4 la care se adună valoarea 1). Dacă se dorește să nu se aleagă întrebări din categoria 3, atunci cheia va trebui sa aibă valoarea 0 pe poziția corespunzătoare categoriei 3, adică $key[3-1] =0. La pasul următor se selectează toate întrebările din tabelul corespunzător selecției utilizatorului și se grupează vectorul, ce urmează să fie creat, după câmpul „cat” ce reprezintă categoria din care face parte întrebarea, cu ajutorul parametrului doi al funcției „sql”.
$tmp = $tpl->db->sql("SELECT `id_intrebare`,`cat`,`rc` FROM `".$tmp2[0]['tabel']."`",'cat');
Din vectorul rezultat avem întrebările grupate pe categorii, cheia primului nivel din acest vector fiind chiar numărul categoriei, pe nivelul doi al vectorului se află lista de întrebări corespunzătoare categoriei din primul nivel iar pe nivelul trei se află câmpurile selectate („id_intrebare”, „cat”, „rc”) și valorile lor.
În continuare se aleg întrebările în mod aleatoriu:
for ($i = 0; $i < count($key); $i++){ //de la 0 la numărul total de categorii
for ($j = 0; $j < $key[$i]; $j++) { //de la 0 numărul de întrebări per categorie
$r = rand(0,count($tmp[$i+1])-1); // se alege aleator o întrebare
$intr[ ] = $tmp[$i+1][$r]['id_intrebare']; // se adaugă id_întrebare în $intr[ ]
$rasp[ ] = ''; // se adaugă valoare nulă în vectorul $rasp[ ]
$rc[ ] = $tmp[$i+1][$r]['rc']; // se adaugă răspunsul corect în vectorul $rc
array_splice($tmp[$i+1],$r,1); //se elimină întrebarea pentru a evita repetițiile
}
}
Întrebarea aleasă va fi descompusă pe câmpuri, iar valorile vor fi adăugate în trei vectori separați. Vectorul $intr[ ] va conține id-ul întrebării, $rasp[ ] va fi un vector având valori nule deoarece se vor completa cu răspunsul utilizatorului iar vectorul $rc[ ] va conține răspunsurile corecte, câmpul „cat” va fi ignorat deoarece nu este necesar în acest caz deoarece a fost folosit doar la gruparea întrebărilor. Variabila $r reprezintă un număr aleatoriu între 0 și numărul de întrebări din categoria curentă.
Pasul următor reprezintă o randomizare suplimentară:
for ($i=0;$i<count($intr);$i++) {
$r=rand(0,count($intr[$i])-1);
$a=$intr[$i];
$b=$rc[$i];
$intr[$i]=$intr[$r];
$rc[$i]=$rc[$r];
$intr[$r]=$a;
$rc[$r]=$b;
}
Elementele sunt interschimbate între ele în mod aleatoriu de „count($intr)” ori.
Ultimul pas este inserarea în baza de date, în tabelul „chestionare”, a chestionarului generat:
$t=time(); //timpul actual exprimat în secunde de la Epoca Unix (01-01-1970 00:00:00 GMT)
$l=$tmp2[0]['timp_alocat']*60; //transformăm în secunde timpul alocat dat în minute
$q="INSERT INTO `chestionare` SET
`id_user`='".$tpl->user_info['id_user']."',
`time_start`='".$t."',
`time_end`='".($t+$l)."',
`timp_alocat`='".$tmp2[0]['timp_alocat']."',
`punctaj_minim`='".$tmp2[0]['punctaj_minim']."',
`nr_intrebari`='".$tmp2[0]['nr_intrebari']."',
`categorie`='".$tmp2[0]['categorie']."',
`subcategorie`='".$tmp2[0]['subcategorie']."',
`tabel`='".$tmp2[0]['tabel']."',
`intrebari`='".join(',',$intr)."',
`raspunsuri`='".join(',',$rasp)."',
`raspunsuri_corecte`='".join(',',$rc)."'";
$tpl->db->sql($q);
$tmp3=$tpl->db->sql("
SELECT * FROM `chestionare`
WHERE `time_end`>'".time()."' AND `id_user`='".$tpl->user_info['id_user']."'");
return $tmp3[0];
După inserarea în baza de date, selectăm înregistrarea cu aceeași metodă folosită la verificarea existenței unui chestionar activ descrisă la începutul acestui subcapitol. De asemenea rezultatul SQL obținut este întors de funcție prin intermediul variabilei $tmp3.
Descrierea funcțiilor din fișierul „funcțions.php”
Funcția „isExamOn” – funcția verifică dacă există chestionar în curs de desfășurare pentru utilizatorul autentificat și întoarce „true” dacă exista sau „false” dacă nu există. Această funcție selectează din baza de date, tabel „chestionare”, înregistrările care au timpul de finalizare mai mare decât timpul curent („time_end” > time( ) ).
function isExamOn($tpl){
if($tpl->auth){ //verifică dacă utilizatorul este autentificat
$tmp3=$tpl->db->sql("
SELECT `id` FROM `chestionare`
WHERE `time_end`>".time()." AND
`id_user`='".$tpl->user_info['id_user']."' LIMIT 1"
);
if (count($tmp3) > 0)return true;
}
return false;
}
Valoarea variabilei publice „$auth” din clasa „tpl” este modificată în fișierul de start „index.php” folosind funcția „isAuth”;
Funcția „isAuth” – verifică dacă există utilizator autentificat, comparând variabila de tip „cookie” denumită „u”, ce este memorată în browser-ul utilizatorului, cu valoarea salvată în baza de date în câmpul „session” din tabelul „users”. Funcția are ca parametru doar instanța clasei „tpl”.
function isAuth($tpl) {
if (!isset($_COOKIE['u'])) return false;
$c = $_COOKIE['u'];
$tmp = $tpl->db->sql("SELECT `session` FROM `users` WHERE `session`='".$c."'");
if (count($tmp) > 0) return true;
return false;
}
Funcția „getUniqueSession” – funcția generează un cod unic format din 15 cifre. Funcția compară valoarea generată cu valoarea din câmpul „session” din tabelul „users”. Dacă există atunci se repetă generarea până când se va găsi un număr unic. Pentru a avea o bună diversitate a numărului generat, la valoarea generată se mai adaugă si timpul curent exprimat în secunde de la data 01.01.1970 și până în prezent, furnizat de funcția PHP „time( )”. Funcția întoarce valoarea dacă nu a fost găsit un număr identic în baza de date prin intermediul variabilei $s.
function getUniqueSession($tpl){
$tmp2=$tpl->db->sql("SELECT `session` FROM `users`",'session',true);
$cnt=0;
do {
$s=rand(100000000000000,900000000000000) + time();
$cnt++;
} while ($s==$tmp2[$s] && $cnt<1000);
if ($cnt<1000){
return $s;
}
return 0;
}
Funcția „setUserSession” – generează un număr unic de 15 cifre folosind funcția descrisă mai sus („getUniqueSession”) și salvează acest număr în browserul utilizatorului prin intermediul variabilei de tip cookie denumită „u” și tabelul „users”, câmpul „session” din înregistrarea utilizatorului curent identificată print câmpul „id_user” ce reprezintă cheia primară a tabelului „users”. Funcția are doi parametri, instanța clasei „tpl” și id-ul utilizatorului curent.
function setUserSession($tpl,$id){
$s=getUniqueSession($tpl); //se obține un număr de sesiune unic format din 15 cifre
if ($s>0){ //dacă există numarul atunci se salvează în baza de date și cookie
$tpl->db->sql(" UPDATE `users`
SET `session`='".$s."' WHERE `id_user`='".$id."'"
);
setCookieEx('u',$s);
return true;
}
return false;
}
Salvarea variabilei „u” în browserul utilizatorului se efectuează cu ajutorul funcției „setCookieEx”. Funcția „setCookieEx” are ca parametri numele variabilei, valoarea, și data expirării. Această funcție se folosește de funcția „set_cookie_fix_domain” și trimite parametri specifici domeniului „examenauto.ro”.
function setCookieEx($name,$val, $exp = 0) {
set_cookie_fix_domain($name, $val, $exp, '/', 'www.examenauto.ro');
}
Funcția „set_cookie_fix_domain” este funcția ce salvează efectiv variabilele de tip cookie, în browser, variabilele fiind trimise către browser cu ajutorul instrucțiunii PHP numită „header”. Această instrucțiune instruiește browserul să salveze „cookies” având diverși parametrii specifici cum ar fi timpul expirării, domeniul, calea (URL) etc. Funcția „set_cookie_fix_domain” rezolvă și problema adresei URL indiferent dacă are „WWW” sau nu, browserul tratând diferit adresele „www.examenauto.ro” și „examenauto.ro”.
function set_cookie_fix_domain ($Name, $Value = '', $Expires = 0, $Path = '', $Domain = '', $Secure = false, $HTTPOnly = false)
{
if (!empty($Domain)) {
// Se șterge www. în cazul în care există
if (strtolower(substr($Domain, 0, 4)) == 'www.')
$Domain = substr($Domain, 4);
$Domain = '.' . $Domain;
// Se șterge portul.
$Port = strpos($Domain, ':');
if ($Port !== false) $Domain = substr($Domain, 0, $Port);
}
//se trimit informațiile către browser
header('Set-Cookie: ' . rawurlencode($Name) . '=' . rawurlencode($Value)
. (empty($Expires) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', $Expires) . ' GMT')
. (empty($Path) ? '' : '; path=' . $Path)
. (empty($Domain) ? '' : '; domain=' . $Domain)
. (!$Secure ? '' : '; secure')
. (!$HTTPOnly ? '' : '; HttpOnly'), false);
}
Funcția „getUserChestInfo” ne furnizează numărul de chestionare rezolvate folosind informațiile salvate în tabelul „chestionare”. Această funcție execută două interogări MySQL, prima întorcând suma chestionarelor rezolvate corect iar a doua suma totală a chestionarelor. În ambele cazuri sunt chestionare ale utilizatorului curent identificate prin câmpul „id_user”. De asemenea se ignoră chestionarul în curs de rezolvare ce nu are timpul „time_end” mai mic decât timpul curent ($t = time( )). Funcția întoarce un vector cu două elemente primul fiind suma chestionarelor ce îndeplinesc condiția de promovare iar al doilea suma chestionarelor ce nu îndeplinesc condiția de promovare.
function getUserChestInfo($tpl,$id_user) {
$t=time( );
$tmp=$tpl->db->sql(" SELECT COUNT(*) AS `c`
FROM `chestionare`
WHERE `time_end`<".$t."
AND `corecte`>=`punctaj_minim`
AND `id_user`='".$id_user."'"
);
$tmp2=$tpl->db->sql(" SELECT COUNT(*) AS `c`
FROM `chestionare`
WHERE `time_end`<".$t." AND `id_user`='".$id_user."'"
);
return array($tmp[0]['c'], $tmp2[0]['c']-$tmp[0]['c']);
}
Funcția „errorMessage” – funcția creează o listă de erori cu un stil predefinit („err”), ce poate fi schimbat cu ajutorul parametrului patru. Funcția are ca parametri de intrare titlul mesajului de eroare, lista de erori furnizată printr-un vector, identificatorul unei etichete HTML ce va conține lista de erori și opțional clasa CSS, inițial fiind „err”. Identificatorul etichetei HTML poate fi un id, o clasa sau eticheta în sine. De preferat este ca identificatorul sa fie unic. În cazul în care nu este unic, conținutul va fi alterat de fiecare dată când este întâlnit. Această funcție este folosită în general la validarea formularelor din aplicație. Dacă utilizatorul nu respectă cerințele unui câmp din formular, se atașează în coada unui vector mesajele de eroare după care la sfârșit se apelează funcția „errorMessage” ce va avea al doilea parametru vectorul creat și va afișa pe ecran lista de mesaje de eroare.
function errorMessage($title, $err, $obj, $cls = 'err') {
if (is_array($err) && count($err) > 0){
$m = '<p class="'.$cls.'">';
if ($title!='')$m .= '<strong>'.$title.'</strong><br />';
for ($i=0; $i < count($err); $i++){
//mesajele de eroare sunt formatate una sub alta folosind eticheta <br>
$m .= $err[$i].($i<count($err)-1?'<br />':'');
}
$m.='</p>';
//se înlocuiește conținutul etichetei identificată prin valoarea variabilei $obj
pq($obj)->html($m);
}
}
Funcția „saveRasp” – salvează, în tabelul „chestionare”, răspunsul dat de utilizator după apăsarea butonului ”Salvează întrebare”. La apăsarea butonului „Finalizează examenul”, funcția este apelată având valoarea „all” a ultimului parametru de intrare, „$save_q”, caz în care funcția va marca cu „răspuns greșit” toate întrebările care nu au fost completate de utilizator și apoi va salva în baza de date toate întrebările. În cazul în care ultimul parametru este „NULL”, funcția va salva răspunsul curent și se va poziționa pe următoarea întrebare disponibilă. Dacă s-a ajuns la ultima întrebare atunci funcția va căuta de la capăt o întrebare disponibilă. Funcția întoarce un vector cu doua elemente, primul element fiind un vector ce reprezintă răspunsurile utilizatorului iar al doilea element reprezintă numărul întrebării disponibile găsite.
Descrierea parametrilor de intrare ai funcției:
$tpl – reprezintă instanța clasei „tpl”
$rc – vector ce reprezintă răspunsurile corecte ale chestionarului
$correct – numărul actual de răspunsuri corecte, este ignorat dacă ultimul parametru „$save_q” are valoarea „all”
$total – numărul total de întrebări
$cuq – numărul întrebării curente
$rasp – vector ce conține toate răspunsurile utilizatorului
$chest – un vector cu detalii legate de chestionar cum ar fi „id” în baza de date, numărul minim de răspunsuri corecte etc.
$raspuns – răspunsul utilizatorului, de asemenea este ignorat daca ultimul parametru are valoarea „all”
$save_q – ultimul parametru ce acceptă valoroarea „all” sau NULL, orice altă valoare este considerată NULL. Funcționalitățile legate de acest parametru sunt descrise mai sus.
După cum se observă în secvența de cod, de mai jos, din interiorul funcției ce reprezintă actualizarea informațiilor chestionarului curent, răspunsurile provenite din vectorul $rasp sunt salvate sub forma de șir de caractere, cu ajutorul funcției „join”, în câmpul „raspunsuri”, răspunsurile fiind separate prin virgulă. La citire din baza de date se efectuează procesul invers folosind funcția „explode”.
function saveRasp($tpl, $rc, $correct, $total, $cuq, $rasp, $chest, $raspuns, $save_q) {
…
$tpl->db->sql(" UPDATE `chestionare` SET
`raspunsuri`='".join(',',$rasp)."', `corecte`='".$correct."'
WHERE `id`='".$chest['id']."'");
…
return array($rasp, $n);
}
Pentru toate detaliile funcției vezi anexa 5
Generarea codului „CAPTCHA”
Codul „captcha” este folosit în special pe paginile de contact, cont nou, recuperare parola pentru a preveni generarea în mod automat de conturi sau folosirea poștei electronice în mod abuziv cu ajutorul scripturilor. „Captcha” este o metoda de a determina daca utilizatorul este o persoana sau un program de calculator. Denumirea „CAPTCHA” este acronimul expresiei ”Completely Automated Public Turing test to tell Computers and Humans Apart”. Această denumire a fost aleasă de un grup de cercetători în anul 2000 de la Universitatea Carnegie Mellon și IBM.
Generarea codului se face cu ajutorul funcției „generateCaptcha” ce întoarce o valoare formată din litere și cifre. În codul sursă de mai jos funcția generează un cod format din 5 caractere numerice și alfanumerice.
function generateCaptcha(){
$ses='';
$codes='1234589ABCDEFGHJKLMNPQRSTUWXYZ12345789';
for ($i=0;$i<5;$i++){
$c=rand(0,strlen($codes)-1);
$ses.=$codes[$c];
}
return $ses;
}
După apelul acestei funcții, valoarea este salvată în variabila de sistem $_SESSION['captcha-code'], după care în fișierul HTML unde se dorește afișarea codului sub formă de imagine, se adaugă imaginea care are ca URL „generate.php”, fișier ce se află direct în directorul rădăcină al aplicației. Pentru a putea avea acces la variabilele de sesiune ale serverului PHP este necesar apelarea funcției „session_start”. Variabilele de sesiune sunt păstrate și după terminarea execuției scriptului.
Exemplu de imagine generată ce conține cod „CAPTCHA”
<img src="generare.php">
În fișierul „generate.php” se va citi codul generat și salvat în variabila de sesiune denumită „captcha-code”, cod ce va fi scris pe o imagine de tip PNG cu ajutorul librăriei PHP denumită GD Lib. Fontul folosit pentru scriere se află în directorul „fonts/”. Funcția PHP folosită, ce ne permite să scriem un text cu un anumit font pe o poză creată în memorie, este „imagettftext”. Crearea unei imagini în memorie de tip „true color” se realizează cu ajutorul funcției „imagecreatetruecolor”.
Fișierul „generate.php”:
<?php
session_start(); //se permite accesul la variabilele de sesiune ale sistemului
header('Content-type: image/png');//conținutul trimis către browser va fi de tip imagine
$width=200; $height=50; //dimensiunile imaginii ce va conține codul CAPTCHA
$im=imagecreatetruecolor($width,$height); //se creează imaginea în memorie
$clr1=imagecolorallocate($im,235,235,235); //se stabilește culoarea de fundal
imagefilledrectangle($im,0,0,$width,$height,$clr1); //se desenează fundalul
$cl=imagecolorallocate($im,0,0,0); //culoarea textului
$x=15; $y=35; //coordonatele de început ale textului
$codes=$_SESSION['captcha-code']; //codul generat
$clr2=imagecolorallocate($im,0,0,0);
//se „desenează” textul fiecare literă având un unghi și spațiere aleatorie
for ($i=0;$i<strlen($codes);$i++) {
$c=rand(0,strlen($codes)-1);
$ang=rand(-20,20);
$yy=rand(-3,3);
imagettftext($im,25,$ang,$x,$y+$yy,$cl,"fonts/arial.ttf",$codes[$i]);
$ses.=$codes[$c];
$x+=35;
}
//se aplică filtrul GAUSSIAN_BLUR
imagefilter($im,IMG_FILTER_GAUSSIAN_BLUR);
//se suprapune o matrice de pixeli având spațiul liber între ei de 1 pixel
for ($x1=0;$x1<$width;$x1+=2) {
for ($y1=0;$y1<$height;$y1+=2){
$clr=imagecolorat($im,$x1,$y1);
$clr=$clr^0xffffff;
imagesetpixel($im,$x1,$y1,$clr);
}
}
imagepng($im); //se trimite imaginea obținută către browser
imagedestroy($im); //se eliberează memoria folosită
?>
Funcția „sendMail” – cu această funcție sunt trimise e-mail-urile către utilizatori în special la validarea contului sau recuperare parola. Funcția se folosește de librăria de clase „Open Source” denumită „PHPMailer”. Este o librărie des folosită în majoritatea aplicațiilor web ce folosesc trimiterea de e-mail-uri. Am ales folosirea acestei librării deoarece corpul e-mail-ului generat este conform standardelor cerute pe internet. Folosirea directă a instrucțiunii „mail” din PHP necesită o cunoaștere amplă a formatului antetului (HEADER), codarea imaginilor sau fișierelor ce se doresc a fi atașate în e-mail. Riscul de a fi considerat „spam” e-mail-ul trimis cu această clasă este mult mai mic. Clasa are posibilitatea să trimită un mail în trei moduri: folosind funcția „mail”, conectare la serverul POP3 sau SMTP.
Funcția „sendMail” are următorul set de parametrii de intrare:
$name – numele celui care va primi e-mail-ul
$email – adresa de e-mail sa
$subject – subiectul e-mail-ului
$session – codul generat, folosit în cazul validării e-mail-ului sau recuperării parolei. Dacă nu există se va trece valoarea „string vid”
$from – parametru predefinit si reprezintă adresa de unde se va trimite e-mail-ul
$fromname – numele celui care va trimite e-mail-ul
$reply – adresa de e-mail unde se poate răspunde (reply address)
$replyname – numele celui căruia se va răspunde
$file – fișierul HTML care va fi citit ca șir de caractere și reprezintă mesajul ce se va trimite.
Fișierele HTML folosite, ce se află în directorul „template”, sunt:
„email-body.html” reprezintă mesajul de confirmare când s-a solicitat cont nou
„email-contact.html” este mesajul, care se trimite către administratorul aplicației, ce provine din pagina de contact
„email-recuperare-parola.html” este mesajul de confirmare trimis către utilizator atunci când solicită recuperarea parolei
„email-parola-trimisa.html” reprezintă mesajul pe care îl primește utilizatorul după ce a confirmat că dorește resetarea parolei.
function sendMail($name, $email, $subject, $session, $from='[anonimizat]', $fromname='examenauto', $reply='[anonimizat]', $replyname='noreply', $file='email-body.html') {
//se include fișierul ce conține clasa PHPMailer
require_once('libs/class.phpmailer.php');
$mail = new PHPMailer(); // inițial clasa folosește „mail()”
$mail->CharSet = 'UTF-8'; //setul de caractere folosit în mail
$body = file_get_contents('template/'.$file); // se citește mesajul din fișierul $file
//se înlocuiește cuvântul cheie {$sess} cu conținutul variabilei $session
$body = str_replace('{$sess}',$session,$body);
$mail->SetFrom($from, $fromname); //infomațiile celui care trimite e-mail-ul
$mail->AddReplyTo($reply,$replyname); //informațiile celui căruia se va răspunde
$address=$email;
$mail->AddAddress($address, $name); //destinatarul
$mail->Subject = $subject; //se memorează subiectul e-mail-ului
// mesaj alternativ pentru situația în care clientul de e-mail nu acceptă formatul HTML.
$mail->AltBody = "To view the message, please use an HTML compatible email viewer!";
$mail->MsgHTML($body); //se memorează mesajul ce urmează a fi trimis
//se trimite e-mail-ul și funcția va întoarce rezultatul,
//true pentru reușită și false dacă nu s-a trimis.
return $mail->Send();
}
Funcții JavaScript
Codul JavaScript este executat după ce informațiile au fost trimise către browser adică după încărcarea unei pagini web, pe calculatorul utilizatorului. Fișierul în care sunt situate funcțiile JavaScript, pe care aplicația le rulează în funcție de pagina accesată, se află în directorul „js/” și este denumit „main.js”. Acest fișier este încărcat din „index.html” folosind eticheta „script”. Înainte de a încărca acest fișier este necesară încărcarea librăriei „jQuery” deoarece în „main.js” sunt funcții ce folosesc proprietățile librăriei „jQuery”:
…
<script type="text/javascript" src="js/jquery-1.10.1.min.js"></script>
<script type="text/javascript" src="js/jquery-ui.min.js"></script>
<script type="text/javascript" src="js/main.js?ver=1"></script>
…
Se observă folosirea unei variabile PHP „ver=1”. Browser-ele moderne folosesc sistem „cache”, ce reprezintă o copie a fișierelor descărcate de pe server, cum ar fi imagini, fișiere CSS, fișiere JavaScript, fișiere HTML. Acest lucru are avantajul că fișierele descărcate pe calculatorul utilizatorului vor fi citite din memoria „cache”, memorie ce se află pe discul calculatorului utilizatorului, sporind astfel viteza de încărcare a paginilor. Totuși există și un dezavantaj, dacă fișierele sunt modificate pe server, aceste modificări nu vor fi actualizate imediat în memoria „cache” a clientului web, fapt ce duce la afișarea unor informații ce nu sunt de actualitate sau chiar erori în cazul codului JavaScript neactualizat. Putem rezolva această problemă „păcălind” browser-ul cu ajutorul unei variabile PHP fictive pe care nu o vom folosi dar servește la alterarea numelui fișierului. În cazul nostru serverul va citi fișierul „main.js”, va primi ca parametru variabila „ver=1” pe care o putem ignora, iar browser-ul va considera numele fișierului ce trebuie încărcat ca fiind „js/main.js?ver=1”, ce nu se află în memoria „cache”. Deci la modificarea fișierului „main.js” putem schimba valoarea variabilei „ver” iar browser-ul va considera un nou fișier ce trebuie descărcat.
În capitolul 3.2.1. Pagina de start, am vorbit despre prezentarea animată a diverselor informații oferite de aplicația. Această animație se realizează folosind funcțiile JavaScript „initBlue” și „animateBlue”. În prima funcție se fac diferite inițializări legate de etichetele ce vor fi animate, poziția lor inițială, inițializarea evenimentului „onClick” a pictogramelor și în final apelarea funcției „animateBlue” cu ajutorul instrucțiunii „setTimeout”, ce execută un cod sau apelează o funcție la un anumit interval de timp.
$(window).data('home_anim_timer',setTimeout(animateBlue,20000));
Valoarea întoarsă de funcția „setTimeout” reprezintă o resursă de sistem (handle) ce identifică acest „timer”, cu ajutorul căreia putem manipula „timer-ul” creat. Valoarea este păstrată în secțiunea de variabile interne ale librăriei „jQuery”, variabila fiind denumită „home_anim_timer”.
Exemplu inițializare eveniment „onClick” al pictogramelor:
$('.icons a').on('click',function(e) {
e.preventDefault ();
clearInterval($(window).data('home_anim_timer'));
$('.comanda').data('idx',$(this).index());
animateBlue(1);
});
În codul de mai sus observăm funcția „clearInterval”, ce oprește „timer-ul” în curs de execuție. Utilizatorul are posibilitatea să schimbe categoria curentă făcând click pe una dintre pictograme, fiind necesară anularea „timer-ului” în curs de execuție deoarece se execută altă instanță a „timer-ului”. Execuția multipla a mai multor instanțe ale „timer-ului” duce la o funcționare defectuoasă a animației.
Animația se realizează efectiv în funcția „animateBlue”, folosind proprietatea „animate” a librăriei „jQuery”
$('.comanda'+lidx).animate({left:-940},{duration:1000, easing:ease1,
complete:function() {
$(this).css('left',940);
}});
$('.comanda'+i).animate({left:0},{duration:1000, easing:ease1});
Prima comandă mută la stânga cadrul curent iar a doua mută în același timp la stânga, cadru ce urmează. În prima comandă observăm proprietatea „complete” ce reprezintă apelul unei funcții atunci când animația s-a oprit. În acea funcție cadrul care a ieșit din ecran este repoziționat folosind proprietatea CSS, „left”. Funcțiile complete se găsesc în anexa 6.
Funcția „setExamTimer” este funcția ce afișează, în timp real, timpul rămas până la finalizarea chestionarului. Funcția se inițializează la execuția evenimentului „onLoad”, ce se execută atunci când pagina s-a încărcat complet, având ca parametri de intrare, id-ul etichetei unde va fi afișat și timpul curent obținut cu ajutorul funcției „Date”. Proprietatea „getTime”, întoarce numărul de milisecunde din 01.01.1970 până în prezent. Diferența față de funcția „time” din PHP este acela că funcția „time” întoarce numărul de secunde. Pentru a putea sincroniza cu timpul furnizat de PHP se va împărți la 1000.
Inițializare funcție „setExamTimer”:
var t=new Date();
setExamTimer('#timer',t.getTime());
Funcția inițializează un „timer” ce se execută la interval de 100 milisecunde cu ajutorul funcției „setInterval”. La terminarea timpului funcția forțează aplicația să reîncarce pagina, pentru a ajuta scriptul PHP sa determine finalizarea chestionarului.
function setExamTimer(obj,val) {
clearInterval ($(obj).data('time')); //ne asigurăm ca nu exista altă instanță
$(obj).data('start',val+exam_time); // durata examenului
if (exam_time<=0)return; //dacă s-a terminat timpul iese din funcție
var tmr=setInterval(function () { // se inițializează timer
var t=new Date(); //instanța a obiectului Date
var tm=($(obj).data('start')-t.getTime())/1000; //timpul rămas
if (tm<0){ //dacă este < 0 se oprește „timer”
tm=0;
clearInterval ($(obj).data('time'));
// reactualizează pagina curentă cu întârziere de o secundă
setTimeout(function () {
document.location.href=document.location.href;
},1000);
}
var h=Math.floor(tm/3600); //se calculează numărul de ore
var m=Math.floor((tm-h*3600)/60); //se calculează numărul de minute
var s=Math.floor(tm-h*3600-m*60);//se calculează numărul de secunde
//afișează ceasul, se inserează caracterul 0 dacă h, m sau s < 10
$(obj).html((h<10?'0'+h:h)+':'+(m<10?'0'+m:m)+':'+(s<10?'0'+s:s));
},100);
$(obj).data('time',tmr); //se memorează identificatorul „timer-ului”
}
Funcția „localitati” – folosită pentru a afișa localitățile unui județ, în timp real, în funție de selecția județului. Funcția folosește AJAX (Asynchronous JavaScript and XML) pentru a umple lista de tip „select” cu localitățile corespunzătoare. Prin intermediul proprietății „get” a librăriei „jQuery”. Funcția accesează adresa URL „/localitati/ajax/judet”, ce direcționează către fișierul „localități.php” cu parametrii $_GET, param1=localitati, param2=ajax, param3=judet. Dacă aplicația identifica parametrul doi ca fiind „ajax” atunci elimină afișarea codului HTML și va afișa textul în clar, în cazul de față lista de localități sub forma: <option value=”1”>localitate1</option><option value=”2”>localitate2</option>…
Textul obținut este concatenat la lista de județe ce este de tip „select”. Dacă lista conține un singur element, cum ar fi cazul localității București, atunci se va selecta automat acel element.
function localitati(){
var judet=$('#judet').val();
$('#localitate').html('<option value="0">Se incarca lista…</option>');
$.get("/localitati/ajax/"+judet, function(data) {
//după ce serverul trimite răspunsul adaugă în lista elementul 0 urmat de lista trimisă
$('#localitate').html('<option value="0">–Alegeti localitatea–</option>'+data);
if($('#localitate option').length==2){
//dacă lista conține o singură localitate atunci selectează acea localitate
$('#localitate').prop('selectedIndex',1);
}
});
}
Codul CSS
În capitolul 3.1, am vorbit despre aspectul paginilor aplicației ce este alcătuit din 3 părți, antet (header), conținut și subsol (footer). Acest lucru este realizat din HTML cu ajutorul etichetelor „DIV” la care sunt atașate stiluri din fișierul „style.css”, ce se află în directorul rădăcină al aplicației. Stilurile sunt atașate printr-un ID sau o clasa CSS. În exemplul următor este descris layout-ul de pornire al aplicației:
<body>
<div id="main">
<div id="header" class="header"></div>
<div id="content" class="content"></div>
</div>
<div id="footer"><ul id="mid">…</ul></div>
</body>
Fișierul cu stiluri este încărcat din fișierul ”index.html” în secțiunea „head”
<head>
…
<link type="text/css" rel="stylesheet" href="style.css?ver=5" />
…
</head>
Observăm ca și aici folosim variabila PHP „ver=5” pentru a forța browser-ul să încarce fișierul cu stiluri, modificând valoarea variabilei, în cazul în care vom efectua modificări în fișierul de stiluri „style.css”.
Eticheta cu id=”main” definește dimensiunea pe orizontală a întregului site. De asemenea este centrat pe orizontală.
Codul CSS asociat etichetei cu id=„main”:
#main {
width:940px;
padding:0px 30px 0px 30px;
margin:auto; /*centrează pe orizontala daca este specificat „width” */
}
„Footer” se află în exteriorul etichetei cu id=”main” deoarce este necesară o scalare pe orizontală de 100%. În interiorul etichetei cu id=”footer” se află o alta etichetă cu id=”mid” ce are aceleași proprietăți de dimensionare si centrare ca și ”main”:
#footer {
background-color:#efefef;
clear:both;
margin:30px 0px 0px 0px;
padding-bottom:30px;
}
#footer #mid {
width:940px;
margin:0 auto 0 auto; /*centrează doar pe orizontala*/
…
}
În acest mod aspectul paginilor va fi centrat si va avea 940 pixeli pe orizontală. Pe verticală dimensiunea va fi în funcție de conținutul acestor etichete. Observăm ca eticheta „div” cu id=”footer” nu are dimensiuni prestabilite. Această etichetă fiind inițial de tipul „block”, se dimensionează la procent de 100% pe orizontală, în funcție de rezoluția calculatorului sau dimensiunea ferestrei browser-ului. Datorită etichetei cu id=”mid” din interior, ce are dimensiune prestabilită de 940 pixeli, dimensiunea minima a etichetei părinte (#footer) va fi 940 pixeli.
În interiorul etichetei ce are id=„main” sunt incluse partea de antet (header) și conținutul (content). Antetul are dimensiuni fixe pe orizontală și verticală:
.header { width:940px; height:160px; }
Eticheta cu id=”content”, pe orizontală, va avea întotdeauna dimensiunea etichetei părinte (#main), deoarece nu sunt specificate dimensiunile și este tot de tip „block”. În interiorul etichetei #header se va încărca din PHP, cu ajutorul clasei „PHPQuery”, codul HTML din fișierul „tempalte/header.html”. În fișierul „header.html” se află codul ce afișează logo-ul aplicației, meniul principal și formularul de autentificare.
…
<div class="bg_hdr">
<a href="" id="logo"><b>examenauto.ro</b></a>
<div id="menu" class="menu">
<a href="atestate" class="m1"><b>Atestate</b></a>
<a href="#" class="m2" onclick="return false;"><b>Legislație</b></a>
<a href="./contact" class="m4 last"><b>Contact</b></a>
</div>
<div id="submenu-legislatie">
<a href="legislatie/nationala" class="m1"><b>Națională</b></a>
<a href="legislatie/comunitara" class="m2"><b>Comunitară</b></a>
</div>
<div class="clear"></div>
</div>
Logoul va direcționa către prima pagina, adresa fiind introdusă din PHP, fișier „header.php”.
Codul atașat logo-ului:
#logo {
width:265px;
height:47px;
display:inline-block;
background:url(images/logo.png) no-repeat; /*imaginea logoului */
margin:11px 0px 0px 20px;
position:absolute;
}
#logo b {display:none;}
Poziția logo-ului este absolută dar folosind doar coordonatele date de proprietatea „margin” vom obține o poziționare relativă față de poziția curentă, neinfluențând poziția altor etichete datorită proprietății „position: absolute”. Am ales această metodă pentru că este mult mai ușor să poziționăm etichetele la coordonate impuse de grafician, iar modificarea dimensiunilor logo-ului de asemenea nu influențează poziția altor etichete. Logoul fiind o etichetă de tip link („<a href…”), conține și text („<b>examenauto.ro</b>”) iar pentru nu a suprapune textul peste imaginea de fundal am ascuns textul folosind o eticheta „b” ce îi este atașat stilul „display:none”. În acest mod browser-ele care suportă CSS vor afișa imaginea iar celelalte vor afișa doar textul.
Meniul este alcătuit dintr-o înșiruire de etichete de tip link ce au atașat următorul stil:
.menu {
width:630px; height:24px; /* dimensiunea containerului meniului*/
position:relative; margin:22px 24px 0px 0px; /*poziția față de marginea din dreapta */
float: right; text-align: right; /*aliniem containerul si textul din interior la dreapta*/
}
.menu a {
/*se stabilesc fontul, grosimea și dimensiunea acestuia */
font-family:Source Sans Pro; font-weight:600; font-size:15px;
text-transform:uppercase; /* toate literele au majuscule */
text-decoration:none; /* se elimina underline la mouse hover */
color:#424242; /* culoarea textului meniului*/
display:inline-block; /*afișare de tip bloc dar păstram modul „inline”*/
background:url(images/menu-split.png) no-repeat right center;
width:124px; /*dimensiunea pe orizontala a elementelor meniului*/
}
.menu a b {
padding:2px 0px 2px 0px; /*spațiere de 2 pixeli si sus si jos */
display:inline-block;
width:123px; text-align:center;
}
.menu a:hover b, #menu a.sel b{
/* culorile la mouse hover si pagina curenta */
color:#fdfdfd; background-color:#191919;
}
.menu a.last {background:none;} /* se elimina imaginea de fundal a ultimului element */
Subsolul (#footer) nu este încărcat dintr-un fișier separat, acesta fiind integrat direct în „index.html”. În subsol apar din nou logoul și meniul extins. Meniul de asemenea este format dintr-o înșiruire de linkuri grupate pe patru coloane folosind eticheta de tip lista neordonată (ul, li).
<div id="footer">
<ul id="mid">
<li class="c1">
<div class="hfooter">
<a href="/" class="logo2"><b>Examen auto</b></a>
</div>
…
</li>
<li class="c2">
<div class="hfooter"><h2>Atestate</h2></div>
<div class="sc1">
<div><a href="/atestate">Atestat Șofer CPC</a></div>
…
</div>
<div class="sc1">
<div><a href="/atestate">Atestat TAXI</a></div>
…
</div>
</li>
<li class="c3">…</li>
<li class="c4">…</li>
</ul>
<div class="clear"></div>
</div>
Codul CSS atașat elementelor din footer:
/* formatare link-uri ce au ca imagine de fundal arrow.png */
#footer #mid a {
background:url(images/arrow.png) left center no-repeat; padding:0px 0px 0px 10px; text-decoration:none; color:#b3b3b3;
}
/* la mouse over se subliniază linkurile */
#footer #mid a:hover {text-decoration:underline;}
/* cele patru coloane sunt aliniate orizontal una după alta la stânga*/
#footer #mid li {float:left; }
/*dimensiunile fiecărei coloane */
#footer #mid li.c1 {width:275px;}
#footer #mid li.c2 {width:370px;}
#footer #mid li.c3 {width:120px;}
#footer #mid li.c4 {width:165px; padding-top: 37px; padding-left: 0px; margin-left: 0px;}
/*formatare specifică a linkurilor din coloana a patra, se elimina imaginea de fundal */
#footer #mid li.c4 a {
background: none; margin: 20px 0px 0px 0px; padding: 0; display: block;
}
/*sc1 reprezintă un set de două containere ce împarte
linkurile meniului „Atestate” pe doua coloane*/
#footer #mid li.c2 .sc1 {float:left; width:180px;}
/*spațiul, pe verticala, folosit de linkurile mari și logo*/
#footer #mid li .hfooter { height:50px; }
/*formatarea link-urilor mari ce au tag h2 (Atestate, Legislație și Contact) */
#footer #mid li .hfooter h2 {
margin:0px 0px 0px 0px; padding-top:14px; color:#2d2d2d; font-size:22px;
}
/*logoul din footer */
#footer #mid li.c1 .hfooter a.logo2 {
background:url(images/logo2.png) no-repeat;
width:207px; height:36px; display:block;
}
/*se ascunde textul linkului ce conține logoul din footer*/
#footer #mid li.c1 .hfooter a.logo2 b {display:none;}
Concluzii
Aplicația ajută cursanții să își evalueze cunoștințele în domeniul transportului auto în vederea obținerii sau reînnoirii unei certificări din categoriile menționate în aplicație.
Îmbunătățiri propuse pentru aplicație:
adăugarea setului de întrebări pentru categoriile A și B în vederea testării utilizatorilor ce vor să obțină carnet de șofer pentru categoriile menționate;
adăugarea unei interfețe pentru administrarea conturilor de tip „reseller”, în prezent, utilizatorii de tip „reseller” se pot adăuga folosind interfața „phpMyAdmin”;
adăugarea unui modul comercial incluzând diverse modalități de plată online;
modul de teorie și legislație rutieră necesare pregătirii pentru susținerea examenelor;
o interfață prietenoasă pentru actualizarea și adăugarea întrebărilor;
modul pentru evidența rezultatelor cursanților, statistică;
Integrarea mai multor rețele de socializare.
ANEXA 3 – Fișierul „index.php” – primul fișier PHP executat
<?php
require ('config/main.php' );
require ('config/mysql.php' );
require ('libs/functions.php' );
require ('libs/router.php' );
require ('libs/class.tpl.php' );
require ('config/messages.php' );
$tpl = new tpl ($page, $page);
$tpl ->auth = isAuth ($tpl );
if ($tpl ->auth ){
$tpl ->user_info =getUserInfoBySession ($tpl ,getCookieSession ());
$tpl ->db->sql (" UPDATE `users`
SET `date_log`='" .time ()."'
WHERE `id_user`='" .$tpl ->user_info ['id_user' ]."'"
);
}
$tpl ->params =$params ;
$tpl ->setTplDir ('template/' );
$tpl ->setPHPDir ('php/' );
$tpl ->fetch ('#header' ,'header' );
$tpl ->fetch ('#content' ,$page);
if ($params [1]=='ajax' )exit ();
echo $tpl ->display ('index.html' );
?>
ANEXA 4 – Clasa „tpl”, fișier „libs/class.tpl.php”
<?php
require_once ('libs/phpQuery/phpQuery.php');
require_once ('libs/mysql.php');
class tpl {
var $tpl_dir;
var $php_dir;
var $page;
var $html;
var $html_tree;
var $params;
var $doc_array;
var $html_attr;
var $db;
var $auth=false;
var $user_info;
function __construct($params,$page) {
session_start();
$this->page=$page;
$this->params=$params;
$this->doc_array=array();
$this->db=new mysql();
$this->auth=false;
}
function setTplDir($dir) {
$this->tpl_dir=$dir;
}
function setPHPDir($dir) {
$this->php_dir=$dir;
}
function display($file) {
$dom=phpQuery::newDocumentFilePHP($this->tpl_dir.$file);
phpQuery::selectDocument(phpQuery::getDocumentID($dom));
require_once('php/index.php');
call_user_func('tpl_index',$this);
for ($i=count($this->html_tree)-1;$i>=0;$i–)
pq($this->html_tree[$i])->html($this->html[$this->html_tree[$i]]);
for ($i=0;$i<count($this->html_attr);$i++){
if ($this->html_attr[$i]['fn']=='attr') {
pq($this->html_attr[$i]['sel'])->attr($this->html_attr[$i]['name'],
$this->html_attr[$i]['val']);
}
if ($this->html_attr[$i]['fn']=='addClass'){
pq($this->html_attr[$i]['sel'])->addClass(
$this->html_attr[$i]['val']);
}
}
return $dom->html();
}
function fetch($id,$tpl_name) {
$f2=$this->tpl_dir.$tpl_name.'.html';
$h=false;
if (!file_exists($f2)) {
$f2=$this->tpl_dir.'error404.html';
}
$dom=phpQuery::newDocumentFilePHP($f2);
array_push($this->doc_array,phpQuery::getDocumentID($dom));
$f=$this->php_dir.$tpl_name.'.php';
if (file_exists($f)){
require_once($f);
if (function_exists('tpl_'.str_replace('-','_',$tpl_name))){
call_user_func('tpl_'.str_replace('-','_',$tpl_name),$this);
}
}
$this->html_tree[]=$id;
$this->html[$id]=$dom->html();
$dom->unloadDocument();
array_pop($this->doc_array);
if (count($this->doc_array)>0){
$id=array_pop($this->doc_array) ;
phpQuery::selectDocument($id);
array_push($this->doc_array,$id);
}
}
function pq($id,$html) {
$this->html_tree[]=$id;
$this->html[$id]=$html;
}
function attr($sel,$attr,$val){
$this->html_attr[]=array('sel'=>$sel,'name'=>$attr,'val'=>$val,'fn'=>'attr');
}
function addClass($sel,$cls){
$this->html_attr[]=array('sel'=>$sel,'fn'=>'addClass','val'=>$cls);
}
}
?>
ANEXA 5 – Funcția „saveRasp” din fișierul „libs/functions.php”
function saveRasp($tpl,$rc,$correct,$total,$cuq,$rasp,$chest,$raspuns,$save_q) {
$n=1;
if ($save_q=='all'){
$correct=0;
for ($i=0;$i<$total;$i++){
if ($rasp[$i]=='')$rasp[$i]='*';
if ($rasp[$i]==$rc[$i]){
$correct++;
}
}
} else {
if (is_array($raspuns)){
$rasp[$save_q-1]=join('',$raspuns);
} else {
if (!isset($raspuns)){
$rasp[$save_q-1]='-';
} else {
$rasp[$save_q-1]=$raspuns;
}
}
if ($raspuns==$rc[$save_q-1])$correct++;
}
$tpl->db->sql("UPDATE `chestionare` SET
`raspunsuri`='".join(',',$rasp)."',`corecte`='".$correct."'
WHERE `id`='".$chest['id']."'"
);
for ($i=$cuq;$i<=$total;$i++){
if ($rasp[$i]==''){
$n=$i+1;
break;
}
}
if ($n>$total){
$n=1;
for ($i=0;$i<=$total;$i++){
if ($rasp[$i]==''){
$n=$i+1;
break;
}
}
}
if ($n>$total)$n=1;
return array($rasp,$n);
}
ANEXA 6 – funcțiile JavaScript „initBlue” și „animateBlue”
function initBlue() {
var c=$('.comanda');
if (!c.html()) return;
if (c[0].parentNode.parentNode.className != 'content'){
return;
}
var cnt=c.length;
for (var i=1;i<cnt;i++) {
$(c[i]).css('display','block');
$(c[i]).css('left',940);
}
$('.comanda').data('idx',1);
$('.comanda').data('last_idx',0);
$('.comanda').data('cnt',cnt);
$(window).data('home_anim_timer',setTimeout(animateBlue,20000));
$('.icons a').on('click',function(e) {
e.preventDefault ();
clearInterval($(window).data('home_anim_timer'));
$('.comanda').data('idx',$(this).index());
animateBlue(1);
});
}
function animateBlue(ease) {
var ease1='easeInOutExpo';
if (ease==1)ease1='easeOutExpo';
var i=$('.comanda').data('idx');
var c=$('.comanda').data('cnt');
var lidx=$('.comanda').data('last_idx');
var ic=$('.icons a');
$('.comanda'+lidx).animate({left:-940},
{duration:1000, easing:ease1,complete:function() {
$(this).css('left',940);
}});
$('.comanda'+i).animate({left:0},{ duration:1000, easing:ease1 });
$(ic[i]).prop('class','s'+i);
$(ic[lidx]).prop('class','b'+lidx);
$('.comanda').data('last_idx',$('.comanda').data('idx'));
i++;
i=i%c;
$('.comanda').data('idx',i);
$(window).data('home_anim_timer',setTimeout(animateBlue,20000));
}
ANEXA 7 – pagina contact și fișierele sursă atașate.
URL examenauto.ro/contact
Fișier php/contact.php: URL
<?php
function tpl_contact($tpl){
$post=getPost();
$err=array();
if ($post){
if (!( ($s=strstr($post['email'],'@')) && ($s2=strstr($s,'.')) &&
(strlen($s)-strlen($s2))>1&& strlen($s2)>2) ) {
$err[]='E-mail este introdus gresit';
}
if (strtoupper($post['verif'])!=$_SESSION['captcha-code']){
$err[]='Codul de verificare nu corespunde cu cel din imagine';
}
if (trim($post['mesaj'])=='' || strlen(trim($post['mesaj']))<40){
$err[]='Mesajul este prea scurt.';
}
pq('.login-box2 li.c3 h2')->remove();
pq("input[name='nume']")->val($post['nume']);
pq("input[name='email']")->val($post['email']);
pq("input[name='tel']")->val($post['tel']);
pq("textarea[name='mesaj']")->val($post['mesaj']);
}
for ($i=0;$i<5;$i++){
$c=rand(0,strlen($codes)-1);
$ses.=$codes[$c];
}
$_SESSION['captcha-code']=$ses;
if (empty($err) && $post){
pq('li.c1')->html('');
pq('li.c2')->html('
<div style="font-size: 16px; padding-top:50px;">
<h2>Contact</h2>Mesajul dumneavoastra a fost trimis.
</div>
<script type="text/javascript">
setTimeout(function(){document.location.href="/";},5000);
</script>
');
pq('li.c2')->addClass('ico-permis');
pq('li.c3')->html('');
pq('li')->attr('style','height:320px;');
sendMailContact(
$post['nume'],
$post['email'],
'Mesaj din pagina de contact examenauto',
$post['name'],
$post['tel'],
$post['mesaj']);
}
if (!empty($err)){
errorMessage('Eroare:',$err,'#errmsg','error');
}
}
?>
Fișier template/contact.html:
<form method="post">
<ul class="login login-box2">
<li class="c1">
<h2>Date contact</h2>
<div class="text18sb ico-email">
<script type="text/javascript">
document.write('offi'+'ce@'+'exame'+'nauto.ro');
</script>
</div>
</li>
<li class="c2">
<h2>Scrie-ne un mesaj</h2>
<label>Numele:<input type="text" name="nume"></label>
<label>E-mail: <span class="red">*</span>
<input type="text" name="email">
</label>
<label>Telefon:<input type="text" name="tel"></label>
<label>Verificare: introduceti codul din imagine
<img src="generare.php" style="margin-left: 1px;"><br>
<input type="text" name="verif" style="width:200px;">
</label>
<p>Câmpurile marcate cu <span class="red">*</span> sunt obligatorii</p>
</li>
<li class="c3">
<div id="errmsg" class="errmsg"></div>
<h2> </h2>
<label>Mesaj: <span class="red">*</span>
<textarea name="mesaj"></textarea>
</label>
<input type="submit" class="submit" value="Trimite">
</li>
</ul>
</form>
Bibliografie
PÎRNĂU, M., [2009], „Tehnologii Web”, Editura Titu Maiorescu, București, ISBN 978-606-8002-23-1/004.55;
Mihai Popescu, Sisteme de gestiune a bazelor de date, Editura Renaissance, ISBN 978-606-8321-56-1, București, 2010.
Mihai Popescu, Baze de date, Editura Renaissance, ISBN 978-606-8321-83-7, București, 2010.
http://www.php.net
http://ww.wikipedia.com
http://www.w3.org
http://www.w3schools.com/
Bibliografie
PÎRNĂU, M., [2009], „Tehnologii Web”, Editura Titu Maiorescu, București, ISBN 978-606-8002-23-1/004.55;
Mihai Popescu, Sisteme de gestiune a bazelor de date, Editura Renaissance, ISBN 978-606-8321-56-1, București, 2010.
Mihai Popescu, Baze de date, Editura Renaissance, ISBN 978-606-8321-83-7, București, 2010.
http://www.php.net
http://ww.wikipedia.com
http://www.w3.org
http://www.w3schools.com/
ANEXA 3 – Fișierul „index.php” – primul fișier PHP executat
<?php
require ('config/main.php' );
require ('config/mysql.php' );
require ('libs/functions.php' );
require ('libs/router.php' );
require ('libs/class.tpl.php' );
require ('config/messages.php' );
$tpl = new tpl ($page, $page);
$tpl ->auth = isAuth ($tpl );
if ($tpl ->auth ){
$tpl ->user_info =getUserInfoBySession ($tpl ,getCookieSession ());
$tpl ->db->sql (" UPDATE `users`
SET `date_log`='" .time ()."'
WHERE `id_user`='" .$tpl ->user_info ['id_user' ]."'"
);
}
$tpl ->params =$params ;
$tpl ->setTplDir ('template/' );
$tpl ->setPHPDir ('php/' );
$tpl ->fetch ('#header' ,'header' );
$tpl ->fetch ('#content' ,$page);
if ($params [1]=='ajax' )exit ();
echo $tpl ->display ('index.html' );
?>
ANEXA 4 – Clasa „tpl”, fișier „libs/class.tpl.php”
<?php
require_once ('libs/phpQuery/phpQuery.php');
require_once ('libs/mysql.php');
class tpl {
var $tpl_dir;
var $php_dir;
var $page;
var $html;
var $html_tree;
var $params;
var $doc_array;
var $html_attr;
var $db;
var $auth=false;
var $user_info;
function __construct($params,$page) {
session_start();
$this->page=$page;
$this->params=$params;
$this->doc_array=array();
$this->db=new mysql();
$this->auth=false;
}
function setTplDir($dir) {
$this->tpl_dir=$dir;
}
function setPHPDir($dir) {
$this->php_dir=$dir;
}
function display($file) {
$dom=phpQuery::newDocumentFilePHP($this->tpl_dir.$file);
phpQuery::selectDocument(phpQuery::getDocumentID($dom));
require_once('php/index.php');
call_user_func('tpl_index',$this);
for ($i=count($this->html_tree)-1;$i>=0;$i–)
pq($this->html_tree[$i])->html($this->html[$this->html_tree[$i]]);
for ($i=0;$i<count($this->html_attr);$i++){
if ($this->html_attr[$i]['fn']=='attr') {
pq($this->html_attr[$i]['sel'])->attr($this->html_attr[$i]['name'],
$this->html_attr[$i]['val']);
}
if ($this->html_attr[$i]['fn']=='addClass'){
pq($this->html_attr[$i]['sel'])->addClass(
$this->html_attr[$i]['val']);
}
}
return $dom->html();
}
function fetch($id,$tpl_name) {
$f2=$this->tpl_dir.$tpl_name.'.html';
$h=false;
if (!file_exists($f2)) {
$f2=$this->tpl_dir.'error404.html';
}
$dom=phpQuery::newDocumentFilePHP($f2);
array_push($this->doc_array,phpQuery::getDocumentID($dom));
$f=$this->php_dir.$tpl_name.'.php';
if (file_exists($f)){
require_once($f);
if (function_exists('tpl_'.str_replace('-','_',$tpl_name))){
call_user_func('tpl_'.str_replace('-','_',$tpl_name),$this);
}
}
$this->html_tree[]=$id;
$this->html[$id]=$dom->html();
$dom->unloadDocument();
array_pop($this->doc_array);
if (count($this->doc_array)>0){
$id=array_pop($this->doc_array) ;
phpQuery::selectDocument($id);
array_push($this->doc_array,$id);
}
}
function pq($id,$html) {
$this->html_tree[]=$id;
$this->html[$id]=$html;
}
function attr($sel,$attr,$val){
$this->html_attr[]=array('sel'=>$sel,'name'=>$attr,'val'=>$val,'fn'=>'attr');
}
function addClass($sel,$cls){
$this->html_attr[]=array('sel'=>$sel,'fn'=>'addClass','val'=>$cls);
}
}
?>
ANEXA 5 – Funcția „saveRasp” din fișierul „libs/functions.php”
function saveRasp($tpl,$rc,$correct,$total,$cuq,$rasp,$chest,$raspuns,$save_q) {
$n=1;
if ($save_q=='all'){
$correct=0;
for ($i=0;$i<$total;$i++){
if ($rasp[$i]=='')$rasp[$i]='*';
if ($rasp[$i]==$rc[$i]){
$correct++;
}
}
} else {
if (is_array($raspuns)){
$rasp[$save_q-1]=join('',$raspuns);
} else {
if (!isset($raspuns)){
$rasp[$save_q-1]='-';
} else {
$rasp[$save_q-1]=$raspuns;
}
}
if ($raspuns==$rc[$save_q-1])$correct++;
}
$tpl->db->sql("UPDATE `chestionare` SET
`raspunsuri`='".join(',',$rasp)."',`corecte`='".$correct."'
WHERE `id`='".$chest['id']."'"
);
for ($i=$cuq;$i<=$total;$i++){
if ($rasp[$i]==''){
$n=$i+1;
break;
}
}
if ($n>$total){
$n=1;
for ($i=0;$i<=$total;$i++){
if ($rasp[$i]==''){
$n=$i+1;
break;
}
}
}
if ($n>$total)$n=1;
return array($rasp,$n);
}
ANEXA 6 – funcțiile JavaScript „initBlue” și „animateBlue”
function initBlue() {
var c=$('.comanda');
if (!c.html()) return;
if (c[0].parentNode.parentNode.className != 'content'){
return;
}
var cnt=c.length;
for (var i=1;i<cnt;i++) {
$(c[i]).css('display','block');
$(c[i]).css('left',940);
}
$('.comanda').data('idx',1);
$('.comanda').data('last_idx',0);
$('.comanda').data('cnt',cnt);
$(window).data('home_anim_timer',setTimeout(animateBlue,20000));
$('.icons a').on('click',function(e) {
e.preventDefault ();
clearInterval($(window).data('home_anim_timer'));
$('.comanda').data('idx',$(this).index());
animateBlue(1);
});
}
function animateBlue(ease) {
var ease1='easeInOutExpo';
if (ease==1)ease1='easeOutExpo';
var i=$('.comanda').data('idx');
var c=$('.comanda').data('cnt');
var lidx=$('.comanda').data('last_idx');
var ic=$('.icons a');
$('.comanda'+lidx).animate({left:-940},
{duration:1000, easing:ease1,complete:function() {
$(this).css('left',940);
}});
$('.comanda'+i).animate({left:0},{ duration:1000, easing:ease1 });
$(ic[i]).prop('class','s'+i);
$(ic[lidx]).prop('class','b'+lidx);
$('.comanda').data('last_idx',$('.comanda').data('idx'));
i++;
i=i%c;
$('.comanda').data('idx',i);
$(window).data('home_anim_timer',setTimeout(animateBlue,20000));
}
ANEXA 7 – pagina contact și fișierele sursă atașate.
URL examenauto.ro/contact
Fișier php/contact.php: URL
<?php
function tpl_contact($tpl){
$post=getPost();
$err=array();
if ($post){
if (!( ($s=strstr($post['email'],'@')) && ($s2=strstr($s,'.')) &&
(strlen($s)-strlen($s2))>1&& strlen($s2)>2) ) {
$err[]='E-mail este introdus gresit';
}
if (strtoupper($post['verif'])!=$_SESSION['captcha-code']){
$err[]='Codul de verificare nu corespunde cu cel din imagine';
}
if (trim($post['mesaj'])=='' || strlen(trim($post['mesaj']))<40){
$err[]='Mesajul este prea scurt.';
}
pq('.login-box2 li.c3 h2')->remove();
pq("input[name='nume']")->val($post['nume']);
pq("input[name='email']")->val($post['email']);
pq("input[name='tel']")->val($post['tel']);
pq("textarea[name='mesaj']")->val($post['mesaj']);
}
for ($i=0;$i<5;$i++){
$c=rand(0,strlen($codes)-1);
$ses.=$codes[$c];
}
$_SESSION['captcha-code']=$ses;
if (empty($err) && $post){
pq('li.c1')->html('');
pq('li.c2')->html('
<div style="font-size: 16px; padding-top:50px;">
<h2>Contact</h2>Mesajul dumneavoastra a fost trimis.
</div>
<script type="text/javascript">
setTimeout(function(){document.location.href="/";},5000);
</script>
');
pq('li.c2')->addClass('ico-permis');
pq('li.c3')->html('');
pq('li')->attr('style','height:320px;');
sendMailContact(
$post['nume'],
$post['email'],
'Mesaj din pagina de contact examenauto',
$post['name'],
$post['tel'],
$post['mesaj']);
}
if (!empty($err)){
errorMessage('Eroare:',$err,'#errmsg','error');
}
}
?>
Fișier template/contact.html:
<form method="post">
<ul class="login login-box2">
<li class="c1">
<h2>Date contact</h2>
<div class="text18sb ico-email">
<script type="text/javascript">
document.write('offi'+'ce@'+'exame'+'nauto.ro');
</script>
</div>
</li>
<li class="c2">
<h2>Scrie-ne un mesaj</h2>
<label>Numele:<input type="text" name="nume"></label>
<label>E-mail: <span class="red">*</span>
<input type="text" name="email">
</label>
<label>Telefon:<input type="text" name="tel"></label>
<label>Verificare: introduceti codul din imagine
<img src="generare.php" style="margin-left: 1px;"><br>
<input type="text" name="verif" style="width:200px;">
</label>
<p>Câmpurile marcate cu <span class="red">*</span> sunt obligatorii</p>
</li>
<li class="c3">
<div id="errmsg" class="errmsg"></div>
<h2> </h2>
<label>Mesaj: <span class="red">*</span>
<textarea name="mesaj"></textarea>
</label>
<input type="submit" class="submit" value="Trimite">
</li>
</ul>
</form>
Copyright Notice
© Licențiada.org respectă drepturile de proprietate intelectuală și așteaptă ca toți utilizatorii să facă același lucru. Dacă consideri că un conținut de pe site încalcă drepturile tale de autor, te rugăm să trimiți o notificare DMCA.
Acest articol: Aplicatie Pentru Testare Online. Chestionare din Domeniul Transportului Auto (ID: 149471)
Dacă considerați că acest conținut vă încalcă drepturile de autor, vă rugăm să depuneți o cerere pe pagina noastră Copyright Takedown.
