IPRO - PC Magazine Romania, Martie 2003
SOLUȚII PENTRU PROGRAMATORII ȘI DESIGNERII WEB Totul
despre situri dinamice (III)
Konstantin Klyagin
Continuăm seria de articole despre crearea siturilor dinamice. În acest
număr, veți găsi informații despre operațiile asupra bazei de date despre
animale dispărute, utilă binecunoscutului erou Ace Ventura, explicații legate
codul PHP-urilor de pe CD, descrierea metodei de lucru cu fișiere de tip
imagine, trimiterea fișierelor prin formularul online, identificarea caracteristicilor
pozelor, redimensionarea și includerea lor în baza de date.
Conectarea la baza de date
Nu prea are sens să explic fiecare linie din scripturile exemplului nostru,
de aceea vă voi arăta cele mai interesante și utile locuri din cod.
Începem cu metoda de accesare a bazei de date, care, după cum vedem din fișierul
connect.php, se face cu ajutorul a două funcții:
mysql_connect("localhost", "ace", "ace2") or die("Could not connect");
mysql_select_db("acedb") or die("Could not select database");
Prima linie din codul de sus face conectarea cu server-ul de baze de date,
iar a doua accesează baza de date. Apropo, dacă avem mai multe conexiuni
cu baze de date diferite, putem folosi o variabilă, pe care o returnează
prima funcție. Dar în proiectul nostru avem o singură bază de date, deci
și o singură conexiune. Sintaxa cu "or" vine din Perl și permite definirea
unei acțiuni speciale, în caz că funcția care a fost chemată întoarce o eroare.
Respectiv, funcția die() oprește executarea scriptului, afișând mesajul dorit.
Operații
asupra bazei de date
Să vedem cum se adaugă și se șterg informații din baza de date. În fișierul
pets.php selectăm toate înregistrările din tabela pets:
select id, name, lostdate, reward from pets
Iar pentru a o trimite la serverul de baze de date pentru a fi executată,
folosim funcția mysql_query():
$r = mysql_query("select id, name, lostdate, reward from pets");
Rezultatul execuției îl găsim într-o variabilă de tip resursă "$r".
while ($row = mysql_fetch_assoc($r))
Sunt o sumedenie de funcții de genul fetch la partea de suport pentru MySQL
în PHP. Una dintre ele este mysql_fetch_assoc(), care de fapt este foarte
comodă pentru a accesa datele selectate. Rezultatul este un masiv asociativ
ale cărui elemente se referă după nume. Numele câmpului este numele elementului
respectiv din masiv. În exemplul nostru, vom avea următoarele variabile:
$row["id"], $row["name"], $row["lostdate"] și $row["reward"]. mysql_fetch_assoc()
întoarce o valoare pozitivă până când se termină înregistrările, de aceea
am folosit intrucțiunea repetitivă "while".
Ca parametri ai instrucțiunii "select", putem avea atât câmpuri din baza
de date, cât și funcții. Iată, spre exemplu, primul "select" din petdetails.php:
$r = mysql_query("select p.name as pname, p.marks,
date_format(p.lostdate, '%d.%m.%Y') as lostdate, p.reward,
not isnull(p.picture) and p.picture != '' as haspic,
o.name as oname, p.owner_id
from pets p, owners o where p.id = $id and o.id = p.owner_id");
Da, aici avem un "select" adevărat: sunt prezente pseudonime pentru tabele
și parametri, un apel de funcție, precum și o expresie logică al cărei rezultat
îl primim la ieșire. Pseudonimele se folosesc atunci când într-o solicitare
sunt expresii logice, apeluri la funcții, sau numele câmpurilor sunt identice
în mai multe tabele și nu este clar pe care vrem să îl selectăm. Expresia
logică cu câmpul "picture" din tabela pets determină dacă înregistrarea include
o imagine, iar rezultatul se regăsește sub numele "haspic" și va fi 0 sau
1.
Uneori prin cod vedem și apeluri de genul:
header("Location: pets.php");
Ca la orice protocol de comunicare, HTTP are atât părți de conținut (date)
cât și cele de "header", care de obicei spun ce urmează, lungimea și opțiunile
necesare pentru recepție și procesare. Există cazuri în care nu există conținut
ci doar o redirectare către o altă pagină. De exemplu, în owneradd.php, după
ce s-au verificat toate datele trimise de către utilizator, a fost adăugată
o nouă înregistrare în tabela "owners". În continuare, browserul este redirectat
către pagina ce afișează lista. Așa funcționează redirecționarea, cu o singură
limitare: înaintea sa nu poate fi nici un alt "output", altfel PHP ne dă
următoarea înștiințare:
Warning: Cannot add header information - headers already sent by
(output started at <unde: fișierul și linia>)
in <unde s-a produs eroarea>
Formulare online
Dintr-o pagină web, informațiile pot fi trimise către baza de date printr-un
formular online. Definirea unui formular începe cu tag-ul <FORM>. Dacă
numele scriptului care prelucrează formularul diferă de cel care a generat
pagina, se adaugă parametrul "action". Metoda de transfer a datelor se definește
prin parametrul METHOD. Astfel, avem:
<form action="petadd.php" method="get">
<input type="text" name="name" value="Tomcat">
...
</form>
O metodă pentru păstrarea parametrilor de la o prelucrare la alta, este
includerea în formular a unor câmpuri ascunse ("hidden"), care chiar dacă
nu sunt vizibile, se trimit o dată cu datele din formular. Găsim un exemplu
în petadd.php.
<input type="hidden" name="mode" value="<?= $mode ?>">
<input type="hidden" name="id" value="<?= $id ?>">
Sintaxa "<?= $variabilă ?>" este prescurtarea pentru "<?php echo($variabila);
?>" care afișează valoarea variabilei respective.
În instrucțiunea de mai jos, am apelat funcția htmlspecialchars() care transformă
anumite caractere în coduri speciale HTML. De exemplu " (ghilimelele duble)
devin '"'.
<input type="text" name="name" value="<?= htmlspecialchars($name)
?>">
Adăugarea înregistrărilor în petadd.php și owneradd.php se face după o schemă
destul de răspândită: formularul trimite datele către același script care
a generat inițial pagina. Pentru a face diferența între operațiile de adăugare
și modificare a informațiilor în baza de date, folosim un "if" simplu:
if(!empty($name)) {
După trimiterea formularului, în script e suficient să verificăm doar pentru
unul dintre parametri dacă a fost transmis, deoarece dacă un parametru a
ajuns la script, atunci ajung și ceilalți.
Scriptul care primește datele trimise prin formularul online, face atât adăugarea,
cât și modificarea înregistrărilor.
Ștergerea înregistrărilor se face din aceleași script-uri care afișează listele
de animale sau de proprietari. Aici, ca și în petadd.php și owneradd.php,
regimul de folosire depinde de parametrul "mode". Dacă este "remove", se
afișează câte un "checkbox" lângă fiecare înregistrare, precum și două
butoane noi în josul paginii. Acestea sunt "Remove checked" și "Back". Fiecare
"checkbox"
are un identificator "id" din baza de date ca nume. Scriptul care prelucrează
formularul este remove.php, care primește lista de id-uri pentru checkbox-urile
selectate. Acum să vedem ce face programul respectiv. Mai întâi, se verifică
dacă a fost apăsat butonul "Back" care anulează operațiunea:
if(empty($back)) {
Dacă nu, se plimbă prin parametri construind condiția pentru comanda "delete":
foreach($_GET as $id => $val) {
if($id != "src") {
if($del != "") $del .= " or ";
if($upd != "") $udp .= " or ";
$del .= "id = $id";
$upd .= "owner_id = $id";
}
}
" .=" reprezintă operația de concatenare a două șiruri.
Știm că în afară de "src", care reprezintă numele tabelei de modificat, toți
parametrii sunt id-uri, și nu toate, ci doar id-urile checkbox-urilor care
au fost marcate. Astfel, dacă 1, 3 și 4 au fost selectate, condiția va
fi, "id = 1 or id = 3 or id = 4". Restul comenzii nu se schimbă:
mysql_query("delete from $src where $del");
Dacă se șterge un proprietar, ne asigurăm că toate animalele sale se marchează
ca "fără proprietar" (câmpul "owner_id" la ele devenind zero):
if($src = = "owners")
mysql_query("update pets set owner_id = 0 where $upd");
Trimiterea fiȘierelor
prin formulare online
O metodă interesantă se folosește și la transferul fișierelor prin formulare
online. Putem transfera o poză și imediat ea va apare în sit. Dacă ne uităm
la script-ul de adăugare a unui animal, vedem o deosebire în definirea formularului:
<form enctype="multipart/form-data" method="post">
După cum știm, metoda POST permite trimiterea unor șiruri mai mari de informații,
iar parametrul "enctype" este un element obligatoriu pentru încărcarea fișierelor.
Altfel nu va merge. Apoi punem un câmp de tip "file" în formular:
<input type="file" size=50 name="photo">
Pentru fiecare tip de parametru, avem diverse variabile. Pentru un parametru
cu tipul "file", avem variabilele:
$photo
Numele local temporar al fișierului încărcat.
$photo_name
Numele original al fișierului de la client (browser).
$photo_type
Tipul MIME al fișierului. Acest tip conține un text scurt care îi spune
programului "browser" cum să trateze datele care urmează: dacă ceea ce vine
este o imagine sau un document PDF. Imaginile de obicei au image/jpeg, image/gif,
ș.a.m.d.
$photo_size
Mărimea fișierului în octeți.
Iată cum folosim noi aceste variabile:
if(!empty($photo)) {
$orig = @imagecreatefromstring(fread(fopen($photo, "r"),
filesize($photo)));
if(empty($orig)) {
$msg = "The picture format is unknown or unsupported.";
}
}
După trimiterea unei poze, conținutul fișierului este prelucrat de către
funcția imagecreatefromstring() care crează în memorie o variabilă de tip
resursă. Acestă funcție are o sintaxă interesantă: prefixul "@" elimină mesajele
de eroare pe care le poate produce funcția apelată. Aici poate apărea o eroare
spunând că ceea ce a primit funcția n-a fost o imagine, însă noi vrem să
evităm producerea erorilor interne în sit. De aceea, punem "@". Dacă imagecreatefromstring()
nu reușește să citească imaginea, vom avea variabila $orig goală și în acest
caz va apărea un mesaj.
Acesta n-a fost însă cel mai interesant lucru care se poate face cu imaginile,
pentru că urmează schimbarea dimensiunilor pozei. Într-adevăr nu avem nevoie
de niște panouri de reclamă atunci când ne este lene să micșorăm imaginea
într-un editor grafic. Mai bine să lasăm scripturile de pe sit să facă
tot ce e necesar, mai ales că PHP-ul ne permite să facem diverse prelucrări
asupra
fișierelor grafice. Iată funcția scalepicture() din connect.php:
function scalepicture($orig) {
$needx = $needy = 250;
$rx = imagesx($orig);
$ry = imagesy($orig);
if($rx > $needx) {
$ry *= $needx/$rx;
$rx = $needx;
}
if($ry > $needy) {
$rx *= $needy/$ry;
$ry = $needy;
}
$res = imagecreate($rx, $ry);
imagecopyresized($res, $orig, 0, 0, 0, 0, $rx, $ry,
imagesx($orig), imagesy($orig));
$tn = tempnam("img", "/tmp");
imagejpeg($res, $tn);
$content = addslashes(fread(fopen($tn, "r"),
filesize($tn)));
unlink($tn);
return $content;
}
După cum observați din definiție, ea are un parametru reprezentând imaginea
citită și procesată cu fread() și imagecreatefromstring(). La început, limita
o avem în $needx și $needy. Dacă nu ne convin dimensiunile originale - sunt
mai mari decât cele maxime posibile, adică 250x250, calculăm noile dimensiuni
păstrând proporțiile. Este clar ce facem în cele două if-uri. Sintaxa "*="
vine din C, și înseamnă că rezultatul mai întâi se multiplică în partea dreaptă
a expresiei: "$ry *= $needx/$rx" este egal cu "$ry = $ry*$needx/$rx".
După ce am calculat noile dimensiuni, trecem direct la treabă. Creăm imaginea
goală în $res cu dimensiunile dorite, și apoi o copiem pe cea originală
schimbându-i dimensiunea. După ce această operațiune este gata, obținem în
$tn un nume
unic pentru un fișier temporar unde scriem rezultatul în format JPEG. Numele
fișierului rezultat va fi pus într-un șir de caractere, se adaugă și slash-urile
ca să fie gata pentru a-l include într-o comandă "insert". Știm bine, că
în cazul în care valoarea unui câmp conține ghilimele neecranate cu semnul
"slash - /", întreaga comandă va fi considerată incorectă.
Rezultatul returnat de scaleimage() este deja foarte ușor de folosit:
if($id = mysql_insert_id()) {
if(!empty($orig)) {
$content = scalepicture($orig);
mysql_query("update pets set picture = '$content'
where id = $id");
}
}
El se include imediat în comanda de "update". Apropo, să vedem cum putem
accesa ultima înregistrare inclusă în baza de date, în cazul în care tabela
respectivă are un câmp "auto_increment". Funcția mysql_insert_id() ne dă
valoarea acestuia ca apoi să putem adăuga sau schimba ceva știind exact cu
ce înregistrare lucrăm. În exemplu, mai întâi se pun informațiile generale
și apoi, dacă este prezentă, se adaugă și imaginea trimisă de către utilizator.
După ce imaginile se întroduc în baza de date, folosim script-ul fetchimage.php
pentru a le vizualiza. După cum știm din documentația de HTML, imaginea statică
se afișează cu ajutorul tag-ului <IMG SRC="locația imaginii">. Diferența
între afișarea imaginilor dinamice și a celor statice constă în faptul că
la cele dinamice, în loc de calea și numele imaginii trebuie dată locația
programului CGI care ne returnează imaginea. Cum în cazul nostru aceasta
este fetchimage.php, includem atât numele cât și parametrii în tag:
<img src="fetchimage.php?src=owners&id=1">
După fiecare modificare a datelor, se execută comanda "commit", pentru a
salva schimbările:
mysql_query("commit");
În acest loc facem "commit" și noi. Deoarece există atât de multe tehnologii
fascinante, software minunat, inclusiv cel free și Open Source, ne întrebăm
de ce să nu avem mai multe situri interesante și utile. Pentru început, cunoștințele
din acest articol ar trebui să fie suficiente, iar mai multe detalii puteți
găsi foarte ușor în siturile programelor utilizate în exemplu (PHP - www.php.net și MySQL - www.mysql.com). Vă urez să aveți multe idei de realizat și inspirație,
care este foarte importantă pentru a face un produs de calitate.
Situl demo se află online la:
http://konst.org.ua/ace
|