Cum sa faci un chat fara refresh ( folosind PHP & Ajax) ?
45Observam crestere si o dezvoltare tot mai mare a proiectelor web incercand sa ajunga toate pe noul „web 2.0”.Aceasta dorinta intalneste una noua si anume cea de a updata anumite portiuni din pagina fara ca utilizatorul sa fie nevoit sa faca acest lucru.Un bun exemplu in acest caz este bine-cunoscutul Twitter.Acesta are posibilitatea de a adauga ciripiturile fara a fi nevoie de un refresh al paginii.De asemenea multe din actiuni sunt similare : cautarea,autentificarea etc etc.Toate aceste lucruri creaza o viteza si experienta de navigare placuta utilizatorului.
Astazi noi vom incerca sa reproducem o actiune simpla asemanatoare cu cele de la Twitter,insa nu vom incerca sa reproducem nici una dintre acestea.
Practic vom avea o mica baza de date si cun formular HTML in care vom simula discutiile avute intr-un chat.Acest chat va face cereri regulate la o baza de date incercand sa extraga noile comentarii ce au aparut in chat.El va modifica un div si adauga noile discutii deasupra celor deja existente.
Este unul din cele mai bune exemple de a aprofundare a acestui principiu dinamic al paginilor web.
Ce tehnologii web folosim?
Prima tehologie web de care vom avea nevoie este batranul HTML.Acesta ne va ajuta la crearea unei interfete suficient de intuitiva si de simpla pentru a nu ridica probleme nici unui incepator ce a studiat HTML-ul 2-3 zile.Vom avea nevoie de o baza date ce va contine un tabel pentru a stoca informatiile ce le primim de la cei ce vor purta discutiile in chat.Vom folosi o baza de date ce o gasim pe orice server decent si anume o baza de date MySQL.Interogaririle ce la care vom supune baza de date sunt bazice si vor include selectii,stergeri,adaugari de „linii” in baza de date.Aceste interogari precum si alte prelucrari le vom face in cateva fisiere PHP.Pana aici , practic am prezentat doar tehnologiile ce sunt clasice intr-un website obisnuit.Pentru a prelua si a reincarca o anumita sectiune cu continut nou provenit din baza de date, va trebui sa introducem o tehnologie noua ce are la bazaJavascript : Ajax.Aceasta tehnologie va face cereri regulate la anumite fisiere PHP si va edita continutul anumitor taguri HTML, actualizand continutul acestora.
Rezultat
Am pregatit doua imagini facute paralel,una din Mozilla Firefox iar cealalta din Chrome pentru a vedea care va fi rezultatul la care se va ajunge in urma acestui articol. 😀
Formularul HTML
<html> <head> <title>Chat Box - Tutorial in care invatam cum sa aplicam Ajax si PHP pentru o pagina dinamica</title> </head> <body text="#66FF33" OnLoad="trimiteCMD('arata');"> <table align="center" width="50%" border="1" cellspacing="0" cellpadding="0"> <tr> <td> <div id="msg"></div> </td> </tr> <tr> <td align="center"> <form name="chatbox" method="post" onSubmit="return false"> <textarea id="msgtext" name="mesaj" cols="50" rows="3" onFocus="verif_msg(this.value);" onBlur="clr_msg(this.value);">Mesajul tau aici.</textarea><br><br> <button id="send" onClick="trimiteCMD('trimite', document.getElementById('msgtext').value);">Trimite</button> </form> </td> </tr> </table> </body> </html>
Tabelul MySQL din baza de date MySQL
Acest tabel trebuie pus intr-o baza de date MySQL de care vom avea nevoie la stocarea tuturor mesajelor primite de la cei care chatuiesc. 🙂
CREATE TABLE `mesaje` ( `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , `nume` CHAR( 255 ) NOT NULL , `mesaj` TEXT NOT NULL , `timp` INT NOT NULL ) ENGINE = MYISAM ;
Codul PHP pentru actualizare si adaugare a comentariilor?
Fisierul config.php
In acest fisier vor trebui facute singurele modificari pentru a putea lucra pe serverul dumneavoastra.Trebuie sa configurati accesul la baza de date MySQL creata anterior.De asemenea au loc si deschiderea sesiunile precum si crearea unei variabile ce ne asigura ca suntem unde trebuie! 🙂
<?php session_start(); if(!defined('INTERN')) { define('INTERN',TRUE); mysql_connect('server','user','parola') or die('Nu m-am putut conecta la serverul MySQL.'); mysql_select_db('baza de date') or die('Nu m-am putut conecta la baza de date MySQL.'); } ?>
Fiserul adauga.php
Acest fisier va adauga un mesaj nou $_GET[‘mesaj’] provenind de la $_GET[‘user’] si va returna ultimile mesaje din baza de date noi.
<?php include('config.php'); if(!defined('INTERN')) die(); if(isset($_GET['CMD']) && $_GET['CMD'] == 'trimite' && isset($_GET['nume'],$_GET['mesaj'])) { header("Expires: Mon, 26 Jul 2999 05:00:00 GMT" ); header("Last-Modified: " . gmdate( "D, d M Y H:i:s" ) . "GMT" ); header("Cache-Control: no-cache, must-revalidate" ); header("Pragma: no-cache" ); header("Content-Type: text/xml; charset=utf-8"); $user = htmlentities($_GET['nume'],ENT_QUOTES); $mesaj = htmlentities($_GET['mesaj'],ENT_QUOTES); $query = mysql_query('INSERT INTO `mesaje` (`nume`,`mesaj`,`timp`) VALUES ("'.$user.'","'.$mesaj.'","'.time().'")'); $result = ($query) ? '1' : '0'; ?> <root> <cmd><?php echo $_GET['CMD'];?></cmd> <status><?php echo $result; ?></status> <?php include('ultimile.php'); ?> </root> <?php } ?>
Fiserul last.php
Acesta returneaza ultimile mesaje ale cititorului curent.
<?php include('config.php'); if(isset($_GET['CMD']) && $_GET['CMD'] == 'arata') { header("Expires: Mon, 26 Jul 2999 05:00:00 GMT" ); header("Last-Modified: " . gmdate( "D, d M Y H:i:s" ) . "GMT" ); header("Cache-Control: no-cache, must-revalidate" ); header("Pragma: no-cache" ); header("Content-Type: text/xml; charset=utf-8"); ?> <root> <cmd> <?php echo $_GET['CMD'];?> </cmd> <status>1 </status> <?php include('ultimile.php'); ?> </root> <?php } ?>
Fiserul ultimile.php
Fisierul ultimile.php este defapt cel care stabileste care mesaje sa le afiseze.Daca e prima cerere va returna ultimile 10 mesaje, in caz contrar va afisa doar ce a aparut nou de la ultima cerere.Acest ultim moment la care s-a facut verificarea este stocat intr-o variabila globala de tip SESSION.
<?php if(!defined('INTERN')) die(); $time = time(); $time = isset($_SESSION['lastcheck']) && is_numeric($_SESSION['lastcheck']) ? $_SESSION['lastcheck'] : 0; $_SESSION['lastcheck'] = time(); if($time == 0) { $query = "SELECT * FROM `mesaje` ORDER BY `timp` DESC LIMIT 0,10"; } else { $query = "SELECT * FROM `mesaje` WHERE timp >=".$time." ORDER BY `timp` DESC"; } $int = @mysql_query($query); $result = ($query) ? '1' : '0'; ?> <statusMesaje><?php echo $result; ?></statusMesaje> <mesaje> <?php while($row = @mysql_fetch_array($int)) { ?> <mesaj id="<?php echo $row['id']; ?>"> <nume><?php echo $row['nume']; ?></nume> <msg><?php echo $row['mesaj']; ?></msg> <timp><?php echo gmdate('D, d M Y H:i:s',$row['timp']); ?></timp> </mesaj> <?php } ?> </mesaje>
Codul AJAX pentru a face cererile dinamic?
//verifica daca avem vreun mesaj function verif_msg(data) { if(data=='Mesajul tau aici.') { document.getElementById('msgtext').value=''; } } //curata mesajul function clr_msg(data) { if(data == '') { document.getElementById('msgtext').value='Mesajul tau aici.'; } } //cream un obiect Http(acesta ne va ajuta sa lucram cu cereri Ajax) //el incearca sa creeze obiectul pentru diverse versiuni de Browser function creazaObiectHttp() { if (window.XMLHttpRequest) return new XMLHttpRequest(); else if(window.ActiveXObject) return new ActiveXObject("Microsoft.XMLHTTP"); else { document.getElementById('msg').innerHTML='Status: Nu am putut crea obiectul XML Http.' + 'Va rugam frumos schimbati browserul.'; } } var mTimer; //timerul ce face regulat cereri de noi mesaje var receiveReq = creazaObiectHttp(); //cream obiectul var randomUser = Math.floor((Math.random() * (2000-1000+1))+1000); //numele utilizatorului //functia principala ce trimite mesajele catre diverse fisiere php function trimiteCMD(cmd, data) { if(cmd=='trimite' && data=='Mesajul tau aici.') { alert('Te rog scrie un mesaj!') } else { //daca nu este trimis nici un pachet acum si nu este nici unul in decurs if (receiveReq.readyState == 4 || receiveReq.readyState == 0) { var file,param; if(cmd=='trimite') { file = 'adauga.php'; //fisierul ce trebuie prelucrat + parametri param = 'CMD=trimite&nume=user' + randomUser + '&mesaj=' + data; clearTimeout(mTimer);//inchidem toate cererile existente document.getElementById('msgtext').value='Mesajul tau aici.'; } else if(cmd=='arata') { file = 'last.php'; param = 'CMD=arata'; clearTimeout(mTimer); //deschidem o noua cerere peste 5 secunde sa vedem daca mai exista mesaje noi mTimer = setTimeout("trimiteCMD('arata', '');",5000); } receiveReq.open("POST", file, true); //facem cererea receiveReq.setRequestHeader('Content-Type','application/x-www-form-urlencoded');//setam headere receiveReq.onreadystatechange = handleCMD;//functia ce va procesa cererile receiveReq.send(param); //trimitem parametrii } } } //functie ce returneaza true daca pagina curenta a fost descarcata corect si complet function check_state() { if (receiveReq.readyState == 4) if (receiveReq.status == 200) return "True"; } //procesam mesajele primite de la fisierele PHP function handleCMD() { var resultState = check_state(); if (resultState == "True") { var chat_div = document.getElementById('msgtext'); xmldoc = receiveReq.responseXML; var cmd = xmldoc.getElementsByTagName('cmd'); var status = xmldoc.getElementsByTagName('status'); if(cmd[0].firstChild.nodeValue == 'trimite') { //daca s-a adaugat mesajul nou afisam asta utilizatorului if(status[0].firstChild.nodeValue == '1') { document.getElementById('err').innerHTML = 'Mesajul a fost trimis.'; } else { //in caz contrar afisam mesajul corespunzator document.getElementById('err').innerHTML = 'Nu am putut trimite mesajul.'; } //repornim cererile regulate o data la 5 secunde mTimer = setTimeout("trimiteCMD('arata', '');",5000); setTimeout('document.getElementById("err").innerHTML = "";',3000); } else if(cmd[0].firstChild.nodeValue == 'arata') { //nimic } var status = xmldoc.getElementsByTagName('statusMesaje'); //daca avem mesajele trimise ok le procesam si le afisam utilizatorului if(status[0].firstChild.nodeValue == '1') { var msg = xmldoc.getElementsByTagName('mesaje'); var msgs_nodes = msg[0].getElementsByTagName('mesaj'); for(i = 0; i < msgs_nodes.length; i++) { //mesajul i var userNode = msgs_nodes[i].getElementsByTagName('nume'); var bodyNode = msgs_nodes[i].getElementsByTagName('msg'); var timeNode = msgs_nodes[i].getElementsByTagName('timp'); var add = '<small>[ ' + timeNode[0].firstChild.nodeValue + ' ]</small>'; add += ' ' + userNode[0].firstChild.nodeValue + ' '; add += ' ' + bodyNode[0].firstChild.nodeValue + ''; //il adaugam inaintea celor deja existente document.getElementById('msg').innerHTML = add + document.getElementById('msg').innerHTML; add = ''; } } else {//in caz contrar afisam o eroare document.getElementById('err').innerHTML = 'Nu am putut primi noile mesaje.'; setTimeout('document.getElementById("err").innerHTML = "";',3000); } } }
Sa le unim pe toate
Am creat o arhiva in care am unit toate aceste fisiere, pentru a face un sistem complet functionabil.Exista si un fisier sql.sql care are baza de date MySQL in cazul in care nu aveti rabdare sa o luati de aici.Descarcati arhiva,configurati fisierul config.php si adaugati tabelul in baza de date si dupa puteti testa.Fisierele nu sunt comentate,singurele comentarii find puse aici,asa ca veti fi nevoiti sa nu sariti peste pasul de a analiza codul in care doriti sa invatati ce am facut.
Pe scurt am interceptat pachetele sub forma de mesaje XML de la serverul PHP ce le-a generat cu ajutorul fisierelor ultimile.php si adauga.php respectiv last.php. Am tratat obiectul ca unul HTML si am extras din el pe rand noile mesaje,daca acestea erau.Codul pare mare datorita faptului ca am incercat sa tratez si majoritatea erorilor de baza, sperand ca asa nu veti avea probleme.
Concluzii
Desi, acest articol nu se referea neaparat la cum se lucreaza cu Ajax si PHP, acest tutorial este unul din cele mai bune exemple ce pot fi facute de un incepator.Nu trebuie sa te sperii de marele cod, este doar o impresie, in browser acesta pare mai complex decat este.Daca vei dori sa intelegi acest articol , iti sugerez sa-l descarci pe calculator si sa stai cu browserul langa tine pentru a citi explicatiile.
De asemenea, in acest „mic proiect” , am folosit doar cereri bazate pe POST, si le-am omis intentionat din discutie pe celelalte.Daca doriti cateva exemple si folosind cereri Ajax dar bazate pe argumente GET lasati un comentariu si in maxim cateva ore voi veni cu explicatiile si exemplele. 🙂
Intrebari?
😀 … nimic ?
Salut!
Cum pot realiza totul cu tabele Visual FoxPro si nu baze de date MySQL?
Multumesc foarte mult!
Cu deosebita stima,
Liviu.