Sunteți pe pagina 1din 301

PHP si MYSQL (PROGRAMATOR WEB 2)

1 Introducere in PHP
2 Bazele limbajului PHP I
3 Bazele limbajului PHP II
4 Arrays (tablouri)
5 Strings (siruri de caractere)
6 Procesarea formularelor. $_GET si $_POST
7 Baze de date. MySQL.
8 PHP si MySQL
9 Lucrul cu fisiere din PHP
10 Cookies. Sesiuni
11 Clase si obiecte (I)
12 Clase si obiecte (II)
13 Diverse
14 Realizarea unui magazin virtual
15 Symfony
16 TCPDF - generare fisiere pdf

Cap 1. Introducere in PHP

1.1 Ce este PHP ? Ce este MySQL ?


1.2 Instalare si configurare
1.3 Editoare. Primul program PHP
1.4 Interactiunea dintre PHP, serverul Web si browser
1.5 Imbinarea dintre PHP si HTML
1.6 Tema

1.1.Ce este PHP ? Ce este MySQL ?

Limbajul PHP

PHP este un limbaj de programare intrepretat, cu sintaxa asemanatoare cu


cea a limbajului C, proiectat inca de la inceput pentru a folosi la realizarea
dinamica a paginilor web. Din acest motiv, limbajul PHP are facilitati pentru
interactiunea cu serverul Web folosind protocolul HTTP si in acelasi timp
facilitati pentru imbinarea cu limbajul HTML.

Limbajul PHP a pornit de la un proiect numit PHP/FI (Personal Home Page


/ Forms Interpreter) scris de Rasmus Lerdorf in 1995. Proiectul a fost rescris
de catre Andi Gutmans si Zeev Suraski si a fost redenumit PHP
(PHP: Hypertext Preprocessor), fiind nucleul PHP-ului de astazi. Aceasta
noua versiune complet rescrisa este de fapt PHP 3.0 si a fost creata in 1997.
Cei doi au infiintat compania Zend Technologies, companie ce dezvolta in
continuare limbajul PHP.

PHP, fiind la baza un limbaj procedural, a ajuns la versiunea 5, versiune ce


aduce multe imbunatatiri pentru programarea orientata pe obiecte. (OOP =
obiect oriented programming).

Mai multe despre istoria PHP la www.php.net/history. PHP este un proiect


de tip open-source, este gratuit, si este unul din cele mai folosite limbaje
pentru programarea web (http://www.php.net/usage.php).

Pagina oficiala a limbajului PHP este http://www.php.net/


Manualul limbajului PHP este http://www.php.net/manual
Documentatia (helpul) pentru orice functie din libraria limbajului poate fi
gasita la http://www.php.net/nume_functie.
Exemplu: http://www.php.net/nl2br

MySQL

MySQL este o aplicatie destinata realizarii si administrarii bazelor de date.


Terminologia folosita pentru astfel de aplicatii este DBMS (Database
Management System). O baza de date este o modalitate de a pastra
informatiile in mod structurat, de a cauta eficient in aceste informatii, si de a
extrage datele utile. Ca exemplu, va puteti gandi la toate datele unei banci
(informatii despre tranzactii, clienti, angajati) sau datele unui site de licitatii
(utilizatori, produsele licitate, categoriile produselor).

Pentru a dezvolta o aplicatie web, (un site web ceva mai complex, ce
primeste si manipuleaza date) limbajul in care este dezvoltat site-ul (sa
zicem PHP) trebuie sa lucreze cu un sistem de baze de date (sa zicem
MySQL). PHP-ul poate lucra si cu alte sisteme de baze de date (MS SQL,
Oracle, DB2, PostgreSQL), insa combinatia PHP cu MySQL este clasica,
pentru ca ambele softuri sunt gratuite, open-source, si au fost dezvoltate
astfel incat sa fie compatibile si sa lucreze eficient impreuna.
Pagina oficiala a limbajului MySQL: http://www.mysql.com

1.2 Instalare si configurare

Durata: 13:32
min
Marime: 13MB
Descarca tutorial in format avi
Instalarea si configurarea WAMP pe Windows. WAMP Server este o
aplicatie ce faciliteaza instalarea si configurarea programelor Apache Mysql
si PHP pe Windows, cu scopul de a dezvolta si testa aplicatii web in PHP si
MySQL.
Ai probleme cu vizualizarea filmului ? Instaleaza acest
codec sau contacteaza-ne

1.3 Editoare. Primul program PHP

Alegerea editorului este foarte importanta pentru dezvoltarea paginilor web


sau aplicatiilor in general, pentru ca are o contributie importanta la
productivitatea cu care lucrezi. Editorul ales poate fi mai simplu, sau mai
complex, in functie de preferinte. Oricat de simplu ar fi, e indicat cel putin sa
coloreze sintaxa atat pentru html si css cat si pentru php. Pentru ca de multe
ori, editorul folosit pentru realizarea codului html si css, va fi folosit si
pentru realizarea codului php. Alta facilitate importanta este posibilitatea de
a realiza shortcut-uri pentru inserarea rapida de cod.

Exista foarte multe editoare gratuite sau contra cost orientate spre
dezvoltarea web, deci spre dezvoltarea de cod html, css si php. Unele sunt
orientate mai mult spre html si css, altele sunt specializate si in programarea
in php.

Voi enumera doar cateva dintre ele:


pe Windows
Notepad++ (gratuit)
Este un editor simplu, usor de folosit si intuitiv. Coloreaza sintaxa pentru
html si php, are posibilitatea de a realiza shortcut-uri pentru inserarea
automata de cod (meniul Macro).
Pagina editorului: http://notepad-plus.sourceforge.net/uk/site.htm
HTML Kit (gratuit)
Este un editor specializat mai mult pe codul HTML, dar coloreaza sintaxa si
pentru php. Pot fi inserate fragmente de cod automat prin facilitatea auto-
completion.
Pagina editorului: http://www.htmlkit.com
Zend Studio (costa)
Zend este compania ce dezvolta limbajul PHP. Zend Studio este un IDE
(Integrated Development Environment) specializat in PHP, deci este mai
mult decat un editor.
Cateva caracteristici importante ale Zend Studio:
 coloratul sintaxei
 code assist (programul ofera optiuni pentru continuarea numelui unei
functii, variabile sau clase existente in php sau in proiectul curent)
 detectarea erorilor de sintaxa in timp ce se scrie codul
 bookmarks
 navigarea usoara intre clasele sau functiile aceluiasi proiect
 debugging si profiler
Pagina editorului: http://www.zend.com/en/products/studio/
phpDesigner 2008 (costa)
Este un editor specializat atat in HTML, CSS cat si in PHP. Are facilitati
comparabile cu cele ale aplicatiei Zend Studio: coloratul sintaxei, code
assist, navigarea usoara intre functiile, variabilele sau clasele din acelasi
proiect, debugger, profiler, etc.
Pagina editorului: http://www.mpsoftware.dk/phpdesigner.php
pe Linux
Kate
Kate este un editor de text clasic din pachetul KDE. Coloreaza sintaxa
pentru mai multe limbaje: c, c++, java, html, css, php.Kate pe Wikipedia
Kate
Quanta plus
Quanta este un IDE (Integrated Development Editor) special pentru
programarea web. Este axat deci in jurul limbajelor HTML, XHTML, CSS,
PHP si are facilitati pentru a lucra mai usor cu aceste limbaje, si pentru a
construi pagini web. Are code assist / code completion pentru limbajele
enumerate mai sus, are un sistem de shortcut-uri pentru inserarea de
fragmente de cod, editor vizual pentru HTML si CSS, si multe alte facilitati
interesante.
Quanta Plus pe Wikipedia
Quanta Plus
Emacs
Emacs este un editor (sau o clasa de editoare) cu o istorie solida in sistemul
de operare Unix. Cea mai populara versiune este editorul GNU Emacs
dezvoltat de Richard Stallman, persoana cu cel mai mare impact asupra
miscarii "free software" din care a derivat si cu care este confundata
miscarea open-source.
GNU Emacs este mult mai mult decat un editor, este o aplicatie sofisticata,
foarte flexibila, dedicata in special programatorilor, avand scopul principal
de a face editarea de text (sau cod) foarte eficienta. Exista plugin-uri ce
realizeaza coloratul sintaxei pentru orice limbaj de programare (deci inclusiv
html, css, php). Shortcut-urile pentru inserarea si manipularea de cod sunt
mult avansate fata de a celorlalte editoare si pot fi adaptate (dar nu
intotdeauna usor) la nevoile celui ce stapaneste editorul. GNU Emacs este
preferat in general de programatori si efortul pentru customizarea lui merita
pentru cei ce editeaza cod (text) 8-10 ore pe zi, ani la rand.

1.4. Interactiunea dintre PHP, serverul Web si browser

PHP este un limbaj interpretat, adica un program php este executat direct de
interpretorul PHP care este un fisier binar (numit php.exe sau php-win.exe
pe Windows si php pe Unix).

Programele PHP pot fi rulate in doua moduri:


 din linia de comanda prin apelarea interpretorului php avand ca
argument scriptul de executat. Rezultatul executiei va fi afisat pe ecran:

 cu ajutorul serverului web. Serverul web folosit in general pentru


colaborarea cu interpretorul PHP este Apache. Este in prezent cel mai
folosit server web, este un proiect open-source (ca si php si mysql), si
este gratuit.
Serverul web trebuie configurat astfel incat sa functioneze impreuna
cu interpretorul PHP. Serverul web va fi configurat astfel incat va
diferentia fisierele cu extensia .html fata de fisierele cu extensia .php
astfel:
- fisierele html le trimite direct catre browser (clientul web)
- fisierele php le va trimite interpretorului php pentru a fi executate, si
rezultatul executarii va fi trimis in final catre browser
Ca si programatori web ne intereseaza inspecial a doua optiune,
executarea programului PHP prin intermediul serverului web.
Nota
Prescurtarea LAMP este folosita in mod frecvent pentru combinatia
Linux + Apache + Mysql + PHP. PrescurtareaWAMP este folosita pentru
Windows + Apache + Mysql + PHP. In productie, (adica in conditii reale,
nu de test) site-ul web va functiona pe un server Unix/Linux ce va avea
suita Apache + PHP + Mysql instalata si configurata de un administrator
de sistem. Orice pachet de gazduire pe Linux/Unix ofera aceasta solutie,
deci nu trebuie sa te ocupi de acest lucru. Totusi, pentru cei interesati,
configurarea LAMP este prezentata in cursul Linux Server
Administration. Solutia WAMP este oferita de aplicatia WampServer si
este prezentata in capitolul Instalare si configurare.

Interactiunea dintre PHP, Apache, Mysql si clientul web


Voi lua ca exemplu accesarea adresei http://www.invata-
online.ro/courses.php pentru explicarea modului in care aceste aplicatii
interactioneaza.

Pasul 1
Utilizatorul tasteaza in browser adresa http://www.invata-
online.ro/courses.php sau da click pe un link ce trimite browserul la aceasta
adresa. Aceasta adresa, numita URL, este formata din 3 parti:
 http:// - reprezinta protocolul (setul de reguli) prin care clientul web
comunica cu serverul web. Acest protocol se numeste HTTP.
 www.invata-online.ro - reprezinta numele serverului la care clientul
trebuie sa se conecteze
 /courses.php - indica locatia resursei cautata de client pe acel server
(poate fi si mai complicata, gen: /courses/web1.php)

Pasul 2
Browserul (clientul web), prin intermediul unui server DNS afla adresa IP a
serverului www.invata-online.ro si trimite acestui server web o cerere
HTTP ce solicita resursa /courses.php de pe server.
Pasul 3
Serverul web primeste cererea HTTP si determina locatia fisierului respectiv
pe harddisk. Acest lucru se realizeaza prin configurarea
optiunii DocumentRoot sau prin configurarea de alias-uri.
DocumentRoot indica locatia de pe harddiskul serverului in care se afla si
din care sunt partajate paginile web. Astfel, calea/courses.php este
transformata de server in c:\www\courses.php, daca DocumentRoot este
setat cu valoarea c:\www.

Pasul 4
Extensia fisierului cerut fiind .php, serverul web va trimite continutul
fisierului .php catre interpretorul PHP pentru a fi executat.

Pasul 5
Interpretorul PHP citeste sursa fisierului .php, si construieste output-ul final,
ce constituie sursa paginii web ce va fi trimisa browserului. La aceasta etapa,
daca exista cereri catre serverul de baze de date, interpretorul PHP comunica
cu serverul mysql pentru interogarea bazei de date si folosirea datelor
obtinute astfel in program.

Pasul 6
Output-ul generat de interpretorul .php este trimis serverului web, si
reprezinta sursa finala a paginii web. Serverul web trimite sursa paginii catre
clientul web (browser).

Pasul 7
Browserul primeste in final sursa paginii web (cod html, css si javascript) si
o formateaza pentru a fi afisata utilizatorului.
Nota
Atat alias-urile cat si DocumentRoot sunt setari in fisierul de configurare
al serverului web. In cazul Apache-ului, fisierul de configurare se
numeste httpd.conf. Alias-urile reprezinta o corespondenta directa intre
cererea unei resurse (ex: /courses.php) si calea resursei respective in
sistemul de fisiere
(ex: c:\projects\myproject\courses.php)
Nota
Pentru a testa o pagina .php in browser, pe calculatorul local, intotdeauna
trebuie sa folosim url-ul prefixat cu http:// , ce conduce cererea noastra
catre serverul web (Exemplu: http://localhost/project/index.php). In
aplicatiile de retea (deci si penru serverul web), localhost inseamna
calculatorul curent si se traduce in adresa ip 127.0.0.1. Deschiderea
fisierului direct in browser este gresita pentru ca in acest fel nu va ajunge
la serverul web si deci nici la interpretorul php.

Nota
Codul PHP nu ajunge catre browserul web, pentru ca el este executat pe
server, iar serverul web trimite clientului web doar rezulatul executiei,
adica sursa HTML a paginii web. Deci, spre deosebire de html, css, si
javascript, care sunt numite limbaje "client-side" pentru ca sunt rulate de
browser, php este "server-side", fiind executat pe server. Daca in
browser, in meniul View -> Page source, vezi cod php, inseamna ca e o
problema, codul respectiv nu a fost executat de PHP.
1.5. Imbinarea dintre PHP si HTML

Scripturile in PHP au in general rolul de a contribui la constructia unei aplicatii web. Din acest motiv, limbajul PHP a fost gandit astfel incat sa fie
"amestecat" foarte usor cu cod html in interiorul aceluiasi fisier.
Cu toate astea, interpretorul PHP va citi si executa doar codul PHP din fisier, aflat in zone de PHP. Orice text din afara zonelor de PHP (fie el cod html sau
text simplu) va fi tratat direct ca output (rezultat final) al programului, si va fi adaugat la outputul generat de zonele de PHP, formandu-se astfel un output
final ce va fi trimis catre serverul web si apoi catre browser, ca sursa a paginii web.

Zonele de PHP sunt delimitate de restul textului (in general cod HTML) prin asa-numitele taguri de php:

1. Tagurile standard - cele mai folosite, si recomandate:

<?php
.... cod php ...
?>

2. Tagurile "scurte" ("short open tags" sau "short tags") - sunt destul de folosite, dar mai putin recomandate datorita faptului ca pot fi dezactivate
din fisierul de configurare al php-ului (php.ini) si pentru ca pot intra in conflict cu taguri din codul XML atunci cand se afla in acelasi fisier cu cod PHP.

<?
.... cod php ...
?>

Folosind tagurile "scurte" si semnul egal (=) dupa tagul de deschidere obtinem sintaxa <?=$variabila?> numita "short echo" si este echivalenta cu <?
php echo $variabila; ?>, adica este o scurtatura pentru a afisa o variabila sau rezultatul unei functii din php in interiorul codului html.

Nota
Folosirea tagurilor scurte (short open tags), si implicit a sintaxei <?=$variabila?> nu este recomandata din urmatoarele motive:
- pot fi dezactivate pe server, deci la mutarea aplicatiei pe alt server pot aparea probleme
- nu sunt recomandate de echipa PHP, fiind considerate invechite, sau non-standard

3. Tagurile script - sunt destul de rar folosite:

<script language="php">
.... cod php ...
</script>

4. Tagurile stil ASP - (ASP este un limbaj de scripting pentru web dezvoltat de Microsoft) sunt si ele destul de rar folosite si pot fi activate/dezactivate
din php.ini

<%
.... cod php ...
%>

Exemplu

Sursa script Sursa HTML in browser Vizualizare in browser


Ora serverului este 15:48:03.
1 <html> 1 <html>
2 2
3 <head> 3 <head>
4 <title></title> 4 <title></title>
5 5
6 </head> 6 </head>
7 7
8 <body> 8 <body>
9 9
10 Ora serverului 10 Ora serverului
11 este <?php echo 11 este 15:48:03.
12 date('H:i:s') ?>. 12
13 13
14 14 </body>
</body> </html>
</html>

1.6. Tema
Instaleaza WampServer sau alta solutie pentru rularea PHP pe Windows. Apoi:

 seteaza DocumentRoot catre o locatie convenabila (ex D:\www), si verifica in browser incarcarea fisierelor din locatia respectiva

 Testele PHP se pot face cu codul

1 <?php
2
3 $x = 'invat PHP';
4
5 echo $x;
6
7 ?>

 Adauga un director in DocumentRoot, si incearca incarcarea scripturilor .php in browser din acel director

 Adauga un alias, catre alta locatie, si testeaza

 Incearca generarea unei erori de tip E_NOTICE (ca in tutorial), si schimba error_reporting astfel incat sa NU se afiseze, iar apoi sa se afiseze
notice-urile. In final, setarea error_reporting e bine sa fie E_ALL (cel putin local), astfel incat sa vezi toate erorile
CAP.2. Bazele limbajului PHP I
2.1 Instructiuni. Blocuri de instructiuni
2.2 Comentarii
2.3 Variabile
2.4 Tipuri de date
2.5 Constante
2.6 Operatori
2.7 Expresii
2.8 Conversia intre tipuri de date

2.1. Instructiuni. Blocuri de instructiuni

Un script PHP este alcatuit din instructiuni. Instructiunile se termina prin punct si virgula (;). O instructiune poate fi: o atribuire de variabila, afisarea
unui text, apelarea unei functii, etc. In general se scrie cate o instructiunie pe linie, dar nu obligatoriu.

1 <?php
2 echo 'Salut ! ';
3 echo 'Numele meu este Stefan';
4 ?>

Blocurile de instructiuni apar in cazul cand acelasi grup de instructiuni este executat doar in anumite conditii sau de un anumit numar de ori.
Intalnim blocurile de instructiuni in capitolul urmator, la "Structuri de control". Un bloc de instructiunieste deschis prin { si inchis prin }. Dupa
acolade, nu se pune punct si virgula.

1 <?php
2 if ($nume == 'Stefan') {
3 echo 'Salut ! ';
4 echo 'Numele meu este Stefan';
5 } else {
6 echo 'Salut ! Ce mai faci ?';
7 }
8 ?>
2.2 Comentarii

Comentariile sunt folosite de programatori pentru a comenta sau a explica portiuni de cod. Acest lucru este necesar si este foarte indicat atunci cand se
lucreaza in echipe, sau cand codul pe care-l face un programator va fi citit si de alti programatori. Dar nu numai. Este foarte usor sa va recititi propriul
cod, atunci cand nu este foarte simplu, si reveniti peste cateva zile sau cateva luni asupra aplicatiei, pentru anumite modificari.

In concluzie, comentariile nu fac parte din codul propriu-zis, sunt ignorate de interpretor.

Comentariile pe mai multe linii se deschid cu /* si se inchid cu */


Comentariile pe o singura linie incep cu simbolul // (dublu slash) sau # (diez)

Sursa script Vizualizare in browser


O instructiune in PHP
1 <?php
2 /* aici avem
3 un comentariu
4 pe mai multe linii */
5
6 echo 'O instructiune in PHP';
7
8 // alt comentariu
9 # un al 3-lea comentariu
10
11 ?>

Daca pe linia comentata avem tagul de inchidere al zonei de php, eventualul text html ce urmeaza dupa acest tag va fi bineinteles tratat ca output.
Sursa script Vizualizare in browser
text in HTML
1 <?php
2
3 // echo 'aceasta instructiune
este comentata' ?> text in HTML

2.3. Variabile
Ce sunt variabilele ?
Un program lucreaza cu anumite date, cu anumite valori. Un programator, in timp ce scrie codul sursa pentru un program, nu stie si nici nu trebuie sa stie
care sunt valorile respective de fiecare data cand programul se executa. Majoritatea valorilor/datelor sunt calculate dinamic, la fiecare executie a
programului. Daca valorile respective ar fi cunoscute, probabil programul nu si-ar mai avea rostul. De exemplu, realizez un program ce face o cautare intr-
o baza de date dupa un cuvant introdus de utilizator. In momentul cand scriu programul, nu stiu care este cuvantul respectiv, pentru ca acel cuvant va fi
primit ca input de la utilizator la fiecare executie a programului. Nici nu stiu ce rezultate voi afisa prin program. Pentru ca acele rezultate vor fi calculate
dinamic in functie de cuvantul introdus. Atat cuvantul introdus de utilizator cat si rezultatele returnate, vor fi tinute in variabile.

Definitie
Variabilele sunt nume, etichete (abstractizari) ale datelor cu care lucram. Tehnic, o variabila face o referire la o zona din memoria RAM a calculatorului. In
momentul cand atribuim o valoare unei variabile, in zona respectiva de memorie este tinuta valoarea respectiva. Putem atribui de oricate ori aceleasi
variabile alte valori.

Nota
Numele de variabile PHP sunt case-sensitive (conteaza litera mare / mica ) dar numele de functii si clase nu sunt ! Asta inseamna ca $nume este
diferit de $Nume

Variabilele PHP incep cu simbolul $, urmat de o combinatie de litere, cifre sau underscore (_). Primul caracter de dupa $ este obligatoriu litera sau
underscore.

1 <?php
2 $nume persoana = 'John Smith'; // eroare: am spatiu in numele
3 variabilei
4 $nume-persoana = 'John Smith'; // eroare: am - in numele variabilei
5 $numePersoana = 'John Smith'; // corect
6 $numePersoana23 = 'John Smith'; // corect: am si cifre, dar nu se afla
7 la inceput
8 $2numePersoana = 'John Smith'; // eroare: am cifra la inceput
$nume_persoana = 'John Smith'; // corect
?>

Initializarea unei variabile


O variabila capata o valoare prin operatorul de atribuire/asignare (=). Variabila poate fi folosita apoi in program, sau pur si simplu afisata cu
constructia echo, de care vom vorbi mai tarziu.

Sursa script Vizualizare in browser


55
1 <?php
2 $a = 5;
3 $b = 5;
4 echo $a;
5 echo $b;
6 ?>

Nota
Asa cum deja ati observat, instructiunile de afisare in PHP sunt pe linii diferite dar outputul (sirul de caractere rezultat din program) este continuu,
adica nu contine newline (\n) sau spatiu intre diferitele valori afisate. Si chiar daca ar contine newline, in browser newline-ul se traduce printr-un
spatiu. Cand vrem sa vedem o valoare pe o alta linie, introducem inainte instructiunea echo '<br />'; ca sa adaugam echivalentul newline-ului in
HTML pentru afisarea pe care o dorim in browser.

Exemplul de mai sus poate arata astfel:

Sursa script Vizualizare in browser


55
1 <?php
2 $a = 5;
3 $b = 5;
4 echo $a;
5 echo ' ';
6 echo $b;
7 ?>

sau:

Sursa script Vizualizare in browser


5
1 <?php 5
2 $a = 5;
3 $b = 5;
4 echo $a;
5 echo '<br />';
6 echo $b;
7 ?>

isset(), unset(), NULL


O variabila neinitializata are implicit valoarea NULL. Valoarea NULL este singura valoarea posibila din tipul de date cu acelasi nume, NULL.
NULL este un cuvant rezervat in PHP si este case-insensitive. Cand "distrugem" o variabila cu ajutorul functiei unset(), memoria alocata variabilei
respective este eliberata, si variabila va deveni NULL. Cu ajutorul functiei isset() verificam daca o variabila a fost setata. isset($var) va returna TRUE daca
$var este setata, si FALSE daca $var nu este setata sau a fost distrusa cu unset().

Sursa script Vizualizare in browser


NULL
1 <?php abia acum a este setat
2
3 echo $a; // nu se afiseaza nimic
4 echo gettype($a); // se
5 afiseaza: NULL
6 echo '<br />';
7
8 /* isset($a) va returna FALSE
9 deci
10 instructiunea din if nu va fi
11 executata
12 */
13
14 if (isset($a)) {
15 echo 'a este setat';
16 }
17
18 $a = 5;
19
20 if (isset($a)) {
21 echo 'abia acum a este setat';
22 }
23
24 unset($a);
25
26
27 if (isset($a)) {
28 echo 'mai este a setat ? '; //
29 nu
}

?>

empty()
Functia empty() este deseori utila in verificarea variabilelor. Ca si isset() sau unset() primeste ca argument numele unei variabila. empty() verifica daca
variabila respectiva are o valoare "goala" sau "empty" caz in care returneaza TRUE. Altfel, returneaza FALSE. Urmatoarele valori sunt considerate "empty":

 NULL - deci empty() poate primi ca argument un nume de variabila neinitializata (cu valoarea null), si NU va genera o eroare. Bineinteles va
returna TRUE

 "" - sirul gol

 0 (intregul 0)

 "0" (stringul 0)

 FALSE

 array() - un array fara elemente

In multe cazuri, este mai simplu sa folosim empty() in loc sa folosim isset() si sa verificam apoi ca variabila respectiva are valoare. Ex: if (empty($nume))
versus if (isset($nume) && $nume != "")
Sau, pentru un array: if (empty($data)) versus if (isset($data) && count($data))

2,4, Tipuri de date


2.4.1 bool sau boolean
2.4.2 int sau integer
2.4.3 float
2.4.4 string
In PHP, in functie de valorile primite, variabilele au un anumit tip de date.

Important
Spre deosebire de alte limbaje (C, Java), programarea in limbajul PHP implica mult mai putin efort in lucrul cu variabile pentru ca este un limbaj "weakly
typed" (sau "loosely typed") adica:

 NU trebuie sa declaram tipul de date al unei variabile (ex: int x;) ... folosim direct variabila respectiva, atribuindu-i o valoare (ex: $a = 3;)

 tipul de date al unei variabile va fi determinat de tipul valorii atribuite

 aceeasi variabila isi poate schimba tipul de date pe parcursul executiei unui program

1 <?php
2 $a = 3; // a este de tip integer
3 $a = 'abc'; // a este acum de tip string
4
5 ?>

Schimbarea tipului de date al unei variabile


Tipul de date al unei variabile poate fi schimbat in urmatoarele conditii:
 prin atribuirea unei valori variabilei respective

 conversia explicita - convertim variabila la un anumit tip de date, cu ajutorul functiei settype(). Ex: setttype($a, 'string'). $a are acum tipul
string.

 cast - intr-un anumit context, fortam tipul de date al variabilei; acest lucru se obtine punand tipul de date nou intre paranteze, urmat de
variabila. ex: $b = (string)$a; Desi $b are valoarea lui $a convertita la string, tipul variabilei $a este neschimbat. Asta inseamna ca tipul
variabilei $a este fortat la string doar in expresia respectiva.

 conversia automata - in PHP se realizeaza conversii implicite (automate) in functie de locul (contextul, operatia, operanzii) in care este
folosita o anumita variabila. Variabila nu-si schimba tipul de date decat in acel context (expresie), cand este evaluata.

Acest subiect este dezbatut pe larg in capitolul Conversia intre tipuri de date.

Tipuri de date in PHP


In PHP exista urmatoarele tipuri de date:

 tipuri de date scalare - ce pot avea o singura valoare:

o int sau integer - tip de date folosit pentru a reprezenta numerele intregi. inclusiv cele negative (ex: $a = -4; // a este int)

o float - tip de date folosit pentru a reprezenta numerele cu zecimale (ex: $a = 2.3; // a este float)

o string - valori ce reprezinta sir de caractere. Se scriu intre apostroafe sau ghilimele. (ex: $a = 'acasa'; // a este string)

o bool sau boolean - acest tip de date poate avea doar doua valori, adevarat sau fals Aceste valori sunt cuvintele
cheie TRUE sau FALSEsi sunt case-insensitive.

 tipuri de date compuse - variabilele ce au acest tip sunt formate din informatii compuse, fiecare informatie putand avea alt tip
de date:

o array - acest tip de date este compus din mai multe elemente. Fiecare element este o pereche formata dintr-o cheie si o
valoare. Cheile pot fi intregi sau stringuri, valorile pot avea orice tip de date

o object - o colectie de variabile (proprietati) si functii (metode)

 tipuri de date speciale:

o resource - variabilele din tipul resource sunt folosite pentru a memora informatii externe programului (referinta catre un fisier
deschis, rezultatul interogarii unui tabel dintr-o baza de date, etc)

o NULL - tip de date ce indica faptul ca o variabila nu este setata.

*Atat in aceasta documentatie cat si in cea oficiala se vorbeste despre tipul de date numar (number) ce se refera de fapt la faptul ca acea valoare este
un int sau un float.
Verificarea tipului de date

Functia gettype($var) primeste ca parametru o variabila, si returneaza tipul de date al variabilei respective. Functia va returna: boolean, integer, double
(echivalent cu float), string, array, object, resource, NULL

Nota
Manualul PHP nu recomanda folosirea acestei functii pentru a testa daca o variabila are un anumit tip. Pentru acest lucru, se recomanda folosirea
functiilor ce incep cu "is_".

Functiile destinate testarii tipului de date al unei variabile, sunt:

 is_int($var) - verifica daca $var are tipul int

 is_float($var) - verifica daca $var are tipul float

 is_bool($var) - verifica daca $var are tipul bool sau boolean

 is_string($var) - verifica daca $var are tipul string

 is_array($var) - verifica daca $var are tipul array

 is_null($var) - verifica daca $var are tipul null. Acest tip de date permite o singura valoare, valoarea NULL; asta inseamna ca implicit
variabila are valoarea NULL, deci nu este setata.

 is_numeric($var) - verifica daca $var este un numar (int sau float) sau un string numeric, ex: "23"

 is_scalar($var) - verifica daca $var are un tip scalar, adica unul din tipurile: int, float, boolean sau string.

 is_object($var) - verifica daca $var este de tip object

 is_resource($var) - verifica daca $var este de tip resource


Sursa script Sursa HTML in browser
1 <?php 1 integer double string boolean
2 $a = 3; array
3 echo gettype($a); // output:
4 integer
5 echo ' ';
6
7 $b = 2.45;
8 echo gettype($b); // output:
9 double
10 echo ' ';
11
12 $c = 'abc';
13 echo gettype($c); // output:
14 string
15 echo ' ';
16
17 $d = true;
18 echo gettype($d); // output:
19 boolean
20 echo ' ';
21
$e = array(2, 3, 4);
echo gettype($e); // output:
array
echo ' ';
?>

Sursa script Sursa HTML in browser


1 <?php 1 este intreg. acum este string.
2 $a = 3; 3.3 este numeric. stringul '243'
3 este numeric.
4 if (is_int($a)) { // true
5 echo 'este intreg. '; //
6 afiseaza
7 }
8
9
10 $a = 'ceva';
11
12 if (is_int($a)) { // false
13 echo 'este string. '; // nu
14 afiseaza
15 }
16
17 if (is_string($a)) { // true
18 echo 'acum este string. '; //
19 afiseaza
20 }
21
22 $a = 3.3;
23
24 if (is_numeric($a)) { // true
25 echo '3.3 este numeric. ';
26 }
27
28 $a = '243';
29
30 if (is_numeric($a)) { // true
echo "stringul '243' este
numeric. "; // afiseaza
}
?>

Afisarea informatiilor despre o variabila se poate face si cu var_dump($arg1, $arg2....);. var_dump() primeste un numar variabil de argumente si
afiseaza pentru fiecare variabila valoarea si tipul variabilei si eventual alte informatii (lungime, elemente componente pentru variabilele array, object).

Sursa script Sursa HTML in browser Vizualizare in browser


int(3)
1 <?php 1 int(3) float(-12.4)
2 $a = 3; 2 <br>float(-12.4) string(6) "abc123"
array(3) { [0]=> string(1) "a" [1]=> int(1) [2]=>
3 var_dump($a); 3 <br>string(6) float(-2.3) }

4 echo '<br>'; 4 "abc123"


5 5 <br>array(3) {
6 $a = -12.4; 6 [0]=>
7 var_dump($a); 7 string(1) "a"
8 echo '<br>'; 8 [1]=>
9 9 int(1)
10 $a = 'abc123'; 10 [2]=>
11 var_dump($a); 11 float(-2.3)
12 echo '<br>'; 12 }
13 <br>
14 $a = array('a', 1,
15 -2.3);
16 var_dump($a);
17 echo '<br>';
18
19
?>

2.4.1.bool sau boolean


Definitie
Acest tip de date poate avea doar doua valori, TRUE sau FALSE. Aceste valori sunt cuvinte cheie si sunt case-insensitive. Valorile NU trebuie incluse intre
ghilimele.

1 <?php
2 $x = TRUE; // x are acum tipul boolean si valoarea booleana TRUE
3 ?>

In functie de context si operatori, anumite expresii (sau variabile) vor fi evaluate la tipul de date boolean, deci se va stabili valoarea TRUE sau FALSE
pentru expresiile (variabilele) respective. De exemplu, in constructia if (expresie) expresia din paranteze va fi evaluata ca boolean. La fel si
operatorul == al carui rezultat este o valoarea booleana.

Sursa script Sursa HTML in browser


1 <?php 1 Este adevarat
2 $nume ='John';
3
4 /*
5 conditia de egalitate intre
6 stringurile 'Ion' si 'John' nu
7 se respecta,
8 asta inseamna ca expresia $nume
9 == 'Ion' e evaluata la FALSE
10 */
11
12 if ($nume == 'Ion') {
13 echo 'Ma numesc Ion'; // nu se
14 afiseaza
15 }
16
17 if (TRUE) {
18 echo 'Este adevarat'; // se
19 afiseaza
20 }
21
22 $b = false;

if ($b) {
echo 'b nu este adevarat'; //
nu se afiseaza
}
?>

Sursa script Sursa HTML in browser


1 <?php 1 bool(false)
2 $a = (1 > 2); // expresia (1 < 2) 2 bool(true)
3 este evaluata la FALSE, prin
4 urmare $a devine FALSE
5 var_dump($a);
6
7 $b = 5;
8 $a = (6 > $b); // $a devine true
var_dump($a);
?>

2.4.2.int sau integer

Definitie
Este tipul numerelor intregi, cu semn. ex: -23, 7, 1999.

In general numerele intregi sunt specificate in baza 10, dar in anumite cazuri se foloseste baza 16 (hexazecimal) sau baza 8 (octal). Pentru a specifica o
valoare in hexazecimal, se pune "0x" inaintea valorii respective. Pentru octal se pune "0" inainte.

Sursa script Sursa HTML in browser


1 <?php 1 int(-5)
2 $a = -5; 2 int(83)
3 var_dump($a); 3 int(26)
4
5 $a = 0123; // numar octal
6 (echivalent to 83 zecimal)
7 var_dump($a);
8
9 $a = 0x1A; // numar hexazecimal
10 (echivalent to 26 zecimal)
var_dump($a);
?>

Dimensiunea unui nr intreg in PHP depinde de platforma, dar de obicei este reprezentat pe 32 de biti (cu semn) adica intre: -2147483648 si 2147483647
(2 miliarde, 147 de milioane...). Numerele ce depasesc aceste limite sunt convertite automat la float. Dimensiunea maxima a unui intreg pe platforma pe
care ruleaza un script este completata automat in constanta predefinitaPHP_INT_MAX

Sursa script Sursa HTML in browser


1 <?php 1 int(9223372036854775807)
2 2 float(9.2233720368548E+18)
3 $a = PHP_INT_MAX; 3 int(-9223372036854775808)
4 var_dump($a); // int maxim 4 float(-9.2233720368548E+18)
5
6 $b = $a + 1;
7 var_dump($b); // devine float
8
9 $c = -$a -1;
10 var_dump($c); // int minim
11 (valoarea negativa cea mai mica
12 pe care o poate lua un int)
13
14 $c = $c -1;
var_dump($c); // devine float
?>

Nota
Impartirea dintre doua numere intregi care NU se impart exact este float.

Sursa script Sursa HTML in browser


1 <?php 1 int(2)
2 $a = 4/2; 2 float(1.5)
3 var_dump($a);
4
5 $a = 3/2;
6 var_dump($a);
7
8 ?>

2.4.3.float

Definitie
float este tipul numerelor cu zecimale. ex: 2.3 , -19.08

Numerele float pot fi exprimate in php folosind si sintaxa exponentiala, cu ajutorul literei e. Numarul ce urmeaza dupa litera ereprezinta o putere a lui 10.
ex: 3.4e3 este echivalent cu 3.4 * 103 adica 3400.
Sursa script Sursa HTML in browser
1 <?php 1 float(2.33)
2 $a = 2.33; 2 float(14090)
3 var_dump($a); // float(2.33) 3 float(0.087216)
4
5 $a = 14.09e3;
6 var_dump($a); // float(14090)
7
8 $a = 87.216e-3;
9 var_dump($a); // 87.216 se
10 inmulteste cu 10 la puterea -3.
afiseaza: float(0.087216)
?>

Tipul de date float poate intinde capcane in anumite cazuri. Nu se recomanda verificarea egalitatii a doua numere floatdatorita modului in care sunt
reprezentate intern si preciziei limitate.

Sursa script Sursa HTML in browser


1 <?php 17
2 /*
3 afiseaza: 7. desi 0.8 * 10 este
4 8.
5 Dar, rezultatul 0.7 + 0.1 este
6 tinut intern ca 7.9999,
7 convertit la int => 7
8 */
9 echo (int)((0.1 + 0.7) * 10);
10 // afiseaza 7
11
12 echo "\n";
13
14 /*
15 numerele foarte mari au o
16 precizie limitata (adica nu sunt
17 reprezentate exact si complet)
18 din acest motiv desi a2 este a1
19 - 1, comparandu-le cu PHP ele
20 sunt egale
21 */
22 $a1 = 12345678901234567;
23 $a2 = $a1 - 1;
24 if ($a1 == $a2) {
echo 'a1 si a2 sunt egale desi
nu sunt de fapt';
echo "\n";
var_dump($a1);
var_dump($a2);

}
?>

2.4.4. string

Definitie
string este un tip de date folosit pentru a reprezenta siruri de caractere. Valorile de tip string se scriu (de cele mai multe ori) intre ghilimele simple (ex:
$s = 'abc') sau intre ghilimele duble (ex: $s = "abc").

Exista diferente foarte importante intre cele doua sintaxe (folosirea ghilimelelor duble sau simple). Un string intre ghilimele simple este reprezentat exact
asa cum este scris. In schimb, anumite caractere ce apartin unui string intre ghilimele duble vor avea inteles special.

Mai precis, in stringurile cu ghilimele duble se intampla doua lucruri:

 variabilele sunt inlocuite cu valoarea lor

 caracterele de control (newline, tab) pot fi reprezentate prin caracterul \ (backslash) urmat de alte caractere. ex: \n (newline) , \t (tab)

Nota
In browser (in HTML), newline-ul (\n) este interpretat ca un simplu spatiu. In schimb, cand vedem sursa paginii HTML newline-ul este chiar trecerea
pe o linie noua.
Pentru a vizualiza in browser un newline trebuie, sa folosim <br />

2.5. Constante
Definitie
O constanta este o eticheta pentru o valoare simpla, ce nu poate fi schimbata. Numele constantelor sunt case-sensitiv, ca si variabilele. Constantele sunt
definite doar cu ajutorul functiei define() care ia 2 parametri. Primul este numele constantei, al doilea este valoarea ei.
Valorile unei constante pot fi doar de tip scalar (int, float, boolean, string). Constantele NU au semnul $ in fata.

Sursa script Vizualizare in browser


John
1 <?php 24
2 define('NUME', 'John');
3 define('NUMAR', 24);
4 echo NUME;
5 echo "<br />";
6 echo NUMAR
7
8 ?>

1 <?php
2 SITE = 'www.invata-online.ro'; // eroare. nu asa se defineste o
3 constanta
4 define('SITE', 'www.invata-online.ro');
5
6 define('SITE', 'www.invataonline.ro'); // eroare. o constanta nu-si
7 poate schimba valoarea

?>
Sursa script Sursa HTML in browser
1 <?php 1 Numarul este 5
2 $numar = 5; 2 Linie2
3 3 Linie3
4 $d = "Numarul este $numar \n";
5 echo $d;
6
7 $e = "Linie2\nLinie3";
8 echo $e;
9 ?>

acelasi exemplu, folosind ghilimele simple (variabilele nu sunt substituite, si, in plus, secventa "\n" nu mai este speciala):

Sursa script Sursa HTML in browser


1 <?php 1 Numarul este $numar
2 $numar = 5; \nLinie2\nLinie3
3
4 $d = 'Numarul este $numar \n';
5 echo $d;
6
7 $e = 'Linie2\nLinie3';
8 echo $e;
9 ?>

Caracterul backslash (\) indeplineste rolul de a reprezenta caractere de control in stringurile cu ghilimele duble asa cum am vazut mai sus, dar mai
indeplineste un rol, acela de escape character, adica ajuta la anularea caracterului special pentru anumite caractere pentru inserarea acestora in
interiorul stringului. De exemplu, nu putem insera (decat precedate de backslash) ghilimele duble in interiorul unui string pe care-l scriem intre ghilimele
duble , pentru ca interpretorul PHP va termina stringul acolo unde intalneste ghilimele duble. Similar, daca dorim inserarea caracterului dolar ($) in
interiorul unui string cu ghilimele duble, interpretorul va incerca sa gaseasca o variabila, pentru a-i anula acest sens (de inceput de variabila) trebuie sa-l
precedam cu backslash (\). La fel si in cazul inserarii ghilimelelor simple in interiorul unui string intre ghilimele simple.

Sursa script Sursa HTML in browser


1 <?php 1 Il cheama O'Connor. Probabil e
2 2 irlandez ?
3 $s = 'Il cheama O\'Connor. 3 Caracterul \ are rol de "escape
4 Probabil e irlandez ?'; 4 character"
5 echo $s; Aici \n nu voi mai avea un
6 echo "\n"; newline desi sunt intre ghilimele
7 duble
8 $s = "Caracterul \ are rol de Voi scrie chiar numele variabilei
9 \"escape character\" "; $numar
10 echo $s;
11 echo "\n";
12
13 /* Caracterul \ poate fi folosit
14 si pentru a-si anula propriului
15 caracter special. */
16 $s = "Aici \\n nu voi mai avea
17 un newline desi sunt intre
18 ghilimele duble";
19 echo $s;
echo "\n";

$numar = 5;
$s ="Voi scrie chiar numele
variabilei \$numar";
echo $s;
?>

Sintaxa heredoc
Sintaxa heredoc este folosita pentru reprezentarea stringurilor in mod similar cu ghilimelele duble, prin urmare variabilele sunt inlocuite cu valorile lor, si
pot fi inserate caractere de control cu ajutorul caracterului \. Heredoc are totusi un avantaj fata de ghilimelele duble, pentru stringuri mai complexe in care
probabilitatea sa apara chiar ghilimelele duble in interiorul stringului este foarte mare. Mai ales cand stringul respectiv este cod html, si atributele din html
sunt inconjurate de ghilimele duble. Pentru a folosi heredoc, scriem <<< de la capatul randului, apoi imediat un sir de caractere (numit identificator) apoi
newline (trecem la linia urmatoare) si scriem sirul dorit. Apoi pe o noua linie, de la capat, scriem din nou identificatorul urmat de ;.

Sursa script Sursa HTML in browser Vizualizare in browser


1 <?php 1 <table border="1" John Doe
2 $prenume = 'John'; 2 cellspacing="0" Da, prenumele lui este "John"
3 $nume = 'Doe'; 3 cellpadding="4">
4 4 <tr>
5 /* 5 <td>John</td>
6 atat prima linie din 6 <td>Doe</td>
7 heredoc (ce contine 7 </tr>
8 <<< urmate de </table>
9 identificator) Da, prenumele lui
10 cat si ultima linie este "John"
11 (identificator si ;)
12 trebuie sa NU
13 contina alte
14 caractere
15 pe aceeasi linie
16 inainte sau dupa.
17 Daca obtineti o
18 eroare aici,
19 verificati sa nu fie
20 spatiu dupa <<<STR
21 sau inainte de STR;
22 */
23
24 $s = <<<STR
<table border="1"
cellspacing="0"
cellpadding="4">
<tr>

<td>$prenume</td>
<td>$nume</td>
</tr>
</table>
Da, prenumele
lui este "$prenume"
STR;

echo $s;
?>

Concatenarea stringurilor
Important
Operatorul pentru concatenarea (unirea) stringurilor este punct (.).

Unul din cazurile cand avem nevoie de concatenare apare daca vrem sa afisam valoarea unei variabile in interiorul unui string intre ghilimele simple.

Sursa script Vizualizare in browser


Se numeste $nume
1 <?php Se numeste Maria
2 $nume = 'Maria'; Se numeste Maria

3
4 echo 'Se numeste $nume'; //
5 output: Se numeste $nume
6 echo '<br /> ';
7 echo 'Se numeste '.$nume; //
8 output: Se numeste Maria
9 echo '<br /> ';
echo "Se numeste $nume"; // nu e
nevoie sa concatenam. output: Se
numeste Maria
?>

Alte exemple de concatenare:

Sursa script Vizualizare in browser


Ion Popescu
1 <?php
2 $prenume = 'Ion';
3 $nume = 'Popescu';
4
5 $str = '<b>'.$prenume.' '.
6 $nume.'</b>';
7 echo $str;
?>

Important
Operatorul .= (punct urmat de egal) este echivalent cu adaugarea stringului din dreapta operatorului la stringul din stanga. Adica $str .= 'ceva'; este
echivalent cu $str = $str . 'ceva';

Sursa script Vizualizare in browser


1 <?php Ion Popescu are cnp: 1720215440033
2 $str = '';
3 $cnp = '1720215440033';
4 $prenume = 'Ion';
5 $nume = 'Popescu';
6
7 $str .= $prenume;
8 $str .= ' ';
9 $str .= $nume;
10 $str .= ' are cnp: ';
11 $str .= $cnp;
12
13 echo '<h2>'.$str.'</h2>';
14 ?>

2.6. Operatori
2.6.1 Operatori aritmetici
2.6.2 Operatori de atribuire
2.6.3 Operatori de comparare
2.6.4 Operatorii ++ si --
2.6.5 Operatori logici
2.6.6 Operatorul de concatenare
2.6.7 Operatorul ternar
Definitie
Operatorii sunt folositi pentru efectuarea diferitelor operatii intre doua sau mai multe valori (sau expresii), numite operanzi. Rezultatul operatiei este o alta
valoare.
De multe ori, operatorii (sau alte constructii de limbaj in PHP) convertesc tipul operanzilor din operatia respectiva.

Operatorii au o prioritate diferita, deci nu putem prezice intotdeauna ordinea in care se fac operatiile intr-o expresie complexa. Daca vrem sa fortam
ordinea in care se fac operatiile, folosim paranteze.

Sursa script Sursa HTML in browser


1 <?php 1 int(22)
2 $a = 2 + 4 * 5; // * are o 2 int(30)
3 prioritate mai mare decat +
4 var_dump($a);
5
6 $a = (2+4) * 5;
7 var_dump($a);
8
?>

2.6.1.Operatori aritmetici

Operatorii aritmetici realizeaza operatiile matematice de baza.

+ adunare

- scadere

* inmultire

/ impartire. Daca impartirea nu este exacta, rezultatul este de tip float

% modulo. Restul impartirii primului operand la cel de-al doilea

Important
Operatorii aritmetici converesc operanzii la valori numerice (int sau float) !

1 <?php
2
3 $x = 3;
4 $y = 5;
5
6 $a = $x + $y;
7 echo $a; // 8
8
9 $b = $x - $y;
10 echo $b; // -2
11
12 $c = $x * $y;
13 echo $c; // 15
14
15 $d = $x / $y;
16 echo $d; // 0.6 - float
17
18 $e = $x % $y;
19 echo $e; // 3
20
21 ?>

Sursa script Sursa HTML in browser


1 <?php 1 int(4)
2 $a = true; 2 float(3.3)
3 $b = 3; 3 int(3)
4 $c = 2.3; 4 int(4)
5 $d = "3 lei";
6 $e = "John";
7
8 var_dump($a + $b); // int(4) -
9 valoarea booleana true se
10 converteste la intreg si devine
11 1
12 var_dump($a + $c); // float(3.3)
var_dump($b + $e); // int(3) -
$e este string, si convertit la
intreg este 0. Si atunci,
expresia devine 3 + 0 = 3
var_dump($a + $d); // int(4) -
true este converit la 1,
stringul "3 lei" este convertit
la 3.
?>

2.6.2. Operatori de atribuire

Operatorul de atribuire este "=". $a = 4 atribuie valoarea din dreapta semnului, "4", variabilei din stanga, "$a".
$a = 4 o numim expresie, sau expresie de atribuire. Aceasta expresie are si ea insasi o valoare, si anume valoarea atribuita. Adica, expresia ($a=4) are
valoarea 4.

Sursa script Sursa HTML in browser


1 <?php 1 int(2)
2 $x = 2; 2 int(2)
3 $y = $x; 3 int(17)
4 var_dump($x); // 2 4 int(2)
5 var_dump($y); // 2
6
7 $y = 17;
8 var_dump($y); // 17
9 var_dump($x); // 2
10
11 ?>

Exemplul urmator pune in evidenta valoarea unei expresii de atribuire.

Sursa script Sursa HTML in browser


1 <?php 1 int(5)
2 /* 2 int(5)
3 atribuirile (=) intr-o expresie 3 int(8)
4 sunt evaluate de la dreapta la
5 stanga.
6 asta inseamna ca este evaluat
7 intai $b = 5: $b ia valoarea 5
8 si in plus expresia ($b = 5) ia
9 valoarea 5
10 apoi este evaluat $a = expresie
11 unde expresie este $b = 5, si
12 expresie are valoarea 5. Deci si
13 $a devine 5
14 */
15
16 $a = $b = 5;
var_dump($b);
var_dump($a);

$y = ($x = 3) + 5; // ($x = 3)
seteaza variabila $x la 3 si in
plus este o expresie cu valoarea
3. $y devine 8

var_dump($y);
?>

+= , -=, *= ...
Operatorul de asignare poate fi combinat cu operatorii aritmetici si cu operatorul de concatenare stringuri astfel:

Sursa script Sursa HTML in browser


1 <?php 1 int(6)
2 $a = 1; 2 int(12)
3 $a += 5; // echivalent cu $a = 3 int(6)
4 $a + 5; 4 string(8) "6un text"
5 var_dump($a);
6
7 $a *= 2; // echivalent cu $a =
8 $a * 2
9 var_dump($a);
10
11 $a /= 2; // echivalent cu $a =
12 $a / 2;
13 var_dump($a);
14
$a .= 'un text';
var_dump($a) // echivalent cu $a
= $a . 'un text'; $a (atat
operandul cat si rezultatul)
este transformat in string de
operatorul de concatenare
?>

2.6.3. Operatori de comparare

Definitie
Operatorii de comparare stabilesc daca doua expresii (valori) sunt egale (sau diferite), sau daca una din ele este mai mare (mai mica) decat cealalta.
Rezultatul operatiei de comparare este de tip boolean (true sau false)

Operatorii de comparare sunt:

== Egalitate. Returneaza true daca ambii operanzii au aceeasi valoare (chiar daca nu au acelasi tip).

=== Identitate. Returneaza true daca ambii operanzi au aceeasi valoare si acelasi tip de date.

!= Valori diferite. Returneaza true daca operanzii au valori diferite.

<> Sinonim cu !=

!== Returneaza true daca au valori diferite, sau tip de date diferit.

< mai mic

<= mai mic sau egal

> mai mare

>= mai mare sau egal


Sursa script Sursa HTML in browser
1 <?php 1 bool(false)
2 $x = (1 > 2); 2 bool(true)
3 var_dump($x); // false 3 bool(true)
4 4 bool(false)
5 $x = (3 == 3); 5 bool(true)
6 var_dump ($x); // true 6 bool(true)
7 7 bool(false)
8 $x = ('3' == 3);
9 var_dump ($x); // true
10
11 $x = ('3' === 3);
12 var_dump ($x); // false - au
13 valori egale dar tip de date
14 diferit (primul operand e
15 string, al doilea e intreg)
16
17 $x = ('3' !== 3);
18 var_dump($x); // true - au tip
19 de date diferit
20
21 $x = (1 != 2);
22 var_dump($x); // true
23
$x = (3 >= 4);
var_dump($x); // false

?>
Nota
Cand se foloseste un operator de comparare pentru a compara un string cu un numar ambii operanzi sunt convertiti la numar (int sau float).
Acelasi lucru se intampla cand ambii operanzi sunt stringuri numerice.
Sursa script Sursa HTML in browser
1 <?php 1 bool(true)
2 $a = 2; 2 bool(true)
3 $b = '3'; 3 string(1) "3"
4 var_dump($a < $b); // true - '3' 4 bool(true)
5 este convertit la int(3) 5 bool(false)
6
7 $a = 3;
8 $b = '3';
9 var_dump($a == $b); // true -
10 $b este convertit la int(3) si
11 este egal cu $a
12 var_dump($b); // $b este in
13 continuare string. conversia a
14 fost facuta doar in cadrul
15 expresiei de comparare
16
17 $a = 'text';
18 $b = 0;
19
20
21 /*
22 cand se compara un string cu un
23 numar,
24 se convertesc ambii operanzi la
25 numar.
26 in acest caz la intreg. 'text'
27 convertit la intreg este 0
28 */
var_dump($a == 0); // true.

$a = '3text';
$b = 2;
var_dump($a == $b) // false -
'3text' convertit la intreg este
3

?>

2.6.4. Operatorii ++ si --

Definitie
Operatorul ++ se numeste operator de incrementare si are ca rezultat cresterea variabilei cu o unitate. Operatorul --se numeste operator de
decrementare si are ca rezultat scaderea variabilei cu o unitate.

$x++ post incrementare. Expresia returneaza valoarea lui x, si apoi creste x cu o unitate

++$x pre incrementare. Expresia creste x cu o unitate, si apoi il returneaza pe x (deja crescut cu o unitate)

$x-- post decrementare

--$x pre decrementare


Sursa script Sursa HTML in browser Vizualizare in browser
$x++ este : 1 $x este acum: 2 ++$y este : 2 $y
1 <?php 1 $x++ este : 1 este acum: 2 4 5
2 $x = 1; 2 $x este acum: 2
3 3
4 echo '$x++ este : '. 4 ++$y este : 2
5 $x++; 5 $y este acum: 2
6 echo "\n"; 6
7 echo '$x este acum: 74
8 '.$x; 8
9 95
10 $y = 1;
11
12 echo "\n\n";
13
14 echo '++$y este : '.
15 ++$y;
16 echo "\n";
17 echo '$y este acum:
18 '.$y;
19
20
21 echo "\n\n";
22
23 $e = 3;
24 $a = ($e++) + 1;
25 echo $a;
26
27 echo "\n\n";
28
29 $e = 3;
$a = (++$e) + 1;
echo $a;

?>

2.6.5. Operatori logici

Definitie
Operatorii logici sunt folositi pentru a opera cu valori boolene iar rezultatul acestor operatori este tot o valoare booleana.

&& SI logic. Rezultatul este true daca ambii operanzi sunt evaluati boolean ca true.

|| SAU logic. Rezultatul este true daca cel putin unul din cei doi operatori este evaluat boolean ca true.

and SI logic. Similar cu && dar cu o prioritate mai mica.

or SAU logic. Similar cu or dar cu o prioritate mai mica

xor SAU exclusiv true daca operanzii sunt diferiti, si false daca operanzii sunt egali.

Alt operator logic este "!". Doar ca are un singur operand, si se aseaza in fata acestui operand. Operatorul inverseaza valoarea booleana a
operatorului.

Sursa script Sursa HTML in browser


1 <?php 1 bool(false)
2 $a = true; 2 e adevarat
3 $b = !$a; // $b devine false
4
5 var_dump($b);
6
7 // $b e false. atunci !$b este
8 true
9 if (!$b) {
10 echo 'e adevarat';
11 }
12
?>

Sursa script Sursa HTML in browser


1 <?php 1 bool(false)
2 var_dump(true && false); 2 bool(true)
3 var_dump(true && true); 3 bool(true)
4 var_dump(true || false); 4 bool(true)
5 var_dump(false || true);
6 ?>

pot folosi paranteze pentru a dicta ordinea operatiilor.

Sursa script Sursa HTML in browser


1 <?php 1 bool(false)
2 $a = false && (false || true); 2 bool(true)
3 var_dump($a);
4
5 $a = false && false || true;
6 var_dump($a);
7 ?>

Nota
Operatorii logici evalueaza operanzii ca valori booleene.

Sursa script Sursa HTML in browser


1 <?php 1 e adevarat
2 2 bool(true)
3 /* 3 int(1)
4 1 este intreg. convertit la 4 int(0)
5 boolean este true 5 bool(false)
6 0 este intreg. convertit la
7 boolean este false
8 true || false = true
9 */
10
11 $a = 1;
12 $b = 0;
13
14 if ($a || $b) {
15 echo 'e adevarat'; // e
16 adevarat
17 }
18
19 echo "\n";
20
21 var_dump($a || $b); //
22 bool(true)
23
24 /*
25 a si b au fost convertiti doar
26 in cadrul operatiei logice la
27 boolean.
28 ele isi pastreaza insa tipul de
29 date initial
30 */
31 var_dump($a); // int(1)
32 var_dump($b); // int(0)

var_dump("" || 0); // sirul ""


este evaluat ca false , la fel
si 0. output: bool(false)

?>

Important
Operatorii &&, and, ||, or, functioneaza cu "scurtcircuitare", adica al doilea operand nu este evaluat daca se poate stabili rezultatul sigur al operatiei
logice doar din primul operand. Acest lucru este important atunci cand al doilea operand este de exemplu apelarea unei functii, pentru ca functia poate fi
(sau nu) apelata in functie de acest lucru.

Sursa script Sursa HTML in browser


1 <?php 1 altceva cu ||
2 2 ceva cu &&
3 function scrie($ceva)
4{
5 echo $ceva;
6 echo "\n";
7 return false;
8}
9
10 /*
11 functia scrie() nu este apelata
12 pentru ca primul operator al ||
13 (sau logic) este true,
14 deci rezultatul operatiei va fi
15 true indiferent de al doilea
16 operand
17 */
18 $a = true || scrie('ceva cu ||
19 ');
20
21 // in acest caz, nu se poate
22 stabili rezultatul operatiei
23 doar din primul operand, deci se
24 executa si functia
25 $a = false || scrie('altceva cu
|| ');

$a = true or scrie('ceva cu
or'); // similar cu primul
exemplu

$a = true && scrie('ceva cu


&&');

?>

Diferenta de prioritate intre && si and, si intre || sau or, poate fi importanta in anumite cazuri. Pentru detalii, vezi capitolul din php manual Operators
precedence. Un exemplu clasic, este codul: $link = mysql_connect(...) or die('Eroare la conectare'); folosit uneori pentru conectarea la baza de date.

Sursa script Sursa HTML in browser


1 <?php 11
2 function test($s) 22
3{ 3 bool(false)
4 echo $s; 4 bool(true)
5 echo "\n";
6 return true;
7}
8
9
10
11
12 /*
13 in ambele cazuri de mai jos se
14 evalueaza si al doilea operand
15 (deci se executa functia
16 test() ) pentru ca
17 din punctul de vedere al
18 scurtcircuitarii si al
19 operatiilor logice "or" si "||"
20 functioneaza la fel. (precum si
21 "&&" si "and")
22 diferenta apare insa intre
23 valoarea lui $a si valoarea lui
24 $b datorita diferentei de
25 prioritate intre operatori
26 */
27
28 /* se executa intai $a = false
29 (pentru ca operatorul "=" are
30 prioritate mai mare fata de
31 "or").
32 apoi, expresia $a = false luand
33 valoarea false, se face mai
34 departe false or test(1)
(rezultat care nu este atribuit
nimanui).
*/

$a = false or test(1);

/*
se executa intai false ||
test(2) (pentru ca operatorul
"||" are prioritatemai mare
decat "=").
rezultatul false || test(2) este
true, apoi se face $b = true.
*/

$b = false || test(2);

var_dump($a);
var_dump($b);
?>

2.6.6. Operatorul de concatenare


Operatorul de concatenare este descris in subcapitolul de la tipuri de date: string

2.6.7. Operatorul ternar


Operatorul ternar seamana cu un "if...else..." simplu. Asa cum ii spune numele, este un operator ce foloseste trei operanzi.

Definitie
El arata astfel:
(conditie) ? valoare_daca_true : valoare_daca_false
Se evalueaza boolean conditia din paranteze. Daca aceasta conditie este true, rezultatul expresiei este valoarea de dupa ?. Daca este false, rezultatul
expresiei este valoarea de dupa :

Sursa script Sursa HTML in browser


1 <?php 1 text1
2 $a = (2 < 3) ? 'text1' : 2y
3 'text2';
4
5 echo $a;
6 echo "\n";
7
8 $a = (2 > 3) ? 'x' : 'y';
9
10 echo $a;
11 echo "\n";
?>

2.7. Expresii
In PHP "orice are o valoare" este o expresie. Prin urmare, cele mai simple expresii sunt variabilele si constantele. Expresii mai complexe sunt functiile
ce returneaza un rezultat. Atribuirea unei valori (ex: $a = 5) este o expresie avand valoarea atribuita (in acest caz "$a=5" este o expresie cu valoarea 5).
Compararea dintre doua valori (1>2) este o expresie cu o valoare booleana, in acest caz false. Bineinteles, o expresie complexa este compusa din expresii
mai simple.

Sursa script Sursa HTML in browser


1 <?php 1 int(5)
2 $a = $b = 5; // b devine 5. $b = 2 bool(false)
3 5 este o expresie cu valoarea 5. 3 bool(true)
4 $a devine astfel 5 4 int(9)
5
6 var_dump($a); // 5
7
8 $c = (1>2); // false
9 var_dump($c);
10
11 $d = (1 > 2) || (1 < 3); //
12 false || true este true
13 var_dump($d);
14
15
16 /*
17 in exemplul urmator $a+=1 este
18 o expresie echivalenta cu $a =
19 $a + 1; valoarea atribuita
20 in aceasta expresie este $a + 1,
21 adica 6. Deci expresia ($a+=1)
22 are valoarea 6.
23 expresia (2 > 1) are valoarea
24 true. Datorita operatorului
25 aritmetic + , aceasta valoare
26 este convertita la intreg. true
27 convertit la intreg este 1.
28 iar functia_mea() este o
expresie cu valoarea 2.
*/

$e = $a+=1 + (2 > 1) +
functia_mea();
var_dump($e);
function functia_mea()
{
return 2;
}
?>

2.8. Conversia intre tipuri de date


2.8.1 Conversia la boolean
2.8.2 Conversia la integer
2.8.3 Conversia la float
2.8.4 Conversia la string
2.8.5 Conversia la numar a stringurilor
Acest capitol este o continuare a capitolului Tipuri de date. Vorbesc despre modul in care variabilele isi schimba tipul de date in PHP. Spuneam ca o
variabila isi schimba tipul de date prin: atribuirea unei valori, conversie explicita cu settype(), prin cast ($a = (int)$x) sau prin conversie automata. De
multe ori in PHP variabilele din scriptul nostru vor "suferi" conversia automata in functie de contextul in care sunt implicate sau de operatorii dintre ele.

Nota
In aceasta documentatie, cand vorbesc despre "conversia la un tip de date" sau este "evaluarea ca un anumit tip de date" ma refer de multe ori la
conversia automata (deci temporara) in care variabila nu-si schimba tipul de date decat in cadrul expresiei respective, si ramane apoi cu tipul de
date original.

Sursa script Sursa HTML in browser


1 <?php 1 int(0)
2 $i = 0; 2 orice intreg diferit de zero e
3 3 evaluat boolean la true
4 4 int(-17)
5 /* adevarat
6 in cadrul constructiei if,
7 expresia dintre paranteze este
8 evaluata ca boolean.
9 intregul 0 evaluat ca boolean
10 este FALSE
11 */
12
13 if ($i) {
14 echo 'fals';
15 }
16
17 var_dump($i);
18
19 $i = -17;
20
21 if ($i) {
22 echo 'orice intreg diferit de
23 zero e evaluat boolean la true';
24 echo "\n";
25 }
26
27 var_dump($i);
28
29 $a = 1;
30 $b = 'text';
31
32
33 /*
34 intr-o comparatie, daca avem un
35 numar, ambii operanzi sunt
36 convertiti la numar.
37 'text' convertit la intreg este
38 0.
1 > 0
*/

if ($a > $b) {


echo 'adevarat';
}
?>

Nota
Alt exemplu de conversie automata ne ofera operatorul +. Cand unul din operanzi este float atunci ambii operanzi sunt evaluati ca float. Altfel,
operanzii sunt evaluati ca intregi.

Sursa script Sursa HTML in browser


1 <?php 1 float(7.3)
2 2 int(6)
3 $a = 2.3 + "5"; 3 int(35)
4 var_dump($a);
5
6 $a = 5 + true;
7 var_dump($a);
8
9 $a = 2 + false + 'text' +
10 '33text';
11 var_dump($a)
?>

2.8.1. Conversia la boolean


Conversia la boolean este foarte importanta in PHP pentru ca este des intalnita in cadrul structurilor de control gen if(), while().

In conversia la boolean, urmatoarele valori sunt considerate FALSE:

 intregul 0 (zero)

 floatul 0.0

 sirul gol (empty) "" sau ''. Precum si sirul "0"

 un array cu zero elemente

 tipul special NULL

Sursa script Sursa HTML in browser


1 <?php 1 orice string diferit de stringul
2 gol va fi evaluat la true
3 // $y nu este setat, are deci
4 tipul si valoarea NULL deci va
5 fi evaluat ca false
6 if ($y) {
7 echo 'y nu este setat. acest
8 text nu va fi afisat';
9 }
10
11 $x = 0;
12
13 // 0 intreg este evaluat ca
14 false
15 if ($x) {
16 echo '0 este evaluat la
17 false';
18 }
19
20 $z = 'text';
21
22
23 // orice text cu exceptia ""
este evaluat ca true
if ($z) {
echo 'orice string diferit de
stringul gol va fi evaluat la
true';
}

?>

2.8.2. Conversia la integer


Conversia din boolean:

 TRUE convertit la intreg este 1

 FALSE convertit la intreg este 0

Conversia din float:

 numarul este lipsit de partea factionara (sau rotunjit catre zero).

Conversia din string:

 vezi Conversia la numar a stringurilor

Sursa script Sursa HTML in browser


1 <?php 1 int(1)
2 2 int(1)
3 $a = (int)(true); 3 int(2)
4 var_dump($a);
5
6
7 $x = true + false;
8 var_dump($x);
9
10 $y = (int)(2.99);
11 var_dump($y); // 2
12
13 ?>

2.8.3. Conversia la float


Pentru convertirea stringurilor la float vezi Conversia la numar a stringurilor. Orice alt tip in afara de string, pentru a fi convertit la float, este intai convertit
la intreg.

2.8.4. Conversia la string


Conversia la string se face ca si in celelalte cazuri acolo unde contextul o cere, sau prin conversia explicita sau cast. De exemplu, constructia echo sau
functia print convertesc argumentele primite la string. Alt exemplu este folosirea operatorului de concatenare. Conversia din boolean:

 TRUE convertit la string este "1"

 FALSE convertit la string este sirul gol, ""

Un intreg sau float este convertit la un string numeric, ce reprezinta textual numarul respectiv. Destul de intuitiv. Tipul NULLeste convertit la sirul gol, "".
Tipurile speciale array, object si resource nu pastreaza informatie utila in cazul conversiei la string. De exemplu, orice array convertit la string este sirul
"Array". Din aceasta cauza nu pot sa vad ce contine un array cu echo sau print. Pentru afisarea variabielor avand aceste tipuri pot folosi
functiile print_r sau var_dump().

Sursa script Sursa HTML in browser


1 <?php 11
2 2 ab
3 echo true; // 1 3 string(1) "2"
4 echo "\n"; 4 string(6) "5237.6"
5
6 echo 'a' . false . 'b'; // ab -
7 pentru ca false este sirul gol
8 echo "\n";
9
10
11 $x = (string)2;
12 var_dump($x);
13
14
15
16 $y = (string)5.2376e3; // $y
17 este float avand valoarea 5237.6
avand notatia stiintifica
var_dump($y);
?>

2.8.5. Conversia la numar a stringurilor

Cand un string este evaluat numeric (de exemplu langa un operator aritmetic), atunci stringul este evaluat ca float daca are unul din caracterele ".", "e"
sau "E". Altfel stringul este evaluat ca intreg. Valoarea lui (numerica) este data de portiunea de inceput a stringului. Daca stringul incepe cu o valoare
numerica valida, atunci stringul este convertit la acel numar (float sau intreg). Altfel, stringul este convertit la intregul 0.

Sursa script Sursa HTML in browser


1 <?php 1 int(3)
2 $str = '3text'; 2 float(9.3)
3 $str = (int)($str); // conversie 3 int(1)
4 cu cast
5 var_dump($str);
6
7
8 $str = '2.3parti';
9 $x = $str + 7;
10 var_dump($x);
11
12 $str = 'text2.9';
13 $x = $str + 1;
14 var_dump($x); // rezultatul este
1. pentru ca text2.9 convertit
la numar este 0
?>

CAP 3. Bazele limbajului PHP II


3.1 Structuri de control
3.2 Variabile - notiuni avansate
3.3 Functii
3.4 Tema

3.1. Structuri de control


3.1.1 if
3.1.2 switch
3.1.3 while
3.1.4 do-while
3.1.5 for
3.1.6 foreach
3.1.7 break, continue
3.1.8 include, require
Structurile de control (en: "Control Structures") sunt constructii de limbaj de baza, ce indica executia unor blocuri de cod in functie de anumite conditii,
sau repetarea unor blocuri de cod de un anumit numar de ori.
Structurile de control conditionale organizeaza blocurile de cod astfel incat sa fie executate doar cand se indeplinesc anumite conditii si
sunt: if/else si switch.
Cealalta categorie, structurile de control repetitive, executa blocurile de cod de un anumit numar de ori (dar tot cu ajutorul respectarii unor conditii), iar
din aceasta categorie fac parte: while, do-while, for, foreach . Aceste repetari ale unui bloc de cod se numesc "iteratii", "cicluri", "bucle" sau in engleza
"loops", "iterations".
Cu ajutorul cuvintelor cheie break si continue programul indica iesirea dintr-un ciclu, sau intreruperea ciclului si reluarea urmatorului
ciclu. include si require sunt doua constructii de limbaj ce permit includerea de cod php din alte fisiere .php in interiorul scriptului curent.

3.1.1. if
Constructia if este una din cele mai importante si folosite structuri decizionale, si nu doar in PHP. Forma ei cea mai simpla este:
if (expr)
instructiune;
Doar daca expr este evaluata boolean la TRUE se executa insructiune.

Daca avem mai multe instructiuni de executat in cazul in care expr este TRUE, atunci formam un bloc de instructiuni adica incadram codul intre acolade:
if (expr) {
instructiune1;
instructiune2;
}

Sursa script Sursa HTML in browser


1 <?php 1 $a este mai mare ca $b
2 $a = 99; 2 $str este definit si are o
3 $b = 1; valoare diferita de sirul
4 golvaloarea lui este text
5 if ($a > $b)
6 echo '$a este mai mare ca $b';
7
8
9 echo "\n";
10 $str = 'text';
11
12 if ($str) {
13 echo '$str este definit si are
14 o valoare diferita de sirul
15 gol';
16 echo "valoarea lui este $str";
17 }

?>

else, elseif
Daca vreau sa execut o instructiune (un bloc de instructiuni) cand expr este adevarata si un alt bloc atunci cand este falsa, folosesc cuvantul cheie else.

Sursa script Sursa HTML in browser


1 <?php 1 a este mai mic sau egal cu b
2 $a = 1;
3 $b = 2;
4
5 if ($a > $b)
6 echo 'a este mai mare ca b';
7 else
8 echo 'a este mai mic sau egal
9 cu b';
10
?>

Sursa script Sursa HTML in browser


1 <?php 1 acest bloc se executa daca expr
2 $a = 0; 2 adica $a este evaluat la false.
3 int(0)
4
5 if ($a) {
6 echo 'expresia din if, adica
7 $a, este evaluata la false. prin
8 urmare acest bloc nu se
9 executa';
10 echo 'valoarea lui a
11 (convertita la string) este ' .
12 $a;
} else {
echo 'acest bloc se executa
daca expr adica $a este evaluat
la false.' . "\n";
var_dump($a);
}
?>
Constructia elseif (sau else if) ofera mai multe posibilitati de executare in cazul cand expr este fals. Blocul de cod de dupa else if se executa
daca expr este falsa, si daca toate constructiile else if de pana atunci au avut o conditie falsa, si, in plus, conditia acestui else if este adevarata.

Sursa script Sursa HTML in browser


1 <?php 1 a este mai mare decat b
2 $a = 2; 2 optiunea este d
3 $b = 1;
4 if ($a < $b) {
5 echo 'a este mai mic decat b';
6 } elseif ($a == $b) {
7 echo 'a este egal cu b';
8 } elseif ($a > $b) {
9 echo 'a este mai mare decat
10 b';
11 }
12
13 echo "\n";
14
15
16 $optiune = 'd';
17
18 if ($optiune == 'a') {
19 echo 'optiunea este a';
20 } elseif ($optiune == 'b') {
21 echo 'optiunea este b';
22 } elseif ($optiune == 'c') {
23 echo 'optiunea este c';
24 } elseif ($optiune == 'd') {
25 echo 'optiunea este d';
26
27 } else {
28 echo 'optiunea nu este nici a,
29 b, c sau d';
30 }

?>

3.1.2. switch

Constructia switch este conditionala, si permite executia unui bloc de cod in functie de diferitele valori pe care le poate lua o variabila/expresie. Implicit,
operatorul de comparare intre expresie si diferitele valori posibile este "=="

Sursa script Sursa HTML in browser


1 <?php 1 a este 1
2 $a = 1;
3
4 switch ($a) { // $a este
5 expresia ce poate lua diferite
6 valori
7
8 case 0: // aici incepe prima
9 ramura "case"
10 echo 'a este 0';
11 break; // aici se termina
12 prima ramura "case"
13
14 case 1:
15 echo 'a este 1';
16 break;
17
18 case 2:
19 echo 'a este 2';
20 break;
21
22 case 3:
23 echo 'a este 3';
24 break;
25
26 default: // $a nu are nici una
27 din valorile de mai sus
28 echo 'a are alta valoare';

} /// end switch

?>

In general, dupa fiecare ramura "case" a switchului introducem instructiunile dorite si apoi cuvantul cheie break. Introducerea lui break limiteaza
executia doar la acea portiune de cod (din acel case), altfel, ar trece mai departe si ar executa "case"-urile de dedesubt, indiferent ca exista egalitate cu
acele valori sau nu. Alt cuvant cheie folosit este default folosit in cazul in care expresia comparata nu are nici una din valorile din case.

Sursa script Sursa HTML in browser


1 <?php 1 $sir este abc $sir este b $sir
2 $sir = 'abc'; este c $sir are alta valoare
3
4 /* in acest exemplu, se
5 potriveste doar egalitatea cu
6 "abc"
7 dar pentru ca nu avem break de
8 aici in jos, se executa si
9 restul case-urilor
10 de cele mai multe ori punem
11 break la sfarsitul fiecarui
12 case.
13 dar uneori, vrem sa omitem
14 breakul, special pentru un
15 astfel de comportament
16 */
17
18 switch ($sir) { // $a este
19 expresia ce poate lua diferite
20 valori
21
22 case "a":
23 echo '$sir este a ';
24
25 case "abc":
26 echo '$sir este abc ';
27
28 case "b":
29 echo '$sir este b ';
30
case "c":
echo '$sir este c ';

default: // $a nu are nici una


din valorile de mai sus
echo '$sir are alta valoare
';

} /// end switch

?>

Se pot combina mai multe ramuri case intr-una singura:

Sursa script Sursa HTML in browser


1 <?php 1 Destinatie potrivita: mare
2 $hobby = 'inot';
3
4 switch ($hobby) {
5
6 case "inot":
7 case "volei":
8 case "plaja":
9
10 echo "Destinatie potrivita:
11 mare";
12 break;
13
14 case "catarat":
15 case "ski":
16 case "sanie":
17 echo "Destinatie potrivita:
18 munte";
19 break;
20
21 default:
22 echo "Alege o alta
23 destinatie";
24 break;
25
26
27 }
28

?>
3.1.3. while
In forma cea mai simpla, while arata asa:
Pseudocod
while (expr)
instructiuni;

si are ca efect executarea instructiunilor atata timp cat expr este evaluata boolean ca TRUE. In cadrul blocului de instructiuni, trebuie sa avem ceva ce
schimba valoarea lui expr din TRUE in FALSE altfel instructiunile se executa la nesfarsit. Daca expreste de la inceput FALSE, blocul de instructiuni nu se
executa niciodata.

Sursa script Sursa HTML in browser


1 <?php 1 i este inca mai mic decat 10
2 $i = 1; 2 $i este 1
3 3
4 while ($i <= 10) { 4 i este inca mai mic decat 10
5 echo 'i este inca mai mic decat 5 $i este 2
6 10'; echo "\n"; 6
7 echo '$i este '.$i; echo 7 i este inca mai mic decat 10
8 "\n\n"; 8 $i este 3
9 $i++; 9
} 10 i este inca mai mic decat 10
?> 11 $i este 4
12
13 i este inca mai mic decat 10
14 $i este 5
15
16 i este inca mai mic decat 10
17 $i este 6
18
19 i este inca mai mic decat 10
20 $i este 7
21
22 i este inca mai mic decat 10
23 $i este 8
24
25 i este inca mai mic decat 10
26 $i este 9
27
28 i este inca mai mic decat 10
29 $i este 10

Sursa script Sursa HTML in browser


1 <?php 1 aceasta bucla se executa o
2 $i = 1; singura data
3
4 while ($i != 2) {
5 $i = 2;
6 echo 'aceasta bucla se executa
7 o singura data';
8}
9
10
11
?>
Sursa script Sursa HTML in browser
1 <?php 1 valoarea lui $a este: 4
2 $a = 5; 2 valoarea lui $a este: 3
3 3 valoarea lui $a este: 2
4 /* 4 valoarea lui $a este: 1
5 $a devine 0, si atunci 5 valoarea lui $a este: 0
6 executarea lui while se opreste
7 pentru ca 0 este evaluat ca
8 FALSE
9 */
10
11 while ($a) {
12 $a--;
13 echo 'valoarea lui $a este: '.
$a."\n";
}
?>

3.1.4. do-while

Constructia do-while este foarte asemanatoare constructiei while cu singura diferenta ca instructiunile din bucla (loop) se executa cel putin o singura
data; pentru ca intai se executa codul apoi se verifica daca expresia este evaluata la TRUE. Codul continua sa se execute atata timp cat expr ramane
TRUE.
Pseudocod
do {

} while (expr)

Sursa script Sursa HTML in browser


1 <?php 1 $i nu va fi egal niciodata cu 3
2 $i = 4; 2 in acest script
3 do { totusi, acest cod se executa
4 echo '$i nu va fi egal macar o data
5 niciodata cu 3 in acest
6 script'."\n";
7 echo "totusi, acest cod se
executa macar o data";
} while ($i == 3);
?>

Sursa script Sursa HTML in browser


1 <?php 1 creste $i
2 $i = 0; 2 $i este 0
3 3
4 do { 4 creste $i
5 echo 'creste $i'."\n"; 5 $i este 1
6 echo '$i este ' . $i; 6
7 echo "\n\n"; 7 creste $i
8 $i++; 8 $i este 2
9 } while ($i <= 5); 9
10 ?> 10 creste $i
11 $i este 3
12
13 creste $i
14 $i este 4
15
16 creste $i
17 $i este 5

3.1.5. for
Structura de control for este o structura repetitiva. Arata astfel:
Pseudocod
for (expresie1;expresie2;expresie3)
bloc instructiuni;

La fel ca si in celelalte cazuri, daca in cadrul buclei for vreau sa execut mai multe instructiuni, le grupez intr-un bloc de instructiuni folosind acolade.

Structura for functioneaza astfel:

 expresie1 este evaluata o singura data, neconditionat, la inceputul primei bucle

 expresie2 este o conditie, o expresie evaluata boolean la inceputul fiecarei bucle

 expresie3 este evaluata/executata la sfarsitul fiecarei bucle

Se obisnuieste ca expresie1 sa fie o initializare a unei variabile gen $i = 1, expresie2 o conditie gen $i <10, iar expresie3 o incrementare, sau
decrementare sau alta operatie aritmetica ce afecteaza variabila $i ($i++ sau $i+=3 , etc)

Sursa script Sursa HTML in browser


1 <?php 1 valoarea lui $i este: 0
2 /* 2 valoarea lui $i este: 1
3 clasic exemplu de for ce rezulta 3 valoarea lui $i este: 2
4 in 10 iteratii (de la 0 la 9) 4 valoarea lui $i este: 3
5 */ 5 valoarea lui $i este: 4
6 6 valoarea lui $i este: 5
7 for ($i = 0; $i < 10; $i++) { 7 valoarea lui $i este: 6
8 echo 'valoarea lui $i este: 8 valoarea lui $i este: 7
9 '."$i \n"; 9 valoarea lui $i este: 8
10 } 10 valoarea lui $i este: 9
11 11 int(10)
12
13 /*
14 ATENTIE: daca folosesti in
15 continuare variabila $i,
16 valoarea ei este 10 dupa for,
17 pentru ca la sfarsitul ultimului
18 ciclu (cand $i a fost 9) s-a
19 executat $i++
*/

var_dump($i);

?>

expresie1, expresie2 sau expresie3 pot fi de fapt formate din mai multe expresii separate prin virgula.
Sursa script Sursa HTML in browser
1 <?php 10 9
2 21 7
3 for ($i = 0, $j= 9; $i + $j > 0; 32 5
4 $i++, $j-=2) { 43 3
5 echo $i.' '.$j."\n"; 54 1
6 } 65 -1
7 76 -3
?> 87 -5
98 -7

Oricare din expresie1, expresie2 sau expresie3 poate lipsi. Dar ramane separatorul ";" dintre cele 3 expresii. Daca expresie2lipseste, deci conditia ce este
evaluata la inceputul fiecarei bucle, atunci expresie2 este evaluata automat la TRUE. Dintr-o astfel de bucla se poate iesi doar cu break.

Sursa script Sursa HTML in browser


1 <?php 10 1 2 3 4 5 6 7 8 9
2 for ($i = 0; ;$i++) { 2
3 3 1 2 3 4 5 6 7 8 9 10
4 if ($i > 9 ) {
5 break;
6 }
7 echo $i . ' ';
8}
9
10 echo "\n\n";
11
12
13 for (; ;) { // echivalent cu
14 while(TRUE)
15 $k++;
16 if ($k > 10) {
17 break;
18 }
19 echo $k.' ';
20 }
21
?>

3.1.6. foreach

Constructia foreach este destinata trecerii prin tablouri (array). Daca in alte limbaje aceasta trecere (iteratie) prin elementele unui tablou se face folosind
constructia for, in PHP se prefera foreach din urmatorul motiv: cheile tablourilor in PHP nu sunt neaparat numerice sau daca sunt numerice nu sunt
neaparat consecutive, deci e imposibil sa folosim for.
Lucrul cu tablouri, si implicit exemple ale constructiei foreach vor fi detaliate in capitolul Arrays.

Sursa script Sursa HTML in browser


1 <?php 1 In aceasta iteratie avem:
2 $persoana = array( 2 cheia: prenume;valoare: Mihai;
3 'prenume' => 'Mihai', 3
4 'nume' => 'Ionescu', 4 In aceasta iteratie avem:
5 'varsta' => 25, 5 cheia: nume;valoare: Ionescu;
6 'sex' => 'm', 6
7 ); 7 In aceasta iteratie avem:
8 8 cheia: varsta;valoare: 25;
9 foreach ($persoana as $cheie => 9
10 $valoare) { 10 In aceasta iteratie avem:
11 echo 'In aceasta iteratie 11 cheia: sex;valoare: m;
12 avem: '."\n";
13 echo 'cheia: ' . $cheie;
14 echo ';';
15 echo 'valoare: '. $valoare;
16 echo ";\n\n";
}
?>

3.1.7. break, continue

Cuvantul cheie break forteaza iesirea dintr-o bucla de tip for, foreach, while, do-while sau switch. Aceasta constructie poate primi ca argument un
numar ce reprezinta numarul de constructii repetitive din care iese.

Sursa script Sursa HTML in browser


1 <?php 1 for terminat
2 $forloops = 0; 2 for terminat
3 3 while terminat
4 while (true) { 4 5 22
5
6
7 for ($i = 0; $i < 5; $i++) {
8 $k = rand(1, 30); // alege
9 un numar intamplator de la 1 la
10 30
11 if ($i == $k) {
12 echo '$i a ajuns egal cu
13 $k si anume egal cu '.$i."\n";
14 break 2;
15
16 }
17 }
18
19 $forloops++;
20
21 if ($forloops > 2) {
22 break;
23 }
24 echo "for terminat \n";
25 }
26
27 echo "while terminat \n";

echo $i.' '.$k;


?>
Sursa script Sursa HTML in browser
1 <?php 1i este: 1
2 2i este: 2
3 3i este: 3
4 $i = 0; 4i este: 4
5 $j = 5; 5i este j
6 // $j = 14;
7
8 /* in aceasta constructie, se
9 executa blocul de instructiuni
10 atata timp cat $i < 100,
11 dar daca $i va fi egal cu $j,
12 iese brusc din while
13 */
14
15 while ($i < 10) {
16 $i++;
17
18 if ($i == $j) {
19 echo 'i este j';
20 break;
21 }
22
echo 'i este: ' .$i."\n";
}
?>

continue are rolul de a indica continuarea executiei cu inceputul buclei urmatoare, prin urmare se ignora restul codului din bucla curenta. (mai corect
spus, executia sare direct la sfarsitul buclei curente, pentru ca in cazul constructiei for, se executa inca acel $i++ de la sfarsitul fiecarei bucle, inclusiv de
la sfarsitul buclei curente). Similar cu break, continue poate primi un parametru ce indica nivelul buclei cu care se continua executia codului.

Sursa script Sursa HTML in browser


1 <?php 10
2 for ($i = 0; $i < 5; ++$i) { 21
3 if ($i == 2) // se executa 33
4 doar continue; nu se mai executa 44
5 echo sau alte instructiuni
6 ulterioare
7 continue;
8
echo "$i\n";
}
?>

Sursa script Sursa HTML in browser


1 <?php 1
2 $n = 100; 2 $i este 2, si este prim
3 3
4 for ($i = 2; $i < $n; $i++) { 4
5 5 $i este 3, si este prim
6 6
7 if ($i % 2 == 0 && $i != 2) { 7 $i este 4 , si este multiplu de
8 echo "\$i este $i , si este 8 2, si NU este prim
9 multiplu de 2, si NU este prim 9
10 \n"; 10 $i este 5, si este prim
11 continue ; 11
12 } 12 $i este 6 , si este multiplu de
13 13 2, si NU este prim
14 14
15 15 $i este 7, si este prim
16 if (is_array($primeDivizori)) 16
17 { 17 $i este 8 , si este multiplu de
18 foreach ($primeDivizori as 18 2, si NU este prim
19 $p) { 19 $i este 9 , si este multiplu de
20 if ($i % $p == 0) { 20 3, deci NU este prim
21 echo "\$i este $i , si este 21 $i este 10 , si este multiplu
22 multiplu de $p, deci NU este 22 de 2, si NU este prim
23 prim \n"; 23
24 continue 2; 24 $i este 11, si este prim
25 } 25
26 } 26 $i este 12 , si este multiplu
27 } 27 de 2, si NU este prim
28 28
29 echo "\n"; 29 $i este 13, si este prim
30 echo "\$i este $i, si este 30
31 prim \n"; 31 $i este 14 , si este multiplu
32 echo "\n"; 32 de 2, si NU este prim
33 33 $i este 15 , si este multiplu
34 if ($i <= sqrt($n)) { 34 de 3, deci NU este prim
35 $primeDivizori[] = $i; 35 $i este 16 , si este multiplu
} 36 de 2, si NU este prim
37
} /// end for 38 $i este 17, si este prim
39
40 $i este 18 , si este multiplu
//print_r($primeDivizori); 41 de 2, si NU este prim
?> 42
43 $i este 19, si este prim
44
45 $i este 20 , si este multiplu
46 de 2, si NU este prim
47 $i este 21 , si este multiplu
48 de 3, deci NU este prim
49 $i este 22 , si este multiplu
50 de 2, si NU este prim
51
52 $i este 23, si este prim
53
54 $i este 24 , si este multiplu
55 de 2, si NU este prim
56 $i este 25 , si este multiplu
57 de 5, deci NU este prim
58 $i este 26 , si este multiplu
59 de 2, si NU este prim
60 $i este 27 , si este multiplu
61 de 3, deci NU este prim
62 $i este 28 , si este multiplu
63 de 2, si NU este prim
64
65 $i este 29, si este prim
66
67 $i este 30 , si este multiplu
68 de 2, si NU este prim
69
70 $i este 31, si este prim
71
72 $i este 32 , si este multiplu
73 de 2, si NU este prim
74 $i este 33 , si este multiplu
75 de 3, deci NU este prim
76 $i este 34 , si este multiplu
77 de 2, si NU este prim
78 $i este 35 , si este multiplu
79 de 5, deci NU este prim
80 $i este 36 , si este multiplu
81 de 2, si NU este prim
82
83 $i este 37, si este prim
84
85 $i este 38 , si este multiplu
86 de 2, si NU este prim
87 $i este 39 , si este multiplu
88 de 3, deci NU este prim
89 $i este 40 , si este multiplu
90 de 2, si NU este prim
91
92 $i este 41, si este prim
93
94 $i este 42 , si este multiplu
95 de 2, si NU este prim
96
97 $i este 43, si este prim
98
99 $i este 44 , si este multiplu
100 de 2, si NU este prim
101 $i este 45 , si este multiplu
102 de 3, deci NU este prim
103 $i este 46 , si este multiplu
104 de 2, si NU este prim
105
106 $i este 47, si este prim
107
108 $i este 48 , si este multiplu
109 de 2, si NU este prim
110 $i este 49 , si este multiplu
111 de 7, deci NU este prim
112 $i este 50 , si este multiplu
113 de 2, si NU este prim
114 $i este 51 , si este multiplu
115 de 3, deci NU este prim
116 $i este 52 , si este multiplu
117 de 2, si NU este prim
118
119 $i este 53, si este prim
120
121 $i este 54 , si este multiplu
122 de 2, si NU este prim
123 $i este 55 , si este multiplu
124 de 5, deci NU este prim
125 $i este 56 , si este multiplu
126 de 2, si NU este prim
127 $i este 57 , si este multiplu
128 de 3, deci NU este prim
129 $i este 58 , si este multiplu
130 de 2, si NU este prim
131
132 $i este 59, si este prim
133
134 $i este 60 , si este multiplu
135 de 2, si NU este prim
136
137 $i este 61, si este prim
138
139 $i este 62 , si este multiplu
140 de 2, si NU este prim
141 $i este 63 , si este multiplu
142 de 3, deci NU este prim
143 $i este 64 , si este multiplu
144 de 2, si NU este prim
145 $i este 65 , si este multiplu
146 de 5, deci NU este prim
147 $i este 66 , si este multiplu
148 de 2, si NU este prim

$i este 67, si este prim

$i este 68 , si este multiplu


de 2, si NU este prim
$i este 69 , si este multiplu
de 3, deci NU este prim
$i este 70 , si este multiplu
de 2, si NU este prim

$i este 71, si este prim

$i este 72 , si este multiplu


de 2, si NU este prim

$i este 73, si este prim

$i este 74 , si este multiplu


de 2, si NU este prim
$i este 75 , si este multiplu
de 3, deci NU este prim
$i este 76 , si este multiplu
de 2, si NU este prim
$i este 77 , si este multiplu
de 7, deci NU este prim
$i este 78 , si este multiplu
de 2, si NU este prim

$i este 79, si este prim

$i este 80 , si este multiplu


de 2, si NU este prim
$i este 81 , si este multiplu
de 3, deci NU este prim
$i este 82 , si este multiplu
de 2, si NU este prim

$i este 83, si este prim

$i este 84 , si este multiplu


de 2, si NU este prim
$i este 85 , si este multiplu
de 5, deci NU este prim
$i este 86 , si este multiplu
de 2, si NU este prim
$i este 87 , si este multiplu
de 3, deci NU este prim
$i este 88 , si este multiplu
de 2, si NU este prim

$i este 89, si este prim

$i este 90 , si este multiplu


de 2, si NU este prim
$i este 91 , si este multiplu
de 7, deci NU este prim
$i este 92 , si este multiplu
de 2, si NU este prim
$i este 93 , si este multiplu
de 3, deci NU este prim
$i este 94 , si este multiplu
de 2, si NU este prim
$i este 95 , si este multiplu
de 5, deci NU este prim
$i este 96 , si este multiplu
de 2, si NU este prim

$i este 97, si este prim

$i este 98 , si este multiplu


de 2, si NU este prim
$i este 99 , si este multiplu
de 3, deci NU este prim

3.1.8. include, require


include si require sunt constructii de limbaj ce permit includerea si evaluarea unor fisiere externe in cadrul fisierului curent. Daca fisierele incluse au cod
php (desi nu e neaparat nevoie), trebuie ca de obicei, delimitat intre tagurile de php. Aceasta includere este ca si cum am scrie efectiv codul din fisierele
externe in fisierul curent. Deci orice variabile, functii, etc definite in fisierele incluse, sunt disponibile si in scriptul curent (dar trebuiesc incluse inainte de
folosirea lor).

Nota
Diferenta intre include si require este ca lipsa fisierului cerut de require determina aparitia unei erori ce opreste executia scriptului curent, eroare
de tip Fatal Error, in timp ce lipsa fisierului cerut de include nu va incheia executia scriptului curent.

Nota
include si require sunt constructii de limbaj, deci pot primi argumentele cu sau fara paranteze, spre deosebire de functii ce au argumentele doar
intre paranteze. Este corect deci
include "fisier.php"
sau
include("fisier.php")

Sursa script fisier_a.php Sursa HTML in browser


1 <?php
2 function myprint($str)
3{
4 echo $str;
5 echo "\n";
6}
7 ?>

Sursa script Sursa HTML in browser


1 <?php 1 text1
2 2 text2
3 include_once 'fisier_a.php';
4
5 myprint("text1");
6 myprint("text2");
7
8
9 ?>

3.2. Variabile - notiuni avansate


3.2.1 Vizibilitatea unei variabile
3.2.2 "Variable variables"
3.2.3 Atribuirea prin referinta
3.2.4 Variabile predefinite ("superglobals")

3.2.1. Vizibilitatea unei variabile


O variabila in PHP nu este automat vizibila peste tot in scriptul nostru. Diferitele zone din script in care o variabila este vizibila se numesc "contexte".
Exista urmatoarele posibilitati:

 o variabila se afla contextul global - variabila a fost definita in afara oricarei functii sau clase, si atunci variabila este vizibila in contextul
global, deci nu este vizibila in mod automat in interiorul functiilor sau claselor. Aceste variabile se numescglobale.

 o variabila este definita in interiorul unei functii - variabila este vizibila doar in contextul functiei respective, adica intre acoladele ce
delimiteaza corpul functiei. Se spune ca variabilele sunt locale functiei.

 un caz aparte il reprezinta variabilele predefinite sau "super globals", variabile cu un scop precis in PHP, ce sunt automat disponibile
peste tot in script

Cand folosim doua variabile cu acelasi nume in contexte diferite, ele nu au absolut nici o legatura, modificarea uneia nu o afecteaza pe cealalta, este ca si
cum am avea doua variabile diferite. De exemplu, cand avem o variabila globala numita $a, si folosim/definim variabila $a in interiorul unei functii, noi de
fapt nu modificam si nu ne referim la variabila globala $a.

1 <?php
2 $a = 3;
3
4 function functia_mea()
5{
6 var_dump($a); // NULL - ne referim aici la variabila locala $a,
7 care nu a fost definita
8 $a = 5; // tot variabila locala
9 var_dump($a); // int(5) - variabila locala $a este 5
10
11 }
12
13 functia_mea();
14 var_dump($a); // int(3) - aceasta este variabila globala $a
?>

Pentru a accesa din interiorul unei functii o variabila globala avem doua metode:
1. Declaram in interiorul functiei variabila globala cu ajutorul cuvantului cheie global.
2. Folosim variabila "superglobala" $GLOBALS, un vector ce are ca si chei numele variabilelor globale.

1 <?php
2
3 $a = 3;
4
5 function functia_mea2()
6{
7 global $a;
8 var_dump($a); // int(3) - ne referim la variabila globala $a
9 $a = 5;
10 var_dump($a); // int(5)
11 }
12
13 functia_mea2();
14 var_dump($a); // int(5) - variabila globala $a a fost modificata cu
15 ajutorul functiei
16
?>

3.2.2. "Variable variables"

Este un concept poate ceva mai putin folosit, prin care numele variabilei este la randul sau o variabila.

Sursa script Surs a HTML in browser


1 <?php 1 John
2 $nume = 'John';
3 $a = 'nume';
4
5 echo $$a; // $a devine 'nume' si
6 $$a devine $nume
7
8
?>

3.2.3. Atribuirea prin referinta

Folosind semnul "egal" in expresia $a = $b; obtinem ceea ce se numeste "atribuire prin valoare" - continutul variabilei $b se copiaza in variabila $a.
Dar $a si $b sunt doua variabile independente, cu doua zone de memorie diferita. Modificarea uneia NU o afecteaza pe cealalta.
Uneori avem nevoie de comportamentul opus, si anume cele doua variabile sa fie dependente una de cealalta, sa adreseze aceeasi zona de memorie, caz
in care modificarea uneia inseamna de fapt si modificarea celeilalte. In acest caz folosim"atribuirea prin referinta" cu ajutorul operatorului "=&". Ex: $a
=& $b;

Sursa script Sursa HTML in browser


1 <?php 1 int(5)
2 $b = 5; 2 int(5)
3 $a = $b; // variabilele a si b 3
4 sunt independente 4 int(99)
5 5 int(5)
6 var_dump($a); // 5
7 var_dump($b); // 5
8 echo "\n";
9 $a = 99;
10 var_dump($a); // 99
11 var_dump($b); // 5
12
13
?>

Sursa script Sursa HTML in browser


1 <?php 1 int(5)
2 $b = 5; 2 int(5)
3 $a =& $b; // variabilele a si b 3
4 indica aceeasi zona de memorie, 4 int(99)
5 aceeasi variabila 5 int(99)
6
7 var_dump($a); // 5
8 var_dump($b); // 5
9 echo "\n";
10 $a = 99;
11 var_dump($a); // 99
12 var_dump($b); // 99
13

?>

3.2.4. Variabile predefinite ("superglobals")

Variabilele predefinite, numite si "super globals" sunt disponibile peste tot in interiorul unui script (si in interiorul functiilor sau claselor, fara sa fie
importate cu "global"), si contin informatii importante venite de la utilizator, sau informatii legate de comunicarea dintre browserul si serverul web
(specifice protocolului HTTP). Acestea sunt:

contine informatii legate atat de serverul web (ip-ul serverului, numele serverului, locatia scriptului curent, diverse setari), cat si informatii
$_SERVER
ale cererii HTTP primite de la client (ip-ul clientului web, tipul browserului, etc)

variabile transmise prin url, sau prin formular, sau direct printr-un link, prin accesarea adreselor gen: http://www.exemplu.com/page.php?
$_GET
idProdus=1&categorie=it

$_POST variabile transmise prin formular, prin intermediul unei cereri HTTP de tip POST.

$_COOKIE informatii (perechi variabila=valoare) salvate de browser pe harddiskul utilizatorului si transmise catre server prin HTTP
informatii (perechi variabila=valoare) salvate pe serverul web si asociate unui utilizator in cadrul unei asa-zise "sesiuni", o succesiune de
$_SESSION
vizite web ale aceluiasi utilizator.

Nota
Aceste variabile predefinite vor fi explicate si folosite in detaliu in capitolele urmatoare. Nu este necesar sa intelegeti acum exact cum (de ce) se
folosesc. Trebuie retinut insa ca variabilele $_GET, $_POST, si $_COOKIE, tin informatii venite de la utilizator (prin formular sau alte modalitati), in
concluzie pot fi manipulate de acesta (deci de oricine din Internet), si folosite pentru a exploata gauri de securitate ale scriptului.

3.3. Functii
3.3.1 Definirea unei functii
3.3.2 Apelarea unei functii
3.3.3 Functii cu argumente implicite
3.3.4 Nr variabil de argumente
3.3.5 Transmiterea argumentelor prin valoare si prin referinta
3.3.6 Returnarea prin valoare si prin referinta
3.3.7 Descrierea functiilor in manualul PHP
Functiile sunt foarte importante in orice limbaj de programare, deci si in PHP, pentru ca sunt principala modalitate de a refolosi cod. O functie este un bloc
de instructiuni ce primeste ca date de intrare niste variabile, numite argumente ale functiei, si executa acel bloc de instructiuni apoi returneaza (sau nu) o
valoare. Astfel, in aplicatiile web pe care le construim, pe masura ce scriem cod, determinam secvente de cod ce apar de mai multe ori in cadrul aplicatiei
si le transformam in functii.

In programele noastre folosim doua tipuri de functii:


- functii predefinite - functii deja existente in PHP, scrise de catre creatorii limbajului PHP. Aceste functii sunt deja definite, noi doar le apelam. Exemple:
mysql_connect(), substr(), trim(), etc
- functii definite de catre programator - aceste functii sunt definite de noi, pe masura ce dezvoltam programul in PHP

3.3.1. Definirea unei functii


O functie poate fi "definita" sau "apelata".

In momentul cand definim o functie, scriem ce trebuie sa faca functia respectiva:

 specificam numele functiei (regulile denumirii unei functii sunt aceleasi ca pentru variabile) precedat de cuvantul cheie function

 numele si numarul argumentelor functiei ce devin apoi variabile locale pentru blocul de instructiuni din functie (scrise intre paranteze)

 scriem blocul de instructiuni (corpul functiei) ce indica ce anume face functia respectiva (scris intre acolade)

In momentul cand definim o functie, blocul de instructiuni nu este executat. Doar in momentul cand apelam o functie.
O functie este definita astfel:

1 <?php
2 function nume_functie($arg1, $arg2, $arg3)
3{
4 /*
5 bloc de instructiuni aici
6 */
7}
8
9 ?>

In exemplul de mai sus, functia se numeste nume_functie, este precedata de cuvantul cheie function, primeste trei argumente $arg1, $arg2 si $arg3 ce
devin variabile locale pentru blocul de instructiuni din interiorul functiei. Daca functia nu primeste argumente (sau parametri) atunci parantezele rotunde
nu au nimic in interior, dar sunt obligatorii. Similar cu orice bloc de instructiuni, corpul functiei este cuprins intre acolade, "{" si "}". Aceasta functie nu
face nimic, cuprinde doar un comentariu.

Constructia return
La definirea unei functii, este necesar uneori sa folosim constructia de limbaj return, pentru a obtine urmatoarele doua efecte:

1. In momentul cand executia ajunge la instructiunea return, se opreste evaluarea restului functiei, si controlul executiei este transferat pe linia unde
functia a fost apelata. Mai pe scurt, return are ca efect iesirea din functie.

2. return poate fi urmat de o expresie, ca argument. Aceasta expresie poate fi o variabila, constanta, valoare, sau o expresie mai complexa. Astfel, de
fiecare data cand apelam functia, aceasta va avea valoarea expresiei de dupa return. In exemplul urmator, definim o functie ce calculeaza media
aritmetica dintre doua numere:

Sursa script Sursa HTML in browser


1 <?php 1 float(2.5)
2 function medie($a, $b)
3{
4 $medie = ($a + $b) / 2;
5
6 return $medie;
7
8 echo 'aceasta instructiune nu
9 va fi executata niciodata pentru
10 ca executia functiei se opreste
11 la return';
12
13 }
14
15
16 $c = medie(2, 3); // apelam
functia medie, si valoarea
acestei functii este valoarea
expresiei de dupa return

var_dump($c);
?>

3.3.2. Apelarea unei functii

In momentul cand apelam o functie, firul executiei "sare" de la locul in care functia a fost apelata la locul in care este definita functia, copiaza valorile cu
care apelam functia in argumentele cu care definim functia rezultand astfel variabile locale functiei, apoi se executa instructiune cu instructiune din corpul
functiei pana la sfarsit sau pana intalneste o instructiune return.
Apoi, executia iese din functie, se intoarce la locul in care functia a fost apelata, iar functia devine o expresie cu valoarea null (in cazul in care nu s-a folosit
return sau s-a folosit return fara argumente) sau cu o valoare diferita de null in cazul cand am folosit return cu argument.

Sintaxa pentru apelarea unei functii este simpla, se scrie numele functiei, urmat de argumentele cu care apelam functia intre paranteze. Numarul de
argumente cu care apelam functia trebuie sa fie cel putin egal cu numarul de argumente obligatorii (exista si argumente optionale cum vom vedea mai
tarziu) din definirea functiei.

1 <?php
2
3 function suma($a, $b)
4{
5 $c = $a + $b;
6
7 return $c;
8}
9
10 $x = suma(1, 5); // suma(1,5) reprezinta apelarea functiei suma()
11 var_dump($x); // int(6)
12
13
14 /* functia poate fi apelata (si este executata) chiar daca
15 valoarea returnata nu este folosita in acest caz */
16 suma(7, 2);
17
18 /* linia urmatoare va genera un warning pentru ca o apelam cu un
19 numar mai mic de argumente
20 decat cele obligatorii specificate la definire: Warning: Missing
21 argument 2 for suma().....*/
suma(5);
?>

Argumentele folosite la apelarea unei functii pot fi valori, constante, variabile sau expresii mai complexe (cum ar fi de exemplu apelarea altor functii).
Sursa script Sursa HTML in browser
1 <?php 1 float(5)
2 function suma($a, $b, $c)
3{
4 return $a + $b + $c;
5}
6
7 function medie($a, $b)
8{
9 return ($a + $b) / 2;
10 }
11
12
13 /*
14 variabilele a si b din script,
15 nu au legatura cu cele din lista
16 de argumente (de la definire)
17 sau din corpul functiei suma sau
18 medie
19 $a si $b din script sunt in
20 contextul global, $a si $b din
21 interiorul functiei sunt
22 variabile locale functiei, si
23 exista doar acolo
24 */
25
26 $a = $b = 1;
27
28 $x = suma(1+1, medie(2,3), $a *
29 $b / 2); // suma dintre 2, 2.5
30 si 0.5

var_dump($x); // output:
float(5)

/*
puteam sa scriem direct
var_dump(suma(1+1, medie(2,3),
$a * $b / 2))
iar apelarea functiei suma() era
o expresie ce devine la randul
ei argument pentru functia
var_dump.
Dar de cele mai multe ori, e
preferabil sa folosim astfel de
variabile intermediare (ca $x)
pentru
a grupa expresiile complexe, si
pentru a realiza un cod mai usor
de citit
*/
?>

3.3.3. Functii cu argumente implicite


Cand definim o functie, putem specifica ca unele argumente sa aiba valori implicite (default), si astfel devin argumente optionale la apelarea functiei. La
definire, argumentele sunt urmate de "=" si apoi de valoarea implicita.

Important
Valorile implicite pot fi doar constante, sau valori fixe. Argumentele optionale (cu valori implicite) se afla intotdeauna in dreapta argumentelor obligatorii

Sursa script Sursa HTML in browser


1 <?php 1 Numele meu este Ion
2 function hobby($nume, $hobby = 2 Imi place sa inot
3 'inot') 3
4{ 4 Numele meu este Vasile
5 $str = 'Numele meu este ' . 5 Imi place sa skiez
6 $nume;
7 $str .= "\n";
8 $str .= 'Imi place sa '.
9 $hobby;
10 $str .= "\n\n";
11
12 return $str;
13 }
14
echo hobby('Ion'); // la
apelare, al doilea argument
devine automat valoarea
implicita la definire, 'inot'
echo hobby('Vasile', 'skiez');
?>

Nota
Valorile implicite pot fi si array()

3.3.4. Nr variabil de argumente

O functie poate fi definita fara nici un argument, si apelata cu orice numar de argumente (nici unul, unul, mai multe argumente). Daca insa definim o
functie cu un numar obligatoriu de argumente, trebuie sa apelam functia cu cel putin acel numar de argumente. Exista urmatoarele functii in PHP ce ne
ajuta sa extragem numarul si valorile argumentelor cu care apelam o functie:
- func_num_args() - returneaza numarul de argumente cu care apelez functia
- func_get_args - returneaza un array ce contine valorile argumentelor cu care apelez functia
- func_get_arg($x) - returneaza valoarea argumentului de pe pozitia $x

Sursa script Sursa HTML in browser


1 <?php 1 bool(false)
2 function medie() 2 int(2)
3{ 3 int(5)
4 $nr = func_num_args(); 4 int(2)
5 $suma = 0;
6 $lista_argumente =
7 func_get_args();
8
9 if ($nr) {
10 foreach ($lista_argumente as
11 $valoare) {
12 $suma += $valoare;
13 }
14
15 $medie = $suma / $nr;
16
17 return $medie;
18
19 } else return false;
20 }
21
22 var_dump(medie()); //
23 bool(false)
24 var_dump(medie(1,3)); // int(2)
var_dump(5); // int(5)
var_dump(medie(1, medie(1,3),
3)); // int(2)
?>

Transmiterea argumentelor prin valoare si prin referinta


Transmiterea "prin valoare"
In sintaxa uzuala, si cea exemplificata pana acum, transmiterea valorii argumentelor la apelarea unei functii s-a facut "prin valoare". In exemplul urmator,
in momentul cand apelam creste($y), se copiaza valoarea lui $y in zona de memorie a variabilei $x, (ca si cum am scrie $x = $y) iar $x devine variabila
locala functiei creste() si este independenta de variabila $y. Astfel, orice modificari ale variabilei $x in interiorul functiei, nu afecteaza variabila $y din afara
functiei.

1 <?php
2
3 function creste($x)
4{
5 $x++;
6}
7
8 $y = 1;
9 creste($y);
10 var_dump($y); // int(1)
11 var_dump($x); // NULL
12 ?>

3.3.5. Transmiterea "prin referinta"

Daca insa vreau sa modific in interiorul functiei argumentul cu care apelez functia, la definire, scriu simbolul "&" in fara argumentului respectiv. Astfel,
daca urmam exemplul anterior, $x este "conectata" la $y, se refera la aceeasi zona de memorie (transmiterea se face echivalent cu $x =&$y). In acest
caz, modificarile variabilei $x in interiorul functiei vor afecta variabila $y din afara functiei. Totusi, si in acest caz, $x este variabila locala functiei, deci nu
poate fi accesata din afara functiei, si orice variabila $x din afara functiei este independenta de $x din interiorul functiei.

1 <?php
2
3 function creste(&$x)
4{
5 $x++;
6}
7
8 $y = 1;
9 creste($y);
10 var_dump($y); // int(2)
11 var_dump($x); // NULL
12 ?>
Nota
Daca la definirea unei functii avem in lista un argument transmis prin referinta, la apelarea functiei poate fi folosita doar o variabila.

1 <?php
2
3 function creste(&$x)
4{
5 $x++;
6}
7
8 $y = 1;
9 //creste(5); // Fatal error: Only variables can be passed by
10 reference...
11 //creste($y+1); // Fatal error: Only variables can be passed by
12 reference in
13
14 creste($y); // corect. $y devine 2
15
16 creste($a); // corect. desi variabila $a nu exista, este creata cu
17 valoarea implicita null.
/* $a este convertit la intreg, devina 0, si $a++ devine 1 */
var_dump($a); // int(1)
?>

Nota
Incepand cu PHP5, argumentele transmise prin referinta pot avea si valori implicite.

Sursa script Sursa HTML in browser


1 <?php 1 int(14)
2 function scade(&$a = 10) 2 int(14)
3{
4 $a--;
5 if ($a == 0) return false;
6}
7
8 $x = 15;
9 scade($x); // se modifica $a in
10 interiorul functiei, deci se
11 modifica si $x pentru ca sunt
12 "conectate"
13 var_dump($x); // $x devine 14
14
scade(); // poate fi apelata
fara nici un argument. $a in
interiorul functiei ia valoarea
implicita 10
var_dump($x); // $x ramane 14.
in apelarea fara argumente s-a
modificat doar $a din interiorul
functiei
?>

3.3.6. Returnarea prin valoare si prin referinta

Sunt anumite cazuri, ce pot fi intalnite in cazul programarii orientate pe obiecte, sau cand functia noastra returneaza variabile de tip resource cand avem
nevoie ca variabila returnata de functie sa fie "conectata" cu variabila rezultata din apelarea functiei. In acest caz, trebuie sa precedam numele functiei cu
"&" atat la definire cat si la apelare. Exemplul de mai jos, arata modul in care se foloseste returnarea prin referinta desi, in acest caz simplu nu prezinta
nici un avantaj:

Sursa script Sursa HTML in browser


1 <?php 1 int(2)
2 function &creste($x) {
3 return ++$x;
4}
5
6
7 $a = 1;
8 $b =& creste($a);
9 var_dump($b);
10
11 ?>

3.3.7. Descrierea functiilor in manualul PHP


Toate functiile predefinite (existente deja in limbajul PHP) sunt descrise in manualul PHP. Desi cele mai folosite dintre ele sunt prezentate si in acest curs,
este foarte important sa folositi si manualul PHP pentru a citi descrierea lor in documentatia oficiala. Cum spuneam, creatorii site-ului php.net au realizat
un "shortcut" pentru accesarea documentatiei fiecarei functii predefinite. Acest shortcut este de forma php.net/nume_functie. Tastati de exemplu in
browser php.net/mysql_connect , php.net/in_array , php.net/trim.

Pentru descrierea functiilor din manualul PHP se foloseste o "sintaxa de descriere" (numita si prototipul functiei, sau definitia functiei) care o data
asimilata, ne ajuta sa citim mai usor descrierea fiecarei functii. De exemplu, prima parte a descrierii din manual a functiei in_array, despre care vom vorbi
intr-un capitol urmator, arata astfel:
Descrierea functiei in_array
in_array

(PHP 4, PHP 5)

in_array — Checks if a value exists in an array

Description
bool in_array ( mixed $needle , array $haystack [, bool $strict ] )

Searches haystack for needle .

Sa luam pe rand fiecare element din aceasta descriere:

 in_array - numele functiei descrise

 (PHP 4, PHP 5) - versiunile de PHP in care aceasta functie e disponibila.

 in_array - Checks if a value exists in an array - O descriere in cuvinte a functiei

 bool in_array ( mixed $needle , array $haystack [, bool $strict ] ) - Aici avem prototipul functiei, descrierea concisa a tipului de date returnat
si a argumentelor primite:

o bool

- acest cuvant de dinaintea numelui functiei specifica tipul de date returnat de functie. In acest caz este boolean (bool) deci
functia returneaza TRUE sau FALSE
o mixed $needle , array $haystack [, bool $strict ] - aici sunt enumerate argumentele (parametrii) functiei, fiecare avand inaintea
lui un tip de date. Variabilele sunt denumite si ele uneori sugestiv.
- mixed $needle - tipul de date este mixed. mixed nu este de fapt un tip de date, inseamna de fapt ca variabila respectiva
poate avea mai multe tipuri de date (dar nu neaparat orice tip de date). Aici, denumirea variabilei,$needle care inseamna "ac"
are sens pentru ca urmatoarea variabila numita $haystack inseamna "capita de fan".
- array $haystack - acest al doilea parametru trebuie sa aiba tipul de date array.
- [, bool $strict] - argumentele intre paranteze patrate sunt optionale. Acest al treilea parametru este deci optional, si are tipul
de date bool (boolean), prin urmare poate fi TRUE sau FALSE.

 Searches haystack for needle. - inca o descriere scurta a functiei, dupa prototip, in functie de argumente

Urmeaza apoi pe pagina cu documentatia functiei sectiunile Parameters o sectiune in care sunt descrisi mai pe larg parametrii functiei, apoi Return
Values in care sunt descrise valorile returnate de functie, plus alte informatii utile (exemple, functii similare, etc).

Nota
In prototipul unei functii, uneori, in fata unui parametru intalnim simbolul "&". Asta inseamna ca functia poate modifica parametrul respectiv pentru
ca transferul parametrului este facut prin referinta.

Nota
In acest curs, voi folosi uneori acelasi format ca cel din manualul PHP pentru a prezenta prototipul (definitia) unei functii.

Resurse
PHP Manual - About prototypes

3.4. Tema
Tema 3-1
Construiti o pagina html, in care sa generati cu ajutorul php-ului un tabel cu 2 coloane si 10 randuri in care sa fie numere incepand cu multiple de 3,
incepand cu 3. Deci numerele vor fi: 3, 6, 9, 12, etc. Pentru asta veti folosi tagurile de html pentru tabele, veti folosi un for (sau while daca doriti) si puteti
eventual sa folositi operatorul % (a % b va fi restul impartirii lui a la b).

Tema 3-2
Realizati un array care sa aiba ca elemente stringuri ce reprezinta cai relative catre imagini. Ex: $a = array('img/pic1.jpg', 'img/pic2.jpg', 'img/pic3.jpg');
Treceti cu for sau foreach prin acest array construind astfel codul html pentru realizarea unui tabel astfel incat in fiecare celula de tabel sa fie afisata o
imagine.

Tema 3-3
Modificati tema3-1 si 3-2, astfel incat sarcinile indeplinite sa fie realizate cu ajutorul unor functii, iar informatiile concrete sa fie transmise prin parametri

Tema 3-4
Realizati o functie ce primeste ca prim parametru un nume de tag, si ca parametru secund un string ce reprezinta atributele si valorile tagului respectiv.
Functia va returna codul html aferent. Exemplu, functia trebuie apelata astfel: htmlElement('div', 'align="center" style="width:200px"')

CAP 4. Arrays (tablouri)


4.1 Bazele tablourilor in PHP
4.2 Printarea unui tablou
4.3 Creearea unui tablou
4.4 Tablouri multidimensionale
4.5 Functii de baza pentru manipularea elementelor unui tablou
4.6 Parcurgerea unui tablou
4.7 list() si each()
4.8 Functii pentru ordonare
4.9 Functii pentru operatii intre tablouri
4.10 Tratarea unui tablou ca stiva sau coada
4.11 Alte functii utile
4.12 Tema

4.1. Bazele tablourilor in PHP


Tablourile, sau arrays, reprezinta unul din tipurile de date cele mai folosite si utile in PHP. Ca urmare a flexibilitatii si raspandirii lor, exista peste 70 de
functii predefinite in PHP specializate in lucrul cu arrays. In acest capitol, voi prezenta cele mai importante si uzuale modalitati si functii de a lucra cu
tablouri.
Ce este un array ?
Un array este o lista de elemente. Fiecare element este de fapt o pereche (cheie, valoare). Cheia este unica in interiorul unui array, adica nu exista doua
elemente cu aceeasi cheie. Astfel, pe baza cheii unui element, putem determina (sau schimba) valoarea elementului respectiv. Cheile pot fi doar intregi
sau stringuri. Daca specificam chei de alt tip, ele vor fi convertite la intreg sau string. Elementele pot avea orice tip, inclusiv alt array.

4.2. Printarea unui tablou

Afisarea elementelor unui array se obtine cu functiile print_r() sau var_dump().


var_dump() afiseaza si tipul de date al elementelor array-ului.
print_r() are un output mai simplu si este foarte des folosita in dezvoltarea aplicatiilor in PHP, ca modalitate de debug pentru aflarea continutului unui
array.
In output-ul generat de print_r, cheia este elementul afisat intre paranteze patrate inainte de "=>" iar valoarea elementului este dupa "=>".
In exemplul nostru primul element are cheia 0 si valoarea 1, al doilea element are cheia 1 si valoarea 2...
Sursa script Sursa HTML in browser
1 <?php 1 Array
2 $a = array(1,2,3); 2(
3 3 [0] => 1
4 print_r($a); 4 [1] => 2
5 ?> 5 [2] => 3
6)

4.3. Creearea unui tablou

Principala modalitate de a creea tablouri in PHP este constructia array(). Intre parantezele rotunde se scriu elementele separate prin virgula. Optional,
pentru fiecare element putem specifica si o cheie, caz in care se separa cheia de valoare prin "=>".

Un array poate fi:


- asociativ - are chei de tip string
- numeric - are chei de tip intreg
- mixt - are chei intregi si stringuri

Sintaxa simpla, in care nu definim chei pentru nici un element arata astfel:

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $a = array(-1, 4, 7, 9); 2(
3 3 [0] => -1
4 print_r($a); 4 [1] => 4
5 ?> 5 [2] => 7
6 [3] => 9
7)

In acest caz, cheile sunt generate automat de tip intreg si pornesc de la 0. Cheia poate fi numita in acest caz si index. Daca un array are 4 elemente,
ultimul index va fi 3 (pentru ca primul element are indexul 0). General vorbind, un array cu n elemente va avea ca ultim index n-1.

In exemplul urmator, definim cheile pentru elementele array-ului. Cheile, chiar si atunci cand sunt doar intregi, nu formeaza neaparat un sir continuu de
numere, pot fi pauze intre ele, iar elementele tabloului nu se aseaza in ordinea (numerica) a cheilor:

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $a = array(1 => 'abc', 9 => 5, 2 2(
3 => 7); 3 [1] => abc
4 4 [9] => 5
5 print_r($a); 5 [2] => 7
?> 6)

Nota
Referitor la cheile unui array, e important sa stiti ca sunt case-sensitive, deci cheia "a" este diferita de cheia "A". Daca insa avem de-a face cu un
string numeric, gen "3" , atunci aceasta cheie va fi echivalenta cu intregul 3 pentru ca este convertita la numar (intreg). Deci $a["3"] si $a[3] este
acelasi lucru.

Sursa script Sursa HTML in browser


1 <?php 1 $a prima data este: Array
2 $a = array('a', 'b', 'c', 'd', 2(
3 'e'); 3 [0] => a
4 $a['3'] = 'gg'; 4 [1] => b
5 echo '$a prima data este: '; 5 [2] => c
6 print_r($a); 6 [3] => gg
7 7 [4] => e
8 $a[3] = 'd'; 8)
9 9 $a apoi este: Array
10 echo '$a apoi este: '; 10 (
11 print_r($a); 11 [0] => a
12 12 [1] => b
13 $a[0.5] = 'x'; // va modifica 13 [2] => c
14 $a[0] pentru ca 0.5 convertit la 14 [3] => d
15 intreg este 0 15 [4] => e
16 16 )
echo 'acum $a este: '; 17 acum $a este: Array
print_r($a); 18 (
?> 19 [0] => x
20 [1] => b
21 [2] => c
22 [3] => d
23 [4] => e
24 )

Un array asociativ - cu chei de tip string - arata astfel:

Sursa script Sursa HTML in browser


1 <?php
2 $persoana = array(
3 'prenume' => 'John',
4 'nume' => 'Smith',
5 'varsta' => 39,
6 'country' => 'UK'
7 );
8 ?>

Atunci cand nu specificam o cheie pentru un element, i se adauga automat o cheie dupa urmatoarele reguli:
- daca este prima cheie numerica din tablou, va primi valoarea 0
- daca exista deja in tablou chei numerice mai mari sau egale decat 0, noua cheie va fi maximul cheilor deja definite plus 1

In urmatorul exemplu avem elemente cu cheie specificata de tip intreg, cu cheie specificata de tip string, si fara cheie (deci generata automat). Rezultatul
functiei print_r ne arata cheile pentru fiecare element al tabloului (indiferent ca este scrisa de noi sau generata automat):

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $a = array ( 2(
3 'unu', 3 [0] => unu
4 'doi', 4 [1] => doi
5 29 => 'trei', 5 [29] => trei
6 'patru' => 'patru', 6 [patru] => patru
7 'altceva' => 'cinci', 7 [altceva] => cinci
8 'sase', 8 [30] => sase
9 'sapte', 9 [31] => sapte
10 ); 10 )
11 11 Array
12 print_r($a); 12 (
13 13 [a] => 1
14 14 [b] => 2
15 $b = array( 15 [0] => c
16 'a' => 1, 16 )
17 'b' => 2,
18 'c');
19
20 print_r($b); // aici, elementul
21 'c' primeste cheia 0 pentru ca
este prima cheie numerica
?>

In sintaxa declaratiei array() pot pune virgula "," si dupa ultimul element, nu este considerata o eroare.
Accesarea elementului unui array
Pentru accesarea unui element dintr-un array, scriem numele array-ului urmat de cheia elementului pe care-l accesam intre paranteze patrate []. Folosim
valoarea respectiva in orice loc am folosi si o variabila. Similar cu o variabila, folosind operatorul de atribuire "=" putem modifica elementul respectiv sau
creea un element nou in array.

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $a = array(-1, 4, 7, 9); 2(
3 3 [0] => -1
4 print_r($a); 4 [1] => 4
5 5 [2] => 7
6 echo $a[1]; // elementul cu 6 [3] => 9
7 cheia 1 este 4 7)
8 echo "\n"; 84
9 9 Array
10 $a[1] = 23; // elementul cu 10 (
11 cheia 1 este acum 23 11 [0] => -1
12 $a[17] = 39; // elementul cu 12 [1] => 23
13 cheia 17 nu exista. Prin urmare, 13 [2] => 7
14 el este creeat. 14 [3] => 9
$a['abc'] = 'altceva'; // 15 [17] => 39
elementul cu cheia 'abc' nu 16 [abc] => altceva
exista. Este creeat 17 )

print_r($a);
?>

Adaugarea elementelor cu sintaxa $a[]


Pseudocod
$a[] = valoare;
In momentul cand folosim aceasta sintaxa, se intampla unul din urmatoarele lucruri:
- daca variabila $a nu exista, va fi creeata, cu tipul de date array, si va avea un singur element cu cheia numerica 0, si valoarea atribuita
- daca variabila $a exista, va fi adaugat un nou element avand un index numeric generat automat

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $a[] = 'a'; 2(
3 print_r($a); 3 [0] => a
4 4)
5 $a[] = 'b'; 5 Array
6 $a[] = 'c'; 6(
7 print_r($a); 7 [0] => a
8 $a['cheie_string'] = 'd'; 8 [1] => b
9 $a[9] = 'e'; 9 [2] => c
10 $a[] = 'f'; 10 )
11 11 Array
12 print_r($a); 12 (
13 ?> 13 [0] => a
14 [1] => b
15 [2] => c
16 [cheie_string] => d
17 [9] => e
18 [10] => f
19 )

4.4. Tablouri multidimensionale

In PHP este impropriu sa vorbim despre un tablou multidimensional, mai simplu este sa gandim ca valoarea fiecare element al unui array poate avea orice
tip de date, inclusiv alt array. Pentru accesarea unui element dintr-un array pe mai multe nivele folosim alaturat simbolurile "[]" si intre ele folosim cheia
potrivita de la fiecare nivel. De exemplu:

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $a = array ( 2(
3 array('nume' => 'Mihai', 3 [0] => Array
4 'varsta' => 23, 'sex' => 'm'), 4 (
5 array('nume' => 'Ioana', 5 [nume] => Mihai
6 'varsta' => 45, 'sex' => 'f'), 6 [varsta] => 23
7 'abc', 7 [sex] => m
8 99, 8 )
9 array(1,2), 9
10 ); 10 [1] => Array
11 11 (
12 print_r($a); 12 [nume] => Ioana
13 13 [varsta] => 45
14 /* 14 [sex] => f
15 Al doilea element din array-ul 15 )
16 mare ($a) il accesam cu $a[1]. 16
17 Acesta este la randul sau un 17 [2] => abc
18 array. 18 [3] => 99
19 Elementul cu cheia 'varsta' din 19 [4] => Array
20 acest array il accesam prin 20 (
21 $a[1]['varsta'] 21 [0] => 1
22 */ 22 [1] => 2
23 23 )
24 print_r($a[1]); 24
25 /* 25 )
26 Array 26 Array
27 ( 27 (
28 [nume] => Ioana 28 [nume] => Ioana
29 [varsta] => 45 29 [varsta] => 45
30 [sex] => f 30 [sex] => f
31 ) 31 )
32 */ 32 45

echo $a[1]['varsta']; // 45
$a[1]["varsta"] = 46;

// print_r($a);

?>

4.5. Functii de baza pentru manipularea elementelor unui tablou


count()

Este o functie foarte des folosita cu care determinam numarul de elemente dintr-un array. Primeste ca parametru array-ul pe care-l analizam. Poate primi
insa si un scalar ca parametru, si va intoarce valoarea 1.

Sursa script Sursa HTML in browser


1 <?php 12
2 $a = array ('a', 'b'); 21
3 echo count($a);
4 echo "\n";
5
6 $x = 7;
7 echo count($x); // 1
8 ?>

Functia count() nu ma ajuta sa deosebesc intre un array cu un element si un scalar, din acest motiv, dar si in multe alte cazuri am nevoie sa stiu daca
variabila pe care o folosesc este sau nu array. Pentru asta e utila functia is_array().
is_array()
Similara cu restul functiilor de tip is_*, verifica daca tipul variabilei primite ca parametru este array, si intoarce un rezultat boolean.

Sursa script Sursa HTML in browser


1 <?php 1 bool(false)
2 $a = 5; 2 $a este array si are 1 element(e)
3 var_dump(is_array($a)); // false
4
5 $a = array('a');
6 if (is_array($a)) {
7 echo '$a este array si are ' .
8 count($a) .' element(e)';
9 }
?>

isset() vs array_key_exists()
Cu functia isset() putem verifica daca exista un element intr-un array pentru o cheie data. De exemplu:
Sursa script Sursa HTML in browser
1 <?php 1 Array
2 $a = array('a', 5 => 'b', 'cheie' 2(
3 => 'c'); 3 [0] => a
4 print_r($a); 4 [5] => b
5 5 [cheie] => c
6 if (isset($a['cheie'])) { 6)
7 echo 'exista'; 7 exista
8 }
?>

Insa, isset() nu prezinta modalitatea cea mai sigura de a verifica daca exista un element intr-un array pentru cheia data. Exceptia este cand exista cheia
respectiva, dar elementul (valoarea) este NULL si atunci elementul este perfect valid, cheia exista, dar nu este detectat de isset(), pentru
ca isset() returneaza FALSE pentru valoarea NULL.

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $a = array ('un element', 'alt 2(
3 element', NULL, 'abc'); 3 [0] => un element
4 print_r($a); 4 [1] => alt element
5 5 [2] =>
6 if (isset($a[2])) { // returneaza 6 [3] => abc
7 false 7)
8 echo 'exista';
}
?>

Pentru a verifica daca un element (fie el NULL sau nu) exista intr-un array pentru o cheie data, putem folosiarray_key_exists(cheie, array). Aceasta
functie primeste doi parametri, primul este valoarea cheii pe care o cautam, al doilea este variabila de tip array in care cautam

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $a = array ('un element', 'alt 2(
3 element', NULL, 'abc'); 3 [0] => un element
4 print_r($a); 4 [1] => alt element
5 5 [2] =>
6 if (array_key_exists(2, $a)) { // 6 [3] => abc
7 returneaza true 7)
8 echo 'exista'; 8 exista
}
?>

in_array($valoare, $array, $strict=false)


in_array($valoare, $array, $strict=false) verifica existenta valorii unui element (unei valori) intr-un array.
Daca $strict=false (i.e. cazul implicit), verificarea este facuta testandu-se egalitati simple ("=="), iar in cazul in care $strict=trueverificarea se va face
testandu-se egalitati stricte ("===").

Sursa script Sursa HTML in browser


1 <?php 1 exista
2 $a = array('ion', 'gigi', 2 valoarea 9string exista in $a
3 'maria', 'john'); 3 valoarea 9string nu este in $a
4
5 if (in_array('maria', $a)) {
6 echo 'exista';
7 }
8
9
10 $a = array(1 => 4, 8, 9, 10);
11
12 if (in_array(1, $a)) { // false
13 -> elementul cu valoarea 1 nu
14 exista in array
15 echo 'da'; // nu se afiseaza
16 }
17 echo "\n";
18 //exemplu verificare simpla =>
19 rezultat eronat
20 //stringul '9string' va fi
21 convertit la numarul 9, de unde
22 va rezulta ca exista in $a
23 if (in_array('9string', $a)){
24 echo 'valoarea 9string exista
25 in $a'; // rezultat eronat
26 } else {
27 echo 'valoarea 9string nu este
28 in $a';
29 }
30 echo "\n";
//exemplu verificare stricta =>
rezultat corect
if (in_array('9string', $a,
true)){
echo 'valoarea 9string exista
in $a';
} else {
echo 'valoarea 9string nu este
in $a'; //rezultat corect
}

?>

array_search($valoare, $array, $strict=false)


array_search() verifica deasemenea existenta unei valori in array, si in plus, daca-l gaseste, returneaza cheia elementului respectiv.
Daca $strict=false (i.e. cazul implicit), verificarea este facuta testandu-se egalitati simple ("=="), iar in cazul in care $strict=trueverificarea se va face
testandu-se egalitati stricte ("===").

Nota
Atat in functia in_array() cat si in array_search() valoarea cautata in array poate fi la randul sau un array

Sursa script Sursa HTML in browser


1 <?php 1 bool(true)
2 $a = array(5, 23, 'john', 3, 0); 22
3 3 int(3)
4 $x = in_array('john', $a); 4
5 var_dump($x); // true 5 bool(false)
6 6
7 $x = array_search('john', $a); 71
8 echo $x; // 2
9 echo "\n";
10
11
12 $a = array(5, 23, 3, 0);
13
14 $x = array_search('john', $a);
15 var_dump($x);
16 // rezultat eronat, $x = 3
17 // gaseste valoarea 'john' ca
18 avand cheia 3, adica in locul
19 lui 0
20 // deoarece stringul 'john' a
21 fost convertit la 0 atunci cand
22 s-a facut cautarea
23
24 echo "\n";
25 $x = array_search('john', $a,
26 true);
27 var_dump($x); //rezultat corect
echo "\n";
$a = array(4, array('a', 'b'),
'xyz');
$x = array_search(array('a',
'b'), $a);
echo $x; // 1
?>

Stergerea elementelor dintr-un array - unset()


unset() este functia cu care putem sterge o variabila sau putem sterge un element dintr-un array.

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $a = array('a', 'b', 'c'); 2(
3 unset($a[0]); 3 [1] => b
4 4 [2] => c
5 print_r($a); 5)
6 6 Array
7 $b = array('nume' => 'ion', 8, 7(
8 'varsta' => 25, 10); 8 [nume] => ion
9 unset($b["varsta"]); 9 [0] => 8
10 print_r($b); 10 [1] => 10
?> 11 )

4.6. Parcurgerea unui tablou


4.6.1 foreach
4.6.2 current(), key(), next(), prev()...
4.6.3 array_walk(), array_map()

4.6.1. foreach
In majoritatea cazurilor vom folosi pentru iterarea / parcurgerea unui array constructia foreach. Sintaxa este:
Pseudocod
foreach (array as $valoare) {
// bloc instructiuni
}

sau
Pseudocod
foreach (array as $cheie => $valoare) {
// bloc instructiuni
}

foreach va executa blocul de instructiuni de atatea ori cate elemente are array-ul. La fiecare iteratie, in variabila $valoare (sau cum o denumim) va copia
valoarea elementului curent. In a doua sintaxa, in plus, va copia in variabila $cheie cheia elementului curent.

Sursa script Sursa HTML in browser


1 <?php 1 autobuz masina tren avion racheta
2 $a = array('autobuz', 'masina',
3 'tren', 'avion', 'racheta');
4
5 foreach ($a as $v) {
6 echo $v;
7 echo ' ';
8}
9
?>

Sursa script Sursa HTML in browser


1 <?php 1 0->autobuz
2 $a = array('autobuz', 'masina', 2 1->masina
3 'tren', 'avion', 'racheta'); 3 2->tren
4 4 3->avion
5 foreach ($a as $k => $v) { 5 4->racheta
6 echo $k . '->' . $v;
7 echo "\n";
8}
9
?>

Nota
La fiecare iteratie, atat variabila ce tine cheia curenta cat si cea ce tine valoarea curenta, primesc valoarea respectiva prin simpla atribuire. Asta
inseamna ca daca modificam $cheie sau $valoare nu se modifica de fapt cheia sau valoarea elementului respectiv. Incepand cu PHP5 exista
posibilitatea transmiterii valorii elementului curent al array-ului prin referinta, punand semnul "&" inaintea variabilei $valoare. Asta inseamna ca
$valoare va fi "conectata" cu elementul respectiv. Acest lucru poate introduce usor un bug, in cazul in care folosim mai departe variabila $valoare
pentru ca schimbam de fapt ultimul element al array-ului parcurs.

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $a = array(1, 2, 3); 2(
3 3 [0] => 2
4 foreach ($a as &$v) { 4 [1] => 3
5 $v++; 5 [2] => 4
6} 6)
7 7 Array
8 print_r($a); 8(
9 9 [0] => 2
10 /* decomenteaza linia cu unset 10 [1] => 3
11 */ 11 [2] => abc
12 // unset($v); // ideal este sa 12 )
13 stergem variabila $v care are o
14 referinta catre $a[2]
15 $v = 'abc'; // ca sa nu o
16 folosim accidental mai tarziu si
sa schimbam fara sa vrem arrayul
$a

print_r($a);

?>

4.6.2. current(), key(), next(), prev()...


In general avem nevoie sa parcurgem un array cap-coada intr-o iteratie continua. Atunci folosim foreach.

Desi mai rar, apar ocazii cand avem nevoie sa "ne miscam" in susul si in josul tabloului si poate doar pe o anumita portiune. Atunci sunt utile functiile ce
deplaseaza "pointerul" intern al array-ului. Pointerul indica elementul curent al array-ului pe care lucram.

Aceste functii sunt:

 reset($array) - aduce pointerul la inceputul array-ului si returneaza primul element (valoarea primului element) sau FALSE daca array-ul nu
are elemente

 end($array) - muta pointerul la sfarsitul array-ului si returneaza ultimul element (valoarea ultimului element) sau FALSE daca array-ul nu
are elemente

 prev($array) - muta pointerul la elementul anterior si returneaza elementul respectiv

 next($array) - muta pointerul la elementul urmator si returneaza elementul respectiv

 current($array) - NU deplaseaza pointerul. returneaza elementul curent (valoarea elementului curent)

 key($array) - NU deplaseaza pointerul. returneaza cheia elementului curent

Nota
prev() si next() returneaza FALSE cand se incearca accesarea dincolo de primul respectiv ultimul element. Insa, nu se poate sti exact daca prev() si
next() returneaza FALSE pentru ca au trecut de capete sau pentru ca returneaza un element ce este evaluat la FALSE. Trebuie sa fiti atenti la acest
lucru, si in plus, e mai sigur sa folositi operatorul "===" ce testeaza si tipul de date, astfel stiti sigur ca next() a returnat false si nu 0 sau "" sau
alta valoare evaluata la FALSE

Sursa script Sursa HTML in browser


1 <?php 10 a
2 $a = array('a', 'b', 'c', 'd', 2c
3 'e'); 3d
4
5 echo key($a); // 0 - cheia
6 elementului curent
7 echo ' ';
8 echo current($a); // a -
9 elementul curent, este primul
10 element
11
12 echo "\n";
13
14 next($a); // pointerul se muta
15 la urmatorul element, la b
16 next($a); // pointerul se muta
17 la urmatorul element, la c
18 echo current($a); // c
19
20 echo "\n";
21
echo next($a); // d -
/* pointerul s-a mutat la
urmatorul element, de data asta
folosim si valoarea returnata
de next() adica urmatorul
element, d
*/

?>

Sursa script Sursa HTML in browser


1 <?php 1 ab
2 $a = array('a', 'b', 0, 'd',
3 'e');
4
5 /*
6 cand next($a) este apelat a doua
7 oara,
8 returneaza 0 (al 3-lea element)
9 care este evaluat la false,
10 si atunci bucla se intrerupe
11 pentru ca (0 != FALSE) este
12 FALSE, mai precis 0 == FALSE
13 */
14
15 do {
echo current($a);
} while (next($a) != FALSE)

?>

Sursa script Sursa HTML in browser


1 <?php 1 ab0de
2 $a = array('a', 'b', 0, 'd',
3 'e');
4
5 /*
6 folosim aici operatorul !== care
7 testeaza daca operanzii sunt
8 diferiti SAU au tip de date
9 diferit
10 in acest caz (0 !== FALSE) este
11 evaluat la TRUE pentru ca au tip
12 de date diferit, si bucla
13 continua
14 sa afiseze pana next($a)
15 returneaza FALSE pentru ca a
16 ajuns la sfarsitul array-ului

*/

do {
echo current($a);
} while (next($a) !== FALSE)

?>

4.6.3. array_walk(), array_map()


array_walk() si array_walk_recursive()

Nota
Unele functii (cum ar fi array_walk() ) accepta printre parametrii un parametru de tip callback. callback este unul din asa-zisele "pseudo-types"
(alaturi de number, mixed) deci are un inteles special. Acest callback este de fapt un string, ce reprezinta numele unei functii definita de
programator ce este apelata in anumite conditii si cu anumiti parametri de catre functia initiala ( in exemplul nostru array_walk() ).

Functia array_walk() are urmatorul prototip:


bool array_walk ( array &$array , callback $funcname [, mixed $userdata ] )

Functia array_walk() va apela functia definita de noi cu numele $funcname pentru fiecare element din arrayul $array, pasand functiei callback
($funcname) doi parametri: primul parametru va fi valoarea fiecarui element, iar al doilea parametru va fi cheia fiecarui element. Daca
functiei array_walk() ii furnizam parametrul optional - mixed $userdata - atunci functia callback va primi si ea ca al treilea parametru valoarea variabilei
$userdata. Din functia callback definita de noi ($funcname) putem schimba valoarea fiecarui element din $array doar daca transmitem punem "&" in fata
primului parametru (valoarea fiecarui element).

Prototipul unei functii callback, definita de noi, pentru array_walk() arata astfel:
void funcname (mixed $v, mixed $k [, mixed $userdata])

Mai simplu se ilustreaza functionalitatea functiei array_walk impreuna cu functia callback in exemple:

Sursa script Sursa HTML in browser


1 <?php 1 0->21
2 $a = array(1, 2, 3, 4, 5); 2 1->22
3 3 2->23
4 function afiseaza($v, $k, 4 3->24
5 $cu_cat) 5 4->25
6{ 6
7 $v += $cu_cat; 7
8 echo $k . '->' . $v; 8 0->101
9 echo "\n"; 9 1->102
10 } 10 2->103
11 11 3->104
12 12 4->105
13 array_walk($a, 'afiseaza', 20); 13
14 echo "\n\n"; 14
15 array_walk($a, 'afiseaza', 100); 15 Array
16 16 (
17 echo "\n\n"; 17 [0] => 1
18 18 [1] => 2
19 /* $a este insa nemodificat */ 19 [2] => 3
20 print_r($a); 20 [3] => 4
?> 21 [4] => 5
22 )

Similar cu exemplu anterior, doar ca s-a pus "&" in fata parametrului $v. De data asta, fiecare element al array-ului este modificat.
Sursa script Sursa HTML in browser
1 <?php 1 0->21
2 $a = array(1, 2, 3, 4, 5); 2 1->22
3 3 2->23
4 function creste(&$v, $k, 4 3->24
5 $cu_cat) 5 4->25
6{ 6
7 $v += $cu_cat; 7
8 echo $k . '->' . $v; 8 0->121
9 echo "\n"; 9 1->122
10 } 10 2->123
11 11 3->124
12 12 4->125
13 array_walk($a, 'creste', 20); 13
14 echo "\n\n"; 14
15 array_walk($a, 'creste', 100); 15 Array
16 16 (
17 echo "\n\n"; 17 [0] => 121
18 18 [1] => 122
19 /* $a este insa nemodificat */ 19 [2] => 123
20 print_r($a); 20 [3] => 124
?> 21 [4] => 125
22 )

array_walk_recursive() este similar cu array_walk() doar ca stie sa patrunda in adancime intr-un array multidimensional.

Sursa script Sursa HTML in browser


1 <?php 1 0->6
2 $a = array(1, 2, array(3, 7)); 2 1->7
3 3 0->8
4 array_walk_recursive($a, 4 1->12
5 'creste', 5); 5 Array
6 // array_walk($a, 'creste', 6(
7 5); // aceasta linie ar fi 7 [0] => 6
8 generat o eroare, pentru ca s-ar 8 [1] => 7
fi incercat adunarea dintre 9 [2] => Array
array(3, 7) si 5 10 (
11 [0] => 8
print_r($a); 12 [1] => 12
?> 13 )
14
15 )

array_map()
Desi din aceeasi categorie de a itera prin array cu ajutorul unui callback, array_map() functioneaza putin diferit.

Prototipul ei este:
array array_map ( callback $callback , array $arr1 [, array $... ] )

Functia array_map primeste ca prim parametru functia callback, si apoi un numar de variabile de tip array, iar aceste array-uri trebuie sa aiba acelasi
numar de elemente, sa zicem n. Functia callback trebuie sa aiba atatia parametri cate array-uri primeste functia array_map, si va fi chemata odata pentru
fiecare element din primul array, primind ca parametri elementul curent din fiecare array.
Functia callback va returna de fiecare data cand e apelata un element al noului array.

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $a = array(1, 2, 3); 2(
3 3 [0] => 2
4 4 [1] => 3
5 function modifica($v) 5 [2] => 4
6{ 6)
7 $v++;
8 return $v;
9}
10
11
12 $x = array_map('modifica', $a);
13
14 print_r($x);
15 ?>

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $a = array(8, 9, 10); 2(
3 3 [0] => 64
4 4 [1] => 81
5 function patrat($v) 5 [2] => 100
6{ 6)
7 $x = $v * $v;
8 return $x;
9}
10
11
12 $x = array_map('patrat', $a);
13
14 print_r($x);
15 ?>

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $a = array(1, 2, 3); 2(
3 $b = array('un', 'dos', 'tres'); 3 [0] => 1 - un
4 4 [1] => 2 - dos
5 function asociaza($v1, $v2) 5 [2] => 3 - tres
6{ 6)
7 $x = $v1 . ' - ' . $v2; // $v1
8 si $v2 iau pe rand fiecare
9 valoare din $a respectiv $b
10 return $x; // la fiecare
11 apelare, returneaza cate un
12 element din array-ul nou format
13 }
14
15 $noul_array =
array_map('asociaza', $a, $b);
// returneaza array-ul format
prin functia callback

print_r($noul_array);
?>

Resurse
PHP Manual - Pseudo types

4.7. list() si each()


list()
list() este o constructie de limbaj (nu o functie) folosita pentru a atribui valori intr-o singura operatie unor variabile.

Sursa script Sursa HTML in browser


1 <?php 1 John
2 $a = array('John', 45, 'zidar'); 2 45
3 3 zidar
4 list($nume, $varsta, $ocupatie)
5 = $a;
6
7 echo $nume;
8 echo "\n";
9
10 echo $varsta;
11 echo "\n";
12
13 echo $ocupatie;
14 echo "\n";
15
?>

Nota
list() lucreaza doar cu tablouri numerice. Daca insa in dreapta atribuirii avem un tablou mixt, list() va folosi din acel array doar elementele cu chei
numerice

Sursa script Sursa HTML in browser


1 <?php 1 string(3) "ion"
2 $a = array( 2
3 'ion', 3 string(5) "maria"
4 'cheie1' => 'john', 4
5 'cheie2' => 'mary', 5 NULL
6 'maria'); 6
7 7 NULL
8 list($x, $y, $z, $t) = $a;
9
10 var_dump($x);
11 echo "\n";
12 var_dump($y);
13 echo "\n";
14 var_dump($z);
15 echo "\n";
16 var_dump($t);
17
18 ?>

each()
each() este o functie predefinita, avand urmatorul prototip:
array each ( array &$array )

Primeste ca parametru un array, returneaza un array ce contine informatii despre valoarea si cheia elementului curent din array (avand cheile 0, 1, 'key',
'value'), si avanseaza pointerul sau returneaza FALSE daca a trecut de ultimul element. E bine sa folosim functia reset() inainte de a folosi each() sau alte
functii ce se folosesc de pointerul array-ului, pentru a fi siguri ca pointerul este pe primul element.

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 /* 2(
3 array-ul returnat de each() are 3 [1] => a
4 o constructie redundanta, 4 [value] => a
5 tocmai pentru a fi util in 5 [0] => 0
6 diferite situatii: 6 [key] => 0
7 7)
8 $x[0] este echivalent cu 8 Array
9 $x['key'] 9(
10 $x[1] este echivalent cu 10 [1] => b
11 $x['value'] 11 [value] => b
12 12 [0] => 1
13 */ 13 [key] => 1
14 14 )
15 $a = array('a', 'b', 'c', 'd');
16
17 $x = each($a);
18 print_r($x);
19
20
$x = each($a);
print_r($x);

?>

Una din situatiile in care formatul array-ului returnat de each() ne foloseste este atunci cand combinam each() cu list(). Se pot combina aceste doua functii
pentru a itera printr-un array.

Sursa script Sursa HTML in browser


1 <?php 1 prenume - > Razvan
2 $a = array('prenume' => 2 varsta - > 29
3 'Razvan', 'varsta' => 29, 'alt 3 0 - > alt element
4 element', 9=>77); 4 9 - > 77
5
6 while(list($cheie, $valoare) =
7 each($a)) {
8 echo $cheie . ' - > ' .
9 $valoare;
10 echo "\n";
}

?>

4.8. Functii pentru ordonare


Exista mai multe functii (ce au la randul lor mai multe optiuni) pentru ordonare in PHP in functie de ce anume vrem sa obtinem exact. Functiile modifica
array-ul primit ca parametru.
sort() / rsort()
Functiile ordoneaza crescator (descrescator pentru rsort ) elementele unui array si NU pastreaza cheile originale ale array-ului.

Au urmatorul prototip:
Pseudocod
bool sort ( array &$array [, int $sort_flags = SORT_REGULAR ] )

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 2(
3 $a = array('Mihai', 'Zamfir', 7, 3 [0] => Ana
4 8, 'George', 'Ana'); 4 [1] => George
5 sort($a); 5 [2] => Mihai
6 6 [3] => Zamfir
7 print_r($a); 7 [4] => 7
8 8 [5] => 8
?> 9)

Al doilea parametru pentru aceste functii este optional, si poate fi una din constantele:
- SORT_REGULAR - ordonarea valorilor se face normal, fara conversia la un tip de date
- SORT_NUMERIC - ordonarea valorilor se face numeric, prin urmare valorile sunt evaluate (convertite temporar) ca numar
- SORT_STRING - ordonarea valorilor se face ca string, valorile sunt evaluate ca string

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 2(
3 $a = array('Mihai', 'Zamfir', 7, 3 [0] => Mihai
4 8, '9George', 'Ana'); 4 [1] => Zamfir
5 5 [2] => Ana
6 sort($a, SORT_NUMERIC); 6 [3] => 7
7 // sort($a, SORT_STRING); 7 [4] => 8
8 8 [5] => 9George
9 print_r($a); 9)
10
?>

asort() / arsort()
Similare cu sort / rsort dar pastreaza cheile originale ale array-ului. Daca va amintiti, ordinea elementelor unui array in php nu este dictata de ordinea
cheilor.

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 2(
3 $a = array('Mihai', 'Zamfir', 7, 3 [5] => Ana
4 8, 'George', 'Ana'); 4 [4] => George
5 5 [0] => Mihai
6 asort($a); 6 [1] => Zamfir
7 7 [2] => 7
8 print_r($a); 8 [3] => 8
?> 9)

usort()
prototipul acestei functii este:
Pseudocod
bool usort ( array &$array , callback $cmp_function )

usort() foloseste o functie definita de catre programator (functia callback primita ca argument) pentru a realiza compararea elementelor array-ului ce
trebuie ordonate. usort() reindexeaza (nu pastreaza cheile originale). Functia similara cu usort() dar care pastreaza cheile orginale este uasort().
Functia de comparare trebuie sa returneze:
- 0 daca elementele comparate sunt egale
- valoare pozitiva daca primul argument e mai mare decat al doilea
- valoare negativa daca al primul argument e mai mic decat al doilea

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $a = array('Dl Ionescu', 'Dna 2(
3 Popescu', 'Mr Smith', 'Mrs 3 [0] => Dl Ionescu
4 Johnson'); 4 [1] => Mrs Johnson
5 usort($a, 'compara'); 5 [2] => Dna Popescu
6 6 [3] => Mr Smith
7 function compara($v1, $v2) 7)
8{
9 $x1 = explode(' ', $v1); //
10 sparge de exemplu "Dl Ionescu"
11 intr-un array ('Dl', 'Ionescu')
12 $x2 = explode(' ', $v2);
13
14 // print_r($x1);
15 // print_r($x2);
16
17 /*
18 strcasecmp($str1, $str2) este o
19 functie ce compara doua
20 stringuri
21 returneaza < 0 daca $str1 <
22 $str2
23 returneaza 0 pentru $str1 =
24 $str2
25 si > 0 pentru $str1 > $str2
26
27 in $x1[1] o sa avem ceva gen
28 "Ionescu" iar in $x2[1] o sa
29 avem geva gen "Popescu" deci
30 exact stringurile care ne
31 intereseaza
32 */
33
34 $x = strcasecmp($x1[1],
35 $x2[1]);
36
37 /*
38 // pentru debug, intelegerea
39 functiei
echo $x1[1];
echo ' ';
echo $x2[1];
echo "\n";
echo 'Rezultatul compararii
este: ' . $x;
echo "\n
--------------------------------
------- \n";
*/

return $x;
}

print_r($a);
?>

natsort() si natcasesort()
nat in acest caz vine de la natural, si se refera la o comparare "umana" a elementelor, adica stringurile "fisier1.txt", "fisier2.txt", "fisier10.txt",
"fisier11.txt" vor fi ordonate astfel, in schimb ce o ordonare ca string o va ordona diferit. natcasesort() este similar cu natsort() dar este case-insensitiv.
Ambele functii primesc un singur argument, array-ul ce trebuie ordonat. Functiile pastreaza cheile originale (nu reindexeaza).

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $a = array('f9', 'f10', 'f1', 2(
3 'f2', 'f12', 'f23'); 3 [2] => f1
4 natsort($a); 4 [3] => f2
5 5 [0] => f9
6 print_r($a); 6 [1] => f10
7 7 [4] => f12
8 /* daca in schimb folosim, 8 [5] => f23
9 sort() pentru o sortare ca 9)
10 string */ 10 Array
11 11 (
sort($a, SORT_STRING); 12 [0] => f1
print_r($a); 13 [1] => f10
?> 14 [2] => f12
15 [3] => f2
16 [4] => f23
17 [5] => f9
18 )

ksort si krsort()
Aceste functii ordoneaza elementele unui array dupa chei. Argumentul $sort_flags reprezinta optiuni de ordonare (vezi sort()).
prototip este similar cu sort() / rsort():
Pseudocod
bool ksort ( array &$array [, int $sort_flags ] )
Sursa script Sursa HTML in browser
1 <?php 1 Array
2 $a = $b = array( 2(
3 9 => 'a', 3 [0] => d
4 3 => 'b', 4 [3] => b
5 10 => 'c', 5 [9] => a
6 0 => 'd' 6 [10] => c
7 ); 7)
8 8 Array
9 ksort($a); 9(
10 sort($b); 10 [0] => a
11 11 [1] => b
12 print_r($a); // sortat cu ksort: 12 [2] => c
13 sorteaza dupa chei, dar 13 [3] => d
14 pastreaza asocierea cheie => 14 )
valoare (nu reindexeaza)
print_r($b); // sortat cu sort:
sorteaza dupa elemente (valori),
si reindexeaza
?>

uksort()
Sorteaza dupa chei, folosind insa functie definita de programator (callback). Este similara cu usort() care insa sorta dupa valori.

prototip:
Pseudocod
bool uksort ( array &$array , callback $cmp_function )

4.9. Functii pentru operatii intre tablouri


Daca privim tablourile in PHP ca multimi, exista functii ce realizeaza operatiile matematice uzuale intre multimi: reuniunea, diferenta, intersectia.
Reuniunea/Adunarea intre tablouri ( + sau array_merge() )
Cand adunam doua tablouri, folosind operatorul plus (+) , elementele tabloului din dreapta sunt adaugate la cel din stanga, formand astfel un array ce
contine elementele ambelor tablouri. Pentru elemente ce au aceleasi chei in cele doua tablouri, sunt pastrate valorile tabloului din
stanga. array_merge() este folosit pentru acelasi lucru, reuneste elementele celor doua tablouri dar se comporta diferit. Elementele tabloului din dreapta
ce au aceeasi cheie (de tip string), inlocuiesc elementele tabloului din stanga. Daca in schimb cele doua tablouri au elemente duplicat de tip
numeric, array_merge() adauga elementele din dreapta si schimba cheile (reindexeaza).

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $a = array('prenume' => 'ion', 2(
3 'varsta' => 23, 'inaltime' => 3 [prenume] => ion
4 182); 4 [varsta] => 23
5 $b = array( 'varsta' => 24, 5 [inaltime] => 182
6 'greutate' => 87); 6 [greutate] => 87
7 7)
8 $c = $a + $b; 8 Array
9 print_r($c); 9(
10 10 [prenume] => ion
11 11 [varsta] => 24
$c = array_merge($a, $b); 12 [inaltime] => 182
print_r($c); 13 [greutate] => 87
?> 14 )

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $a = array(7 => 'a', 'x' => 'b', 2(
3 'y' => 'c', 10 => 'd'); 3 [7] => a
4 $b = array('e', 7 => 'f', 'y' => 4 [x] => b
5 'g'); 5 [y] => c
6 6 [10] => d
7 7 [0] => e
8 $c = $a + $b; 8)
9 print_r($c); 9 Array
10 10 (
11 $c = array_merge($a, $b); 11 [0] => a
print_r($c); 12 [x] => b
?> 13 [y] => g
14 [1] => d
15 [2] => e
16 [3] => f
17 )

Diferenta intre tablouri


Functiile din familia array_diff* vor compara elementele din cele doua tablouri, si returneaza elementele ce exista in primul tablou dar nu se afla in cel
de-al doilea.

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $a = array('verde', 'rosu', 2(
3 'galben'); 3 [0] => verde
4 $b = array('rosu', 'galben', 4)
5 'roz');
6
7 $c = array_diff($a, $b);
print_r($c);
?>

Din aceeasi familie fac parte: array_diff_key, array_diff_assoc, array_diff_ukey, array_diff_uassoc, array_udiff, array_udiff_assoc, array_udiff_uassoc.
Ceea ce difera este modul in care functia stabileste daca un element din primul tablou se afla sau nu in cel de-al doilea. Daca un element din primul tablou
se afla in cel de-al doilea (deci nu apare in diferenta), inseamna ca ele sunt egale dintr-un punct de vedere. array_diff stabileste ca doua elemente (cate
un element din fiecare array) sunt egale daca au aceeasi valoare, array_diff_key stabileste ca doua elemente sunt egale daca au aceeasi cheie,
array_diff_assoc stabileste egalitatea daca doua elemente au aceeasi valoare si aceeasi cheie, etc.

Intersectia intre tablouri


Functii ce formeaza un tablou din elementele comune ale tablourilor ce se intersecteaza.

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $a = array('verde', 'rosu', 2(
3 'galben'); 3 [1] => rosu
4 $b = array('rosu', 'galben', 4 [2] => galben
5 'roz'); 5)
6
7 $c = array_intersect($a, $b);
print_r($c)
?>

Din aceeasi familie fac parte: array_intersect(), array_intersect_assoc(), array_intersect_key(), array_intersect_uassoc(), array_intersect_ukey(),
array_uintersect(), array_uintersect_assoc(), array_uintersect_uassoc().
4.10. Tratarea unui tablou ca stiva sau coada

Exista doua structuri de date clasice in programare numite "stiva" si "coada".


- stiva functioneaza conform principiului "ultimul intrat primul iesit" (LIFO - Last In, First Out)
- coada functioneaza conform principiului "primul intrat primul iesit" (FIFO - First In, First Out)

Stiva poate fi construita in PHP cu ajutorul functiilor array_pop() si array_push().


Coada poate fi construita cu ajutorul functiilor array_unshift() si array_shift().

array_push(), array_pop()
- array_push() - adauga elementele la sfarsitul unui tablou
- array_pop() - elimina ultimul element din tablou si il returneaza

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $a = array('unu', 'doi', 2(
3 'trei'); 3 [0] => unu
4 4 [1] => doi
5 array_push($a, 'patru', 5 [2] => trei
6 'cinci'); 6 [3] => patru
7 7 [4] => cinci
8 print_r($a); 8)
9 9 cinci
10 $x = array_pop($a); 10 Array
11 echo $x; 11 (
12 echo "\n"; 12 [0] => unu
13 print_r($a); 13 [1] => doi
14 14 [2] => trei
15 array_pop($a); 15 [3] => patru
print_r($a); 16 )
?> 17 Array
18 (
19 [0] => unu
20 [1] => doi
21 [2] => trei
22 )

array_unshift(), array_shift()
- array_unshift() - adauga elementele la inceputul tabloului
- array_shift() - elimina primul element din tablou si il returneaza

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 2(
3 $a = array('unu', 'doi', 3 [0] => patru
4 'trei'); 4 [1] => cinci
5 5 [2] => unu
6 array_unshift($a, 'patru', 6 [3] => doi
7 'cinci'); 7 [4] => trei
8 8)
9 print_r($a); 9 patru
10 10 Array
11 $x = array_shift($a); 11 (
12 12 [0] => cinci
13 echo $x; 13 [1] => unu
14 echo "\n"; 14 [2] => doi
15 15 [3] => trei
16 print_r($a); 16 )
17 17 Array
18 // poate avem nevoie doar sa 18 (
19 "scurtam" tabloul cu primul 19 [0] => unu
20 element... 20 [1] => doi
21 // ... nu si de valoarea lui 21 [2] => trei
22 (valoarea returnata de 22 )
array_shift())

array_shift($a);
print_r($a);

?>

4.11. Alte functii utile


explode(), implode()
explode() "sparge" un string in bucati ce devin elemente ale unui tablou. Aceasta rupere a stringului se face pe baza altui string numit delimitator.

explode() are urmatorul prototip:


Pseudocod
array explode ( string $delimiter , string $string [, int $limit=-1 ] )

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 2(
3 $nume = 3 [0] => Maria
4 'Maria,Ionel,Radu,Mioara'; // 4 [1] => Ionel
5 $nume este string, sir de 5 [2] => Radu
6 caractere 6 [3] => Mioara
7 7)
8 $nume_arr = explode(',', $nume);
9 // $nume arr este array. Stringul
a fost "spart" dupa delimitatorul
(,)

print_r($nume_arr);

?>

implode() realizeaza operatia inversa fata de explode(). implode() realizeaza "lipirea" elementelor unui array intr-un string, folosind un alt string pe
post de "lipici".
Pseudocod
string implode ( string $glue , array $pieces )

Sursa script Sursa HTML in browser


1 <?php 1 Maria|Ionel|Radu|Mioara
2 $nume = array('Maria', 'Ionel',
3 'Radu', 'Mioara'); // $nume este
4 array
5
6 $nume_str = implode("|", $nume);
7 // $nume_str este string

echo $nume_str;
?>

array_flip(), array_reverse()
array_flip($arr) primeste ca parametru un tablou, si formeaza un nou tablou ce are ca si chei valorile primului tablou, si ca valori cheile primului tablou.
Asta inseamna ca valorile (ce vor deveni chei) trebuie sa fie chei valide, adica de tipul int sau string. In caz contrar, perechea respectiva cheie, valoare nu
va fi inclusa in noul tablou. In cazul in care exista in primul tablou mai multe valori identice, va fi inclusa in noul tablou ultima pereche (cheie => valoare)
ce contine valoarea respectiva.

Sursa script Sursa HTML in browser


1 <?php
2 $a = array(23 => 'varsta', 'ion'
3 => 'prenume', 'student' =>
4 false);
5
6
7 // $d = array_flip($a); //
8 genereaza un warning pentru ca
false are tipul boolean, si nu va
fi o cheie valida

// print_r($d);
?>

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $a = array(1 => 'unu', 2 => 2(
3 'doi', 'cifra trei' => 'trei', 3 3 [1] => unu
4 => 'trei'); 4 [2] => doi
5 print_r($a); // inainte sa fie 5 [cifra trei] => trei
6 "flipped" 6 [3] => trei
7 7)
8 $a2 = array_flip($a); 8 Array
9(
print_r($a2) // $a flipped 10 [unu] => 1
?> 11 [doi] => 2
12 [trei] => 3
13 )

array_reverse() inverseaza ordinea elementelor unui tablou cu sau fara pastrarea cheilor originale, in functie de un al doilea parametru. Are urmatorul
prototip:
Pseudocod
array array_reverse ( array $array [, bool $preserve_keys=false ] )

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $a = array('a', 'b', 'c'); 2(
3 3 [0] => c
4 4 [1] => b
5 $a2 = array_reverse($a); 5 [2] => a
6 print_r($a2); 6)
7 7 Array
8 8(
9 $a3 = array_reverse($a, true); 9 [2] => c
10 // pastreaza asocierea initiala 10 [1] => b
11 cheie => valoare 11 [0] => a
12 print_r($a3); 12 )
13
14

?>

array_keys(), array_values()
array_keys() returneaza intr-un tablou cheile unui tablou dat. In cazul in care folosim al doilea parametru, ($search_value), returneaza doar cheile ce au
exact valoarea $search_value. Daca folosim al treilea parametru $strict = true, atunci comparatia intre $search_value si valorile din tablou este
comparatie de tip identic (===) deci se compara si tipul de date.
Are urmatorul prototip:
Pseudocod
array array_keys ( array $input [, mixed $search_value [, bool $strict=false ]] )

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $a = array('matematica' => 9, 2(
3 'romana' => 6, 'chimie' => 5, 3 [0] => matematica
4 'fizica' => 9); 4 [1] => romana
5 5 [2] => chimie
6 $k = array_keys($a); 6 [3] => fizica
7 7)
8 print_r($k); 8 Array
9 9(
10 $k2 = array_keys($a, 9); 10 [0] => matematica
11 11 [1] => fizica
12 print_r($k2); 12 )
13

?>

array_values() este oarecum similar cu array_keys() dar extrage valorile unui tablou. Practic tabloul are aceleasi valori doar caarray_values() elimina
cheile originale, si introduce chei numerice incepand cu 0.

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $a = array('matematica' => 9, 2(
3 'romana' => 6, 'chimie' => 5, 3 [0] => 9
4 'fizica' => 9); 4 [1] => 6
5 5 [2] => 5
6 $note = array_values($a); 6 [3] => 9
7 7)
8 print_r($note);

?>
array_rand()
array_rand() returneaza o cheie (sau un tablou de chei) aleatoare dintr-un tablou. Prototip:
Pseudocod
mixed array_rand ( array $input [, int $num_req=1 ] )

Sursa script Sursa HTML in browser


1 <?php 10
2 $imagini = array('img/munte.jpg', 2 img/munte.jpg
3 'img/floare.jpg',
4 'img/oameni.jpg');
5
6 $cheie = array_rand($imagini); //
7 alege o cheie aleatoare
8 (intamplatoare) din array
echo $cheie;
echo "\n";
echo $imagini[$cheie];
?>

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $imagini = 2(
3 array('img/munte.jpg', 3 [0] => 1
4 'img/floare.jpg', 4 [1] => 2
5 'img/oameni.jpg'); 5)
6 6 img/floare.jpg
7 $chei = array_rand($imagini, 2); 7 img/oameni.jpg
8 // alege 2 chei intamplatoare
9 din array
10 print_r($chei); // $chei este
11 acum un array, il afisam cu
12 print_r
13
// afisam acum elementele alese
intamplator din $imagini
foreach ($chei as $cheie) {
echo $imagini[$cheie];
echo "\n";
}

?>

4.12. Tema
Tema 4-1
Realizati un array al carui elemente sa fie alte array-uri cu datele unei persoane.
Array-ul sa contina cel putin 6 persoane... deci 6 array-uri.
Ex: $persoane = array ( array('prenume' => 'Ion', 'nume' => 'Popescu', 'varsta' => 23, 'sex' => 'm'), array('prenume' => 'Maria', 'nume' => 'Ionescu',
'varsta' => 67, 'sex' => 'f'), ... ); Treceti prin array-ul mare cu foreach, si in interiorul acestui foreach faceti un alt foreach ca sa treceti si prin datele
array-ului mic (persoana). Construiti astfel un tabel care sa aiba pe fiecare rand cate o persoana, si pe fiecare coloana cate o informatie: prenume, nume,
varsta, sex.
La sfarsit, in afara tabelului, afisati varsta medie pe total, varsta medie femei si varsta medie barbati. Aceste informatii trebuiesc calculate automat.

Tema 4-2
Realizati o functie care sa primeasca 2 parametri: primul parametru sa fie array-ul $persoane de la tema4-1, si al doilea parametru sa fie 'asc' sau 'desc'.
Functia trebuie sa returneze array-ul $persoane cu elementele ordonate crescator dupa nume (daca al doilea parametru e 'asc') sau descrescator (daca al
doilea parametru e 'desc'). Implicit, daca nu se furnizeaza functiei al doilea parametru, ordonarea sa fie crescatoare.
In rezolvarea acestei teme, folositi una dintre functiile de comparare de la capitolul urmator (Compararea sirurilor).
Tema4-3
Organizati sarcina temei 4-1 intr-o functie. Folosind apoi si functia de la 4-2, apelati-le astfel incat sa realizeze afisarea array-ului $persoane

Tema4-4
Modificati functia ce realizeaza tema4-1 astfel incat trecerea prin array (atat prin cel mare cat si prin tablourile interioare )sa se faca cu list() si each().
Apoi, realizati din nou functia insa trecerea sa se realizeze cu functiile next(), current()....

CAP 5. Strings (siruri de caractere)


5.1 Introducere
5.2 Inserarea variabilelor complexe in string
5.3 Cateva functii utile
5.4 Pozitia unui subsir intr-un sir
5.5 Extragerea unui subsir dintr-un sir
5.6 Compararea sirurilor
5.7 Inlocuirea subsirurilor
5.8 Regular Expressions (REGEX)
5.9 Tema

5.1. Introducere

Lucrurile de baza (si foarte importante) ale tipului de date string sunt prezentate in detaliu in capitolul 2.4.4

5.2. Inserarea variabilelor complexe in string

Asa cum am precizat intr-un capitol anterior, variabilele sunt inlocuite cu valorile lor (procedeu numit variable expansion sau variable substitution) in
interiorul stringurilor scrise intre ghilimele duble (") si folosind sintaxa heredoc. Interpretorul PHP cauta in interiorul stringurilor scrise intre ghilimele duble
simbolul $ si apoi cu ajutorul caracterelor ce urmeaza dupa $, pana la primul caracter ilegal pentru o variabila, incearca sa formeze un nume de variabila.
Caracterele valide pentru variabila sunt: litere, cifre, underscore (fara sa inceapa cu cifre).

Sursa script Sursa HTML in browser


1 <?php 1 El manaca cu placere banane si
2 $fructe = 'banane'; 2 rosii.
3 $legume = 'rosii'; 3 Lui ii plac
4 4 Fructe banane
5 /* Legume: rosii.
6 este gasita de interpretor
7 variabila $fructe (pentru ca
8 este urmata de spatiu)
9 si variabila $legume (pentru ca
10 este urmata de punct).
11 */
12 echo "El manaca cu placere
13 $fructe si $legume.";
14 echo "\n";
15
16
17 /*
18 aici interpretorul incearca sa
19 gaseasca variabila $fructele ,
20 care are valoarea null,
21 convertita la string este sirul
22 empty
23 */
24 echo "Lui ii plac $fructele";
25 echo "\n";
26

/*
\n (caracterul newline) este
invalid pentru un nume de
variabila
deci interpretorul citeste pana
in el => variabila $fructe
*/
echo "Fructe $fructe\nLegume:
$legume.";
?>

Un caz aparte il intalnim cand vrem sa introducem valoarea unui element dintr-un tablou, in interiorul unui string (discutam aici doar despre ghilimelele
duble). Pentru acest lucru, trebuie sa nu includem cheia elementului respectiv intre ghilimele.

Sursa script Sursa HTML in browser


1 <?php 1 Ma numesc Ion
2 $a = array('nume' => 'Ion', 2 Am 20 de ani
3 'varsta' => 20);
4
5 echo "Ma numesc $a[nume]";
6 echo "\n";
7 // echo "Ma numesc
8 $a['nume']"; // genereaza eroare
9 de sintaxa
// echo "Ma numesc $a[\"nume\"]";
// la fel, genereaza eroare de
sintaxa
echo "Am ".$a['varsta']." de ani
"; // o alternativa este
concatenarea
?>

Neincluderea cheii intre ghilimele nu va functiona la tablourile multidimensionale. Acolo, ca si in cazul altor variabile complexe (proprietati variabilelor de
tip obiect), includ variabila intre acolade {}. Astfel se realizeaza inlocuirea variabilelor cu valoarea lor.

Sursa script Sursa HTML in browser


1 <?php 1 Ma numesc Array['nume'] si am
2 2 Array['varsta'] de ani.
3 $persoane = array ( 3 Ma numesc Mihai si am 23 de ani.
4 array('nume' => 'Mihai', Lui ii plac bananele.
5 'varsta' => 23, 'sex' => 'm'),
6 array('nume' => 'Ioana',
7 'varsta' => 45, 'sex' => 'f'),
8 );
9
10 echo "Ma numesc $persoane[0]
11 ['nume'] si am $persoane[0]
12 ['varsta'] de ani."; // incorect
13 -> vezi rezultatul afisat
14 echo "\n";
15 echo "Ma numesc {$persoane[0]
16 ['nume']} si am {$persoane[0]
17 ['varsta']} de ani."; // corect.
18 se foloseste sintaxa cu {}
19 echo "\n";
20
21 /*
22 folosind sintaxa {} putem sa
fortam citirea caracterelor
valide de dupa $ pana la punctul
dorit de noi
*/

$fructe = 'banane';
echo "Lui ii plac {$fructe}le.";
// fara acolade ar fi
interpretorul ar fi citit
variabila $fructele
echo "\n";

?>

5.3. Cateva functii utile


strlen()
strlen($str) returneaza lungimea unui string.

Sursa script Sursa HTML in browser


1 <?php 13
2 $s = 'abc';
3 echo strlen($s);
4
5 ?>

Litere mari / Litere mici


- strtoupper($str) - returneaza sirul $str avand toate literele mari
- strtolower($str) - returneaza sirul $str avand toate literele mici
- ucfirst($str) - returneaza sirul $str avand prima litera mare
- ucwords($str) - returneaza sirul $str avand prima litera din fiecare cuvant mare
Sursa script Sursa HTML in browser
1 <?php 1 ABCDEF
2 $str = 'abcdef'; 2 Abcdef
3
4 echo strtoupper($str);
5 echo "\n";
6 echo ucfirst($str);
7 ?>

Sursa script Sursa HTML in browser


1 <?php 1 CURS PROGRAMATOR WEB
2 $str = 'curs programator web'; 2 curs programator web
3 echo strtoupper($str); 3 Curs Programator Web
4 echo "\n";
5 echo strtolower($str);
6 echo "\n";
7 echo ucwords($str);
8 ?>

Functiile din familia trim()


Functia trim() sterge (in mod implicit) caracterele neprintabile (newline (\n), tab (\t), spatiu ( ), etc) de la inceputul si de la sfarsitul unui string. Primul
parametru este stringul pe care vreau sa-l modific.
Prototip tim()
string trim ( string $str [, string $charlist ] )

Sursa script Sursa HTML in browser


1 <?php 1 x Ion x
2 $nume = ' Ion '; 2 xIonx
3 echo 'x' . $nume . 'x'; // x Ion
4x
5
6 echo "\n";
7
8 echo 'x' . trim($nume) . 'x'; //
9 xIonx

?>

Sursa script Sursa HTML in browser


1 <?php 1 Linie1
2 $t = "\tLinie1\nLinie2\n"; 2 Linie2
3 echo $t; 3a
4 echo 'a'; 4
5 5 Linie1
6 echo "\n\n"; 6 Linie2a
7
8 echo trim($t);
9 echo 'a';
10 ?>

Desi folosit mai rar, al doilea parametru specifica o lista de caractere (altele decat cele implicite) care sa fie sterse de la inceputul sau sfarsitul sirului

Sursa script Sursa HTML in browser


1 <?php 1 fost odat
2 $s = 'A fost odata...';
3 echo trim($s, '.Aa');
4
5
6 ?>

- ltrim() este similar cu trim() doar ca sterge caracterele doar de la inceputul sirului (left trim)
- rtrim() - right trim

5.4. Pozitia unui subsir intr-un sir


Functiile inrudite cu strpos() cauta pozitia unui subsir in interiorul unui sir, si returneaza aceasta pozitie.
Prototip:
int strpos ( string $haystack , mixed $needle [, int $offset=0 ] )

Descriere: Cauta prima aparitie a subsirului $needle in interiorul sirului $haystack (incepand eventual cu pozitia $offset) si returneaza pozitia pe care
este gasit subsirul $needle. Pozitiile caracterelor sunt numerotate de la 0. Astfel, in sirul 'abc', a este pe pozitia 0, b este pe pozitia 1, c este pe pozitia 2.

Sursa script Sursa HTML in browser


1 <?php 16
2 $str = 'Veni, vidi, vici';
3 // primul vi apare prima data
4 incepand cu pozitia 6
5 $pos = strpos($str, 'vi');
6 echo $pos;
?>

Nota
Functia strpos() ne poate ajuta sa stim daca un subsir se afla in interiorul unui sir sau nu. In cazul in care $needle nu se afla in $haystack, strpos()
returneaza FALSE. Insa exista aici o capcana, pentru ca FALSE convertit la intreg este 0. Astfel, daca !strpos($haystack, $needle) este adevarat nu
inseamna ca $needle nu se afla in $haystack. $needle se poate afla in $haystack pe pozitia 0. Din acest motiv trebuie sa folosim operatorul ===.
Pentru ca FALSE == 0 este o afirmatie adevarata. Insa FALSE === 0 este falsa pentru ca au tipuri diferite de date.

Sursa script Sursa HTML in browser


1 <?php 1 Abc nu se afla in Abcdef
2 $str = 'Abcdef'; 2 Ba da, se afla
3
4 if (!strpos($str, 'Abc')) {
5 echo 'Abc nu se afla in ' .
6 $str; // gresit. se afla, dar
7 pe pozitia 0
8 }
9
10 echo "\n";
11
12 if (strpos($str, 'Abc') ===
13 FALSE) {
14 echo 'Abc nu se afla in ' .
15 $str;
} else {
echo 'Ba da, se afla';
}
?>

- stripos() este similar, insa cautarea se face case-insensitive


- strrpos() returneaza pozitia ultimei aparitiei a subsirului $needle in $haystack
- strripos() similar cu strrpos() dar case insensitive

Sursa script Sursa HTML in browser


1 <?php 1 12<br />
2 $str = 'Veni, vidi, vici';
3 // primul vi apare prima data
4 incepand cu pozitia 6
5 $pos = strrpos($str, 'vi');
6 echo $pos; // 12
7
8 echo '<br />';
9
10
?>

Sursa script Sursa HTML in browser


1 <?php 1 12
2 $str = 'Veni, Vidi, vici'; 26
3 // primul vi apare prima data
4 incepand cu pozitia 6
5 $pos = strpos($str, 'vi'); //
6 desi cauta prima aparitie, este
7 case sensitive si gaseste
8 ultimul "vi"
9 echo $pos; // 12
10
11 echo "\n";
12
$pos = stripos($str, 'vi'); //
cauta (case-insensitive) prima
aparitie a lui "vi" si gaseste
"Vi"
echo $pos // 6

?>

5.5. Extragerea unui subsir dintr-un sir


substr()
Are urmatorul prototip:
string substr ( string $string , int $start [, int $length ] )

Extrage din sirul $string, un subsir de lungime $length, incepand cu pozitia $start (pozitiile caracterelor in string se numara incepand cu 0).
Sursa script Sursa HTML in browser
1 <?php 1 pe Diem!
2 $s1 = 'Carpe Diem!'; 2 pe D
3
4 /*
5 a fost specificat doar al doilea
6 parametru, start,
7 deci se porneste de pe pozitia 3
8 */
9
10 $s2 = substr($s1, 3);
11 echo $s2; // pe Diem!
12
13 echo "\n";
14
15 /*
16 se extrage un subsir
17 incepand cu pozitia 3, de
18 lungime 4 caractere
19 */
20
21 $s3 = substr($s1, 3, 4);
22 echo $s3; // pe D
23

?>

- daca parametrul $start este negativ se extrage un sir incepand cu pozitia $start, incepand numaratoarea de la sfarsitul sirului

Sursa script Sursa HTML in browser


1 <?php 1 m!
2 $s1 = 'Carpe Diem!'; 2 Di
3
4 /*
5 se extrage un subsir incepand cu
6 al 2-lea caracter de la coada
7 nefiind specificata lungimea, se
8 extrage pana la capat
9 practic, se extrag ultimele 2
10 caractere
11 */
12
13 $s2 = substr($s1, -2);
14 echo $s2; // m!
15
16 echo "\n";
17
18 /*
19 incepand cu pozitia 5 de la
20 coada, se extrage un sir de 2
21 caractere
22 */
$s3 = substr($s1, -5, 2);
echo $s3; // Di
?>

- daca parametrul $length este negativ se extrage un sir incepand cu pozitia $start, excluzand $length caractere de la sfarsitul sirului

Sursa script Sursa HTML in browser


1 <?php 1 m!
2 $s1 = 'Carpe Diem!'; 2 Die
3
4 /*
5 se extrage un subsir incepand cu
6 primul caracter (pozitia 0) ,
7 fara ultimele 2 caractere
8 */
9
10 $s2 = substr($s1, 0 -2);
11 echo $s2; // Carpe Die
12
13 echo "\n";
14
15
16 /*
17 se extrage un subsir
18 incepand cu pozitia 5 de la
19 coada fara ultimele 2 caractere
20 */
21
22 $s3 = substr($s1, -5, -2);
23 echo $s3; // Die

?>

strstr() si functii asemanatoare


Aceste functii extrag o portiune dintr-un sir de caractere incepand cu cautarea unui subsir sau a unui caracter.

strstr() are urmatorul prototip:


string strstr ( string $haystack , mixed $needle [, bool $before_needle=false ] )

strstr() va returna portiunea din $haystack ce incepe cu $needle. Incepand cu PHP versiunea 5.3.0 a fost adaugat un al treilea parametru $before_needle
cu valoarea implicita false. Daca $before_needle este true, functia returneaza portiunea din $haystack pana la $needle.

Sursa script Sursa HTML in browser


1 <?php 1 cdef
2 $a = 'abcdef';
3 $x = strstr($a, 'cd');
4
5 echo $x;
6 ?>

Functii asemanatoare sunt:


- strchr() - alias pentru strstr()
- stristr() - similar cu strstr(), dar cautarea se face case insensitive
- strrchr($haystack, $needle) - $needle trebuie sa fie un singur caracter. Functia gaseste in $haystack ultima aparitie a caracterului $needle, si
incepand cu acel caracter selecteaza un subsir pana la sfarsitul lui $hastack, si returneaza acest subsir

Sursa script Sursa HTML in browser


1 <?php 1 .78
2 $s = '193.231.25.78';
3 $x = strrchr($s, '.');
4 echo $x;
5
6 ?>

5.6. Compararea sirurilor


Folosind operatorii de comparare

Nota
Este foarte important de retinut ca atunci cand se compara un string cu un numar (sau doua stringuri numerice), ambii operanzi sunt convertiti la
numar (int sau float) Acest lucru implica unele conversii automatesi unele egalitati neprevazute.

Sursa script Sursa HTML in browser


1 <?php 1 bool(true)
2 $s1 = 'abc'; 2 bool(false)
3 $s2 = 0; 3 bool(false)
4 $s3 = '7 pitici'; 4 bool(true)
5 5 bool(false)
6 var_dump($s1 == $s2); //
7 bool(true) pentru ca $s1 este
8 convertit la numar este 0. si 0
9 == 0
10 var_dump($s1 === $s2); //
11 bool(false) au tip de date
diferit
var_dump($s1 > 0); //
bool(false) $s1 convertit la
numar este 0.
var_dump($s3 > $s2); //
bool(true) $s3 convertit la
numar este 7. 7 > 0
var_dump($s3 > $s1); //
bool(false) in acest caz nu se
fac conversii la numar, ambii
operator sunt string. compararea
se face alfabetica
?>

Cand comparam doua stringuri cu operatorii < si > , comparatia se face litera cu litera, alfabetic (dupa codul ascii), cu urmatoarele observatii:
- literele mari au cod ascii mai mic decat literele mici
- cifrele au cod ascii mai mic decat literele

Nota
Codul ASCII al unui caracter il putem afla cu functia ord($str). Functia complementara este chr($cod).

Sursa script Sursa HTML in browser


1 <?php 1 bool(false)
2 var_dump('A' > 'a'); // 2 bool(false)
3 bool(false) 3 bool(true)
4 var_dump('Az' > 'aa'); // 4 A are codul 65
5 bool(false) - comparatia a fost 5 a are codul 97
6 hotarata din comparatia primelor 6 z are codul 122
7 litere, A > a (false)
8 var_dump('z' > 'a'); //
9 bool(true)
10
11 echo 'A are codul ' . ord('A');
echo "\n";
echo 'a are codul ' . ord('a');
echo "\n";
echo 'z are codul ' .ord('z');
?>

Functii de comparare
Pentru compararea alfabetica a sirurilor, exista functii specializate de comparare:
- strcmp($s1, $s2) - returneaza valoare pozitiva daca $s1 > $s2 , 0 daca $s1 este egal cu $s2, si valoare negativa daca $s1 < $s2.
- strcasecmp($s1, $s2) - similar, dar comparatia este case-insensitive
- strncasecmp($s1, $s2, $n) - similar cu strcmp() dar se compara doar primele $n caractere din fiecare sir. ca si strcmp() este case-sensitive
- strnatcmp($s1, $s2) - comparare naturala a celor doua siruri, case-sensitive
- strnatcasecmp($s1, $s2) - similar cu strnatcmp() dar case-insensitive

Sursa script Sursa HTML in browser


1 <?php 1 int(1)
2 $s1 = 'ab'; 2 int(0)
3 $s2 = 'Ab'; 3 int(-1)
4 $s3 = 'Abc';
5
6 var_dump(strcmp($s1, $s2)); //
7 int(1) - valoare pozitiva pentru
8 ca a > A
9 var_dump(strcasecmp($s1, $s2));
// 0, comparatia se face case-
insensitive. Deci A va fi egal cu
a.
var_dump(strcasecmp($s1, $s3));
// int(-1) pentru ca $s3 contine
'c' in plus. Deci $s1 < $s3
?>

Sursa script Sursa HTML in browser


1 <?php 1 int(1)
2 $s1 = 'img2.png'; 2 int(-1)
3 $s2 = 'img12.png';
4
5 var_dump(strcmp($s1, $s2)); //
6 int(1). $s1 > $s2 (pentru ca
7 alfabetic, 2 este mai mare decat
1)
var_dump(strnatcmp($s1, $s2)); //
int(-1). in comparatia naturala
(umana), $s1 este mai mic decat
$s2. pentru ca 2 este mai mic
decat 12
?>

5.7. Inlocuirea subsirurilor

- str_replace($search, $replace, $subject) - inlocuieste stringul $search cu $replace, in cadrul stringului $subject

Sursa script Sursa HTML in browser


1 <?php 1 Invat PHP. Folosesc PHP pentru
2 $s = 'Invat HTML. Folosesc HTML realizarea paginilor web.
3 pentru realizarea paginilor
4 web.';
5 echo str_replace('HTML', 'PHP',
$s);

?>

- str_ireplace($search, $replace, $subject) - similar, case-insensitive

Sursa script Sursa HTML in browser


1 <?php 1 Invat HTML. Folosesc HTML pentru
2 $s = 'Invat HTML. Folosesc HTML 2 realizarea paginilor web.
3 pentru realizarea paginilor Invat PHP. Folosesc PHP pentru
4 web.'; realizarea paginilor web.
5 echo str_replace('html', 'PHP',
6 $s); // nu gaseste sirul html.
7
8 echo "\n";

echo str_ireplace('html', 'PHP',


$s); // acum il gaseste, pentru
ca html este la fel cu HTML
(case-insensitive vorbind)
?>

- substr_replace($string, $replacement, $start, [$length]) - inlocuieste portiunea incepand cu pozitia $start (si eventual de lungime $length) cu
$replacement.

Sursa script Sursa HTML in browser


1 <?php 1 abcx
2 $s = 'abcDEF'; 2 xabcDEF
3 3 xDEF
4 echo substr_replace($s, 'x', 3); 4 abcDxy
5 // inlocuieste incepand cu
6 caracterul de pe pozitia 3, pana
7 la sfarsit, cu 'x'
8 echo "\n";
9 echo substr_replace($s, 'x', 0,
10 0); // adauga la inceput
11 caracterul 'x'
echo "\n";
echo substr_replace($s, 'x', 0,
3); // inlocuieste primele 3
caractere cu 'x'
echo "\n";
echo substr_replace($s, 'xy',
-2, 2); // inlocuieste ultimele
2 caractere cu xy
?>

- strtr($str, $from, $to) - returneaza un string in care fiecare caracter din $from a fost transformat in caracterul corespunzator din $to

Sursa script Sursa HTML in browser


1 <?php 1 Intomplorio foci so ni vidim
2 $str = 'Intamplarea face sa ne
3 vedem';
4
5 echo strtr($str, 'ae', 'oi');
?>

5.8. Regular Expressions (REGEX)


5.8.1 Introducere
5.8.2 Meta-caractere
5.8.3 Clase de caractere
5.8.4 Clase uzuale de caractere
5.8.5 Subexpresii. Repetitii
5.8.6 Referirea la o subexpresie anterioara
5.8.7 expresie1 sau expresie2
5.8.8 Conditia de inceput si sfarsit
5.8.9 Optiuni regex (pattern modifiers)
5.8.10 Functii pentru regex-uri (PCRE)
5.8.11 Resurse

5.1. Introducere

Regular expressions (pe scurt regex) sunt stringuri cu un format si inteles special, avand scopul de a exprima un format al unui alt string.

Folosirea regex-urilor ne ajuta in general in urmatoarele cazuri:

1. in cautarea si extragerea unor stringuri de un anumit format dintr-un text/string dat.


Exemplu: extrag adresele de email dintr-o pagina web.

2. in verificarea formatului unor stringuri date. Mai concret, la validarea unor stringuri primite de exemplu printr-un formular HTML de la utilizator. Vreau
ca numele sa contina doar litere, spatiu, sau cratima (-) ; un numar de telefon sa contina doar cifre (si eventual + si .) si sa aiba o anumita lungime; un
cnp sa inceapa cu 1 si 2, apoi sa fie urmat de 12 cifre; etc.

"Regular expressions" este un concept destul de avansat (si destul de larg), dar prezent si foarte util in multe limbaje de programare sau programe.

PHP are doua seturi de functii ce implementeaza fiecare o modalidate diferita de a lucra cu regex-urile:
1. Sintaxa PCRE (Perl-compatible Regular Expressions) - sintaxa implementata de functiile din familia preg_*. Este un motor de regex-uri imprumutat
din limbajul Perl, si sintaxa folosita aici (modul de scriere a regexurilor) este in mare masura compatibila cu cea folosita in Perl.
2. POSIX extended regular expressions, este implementata de functiile din familia ereg_*. Aceasta extensie (set de functii) este insa marcata ca
invechita incepand cu PHP 5.3.0.

Aceasta documentatie va prezenta regex-urile conform sintaxei PCRE.

Principalele functii folosite pentru regex-urile PCRE sunt preg_match() si preg_match_all(). Aceste functii vor fi detaliate spre sfarsitul capitolului, insa
pentru a testa regex-urile folosite vom incepe folosirea functiei preg_match(). In forma ei simpla, se apeleaza preg_match($pattern, $subject), unde
$pattern este regex-ul si $subject este sirul normal de caractere. Daca expresia $pattern este gasita in sirul $subject, preg_match() returneaza 1, altfel
returneaza 0.

Important
Conform sintaxei PCRE descrisa in continuare, orice regex (regular expression) se delimiteaza (la inceput si la sfarsit) cu un caracter ce nu poate fi
alfanumeric sau backslash (\). Exemplu regex: /a.e/
In plus, daca acest caracter (numit delimitator) se foloseste in cadrul regex-ului, el trebuie precedat de \
Sursa script Sursa HTML in browser
1 <?php 1 int(1)
2
3 /*
4 orice regex se scrie intre
5 caractere delimitatoare. in
6 general o sa folosim /
7 caracterul punct (.) inseamna
8 orice caracter
9 */
10
11 $regex = '/a.c/'; // adica: a
12 urmat de orice caracter, urmat
13 de c
14 $str = 'xyabczt';

$m = preg_match($regex, $str);

var_dump($m); // int(1), adica


$regex se gaseste in $str.
altfel, ar fi fost int(0)
?>

5.2. Inserarea variabilelor complexe in string

Asa cum am precizat intr-un capitol anterior, variabilele sunt inlocuite cu valorile lor (procedeu numit variable expansion sau variable substitution) in
interiorul stringurilor scrise intre ghilimele duble (") si folosind sintaxa heredoc. Interpretorul PHP cauta in interiorul stringurilor scrise intre ghilimele duble
simbolul $ si apoi cu ajutorul caracterelor ce urmeaza dupa $, pana la primul caracter ilegal pentru o variabila, incearca sa formeze un nume de variabila.
Caracterele valide pentru variabila sunt: litere, cifre, underscore (fara sa inceapa cu cifre).

Sursa script Sursa HTML in browser


1 <?php 1 El manaca cu placere banane si
2 $fructe = 'banane'; 2 rosii.
3 $legume = 'rosii'; 3 Lui ii plac
4 4 Fructe banane
5 /* Legume: rosii.
6 este gasita de interpretor
7 variabila $fructe (pentru ca
8 este urmata de spatiu)
9 si variabila $legume (pentru ca
10 este urmata de punct).
11 */
12 echo "El manaca cu placere
13 $fructe si $legume.";
14 echo "\n";
15
16
17 /*
18 aici interpretorul incearca sa
19 gaseasca variabila $fructele ,
20 care are valoarea null,
21 convertita la string este sirul
22 empty
23 */
24 echo "Lui ii plac $fructele";
25 echo "\n";
26

/*
\n (caracterul newline) este
invalid pentru un nume de
variabila
deci interpretorul citeste pana
in el => variabila $fructe
*/
echo "Fructe $fructe\nLegume:
$legume.";
?>

Un caz aparte il intalnim cand vrem sa introducem valoarea unui element dintr-un tablou, in interiorul unui string (discutam aici doar despre ghilimelele
duble). Pentru acest lucru, trebuie sa nu includem cheia elementului respectiv intre ghilimele.

Sursa script Sursa HTML in browser


1 <?php 1 Ma numesc Ion
2 $a = array('nume' => 'Ion', 2 Am 20 de ani
3 'varsta' => 20);
4
5 echo "Ma numesc $a[nume]";
6 echo "\n";
7 // echo "Ma numesc
8 $a['nume']"; // genereaza eroare
9 de sintaxa
// echo "Ma numesc $a[\"nume\"]";
// la fel, genereaza eroare de
sintaxa
echo "Am ".$a['varsta']." de ani
"; // o alternativa este
concatenarea
?>

Neincluderea cheii intre ghilimele nu va functiona la tablourile multidimensionale. Acolo, ca si in cazul altor variabile complexe (proprietati variabilelor de
tip obiect), includ variabila intre acolade {}. Astfel se realizeaza inlocuirea variabilelor cu valoarea lor.

Sursa script Sursa HTML in browser


1 <?php 1 Ma numesc Array['nume'] si am
2 2 Array['varsta'] de ani.
3 $persoane = array ( 3 Ma numesc Mihai si am 23 de ani.
4 array('nume' => 'Mihai', Lui ii plac bananele.
5 'varsta' => 23, 'sex' => 'm'),
6 array('nume' => 'Ioana',
7 'varsta' => 45, 'sex' => 'f'),
8 );
9
10 echo "Ma numesc $persoane[0]
11 ['nume'] si am $persoane[0]
12 ['varsta'] de ani."; // incorect
13 -> vezi rezultatul afisat
14 echo "\n";
15 echo "Ma numesc {$persoane[0]
16 ['nume']} si am {$persoane[0]
17 ['varsta']} de ani."; // corect.
18 se foloseste sintaxa cu {}
19 echo "\n";
20
21 /*
22 folosind sintaxa {} putem sa
fortam citirea caracterelor
valide de dupa $ pana la punctul
dorit de noi
*/

$fructe = 'banane';
echo "Lui ii plac {$fructe}le.";
// fara acolade ar fi
interpretorul ar fi citit
variabila $fructele
echo "\n";

?>

5.3. Cateva functii utile


strlen()
strlen($str) returneaza lungimea unui string.

Sursa script Sursa HTML in browser


1 <?php 13
2 $s = 'abc';
3 echo strlen($s);
4
5 ?>

Litere mari / Litere mici


- strtoupper($str) - returneaza sirul $str avand toate literele mari
- strtolower($str) - returneaza sirul $str avand toate literele mici
- ucfirst($str) - returneaza sirul $str avand prima litera mare
- ucwords($str) - returneaza sirul $str avand prima litera din fiecare cuvant mare

Sursa script Sursa HTML in browser


1 <?php 1 ABCDEF
2 $str = 'abcdef'; 2 Abcdef
3
4 echo strtoupper($str);
5 echo "\n";
6 echo ucfirst($str);
7 ?>

Sursa script Sursa HTML in browser


1 <?php 1 CURS PROGRAMATOR WEB
2 $str = 'curs programator web'; 2 curs programator web
3 echo strtoupper($str); 3 Curs Programator Web
4 echo "\n";
5 echo strtolower($str);
6 echo "\n";
7 echo ucwords($str);
8 ?>

Functiile din familia trim()


Functia trim() sterge (in mod implicit) caracterele neprintabile (newline (\n), tab (\t), spatiu ( ), etc) de la inceputul si de la sfarsitul unui string. Primul
parametru este stringul pe care vreau sa-l modific.
Prototip tim()
string trim ( string $str [, string $charlist ] )

Sursa script Sursa HTML in browser


1 <?php 1 x Ion x
2 $nume = ' Ion '; 2 xIonx
3 echo 'x' . $nume . 'x'; // x Ion
4x
5
6 echo "\n";
7
8 echo 'x' . trim($nume) . 'x'; //
9 xIonx

?>

Sursa script Sursa HTML in browser


1 <?php 1 Linie1
2 $t = "\tLinie1\nLinie2\n"; 2 Linie2
3 echo $t; 3a
4 echo 'a'; 4
5 5 Linie1
6 echo "\n\n"; 6 Linie2a
7
8 echo trim($t);
9 echo 'a';
10 ?>

Desi folosit mai rar, al doilea parametru specifica o lista de caractere (altele decat cele implicite) care sa fie sterse de la inceputul sau sfarsitul sirului

Sursa script Sursa HTML in browser


1 <?php 1 fost odat
2 $s = 'A fost odata...';
3 echo trim($s, '.Aa');
4
5
6 ?>
- ltrim() este similar cu trim() doar ca sterge caracterele doar de la inceputul sirului (left trim)
- rtrim() - right trim

5.4. Pozitia unui subsir intr-un sir


Functiile inrudite cu strpos() cauta pozitia unui subsir in interiorul unui sir, si returneaza aceasta pozitie.
Prototip:
int strpos ( string $haystack , mixed $needle [, int $offset=0 ] )

Descriere: Cauta prima aparitie a subsirului $needle in interiorul sirului $haystack (incepand eventual cu pozitia $offset) si returneaza pozitia pe care
este gasit subsirul $needle. Pozitiile caracterelor sunt numerotate de la 0. Astfel, in sirul 'abc', a este pe pozitia 0, b este pe pozitia 1, c este pe pozitia 2.

Sursa script Sursa HTML in browser


1 <?php 16
2 $str = 'Veni, vidi, vici';
3 // primul vi apare prima data
4 incepand cu pozitia 6
5 $pos = strpos($str, 'vi');
6 echo $pos;
?>

Nota
Functia strpos() ne poate ajuta sa stim daca un subsir se afla in interiorul unui sir sau nu. In cazul in care $needle nu se afla in $haystack, strpos()
returneaza FALSE. Insa exista aici o capcana, pentru ca FALSE convertit la intreg este 0. Astfel, daca !strpos($haystack, $needle) este adevarat nu
inseamna ca $needle nu se afla in $haystack. $needle se poate afla in $haystack pe pozitia 0. Din acest motiv trebuie sa folosim operatorul ===.
Pentru ca FALSE == 0 este o afirmatie adevarata. Insa FALSE === 0 este falsa pentru ca au tipuri diferite de date.

Sursa script Sursa HTML in browser


1 <?php 1 Abc nu se afla in Abcdef
2 $str = 'Abcdef'; 2 Ba da, se afla
3
4 if (!strpos($str, 'Abc')) {
5 echo 'Abc nu se afla in ' .
6 $str; // gresit. se afla, dar
7 pe pozitia 0
8 }
9
10 echo "\n";
11
12 if (strpos($str, 'Abc') ===
13 FALSE) {
14 echo 'Abc nu se afla in ' .
15 $str;
} else {
echo 'Ba da, se afla';
}
?>

- stripos() este similar, insa cautarea se face case-insensitive


- strrpos() returneaza pozitia ultimei aparitiei a subsirului $needle in $haystack
- strripos() similar cu strrpos() dar case insensitive
Sursa script Sursa HTML in browser
1 <?php 1 12<br />
2 $str = 'Veni, vidi, vici';
3 // primul vi apare prima data
4 incepand cu pozitia 6
5 $pos = strrpos($str, 'vi');
6 echo $pos; // 12
7
8 echo '<br />';
9
10
?>

Sursa script Sursa HTML in browser


1 <?php 1 12
2 $str = 'Veni, Vidi, vici'; 26
3 // primul vi apare prima data
4 incepand cu pozitia 6
5 $pos = strpos($str, 'vi'); //
6 desi cauta prima aparitie, este
7 case sensitive si gaseste
8 ultimul "vi"
9 echo $pos; // 12
10
11 echo "\n";
12
$pos = stripos($str, 'vi'); //
cauta (case-insensitive) prima
aparitie a lui "vi" si gaseste
"Vi"
echo $pos // 6

?>

5.5. Extragerea unui subsir dintr-un sir


substr()
Are urmatorul prototip:
string substr ( string $string , int $start [, int $length ] )

Extrage din sirul $string, un subsir de lungime $length, incepand cu pozitia $start (pozitiile caracterelor in string se numara incepand cu 0).

Sursa script Sursa HTML in browser


1 <?php 1 pe Diem!
2 $s1 = 'Carpe Diem!'; 2 pe D
3
4 /*
5 a fost specificat doar al doilea
6 parametru, start,
7 deci se porneste de pe pozitia 3
8 */
9
10 $s2 = substr($s1, 3);
11 echo $s2; // pe Diem!
12
13 echo "\n";
14
15 /*
16 se extrage un subsir
17 incepand cu pozitia 3, de
18 lungime 4 caractere
19 */
20
21 $s3 = substr($s1, 3, 4);
22 echo $s3; // pe D
23

?>

- daca parametrul $start este negativ se extrage un sir incepand cu pozitia $start, incepand numaratoarea de la sfarsitul sirului

Sursa script Sursa HTML in browser


1 <?php 1 m!
2 $s1 = 'Carpe Diem!'; 2 Di
3
4 /*
5 se extrage un subsir incepand cu
6 al 2-lea caracter de la coada
7 nefiind specificata lungimea, se
8 extrage pana la capat
9 practic, se extrag ultimele 2
10 caractere
11 */
12
13 $s2 = substr($s1, -2);
14 echo $s2; // m!
15
16 echo "\n";
17
18 /*
19 incepand cu pozitia 5 de la
20 coada, se extrage un sir de 2
21 caractere
22 */
$s3 = substr($s1, -5, 2);
echo $s3; // Di

?>

- daca parametrul $length este negativ se extrage un sir incepand cu pozitia $start, excluzand $length caractere de la sfarsitul sirului

Sursa script Sursa HTML in browser


1 <?php 1 m!
2 $s1 = 'Carpe Diem!'; 2 Die
3
4 /*
5 se extrage un subsir incepand cu
6 primul caracter (pozitia 0) ,
7 fara ultimele 2 caractere
8 */
9
10 $s2 = substr($s1, 0 -2);
11 echo $s2; // Carpe Die
12
13 echo "\n";
14
15
16 /*
17 se extrage un subsir
18 incepand cu pozitia 5 de la
19 coada fara ultimele 2 caractere
20 */
21
22 $s3 = substr($s1, -5, -2);
23 echo $s3; // Die

?>

strstr() si functii asemanatoare


Aceste functii extrag o portiune dintr-un sir de caractere incepand cu cautarea unui subsir sau a unui caracter.

strstr() are urmatorul prototip:


string strstr ( string $haystack , mixed $needle [, bool $before_needle=false ] )

strstr() va returna portiunea din $haystack ce incepe cu $needle. Incepand cu PHP versiunea 5.3.0 a fost adaugat un al treilea parametru $before_needle
cu valoarea implicita false. Daca $before_needle este true, functia returneaza portiunea din $haystack pana la $needle.

Sursa script Sursa HTML in browser


1 <?php 1 cdef
2 $a = 'abcdef';
3 $x = strstr($a, 'cd');
4
5 echo $x;
6 ?>

Functii asemanatoare sunt:


- strchr() - alias pentru strstr()
- stristr() - similar cu strstr(), dar cautarea se face case insensitive
- strrchr($haystack, $needle) - $needle trebuie sa fie un singur caracter. Functia gaseste in $haystack ultima aparitie a caracterului $needle, si
incepand cu acel caracter selecteaza un subsir pana la sfarsitul lui $hastack, si returneaza acest subsir

Sursa script Sursa HTML in browser


1 <?php 1 .78
2 $s = '193.231.25.78';
3 $x = strrchr($s, '.');
4 echo $x;
5
6 ?>

5.6. Compararea sirurilor


Folosind operatorii de comparare

Nota
Este foarte important de retinut ca atunci cand se compara un string cu un numar (sau doua stringuri numerice), ambii operanzi sunt convertiti la
numar (int sau float) Acest lucru implica unele conversii automatesi unele egalitati neprevazute.

Sursa script Sursa HTML in browser


1 <?php 1 bool(true)
2 $s1 = 'abc'; 2 bool(false)
3 $s2 = 0; 3 bool(false)
4 $s3 = '7 pitici'; 4 bool(true)
5 5 bool(false)
6 var_dump($s1 == $s2); //
7 bool(true) pentru ca $s1 este
8 convertit la numar este 0. si 0
9 == 0
10 var_dump($s1 === $s2); //
11 bool(false) au tip de date
diferit
var_dump($s1 > 0); //
bool(false) $s1 convertit la
numar este 0.
var_dump($s3 > $s2); //
bool(true) $s3 convertit la
numar este 7. 7 > 0
var_dump($s3 > $s1); //
bool(false) in acest caz nu se
fac conversii la numar, ambii
operator sunt string. compararea
se face alfabetica
?>

Cand comparam doua stringuri cu operatorii < si > , comparatia se face litera cu litera, alfabetic (dupa codul ascii), cu urmatoarele observatii:
- literele mari au cod ascii mai mic decat literele mici
- cifrele au cod ascii mai mic decat literele

Nota
Codul ASCII al unui caracter il putem afla cu functia ord($str). Functia complementara este chr($cod).

Sursa script Sursa HTML in browser


1 <?php 1 bool(false)
2 var_dump('A' > 'a'); // 2 bool(false)
3 bool(false) 3 bool(true)
4 var_dump('Az' > 'aa'); // 4 A are codul 65
5 bool(false) - comparatia a fost 5 a are codul 97
6 hotarata din comparatia primelor 6 z are codul 122
7 litere, A > a (false)
8 var_dump('z' > 'a'); //
9 bool(true)
10
11 echo 'A are codul ' . ord('A');
echo "\n";
echo 'a are codul ' . ord('a');
echo "\n";
echo 'z are codul ' .ord('z');
?>

Functii de comparare
Pentru compararea alfabetica a sirurilor, exista functii specializate de comparare:
- strcmp($s1, $s2) - returneaza valoare pozitiva daca $s1 > $s2 , 0 daca $s1 este egal cu $s2, si valoare negativa daca $s1 < $s2.
- strcasecmp($s1, $s2) - similar, dar comparatia este case-insensitive
- strncasecmp($s1, $s2, $n) - similar cu strcmp() dar se compara doar primele $n caractere din fiecare sir. ca si strcmp() este case-sensitive
- strnatcmp($s1, $s2) - comparare naturala a celor doua siruri, case-sensitive
- strnatcasecmp($s1, $s2) - similar cu strnatcmp() dar case-insensitive

Sursa script Sursa HTML in browser


1 <?php 1 int(1)
2 $s1 = 'ab'; 2 int(0)
3 $s2 = 'Ab'; 3 int(-1)
4 $s3 = 'Abc';
5
6 var_dump(strcmp($s1, $s2)); //
7 int(1) - valoare pozitiva pentru
8 ca a > A
9 var_dump(strcasecmp($s1, $s2));
// 0, comparatia se face case-
insensitive. Deci A va fi egal cu
a.
var_dump(strcasecmp($s1, $s3));
// int(-1) pentru ca $s3 contine
'c' in plus. Deci $s1 < $s3
?>

Sursa script Sursa HTML in browser


1 <?php 1 int(1)
2 $s1 = 'img2.png'; 2 int(-1)
3 $s2 = 'img12.png';
4
5 var_dump(strcmp($s1, $s2)); //
6 int(1). $s1 > $s2 (pentru ca
7 alfabetic, 2 este mai mare decat
1)
var_dump(strnatcmp($s1, $s2)); //
int(-1). in comparatia naturala
(umana), $s1 este mai mic decat
$s2. pentru ca 2 este mai mic
decat 12
?>

5.7. Inlocuirea subsirurilor

- str_replace($search, $replace, $subject) - inlocuieste stringul $search cu $replace, in cadrul stringului $subject
Sursa script Sursa HTML in browser
1 <?php 1 Invat PHP. Folosesc PHP pentru
2 $s = 'Invat HTML. Folosesc HTML realizarea paginilor web.
3 pentru realizarea paginilor
4 web.';
5 echo str_replace('HTML', 'PHP',
$s);

?>

- str_ireplace($search, $replace, $subject) - similar, case-insensitive

Sursa script Sursa HTML in browser


1 <?php 1 Invat HTML. Folosesc HTML pentru
2 $s = 'Invat HTML. Folosesc HTML 2 realizarea paginilor web.
3 pentru realizarea paginilor Invat PHP. Folosesc PHP pentru
4 web.'; realizarea paginilor web.
5 echo str_replace('html', 'PHP',
6 $s); // nu gaseste sirul html.
7
8 echo "\n";

echo str_ireplace('html', 'PHP',


$s); // acum il gaseste, pentru
ca html este la fel cu HTML
(case-insensitive vorbind)
?>

- substr_replace($string, $replacement, $start, [$length]) - inlocuieste portiunea incepand cu pozitia $start (si eventual de lungime $length) cu
$replacement.

Sursa script Sursa HTML in browser


1 <?php 1 abcx
2 $s = 'abcDEF'; 2 xabcDEF
3 3 xDEF
4 echo substr_replace($s, 'x', 3); 4 abcDxy
5 // inlocuieste incepand cu
6 caracterul de pe pozitia 3, pana
7 la sfarsit, cu 'x'
8 echo "\n";
9 echo substr_replace($s, 'x', 0,
10 0); // adauga la inceput
11 caracterul 'x'
echo "\n";
echo substr_replace($s, 'x', 0,
3); // inlocuieste primele 3
caractere cu 'x'
echo "\n";
echo substr_replace($s, 'xy',
-2, 2); // inlocuieste ultimele
2 caractere cu xy
?>
- strtr($str, $from, $to) - returneaza un string in care fiecare caracter din $from a fost transformat in caracterul corespunzator din $to

Sursa script Sursa HTML in browser


1 <?php 1 Intomplorio foci so ni vidim
2 $str = 'Intamplarea face sa ne
3 vedem';
4
5 echo strtr($str, 'ae', 'oi');
?>

5.8. Regular Expressions (REGEX)


5.8.1 Introducere
5.8.2 Meta-caractere
5.8.3 Clase de caractere
5.8.4 Clase uzuale de caractere
5.8.5 Subexpresii. Repetitii
5.8.6 Referirea la o subexpresie anterioara
5.8.7 expresie1 sau expresie2
5.8.8 Conditia de inceput si sfarsit
5.8.9 Optiuni regex (pattern modifiers)
5.8.10 Functii pentru regex-uri (PCRE)
5.8.11 Resurse

5.8.1. Introducere

Regular expressions (pe scurt regex) sunt stringuri cu un format si inteles special, avand scopul de a exprima un format al unui alt string.

Folosirea regex-urilor ne ajuta in general in urmatoarele cazuri:

1. in cautarea si extragerea unor stringuri de un anumit format dintr-un text/string dat.


Exemplu: extrag adresele de email dintr-o pagina web.

2. in verificarea formatului unor stringuri date. Mai concret, la validarea unor stringuri primite de exemplu printr-un formular HTML de la utilizator. Vreau
ca numele sa contina doar litere, spatiu, sau cratima (-) ; un numar de telefon sa contina doar cifre (si eventual + si .) si sa aiba o anumita lungime; un
cnp sa inceapa cu 1 si 2, apoi sa fie urmat de 12 cifre; etc.

"Regular expressions" este un concept destul de avansat (si destul de larg), dar prezent si foarte util in multe limbaje de programare sau programe.

PHP are doua seturi de functii ce implementeaza fiecare o modalidate diferita de a lucra cu regex-urile:
1. Sintaxa PCRE (Perl-compatible Regular Expressions) - sintaxa implementata de functiile din familia preg_*. Este un motor de regex-uri imprumutat
din limbajul Perl, si sintaxa folosita aici (modul de scriere a regexurilor) este in mare masura compatibila cu cea folosita in Perl.
2. POSIX extended regular expressions, este implementata de functiile din familia ereg_*. Aceasta extensie (set de functii) este insa marcata ca
invechita incepand cu PHP 5.3.0.

Aceasta documentatie va prezenta regex-urile conform sintaxei PCRE.

Principalele functii folosite pentru regex-urile PCRE sunt preg_match() si preg_match_all(). Aceste functii vor fi detaliate spre sfarsitul capitolului, insa
pentru a testa regex-urile folosite vom incepe folosirea functiei preg_match(). In forma ei simpla, se apeleaza preg_match($pattern, $subject), unde
$pattern este regex-ul si $subject este sirul normal de caractere. Daca expresia $pattern este gasita in sirul $subject, preg_match() returneaza 1, altfel
returneaza 0.

Important
Conform sintaxei PCRE descrisa in continuare, orice regex (regular expression) se delimiteaza (la inceput si la sfarsit) cu un caracter ce nu poate fi
alfanumeric sau backslash (\). Exemplu regex: /a.e/
In plus, daca acest caracter (numit delimitator) se foloseste in cadrul regex-ului, el trebuie precedat de \

Sursa script Sursa HTML in browser


1 <?php 1 int(1)
2
3 /*
4 orice regex se scrie intre
5 caractere delimitatoare. in
6 general o sa folosim /
7 caracterul punct (.) inseamna
8 orice caracter
9 */
10
11 $regex = '/a.c/'; // adica: a
12 urmat de orice caracter, urmat
13 de c
14 $str = 'xyabczt';

$m = preg_match($regex, $str);

var_dump($m); // int(1), adica


$regex se gaseste in $str.
altfel, ar fi fost int(0)
?>

5.8.2. Meta-caractere

Scopul unui regex este sa pot verifica daca un string are un anumit format. In practica, folosind functia preg_match($pattern, $subject) verific daca regex-
ul $pattern se regaseste in interiorul sirului $subject (numit in continuare sirul subiect). Cele mai multe caractere nu au in regex un inteles special. De
exemplu, regex-ul /ele/ se potriveste sirului "ele" sau "telescaun".

Sursa script Sursa HTML in browser


1 <?php 11
2 echo preg_match('/ele/', 'ele'); 21
3 // 1 30
4 echo "\n";
5 echo preg_match('/ele/',
6 'telescaun'); // 1
7 echo "\n";
echo preg_match('/ele/',
'eliminator'); // 1
?>

Exista insa asa-numitele meta-caractere ce au un inteles special in interiorul unui regex. In acest tabel sunt prezentate aceste meta-caractere dar unele
din ele vor fi explicate si prezentate in detaliu in capitolele urmatoare.

Meta-caractere

Are rolul de "escape character" adica "dezbraca" caracterul ce-l urmeaza de orice inteles special l-ar putea avea.
\
Exemplu: \. inseamna chiar punct. Caracterul \ are insa si alte utilizari in regex-uri.

^ indica inceputul unui sir (sau inceputul unei linii - daca este activa optiunea MULTILINE)

$ indica sfarsitul unui sir (sau sfarsitul unei linii - daca este activa optiunea MULTILINE)

. se potriveste cu orice caracter mai putin newline (\n) (daca este activa optiunea DOT-ALL, caracterul . se potriveste si cu \n

[] intre parantezele drepte se scrie o clasa de caractere

() cu ajutorul parantezelor rotunde se formeaza sub-expresii

| caracter ce inseamna "sau"

? semnifica aparitia unui caracter o data sau deloc

* repetarea unui caracter (sau subexpresii) de zero sau de mai multe ori

+ repetarea unui caracter (sau subexpresii) o data sau de mai multe ori

{x,y} indica repetarea unui caracter (sau subexpresii) de cel putin x ori si de cel mult y ori

Exemple de folosire a metacaracterelor intr-un regex:

at.9 "at" urmat de orice caracter apoi de cifra 9

^Ar un sir care incepe cu "Ar"

corespunde grupului de caractere "a." (a urmat de punct). Aici caracterul punct inseamna chiar punct, deci nu mai este un meta-caracter pentru
a\.
ca este precedat de backslash.
^php$ sirul subiect este "php"

^a\.$ sirul subiect este "a."

html|php sirul subiect contine sirul "html" sau "php"

Sursa script Sursa HTML in browser


1 <?php 11
2 $regex = '^a\.$'; 20
3 $subject = 'a.';
4
5 echo preg_match('/'.$regex.'/',
6 $subject); // 1 pentru ca sirul
7 ESTE a.
8
9 echo "\n";
10
11 $regex = '^a\.$';
12 $subject = 'ab.';
13
14 echo preg_match('/'.$regex.'/',
15 $subject); // 0

?>
5.8.3. Clase de caractere

Definitie
O clasa de caractere intr-un regex indica prezenta unui singur caracter din acea lista de caractere in sirul subiect. Clasele de caractere se scriu intre
paranteze drepte [].

In interiorul claselor de caractere sunt valabile DOAR urmatoarele meta-caractere:

Are rolul de "escape character" adica "dezbraca" caracterul ce-l urmeaza de orice inteles special l-ar putea avea.
\
Exemplu: \. inseamna chiar punct. Caracterul \ are insa si alte utilizari in regex-uri.

- indica un interval de caractere. Exemplu: [a-z] indica prezenta unei litere mici (o litera mica este un caracter intre a si z)

are rol de negatie, si se pune la inceputul clasei; o clasa negata (ce incepe cu ^) corespunde oricarui caracter cu exceptia celor din clasa. Ex [^a-z]
^
inseamna orice caracter in afara de litera mica.

Nota
Constructia [az] de exemplu, nu se potriveste unui caracter intre a si z (pentru ca nu avem caracterul "-" ce indica un interval). Si nici nu indica
prezenta grupului "az" in sirul subiect pentru ca fiind o clasa de caractere, rezultatul acestei constructii este un singur caracter. Deci [az] se
potriveste ori lui a ori lui z.

Nota
Un caracter alfanumeric este o litera sau o cifra. Un sir alfanumeric este format doar din litere si cifre

Exemple de constructii folosite cu clase de caractere:

Regex Siruri ce se potrivesc

[a-z] orice litera mica

[A-Z] orice litera mare

[a-zA-Z] orice litera mica sau mare

[azc*&] oricare dintre caracterele a, z, c, * sau &

[xyz] unul dintre caracterele x, y sau z

[c-h] oricare din literele de la c la h


[0-9] orice cifra

apare caracterul de negatie: "^".


[^a-zA-Z]
Aceasta constructie semnifica orice caracter in afara de litera mica sau litera mare.

[A-Z][a-z] un grup de doua caractere din care primul e o litera mare si urmatorul e litera mica

[0-9][0-9][^a-zA-Z0-
orice grup de doua cifre urmat de un al 3-lea caracter care nu este alfanumeric
9]

In clase pot fi combinate intervalele de caractere cu prezenta altor caractere. Exemplu:

[aeiou0-
o vocala sau o cifra
9]

[ar-te] caracterul "a" SAU un caracter de la "r" la "t" (deci r, s sau t), SAU caracterul "e"

[.,:a-z] punct, virgula, doua puncte sau o litera mica

Clasele de caractere vor fi combinate cu alte elemente (cum ar fi caractere normale) pentru formarea unui regex

Io[a-z] caracterele "Io" urmate de orice litera mica. Ex: Ion, Ioc, Ioi, Ioa, Ioz....

[a-z]ar corespunde unui grup ce incepe cu o litera si se termina in "ac". Ex: aar, bar, car, dar

A[rsl]ta corespunde unui grup ce incepe cu "A", continua cu una din literele "r", "s" sau "l" si apoi continua cu grupul "ta". Deci: Arta, Asta, Alta

Formarea unui regex din clase de caractere, caractere normale si meta-caractere

[A-Za-z]. o litera urmata de orice caracter. Ex: A*, c&, g., bA, etc

^[a-h][1-8]$ sirul subiect este de forma litera de la a la h urmata de cifra de la 1 la 8. Ex: a8, g1, e7

0721\.[0-9][0-9][0-9]\.[0-9][0-
sirul subiect contine un numar de telefon mobil ce incepe cu 0721 si se termina in 5
9]5

P...[ei] Incepe cu "P", contine orice trei caractere, si se termina in "e" sau "i". Ex: Peste, Pesti, P&6%i

Sursa script Sursa HTML in browser


1 <?php 11
2 $regex = '^P..t[ei]'; 21
3 $subject1 = 'Pestii inoata
4 nestingheriti.';
5
6 echo preg_match('/'.$regex.'/',
7 $subject1); // 1
8
9 echo "\n";
10
11 $subject2 = 'Pestele respira sub
12 apa.';
13
14
15 echo preg_match('/'.$regex.'/',
$subject2); // 1

?>

Nota
Daca vreau sa folosesc caracterul - (cratima) in interiorul unei clase, pentru a nu fi interpretat ca un meta-caracter ce indica un interval am doua
optiuni: 1 il includ la inceputul clasei; 2 il preced de backslash. Daca vreau sa folosesc . (punct) in interiorul unei clase, nu trebuie sa-l preced cu
backslash pentru ca punctul nu este un meta-caracter in interiorul clasei. Exemplu: [-_.a-z] indica oricare din caracterele: - _ . sau o litera.
5.8.4. Clase uzuale de caractere
Backslash (\) ca si meta-caracter are cum spuneam si alte intrebuintari. Una din ele este ca impreuna cu anumite litere, formeaza clase de caractere
uzuale, predefinite.

Clasele de caractere uzuale sunt:

\d corespunde unei cifre (d - digit)

\D corespunde oricarui caracter care nu este cifra

\s spatiu, tab (\t), newline (\n) . caractere denumite in engleza "whitespace" sau "whitespace character"

\S orice caracter in afara de whitespace

\w orice litera, cifra sau underscore (w - word character)

\W orice caracter ce nu este un "word character"

Nota
Aceste clase de caractere uzuale nu se scriu intre paranteze drepte []

Exemple:

\d\d\. doua cifre urmate de punct. Ex: 01. 23. etc

B\s\d\d\s[A-Z][A-Z][A-Z] un numar de automobil de Bucuresti. Ex: B 01 AGY

5.8.5. Subexpresii. Repetitii


Subexpresiile sunt parti ale expresiilor regulate cuprinse intre paranteze rotunde ().
De exemplu, in regexul "(mymail)@gmail.com" avem subexpresia "mymail". O subexpresie este denumita (in engleza, in documentatii ale regex-urilor)
si subpattern.
Subexpresiile sunt foarte importante. Ele sunt folosite de cele mai multe ori in unul din urmatoarele cazuri:

1. Impreuna cu operatorii (meta-caracterele) de repetitie, pentru a specifica repetitia unui grup de caractere

2. Pentru a captura doar o parte din sirul ce corespunde regex-ului. De exemplu, cautam in sursa unui fisier html toate linkurile dar ne
intereseaza sa extragem doar valorile atributului href. Regex-ul va "prinde" sirurile de forma <a href="...">...</a>, dar cu ajutorul
subexpresiilor voi captura doar valorile atributului href. Exemplificarea acestei tehnici se face in subcapitolul preg_match_all()

3. "Backreferences" - referirea ulterioara a unei subexpresii ce apare intr-un regex. Acest procedeu este explicat si exemplificat in
subcapitolul Referirea la o subexpresie anterioara

Definitie
In cadrul unui regex se poate specifica repetitia unui caracter sau unui grup de caractere folosind sintaxta {} sau operatorii de repetitie: ?, * si +

Repetam semnificatia operatorilor de repetitie:

? semnifica aparitia unui caracter o data sau deloc

* repetarea unui caracter (sau subexpresii) de zero sau de mai multe ori

+ repetarea unui caracter (sau subexpresii) o data sau de mai multe ori

{x,y} indica repetarea unui caracter (sau subexpresii) de cel putin x ori si de cel mult y ori

{x,} sintaxa ce indica repetarea de cel putin x ori

{x} sintaxa ce indica repetarea fix x ori

Repetitia se refera la caracterul imediat anterior sau la subexpresia imediat anterioara. Regex-ul "abc+" inseamna "ab" urmat de "c" o data sau de mai
multe ori. Regex-ul a(bc){1,5} inseamna "a" si apoi grupul "bc" de 1 pana la 5 ori. Operatorii de repetitie au sens (si sunt foarte des folositi) si dupa o
clasa de caractere. De exemplu, [a-z]+inseamna un grup de litere mici, avand cel putin o litera.

Cateva exemple si semnificatia lor:

Regex Explicatie Exemple de siruri ce corespund

[A-z][a-z]+ Litera mare urmata de un grup de litere mici Abc, Ionel, Morcov, Zzx

07\d{8} un numar de mobil: 07 urmat de 8 cifre 0722234456

07, apoi doua cifre, apoi punct, apoi 3 cifre, apoi punct apoi iar
07\d{2}\.\d{3}\.\d{3} 0722.234.456
trei cifre

? indica faptul ca \. (punct) nu apare deloc sau apare cel mult o atat numerele de forma 0722234456 cat si
07\d{2}\.?\d{3}\.?\d{3}
data. 0722.234.456

a(bc){3} a urmat de grupul bc de 3 ori abcbcbc

[-._a-z0-9]+@[-.a-z0-9]+\.[a-z] un grup 1 sau mai multe caractere dintre care - . (punct) _ sau john@gmail.com , ana-
{2,4} litera mica urmat de @, apoi de un grup format din - . (punct) maria.stoica@mydomain.ro,
litere mici si cifre, apoi punct, apoi 2 pana la 4 litere marian_popescu@yahoo.com

5.8.6. Referirea la o subexpresie anterioara

In cadrul unui regex, subexpresiile sunt numerotate in incepand cu 1, in ordinea in care apar. Exista cazuri in care vrem sa construim un regex astfel incat
aceeasi subexpresie sa apara de mai multe ori in sirul nostru, dar fara sa o stim cand aplicam regex-ul . De exemplu, vrem construim un regex care sa
"prinda" toate sirurile de forma <tag>text</tag> indiferent ca e vorba de "tag", "body", "td" sau alt grup de litere. Asta inseamna ca aceeasi subexpresie
(tag, body, td....)dintre caracterele < si > , trebuie sa apara si intre </ >
Astfel, prima subexpresie din regex-ul nostru o putem referi in acelasi regex cu \1. A doua cu \2, apoi \3, etc.

Exemplu:

Sursa script Sursa HTML in browser


1 <?php 11
2 21
3 $regex = '<([a-z]+)>[a-z] 30
4 +</\1>'; // prima subexpresie,
5 este ([a-z]+). o referim mai
6 tarziu in regex cu \1
7 $subject1 = '<td>text</td>';
8 $subject2 =
9 '<orice>text</orice>';
10 $subject3 =
11 '<ceva>text</altceva>';
12
13 $match1 = preg_match('|'.
14 $regex.'|', $subject1);
15 echo $match1; // 1
16
17 echo "\n";
18
19 $match2 = preg_match('|'.
20 $regex.'|', $subject2);
21 echo $match2; // 1
22
23
24 echo "\n";

$match3 = preg_match('|'.
$regex.'|', $subject3);
echo $match3; // in sirul
subiect, ce apare intre < >
difera de ce apare intre </ si
>, deci nu se potriveste regex-
ului

?>

5.8.7. expresie1 sau expresie2

Operatorul folosit pentru indicarea alternativelor este "|".

Regex Explicatie Exemple de siruri ce corespund


(Ion)|(John) grupul de caractere "Ion" sau "John" Ion , John

(021)|
021 sau 07 urmate de 7 cifre 0211234567 , 0721234567
(07)\d{7}

x|(christ)mas xmas sau christmas

5.8.8. Conditia de inceput si sfarsit

^ indica inceputul unui sir (sau inceputul unei linii - daca este activa optiunea MULTILINE)

$ indica sfarsitul unui sir (sau sfarsitul unei linii - daca este activa optiunea MULTILINE)

Nota
In general (in majoritatea exemplelor) testam daca sirul subiect contine un grup de caractere de forma regex-ului. In momentul cand incadram
regex-ul intre ^ si $, testam sirul subiect ESTE de forma regex-ului.
preg_match("/ceva/", $subiect) - testeaza daca sirul subiect contine "ceva"
preg_match("/^ceva$/", $subiect) - testeaza daca sirul subiect este "ceva"
preg_match("/^ceva/", $subiect) - testeaza daca sirul subiect incepe cu "ceva"
preg_match("/ceva$/", $subiect) - testeaza daca sirul subiect se termina cu "ceva"

5.8.9. Optiuni regex (pattern modifiers)

Exista anumite optiuni numite "pattern modifiers" ce modifica modul in care este aplicat un regex unui sir.

Cele mai uzuale optiuni sunt:

Litera optiune Nume optiune Descriere

i PCRE_CASELESS nu se face distinctie intre litere mici si mari

Daca optiunea este activa:


^ va corespunde atat inceputului textului, cat si fiecarui inceput de linie din acest text
$ va corespunde atat sfarsitului textului, cat si fiecarui sfarsit de linie din text
m PCRE_MULTILINE
Daca optiunea este inactiva:
^ si $ vor corespunde doar inceputului si sfarsitului textului respectiv

s PCRE_DOTALL Daca aceasta optiune este activa, punctul va corespunde oricarui caracter inclusiv newline-ul.

Optiunile pot fi modificate specificand literele corespunzatoare optiunilor intre "(?" si ")". Ex: (?im) seteaza optiunile PCRE_CASELESS si PCRE_MULTILINE
in acelasi timp. Daca literele optiunilor sunt precedate de "-" (minus) atunci respectivele optiuni sunt dezactivate.

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $regex1 = '[a-z]+'; 2(
3 $subject = 'Web'; 3 [0] => eb
4 4)
5 $match = preg_match('|'. 5 Array
6 $regex1.'|', $subject, 6(
7 $matches); 7 [0] => Web
8 print_r($matches); 8)
9 9 Array
10 10 (
11 /* se activeaza optiunea 11 [0] => New York
12 caseless. Deci literele mici [a- 12 )
13 z] semnifica si litere mari */ 13 Array
14 $regex2 = '(?i)[a-z]+'; 14 (
15 $match = preg_match('|'. 15 [0] => NeW YORK
16 $regex2.'|', $subject, 16 )
17 $matches);
18 print_r($matches);
19
20
21 $regex3 = '(?i)N(?-i)ew (?i)Y(?-
22 i)ork';
23 $subject3 = 'New York';
24
25 $match = preg_match('|'.
26 $regex3.'|', $subject3,
27 $matches);
28 print_r($matches);
29
30
31 /*
32 $regex4 dezactiveaza optiunea
33 PCRE_CASELESS pentru N si Y.
34 Asta inseamna ca trebuie sa fie
cu litere mari, ca in regex, si
o activeaza pentru "ew" si
pentru "ork"
asta inseamna ca "ew" si "ork"
pot fi scrise oricum (litere
mari si mici)
*/

$regex4 = '(?-i)N(?i)ew (?-i)Y(?


i)ork';
$subject4 = 'NeW YORK';

$match = preg_match('|'.
$regex4.'|', $subject4,
$matches);
print_r($matches);

?>

5.8.10. Functii pentru regex-uri (PCRE)


5.8.10.1 preg_match()
5.8.10.2 preg_match_all()

5.8.10.1. preg_match()
Functia preg_match() are urmatoarea semnatura:
int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags [, int $offset ]]] )

preg_match() cauta un sir de forma $pattern in interiorul sirului $subject, si returneaza 0 daca nu-l gaseste si 1 daca gaseste cel putin o
aparitie.preg_match() se opreste imediat ce gaseste o aparitie de forma $pattern in sirul $subject. Din acest motiv, preg_match() va gasi doar prima
aparitie.

Nota
Daca exista (si vrem sa gasim) mai multe aparitii ale regexului $pattern in sirul subiect, folosim functia preg_match_all()

 $pattern - este regex-ul pe care-l cautam in sirul subiect

 $subject - este sirul subiect

 $matches - este al 3-lea parametru, optional, si va fi populat cu rezultatele cautarii astfel: $matches[0] contine portiunea din sirul subiect ce
a corespuns regex-ului, $matches[1] sirul ce a corespuns primei subexpresii din regex, $matches[2] sirul celei de-a doua subexpresii, etc
 $flags - in general aceste flag-uri sunt valori intregi, ce sunt tinute minte in anumite constante predefinite in php. Aici flag-ul acceptat este:
PREG_OFFSET_CAPTURE, si cand este transmis acest flag, fiecare rezultat al tabloului $matches are doua rezultate: primul este sirul ce
corespunde, al doilea este index-ul (offset-ul) la care a fost gasit in sirul cautat

 $offset - index-ul de la care dorim inceperea cautarii. implicit este 0.

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $regex = '[A-Z][a-z]+'; // cauta 2(
3 un cuvant, ce incepe cu litera 3 [0] => Aceasta
4 mare. 4)
5
6 $subject = 'Aceasta este o
7 propozitie.';
8
9 $match = preg_match('|'.
$regex.'|', $subject, $matches);

print_r($matches);
?>

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 $regex = '[A-Z][a-z]+'; // cauta 2(
3 un cuvant, ce incepe cu litera 3 [0] => Acesta
4 mare. 4)
5 $subject = 'Acesta este un nume: 5 Array
6 Elena.'; 6(
7 7 [0] => Array
8 /* 8 (
9 desi sunt doua aparitii ce 9 [0] => Acesta
10 corespund regex-ului (Acesta , 10 [1] => Elena
11 Elena), in cu preg_match obtinem 11 )
12 doar prima aparitie. 12
13 */ 13 )
14 $match = preg_match('|'. 14 Array
15 $regex.'|', $subject, $matches); 15 (
16 print_r($matches); 16 [0] => Elena
17 17 )
18 18 Array
19 /* 19 (
20 cu preg_match_all() le obtinem 20 [0] => Array
21 pe ambele 21 (
22 */ 22 [0] => Elena
23 $match = preg_match_all('|'. 23 [1] => 21
24 $regex.'|', $subject, $matches); 24 )
25 print_r($matches); 25
26 26 )
27
28 /*
29 folosim la flags 0 (nu ne
30 intereseaza pe ce pozitie e
31 gasita aparitia)
32 si la offset 1 (deci trece de
33 "A" de la Acesta, prin urmare va
34 gasi doar a doua aparitie,
35 Elena)
36 */
37
38 $match = preg_match('|'.
$regex.'|', $subject, $matches,
0, 1);
print_r($matches);

/*
folosim la flags
PREG_PATTERN_ORDER, sa aflam pe
ce pozitie a fost gasit pattern-
ul
*/

$match = preg_match('|'.
$regex.'|', $subject, $matches,
PREG_OFFSET_CAPTURE, 1);
print_r($matches);

?>

5.8.10.2. preg_match_all()
Functia preg_match_all() are urmatoarea semnatura:
int preg_match_all ( string $pattern , string $subject , array &$matches [, int $flags [, int $offset ]] )

preg_match() cauta toate sirurile de forma $pattern in interiorul sirului $subject si populeaza tabloul $matches cu rezultatele gasite si returneaza
numarul de aparitii gasite (sau 0 daca nu e gasita nici o aparitie, sau FALSE daca e o eroare in regex).
Popularea tabloului $matches cu rezultatele gasite se face in functie de parametrul $flags astfel:

 daca $flags este PREG_PATTERN_ORDER - $matches[0] va contine toate sirurile ce corespund regex-ului, $matches[1] va contine toate
sirurile corespunzatoare primei subexpresii, $matches[2] ... celei de-a doua subexpresii, etc

 daca $flags este PREG_SET_ORDER - $matches[0] va contine elementele primului sir gasit, $matches[1] elementele celui de-al doilea sir
gasit, etc. Astfel $matches[0][0] va contine primul sir gasit, $matches[0][1] va contine sirul primei subexpresii din primul sir gasit... etc

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 // ATENTIE - prinde doar 2(
3 tagurile fara atribute 3 [0] => Array
4 4 (
5 // prima expresie () va fi 5 [0] => <b>intre
6 numele tagului 6 taguri 1</b>
7 // a doua subexpresie () va fi 7 [1] => <a>intre
8 textul dintre taguri 8 taguri 2</a>
9 $regex = '<([a-z]+)>([0-9a-z\s] 9 )
10 +)</\1>'; // prima subexpresie, 10
11 este ([a-z]+). o referim mai 11 [1] => Array
12 tarziu in regex cu \1 12 (
13 $subject = 'Text1 text2 <b>intre 13 [0] => b
14 taguri 1</b> text 3 text 3 14 [1] => a
15 <a>intre taguri 2</a>'; 15 )
16 16
17 17 [2] => Array
18 $match = preg_match_all('|'. 18 (
19 $regex.'|', $subject, $matches, 19 [0] => intre taguri
PREG_PATTERN_ORDER); 20 1
print_r($matches); 21 [1] => intre taguri
22 2
echo "\n 23 )
-------------------------------- 24
----------- \n"; 25 )
26
$match = preg_match_all('|'. 27
$regex.'|', $subject, $matches, 28 --------------------------------
PREG_SET_ORDER); 29 -----------
print_r($matches); 30 Array
31 (
32 [0] => Array
?> 33 (
34 [0] => <b>intre
35 taguri 1</b>
36 [1] => b
37 [2] => intre taguri
38 1
39 )
40
[1] => Array
(
[0] => <a>intre
taguri 2</a>
[1] => a
[2] => intre taguri
2
)

5.8.11.Resurse
www.regular-expressions.info
www.php.net/manual/en/regexp.reference.php
www.php.net/manual/en/reference.pcre.pattern.modifiers.php

5.9. Tema
Tema5-1
Realizati o functie, ce primeste urmatorii 4 parametri: $str (string-ul de validat), $vtype, $min (lungimea minima a string-ului de validat), $max (lungimea
maxima a string-ului de validat). $vtype reprezinta tipul validarii si poate fi unul din urmatoarele string-uri: oras sau city, firstname sau prenume,
lastname sau nume, name sau nume, adresa sau address, cnp, email, username, parola sau password. Pentru fiecare tip, functia de validare realizeaza o
validare specifica tipului respectiv; ex: oras-ul sa nu contina decat litere mari litere mici, cratima si spatii, .... etc. Lungimea string-ului de validat trebuie
sa fie intre $min si $max. Functia va returna true daca string-ul s-a validat, si false in caz contrar.

CAP 6. Procesarea formularelor. $_GET si $_POST


6.1 Despre HTTP. Informatii externe programului PHP
6.2 Cereri de tip GET
6.3 Cereri de tip POST
6.4 Diferentele dintre GET si POST
6.5 Scurta recapitulare formulare
6.6 Realizarea unui formular de inscriere
6.7 Tema
6.1. Despre HTTP. Informatii externe programului PHP

Definitie
http este protocolul de comunicare intre un client web si un server web. Comunicatia http incepe de la client. Clientul initiaza o cerere http catre un
anumit server. Serverul proceseaza cererea respectiva, si trimite un raspuns inapoi clientului, numit raspuns http.

Serverul web nu poate trimite raspunsuri catre clientul web, decat ca urmare a unor cereri.

O cerere HTTP catre serverul web contine:

 resursa soliticata de catre client; Aceasta resursa este o cale catre un fisier, cale relativa la document root. Ex: /cursuri/index.php

 tipul de cerere. In general tipul este GET sau POST

 headere http - informatii standard transmise prin protocolul http. Prin aceste headere se transmit informatii despre clientul web sau alte
informatii specifice cererii http. Exemple de headere http:
Host: www.example.com
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8) Gecko/20051111 Firefox/1.5 - acest header comunica serverului informatii
despre versiunea de browser (client web) si implicit despre sistemul de operare al calculatorului client

 informatii introduse de utilizator - prin intermediul formularelor html sau direct prin intermediul unui url (vezi capitolul despre GET)

Mai departe, serverul web, trimite catre interpretorul PHP informatiile primite de la clientul web, precum si alte informatii. Astfel, intr-un program in PHP se
pot accesa aceste informatii din variabile superglobale, predefinite, de tip array:

 $_SERVER - array cu informatii extrase din headerele http (despre clientul web si despre cererea http curenta), si informatii legate de
serverul web sau de sistemul de operare

 $_GET - array cu informatii provenite de la utilizator prin intermediul unei cereri de tip GET

 $_POST - array cu informatii provenite de la utilizator prin intermediul unei cereri de tip POST

 $_COOKIE - array cu informatii stocate pe calculatorul client si trimise inapoi serverului intr-un raspuns http

 $_FILE - array cu informatii legate de upload-ul de fisiere

 $_REQUEST este un array ce contine informatiile cumulate din $_GET, $_POST si $_COOKIE. Aceste 3 tablouri au in comun faptul ca
informatia continuta in ele vine de la utilizator, prin urmare este nesigura.

Nota
Serverul web si interpretorul PHP sunt aplicatii instalate pe acelasi calculator.

Nota
Continutul oricarui array, deci si celor superglobale, poate fi vazut oricand cu functia print_r(); Ex: print_r($_SERVER). Informatiile afisate cu
print_r() se vand mai clar in sursa browserului, pentru ca acolo are efect caracterul newline generat de print_r().

6.2. Cereri de tip GET


In momentul cand navigam pur si simplu la o adresa, realizam o cerere de tip GET catre server. Atunci cand scriem in browser www.invata-
online.ro/index.php , serverul primeste de fapt o cerere HTTP de tip GET catre resursa /index.php.
Definitie
Printr-o cerere de tip GET se pot trimite informatii catre serverul web prin asa-numitul query string, un sir ce se ataseaza la sfarsitul url-ului dupa
caracterul "?". O cerere de tip GET ce are query string (deci trimite informatie aditionala catre server) are forma: http://www.example.com?
variabila1=valoare1&variabila2=valoare2&variabila3=valoare3
Query string-ul este format din perechi variabila=valoare separate prin &.

De exemplu, o cautare pe google dupa cuvantul php are ca rezultat directionarea catre url-ul:
http://www.google.ro/search?hl=en&q=php&btnG=Search

Accesarea unui url de tip GET de catre utilizator se poate realiza prin urmatoarele modalitati:

 Utilizatorul da click pe un link dintr-un site, iar acel link trimite catre un url de tip get (sau are link-ul salvat in Bookmarks/Favorites)

 Utilizatorul completeaza un formular html care are method="get" si cand apasa butonul "Submit" browserul face o cerere de tip GET catre
server

Important
Indiferent cum se realizeaza o cerere de tip GET, rezultatul final este ca informatiile de tip variabila=valoare din query string sunt incarcate in
tabloul $_GET disponibil programatorului PHP.

Codul php pentru fisierul http://www.invata-online.ro/courses/web2/test-get.php este urmatorul:

1 <?php
2 print_r($_GET);
3 ?>
Incercati orice query string, la sfarsitul url-ului de mai sus. Exemplu: http://www.invata-online.ro/courses/web2/test-get.php?nume=ion&varsta=23

Faceti acest test si pe calculatorul local.

A doua modalitate prin care browserul trimite o cerere de tip get catre server, este atunci cand utilizatorul completeaza un formular cu
method="get"

Cod HTML - formular.html

<form method="get" action="test-get.php">


Prenume <input type="text" name="prenume" value="" /> <br />
Varsta <input type="text" name="varsta" value="" /> <br />
<br /><br />
<input type="submit" name="buton" value="Trimite" />

</form>

In momentul cand utilizatorul apasa butonul "Trimite", browserul realizeaza o noua cerere de tip GET catre fisierul descris in atributul action al
formularului (test-get.php) in acest caz.

Nota
Pentru a testa, realizati in folderul de lucru (pe calculatorul local) doua fisiere: unul numit formular.html , avand codul html de mai sus (formularul),
iar celalalt test-get.php avand acelasi cod cu fisierul test-get.php de mai sus

Important
Prin atributele name ale unui formular se specifica de fapt ceea ce vor deveni variabilele de tip GET (sau POST daca formularul se trimite prin POST).
Acestea vor deveni apoi chei ale array-ului superglobal $_GET sau $_POST. Astfel ca, in formularul de mai sus, daca se completeaza de exemplu "ion" si
"23", si apasam pe "Trimite" se trimite cererea de tip GET: test-get.php?prenume=ion&varsta=23 . Apoi, tabloul $_GET il putem vizualiza cu
print_r($_GET)

6.3. Cereri de tip POST


Spre deosebire de cererile de tip GET care "poarta" informatia de la utilizator in URL, cererile de tip POST se pot face doar printr-un formular html cu
action="POST" iar perechile variabile=valoare nu vor fi vizibile de asta data in URL. Deci nu putem tasta sau accesa un link care sa realizeze o cerere de
tip POST.

Cod HTML - formular2.html

<form method="post" action="test-post.php">


Prenume <input type="text" name="prenume" value="" /> <br />
Varsta <input type="text" name="varsta" value="" /> <br />
<br /><br />
<input type="submit" name="buton" value="Trimite" />

</form>

In acelasi folder, realizati un fisier numit test-post.php avand codul:

test-post.php
1 <?php
2 print_r($_POST);
3
4
5 // sau
6 /*
7 echo $_POST['prenume'];
8 echo $_POST['varsta'];
9 */
10 ?>

Nota
La fel, valorile atributului "name" (aici prenume si varsta) se vor transforma in variabile de tip POST, mai precis in chei ale variabilei superglobale
$_POST. Astfel, in test-post.php voi avea $_POST["prenume"] si $_POST["varsta"] continand valorile completate in formular de catre utilizator.
6.4. Diferentele dintre GET si POST
1. Folosind GET, informatia transmisa de la utilizator este incarcata in url, pe cand cea de la POST nu este in url, ea este transmisa prin
conexiunea curenta http. Astfel, un url la care a fost transmisa o cerere POST nu se poate salva pentru o accesare ulterioara.

2. Folosind GET, lungimea datelor primite de la utilizator este limitata la aproximativ 255 de caractere, lungimea maxima a unui URL. Astfel,
formulare care accepta mesaje, sau incarcare de fisiere, sau informatie mai lunga, NU se pot transmite prin GET.

3. Datorita faptului ca informatiile de la utilizator se transmit prin url in cazul metodei GET, nu putem transmite prin GET informatiile dintr-un formular
care are parola, pentru ca, parola va fi vizibila in URL. Decat daca codam parola respectiva.
Cand folosim GET si cand POST ?
In general sunt situatii clare cand se recomanda folosirea metodei get sau post:

1. Daca avem un formular care modifica informatii (insert sau update in baza de date), in general folosim POST. Pentru ca pagina respectiva, nu mai
trebuie sa fie accesata ulterior prin facilitatea History a browser-ului sau prin bookmarks. O practica buna este de fapt dupa ce facem insert-ul sau update-
ul in baza de date, sa redirectam catre alta pagina, astfel incat utilizatorul sa nu poata sa reincarce pagina respectiva. Acest lucru va deveni clar mai tarziu
in curs, in exemplele practice

2. Daca avem o extragere de informatii (in general select dintr-o baza de date) cum ar fi un formular de cautare, in generalse foloseste GET. Pentru
ca pagina respectiva sa poate fi salvata de utilizator, sau accesata prin butoanele Back sau Forward ale browser-ului (facilitatea History). In general la
formularele de search nu se introduc multe informatii, deci se respecta si regula cu limitarea informatiei transmise.

3. Daca avem upload (incarcare) de fisiere de la utilizator, se foloseste doar POST.

4. Pentru formular de login in general se foloseste POST, pentru ca se transmite o parola, si apoi nu vrem sa acceseze acest link prin History sau
Bookmarks.

Nota
De multe ori veti realiza linkuri in site ce transmit anumiti parametri prin GET. De exemplu: produse.php?produsId=5. Asta inseamna ca se
foloseste metoda GET, dar nu prin formular ci direct prin link

6.5. Scurta recapitulare formulare


Formularele sunt tratate in detaliu in cursul Programator Web 1, pentru ca sunt notiuni specifice html. In acest capitol doar reamintesc cateva din
elementele unui formular, si explic folosirea lor cu php.
Important
Testeaza toate exemplele pe calculator, avand un fisier .html cu formularul, si un fisier .php cu codul in care se proceseaza cererea $_GET sau
$_POST. ATENTIE: ambele fisiere trebuie sa se afle sub Document Root (sau un alias), iar fisierul html nu trebuie deschis prin dublu click ci prin
http://localhost/cale/catre/fisier.html astfel incat si cererea catre fisierul .php sa fie trimisa prin http:// deci prin serverul web.

Important
Cum spuneam, valoarea atributului name al unui element de formular, se transforma in parametru de tip GET sau POST, si devine apoi cheie pentru
superglobalele $_GET sau $_POST.
De exemplu, daca am: <input name="prenume" value="" />, si transmit formularul prin GET, in scriptul .php ce primeste cererea o sa am in
$_GET["prenume"] valoarea completata de utilizator in acest input. Apoi, o sa vreau sa scriu probabil $prenume = $_GET["prenume"] ca sa folosesc in
continuare in script variabila $prenume. Desi pot sa dau alt nume variabilei, exemplu $pnume = $_GET["prenume"] de cele mai multe ori este bine sa
folosesc acelasi nume cu cel al parametrului GET, ca sa fie mai simplu de tinut minte. Din acest motiv, valoarea atributului name al unui element din
formular, trebuie sa nu contina spatii, sau caractere speciale, sa aiba o forma ce poate fi mai departe variabila in PHP.

Elementele simple
Numesc elementele simple cele care nu reprezinta o selectie dintr-o lista de valori, si astfel sunt foarte clar preluate in PHP. Acestea sunt: input-ul text,
input-ul password, textarea.

Cod HTML - formular.html Rezultat

<form method="post" action="procesare.php"> Prenume

Prenume <br /> <input type="text" name="prenume"


value="" /> <br /> Nume

Nume <br /> <input type="text" name="nume" value="" />


<br /> Parola
Parola <br /> <input type="password" name="parola"
value="" /> <br />
Mesaj

Mesaj <br />


<textarea name="mesaj" cols="20" rows="20"></textarea>

<br /><br />


<input type="submit" name="buton" value="Trimite" />

<br />
</form>

Trimite

procesare1.php
1 <?php
2 /* intotdeauna pot folosi print_r() pentru debug, pentru a vedea
3 exact cum arata $_GET sau $_POST sau alt array */
4 print_r($_POST);
5
6 // sau folosesc fiecare informatie din $_POST in parte.
7 echo '<br />';
8 echo 'Numele tau este: ' . $_POST["prenume"] . ' ' . $_POST["nume"];
9 echo '<br />';
10 echo 'Parola are ' . strlen($_POST["parola"]) . ' caractere ';
11 echo '<br />';
12 echo 'Mesajul tau este: ';
13 echo '<br />';
14 echo nl2br($_POST["mesaj"]);
15
?>

sau, asa cum vom lucra mai des in practica, voi extrage in variabile simple fiecare element din $_POST:

procesare2.php
1 <?php
2 print_r($_POST);
3
4
5 // sau folosesc fiecare informatie din $_POST in parte.
6 // dar extrag informatia in variabile simple
7 $prenume = $_POST["prenume"];
8 $nume = $_POST["nume"];
9 $parola = $_POST["parola"];
10 $mesaj = nl2br($_POST["mesaj"]);
11
12 echo '<br />';
13 echo 'Numele tau este: ' . $prenume . ' ' . $nume;
14 echo '<br />';
15 echo 'Parola are ' . strlen($parola) . ' caractere ';
16 echo '<br />';
17 echo 'Mesajul tau este: ';
18 echo '<br />';
19 echo $mesaj;
20
21 ?>

Input radio
Dintr-un grup de butoane radio, utilizatorul nu poate alege decat o singura optiune. Dar, pentru acest lucru, butoanele radio din acelasi grup trebuie sa

aiba aceeasi valoare pentru atributul name .


Cod HTML - formular.html Rezultat

<form method="post" action="procesare.php"> Sex

Sex <br /> Masculin


Masculin <input type="radio" name="sex" value="m" /> <br />
Feminin <input type="radio" name="sex" value="f" /> <br /> Feminin

Trimite
<br />
<input type="submit" name="buton" value="Trimite" />
</form>

Rezultatul se poate vedea daca in procesare.php afisam $_POST cu print_r().


Input checkbox
Controalele de tip checkbox pot fi grupate pe grupuri, folosind acelasi name, insa aici utilizatorul are dreptul la selectarea mai multor optiuni. Astfel,
folosind acelasi parametru se primesc mai multe valori. Ca sa facem acest lucru posibil, si sa primim un array si nu o singura valoare in $_GET (sau
$_POST) trebuie sa folosim in html o sintaxa speciala, si anume adaugarea parantezelor drepte [] dupa valoarea de la name. Aceasta sintaxa se va folosi
si la tagul select cand se permit selectii multiple.

Cod HTML - formular.html Rezultat

<form method="post" action="procesare.php">


Hobby Hobby

<input type="checkbox" name="hobby[]" value="sa inot" Trimite


/>
<input type="checkbox" name="hobby[]" value="sa
skiez" />
<input type="checkbox" name="hobby[]" value="sa
alerg" />
<input type="checkbox" name="hobby[]" value="sa cant"
/>

<br />
<input type="submit" name="buton" value="Trimite" />
</form>

procesare.php
1 <?php
2
3 print_r($_POST); // observam ca $_POST["hobby"] este la randul lui un
4 array
5
6
7 /*
8 se poate vedea si astfel:
9 */
10
11 $hobby = $_POST["hobby"];
12 print_r($hobby);
13
14
15 /*
16 il putem transforma la nevoie in string, cu virgula intre elemente
17 */
18 echo join(',', $hobby);
19
?>

Select - o singura optiune

Daca nu avem atributul multiple intr-un tag select, nu se poate transmite decat o singura valoare, si atunci nu e necesara folosirea sintaxei [] .
Cod HTML - formular.html Rezultat

<form method="post" action="procesare.php">

<select name="lang"> Trimite


<option value="ro">Romana</option>
<option value="en">Engleza</option>
<option value="es">Spaniola</option>
<option value="de">Germana</option>
</select>

<br />
<input type="submit" name="buton" value="Trimite" />
</form>

Select - selectie multipla


Similar cu input checkbox, folosesc sintaxa cu [] pentru ca se transmit mai multe valori prin acelasi parametru get (post).

Cod HTML - formular.html Rezultat

<form method="post" action="procesare.php">

<select name="limbi_straine[]" multiple="multiple"> Trimite


<option value="ro">Romana</option>
<option value="en">Engleza</option>
<option value="es">Spaniola</option>
<option value="de">Germana</option>
</select>

<br />
<input type="submit" name="buton" value="Trimite" />
</form>

Pentru procesare am aceleasi posibilitati ca la input checkbox.

6.6. Realizarea unui formular de inscriere


6.6.1 Prima parte
6.6.2 Validarea datelor
6.6.3 Pastrarea datelor in formular
6.6.4 Pastrarea datelor in formular 2
Acest subcapitol prezinta un mod practic de a prelua si a valida informatiile de la utilizator printr-un formular de inscriere. Insa, preluarea informatiilor nu
este completa, pentru ca nu folosim inca baze de date. In capitolele urmatoare va fi explicata si introducerea informatiilor in baza de date.

6.6.1. Prima parte


Desi pana acum v-am obisnuit sa aveti formularul intr-un fisier .html si sa faceti procesarea datelor intr-un alt fisier (.php), de cele mai multe e
recomandat sa faceti ambele lucruri in acelasi fisier, cu extensia .php. In general acesta este stilul in care voi lucra in continuare: formularul si procesarea
sunt in acelasi fisier. Fisierele realizate in php, fiind generate in mod dinamic pot avea mai multe functionalitati in functie de parametrii primiti. De fapt,
pot face un intreg site, oricat de complex, intr-o singura pagina .php. Si incarc diverse module/functii in functie de parametrii GET (sau POST) primiti.

Fisierul pe care lucram in continuare este denumit inregistrare.php. Voi folosi metoda POST pentru transmiterea informatiilor din formular. Fisierul are 2
functionalitati principale:

1. Daca este incarcat fara parametrii din POST, afiseaza formularul.

2. Daca primeste o cerere POST (deci formularul trimite utilizatorul tot catre inregistrare.php) se comporta diferit: proceseaza informatiile si afiseaza un
mesaj.

Nota
Cum verific daca pagina mea a primit o cerere de tip POST ?
De fiecare data cand este trimis un formular, se trimite si $_POST["buton"] unde "buton" este numele butonului de submit. Verific acest lucru cu if
(isset($_POST["buton"])) , adica verific existenta unui element cu cheia "buton" in array-ul $_POST. Similar pentru $_GET.

inregistrare.php
1 <?php
2 if (isset($_POST["buton"])) {
3 // print_r($_POST);
4
5 $prenume = $_POST["prenume"];
6 $nume = $_POST["nume"];
7 $utilizator = $_POST["utilizator"];
8 $parola = $_POST["parola"];
9 $email = $_POST["email"];
10 $hobby = $_POST["hobby"];
11 $limbi_straine = $_POST["limbi_straine"];
12
13 if (is_array($hobby)) {
14 $hobby = join(',', $hobby);
15 }
16
17
18 if (is_array($limbi_straine)) {
19 $limbi_straine = join(',', $limbi_straine);
20 }
21
22
23 echo '<br /><hr><br />';
24 echo 'Va multumim pentru completarea formularului !';
25 echo '<br />';
26
27 echo 'Datele Dvs sunt: <br /><br />';
28 echo 'Nume: ' . $prenume . ' ' . $nume;
29 echo '<br />';
30 echo 'Utilizator: ' . $utilizator;
31 echo '<br />';
32 echo 'Parola: ' . $parola;
33 echo '<br />';
34 echo 'Email: ' . $email;
35 echo '<br />';
36 echo 'Hobby: ' . $hobby;
37 echo '<br />';
38 echo 'Limbi straine: ' . $limbi_straine;
39 echo '<br />';
40
41 echo '<br /><hr><br />';
42
43 }
44
45 ?>
46
47
48 <form method="post" action="">
49 Prenume <br /> <input type="text" name="prenume" value="" /> <br />
50 Nume <br /> <input type="text" name="nume" value="" /> <br />
51 Utilizator <br /> <input type="text" name="utilizator" value="" />
52 <br />
53 Parola <br /> <input type="password" name="parola" value="" /> <br />
54 Email <br /> <input type="text" name="email" value="" /> <br />
55
56 Hobby <br />
57 <input type="checkbox" name="hobby[]" value="inot" />
58 <input type="checkbox" name="hobby[]" value="ski" />
59 <input type="checkbox" name="hobby[]" value="alergat" />
60 <input type="checkbox" name="hobby[]" value="cantat" />
61 <br />
62
63 Limbi straine vorbite <br />
64
65 <select name="limbi_straine[]" multiple="multiple">
66 <option value="ro">Romana</option>
67 <option value="en">Engleza</option>
68 <option value="es">Spaniola</option>
69 <option value="de">Germana</option>
70 </select>
71
72
73 <br /><br />
74 Mesaj <br />
75 <textarea name="mesaj" cols="20" rows="20"></textarea>
76
77
78 <br /><br />
79 <input type="submit" name="buton" value="Trimite" />
80
81 <br />
82
</form>
6.6.2. Validarea datelor
Validarea datelor inseamna obligarea utilizatorului sa trimita doar date intr-un format permis. De exemplu: numele sa nu contina decat litere mari, mici
spatiu si cratima, numarul de telefon sa contina doar cifre (eventual si punct), numele de utilizator sa fie intre 5 si 10 caractere, parola sa fie minim 7
caractere, etc.

Intr-o aplicatie reala, validarea datelor este obligatorie din urmatoarele motive:

 Securitate

 Consistenta bazei de date

In general, validarea datelor cu PHP se face cu ajutorul expresiilor regulate (regex). Vezi subcapitolul 5.8 Regular Expressions (REGEX) Scriptul de
inregistrare devine acum:

inregistrare.php
1 <?php
2 if (isset($_POST["buton"])) {
3
4 $erori = array();
5 $proceseaza = 0;
6 // print_r($_POST);
7
8
9 // preluarea variabilelor din POST
10 $prenume = $_POST["prenume"];
11 $nume = $_POST["nume"];
12 $utilizator = $_POST["utilizator"];
13 $parola = $_POST["parola"];
14 $email = $_POST["email"];
15 $hobby = $_POST["hobby"];
16 $limbi_straine = $_POST["limbi_straine"];
17
18
19 // verificarea erorilor
20
21 if (!$prenume) {
22 $erori[] = 'Completeaza prenume';
23 } else if (!preg_match('/^[a-zA-Z\-\s\']{2,20}$/', $prenume)) {
24 $erori[] = 'Prenume invalid';
25 }
26
27
28 if (!$nume) {
29 $erori[] = 'Completeaza nume';
30 } else if (!preg_match('/^[a-zA-Z\-\s\']{2,20}$/', $nume)) {
31 $erori[] = 'Nume invalid';
32 }
33
34
35 if (!$utilizator) {
36 $erori[] = 'Completeaza utilizator';
37 } else if (!preg_match('/^[a-zA-Z\-0-9]{4,15}$/', $utilizator)) {
38 $erori[] = 'Utilizator invalid';
39 }
40
41 if (!$parola) {
42 $erori[] = 'Completeaza parola';
43 } else if (preg_match('/[\'\"]/', $parola)) {
44 $erori[] = 'Parola contine caractere invalide';
45 }
46
47
48 if (!$email) {
49 $erori[] = 'Completeaza emailul';
50 } else if (!preg_match('/(?i)[a-z0-9\.\-_\+]+@[a-z0-9\-]+\.([a-z0-
51 9\-]+\.)*+[a-z]{2}/', $email)) {
52 $erori[] = 'Email incorect';
53 }
54
55
56
57 if (!is_array($hobby)) {
58 $erori[] = 'Completeaza cel putin un hobby';
59 }
60
61
62 if (!is_array($limbi_straine)) {
63 $erori[] = 'Completeaza cel putin o limba straina';
64 }
65
66
67 // daca nu sunt erori, variabila $proceseaza devine 1
68 if (!count($erori)) {
69 $proceseaza = 1;
70 }
71
72
73 // daca variabila proceseaza este 1, procesam (in cazul nostru
74 afisam) datele si mesajul de multumire
75 if ($proceseaza) {
76
77 if (is_array($hobby)) {
78 $hobby = join(',', $hobby);
79 }
80
81 if (is_array($limbi_straine)) {
82 $limbi_straine = join(',', $limbi_straine);
83 }
84
85
86 echo '<br /><hr><br />';
87 echo 'Va multumim pentru completarea formularului !';
88 echo '<br />';
89
90 echo 'Datele Dvs sunt: <br /><br />';
91 echo 'Nume: ' . $prenume . ' ' . $nume;
92 echo '<br />';
93 echo 'Utilizator: ' . $utilizator;
94 echo '<br />';
95 echo 'Parola: ' . $parola;
96 echo '<br />';
97 echo 'Email: ' . $email;
98 echo '<br />';
99 echo 'Hobby: ' . $hobby;
100 echo '<br />';
101 echo 'Limbi straine: ' . $limbi_straine;
102 echo '<br />';
103
104 echo '<br /><hr><br />';
105 }
106
107
108 // daca sunt erori, le afisam
109 if (isset($erori)) {
110
111 foreach ($erori as $eroare) {
112 echo $eroare;
113 echo '<br />';
114 } /// end foreach
115
116 } //// end if(isset($erori))
117
118 } /// end if (isset($_POST["buton"])) {
119
120 ?>
121
122 <br /><br />
123 <form method="post" action="">
124 Prenume <br /> <input type="text" name="prenume" value="" /> <br />
125 Nume <br /> <input type="text" name="nume" value="" /> <br />
126 Utilizator <br /> <input type="text" name="utilizator" value="" />
127 <br />
128 Parola <br /> <input type="password" name="parola" value="" />
129 <br />
130 Email <br /> <input type="text" name="email" value="" /> <br />
131
132 Hobby <br />
133 Inot<input type="checkbox" name="hobby[]" value="inot" />
134 Ski<input type="checkbox" name="hobby[]" value="ski" />
135 Alergat<input type="checkbox" name="hobby[]" value="alergat" />
136 Cantat<input type="checkbox" name="hobby[]" value="cantat" />
137 <br /><br />
138
139 Limbi straine vorbite <br />
140
141 <select name="limbi_straine[]" multiple="multiple">
142 <option value="ro">Romana</option>
143 <option value="en">Engleza</option>
144 <option value="es">Spaniola</option>
145 <option value="de">Germana</option>
146 </select>
147
148
149 <br /><br />
150 Mesaj <br />
151 <textarea name="mesaj" cols="20" rows="20"></textarea>
152
153
154 <br /><br />
155 <input type="submit" name="buton" value="Trimite" />

<br />

</form>

6.6.3. Pastrarea datelor in formular


In subcapitolul anterior, am realizat validarea datelor. Ce se intampla insa daca utilizatorul completeaza intregul formular corect, dar greseste doar intr-un
loc, sau in cateva locuri ? Pagina se reincarca, avand un mesaj de eroare pentru campul sau campurile gresite, si formularul gol. Asta inseamna ca el
trebuie sa completeze toate datele formularului de la capat. Acest lucru intr-o aplicatie reala nu este permis sa se intample. Prin urmare, odata cu
validarea datelor, trebuie sa pastram aceste date in formular.

Pastrarea datelor in formular se face diferit in functie de fiecare control din formular:

 pentru elementele de tip input text se pastreaza valoarea cu ajutorul atributului value
Ex:

<input type="text" name="prenume" value="Ion" />


 pentru input checkbox si radio se pastreaza cu ajutorul atributului checked="checked"
Ex:

 <input type="radio" name="sex" value="Male">


<input type="radio" name="sex" checked="checked" value="Female">
 pentru tagul select se pastreaza optiunile selectate cu atributul selected="selected" in cadrul tagurilor option
Ex:

 <select name="lang" size="3">


 <option value="en">Engleza</option>
 <option value="ro" selected="selected">Romana</option>
 <option value="es">Spaniola</option>
 <option value="de">Germana</option>
 </select>
 pentru tagul textarea se scrie textul ce trebuie pastrat intre tagul de inceput si cel de sfarsit

Ex:
<textarea name="mesaj">
Text aici
</textarea>

Un script .php ce proceseaza un formular, asa cum il avem noi organizat, are una din cele 3 ipostaze:

1. Scriptul este incarcat prima data in browser. Deci nu are date trimise prin get sau post. In aceasta ipostaza scriptul ofera utilizatorului doar
formularul de completat.

2. Utilizatorul a apasat butonul de submit, deci browserul acceseaza aceeasi pagina dar de data asta cu date trimise prin post (de exemplu).
In script verificam daca s-a apasat butonul de submit, si incepem sa extragem informatia din post in variabile, si sa validam datele. In cazul
in care sunt erori, populam un array cu aceste erori, si reafisam formularul completat cu datele primite din POST (adica cu datele pe care
utilizatorul le-a completat la pasul 1).

3. Nu exista erori, afisam mesajul de multumire, procesam informatiile.

Nota
La pasul 2 voi folosi un array ce contine datele cu care populam formularul. Acest array va fi in general $_GET sau $_POST dar prefer
sa-l numesc $formData care in general va fi acelasi lucru cu $_GET sau $_POST

inregistrare.php
1 <?php
2 $formData = array();
3 $formData["prenume"] = '';
4 $formData["nume"] = '';
5 $formData["utilizator"] = '';
6 $formData["parola"] = '';
7 $formData["email"] = '';
8 $formData["mesaj"] = '';
9
10 $formData["hobby"] = array();
11 $formData["limbi_straine"] = array();
12
13 $proceseaza = 0;
14
15
16 if (isset($_POST["buton"])) {
17
18 $erori = array();
19
20 $formData = $_POST;
21
22 // print_r($_POST);
23
24
25 // preluarea variabilelor din POST
26 $prenume = $_POST["prenume"];
27 $nume = $_POST["nume"];
28 $utilizator = $_POST["utilizator"];
29 $parola = $_POST["parola"];
30 $email = $_POST["email"];
31
32 if (isset($_POST["hobby"])) {
33 $hobby = $_POST["hobby"];
34 } else {
35 $hobby = '';
36 }
37
38
39 if (isset($_POST["limbi_straine"])) {
40 $limbi_straine = $_POST["limbi_straine"];
41 } else {
42 $limbi_straine = '';
43 }
44
45
46
47 // verificarea erorilor
48
49 if (!$prenume) {
50 $erori[] = 'Completeaza prenume';
51 } else if (!preg_match('/^[a-zA-Z\-\s\']{2,20}$/', $prenume)) {
52 $erori[] = 'Prenume invalid';
53 }
54
55
56 if (!$nume) {
57 $erori[] = 'Completeaza nume';
58 } else if (!preg_match('/^[a-zA-Z\-\s\']{2,20}$/', $nume)) {
59 $erori[] = 'Nume invalid';
60 }
61
62
63 if (!$utilizator) {
64 $erori[] = 'Completeaza utilizator';
65 } else if (!preg_match('/^[a-zA-Z\-0-9]{4,15}$/', $utilizator)) {
66 $erori[] = 'Utilizator invalid';
67 }
68
69 if (!$parola) {
70 $erori[] = 'Completeaza parola';
71 } else if (preg_match('/[\'\"]/', $parola)) {
72 $erori[] = 'Parola contine caractere invalide';
73 }
74
75
76 if (!$email) {
77 $erori[] = 'Completeaza emailul';
78 } else if (!preg_match('/(?i)[a-z0-9\.\-_\+]+@[a-z0-9\-]+\.([a-z0-
79 9\-]+\.)*+[a-z]{2}/', $email)) {
80 $erori[] = 'Email incorect';
81 }
82
83
84
85 if (!is_array($hobby)) {
86 $erori[] = 'Completeaza cel putin un hobby';
87 }
88
89
90 if (!is_array($limbi_straine)) {
91 $erori[] = 'Completeaza cel putin o limba straina';
92 }
93
94
95 // daca nu sunt erori, variabila $proceseaza devine 1
96 if (!isset($erori) or !count($erori)) {
97 $proceseaza = 1;
98 }
99
100
101 // daca variabila proceseaza este 1, procesam (in cazul nostru
102 afisam) datele si mesajul de multumire
103 if ($proceseaza) {
104
105 if (is_array($hobby)) {
106 $hobby = join(',', $hobby);
107 }
108
109 if (is_array($limbi_straine)) {
110 $limbi_straine = join(',', $limbi_straine);
111 }
112
113
114 echo '<br /><hr><br />';
115 echo 'Va multumim pentru completarea formularului !';
116 echo '<br />';
117
118 echo 'Datele Dvs sunt: <br /><br />';
119 echo 'Nume: ' . $prenume . ' ' . $nume;
120 echo '<br />';
121 echo 'Utilizator: ' . $utilizator;
122 echo '<br />';
123 echo 'Parola: ' . $parola;
124 echo '<br />';
125 echo 'Email: ' . $email;
126 echo '<br />';
127 echo 'Hobby: ' . $hobby;
128 echo '<br />';
129 echo 'Limbi straine: ' . $limbi_straine;
130 echo '<br />';
131
132 echo '<br /><hr><br />';
133 }
134
135
136 // daca sunt erori, le afisam
137 if (isset($erori)) {
138
139 foreach ($erori as $eroare) {
140 echo $eroare;
141 echo '<br />';
142 } /// end foreach
143
144 } //// end if(isset($erori))
145
146 } /// end if (isset($_POST["buton"])) {
147
148 ?>
149
150 <br /><br />
151 <form method="post" action="">
152 Prenume <br /> <input type="text" name="prenume" value="<?php echo
153 $formData["prenume"] ?>" /> <br />
154 Nume <br /> <input type="text" name="nume" value="<?php echo
155 $formData["nume"] ?>" /> <br />
156 Utilizator <br /> <input type="text" name="utilizator" value="<?php
157 echo $formData["utilizator"] ?>" /> <br />
158 Parola <br /> <input type="password" name="parola" value="<?php echo
159 $formData["parola"] ?>" /> <br />
160 Email <br /> <input type="text" name="email" value="<?php echo
161 $formData["email"] ?>" /> <br />
162
163 Hobby <br />
164 Inot <input type="checkbox" name="hobby[]" value="inot" <?php if
165 (isset($formData["hobby"]) && in_array('inot', $formData["hobby"]))
166 echo 'checked="checked"' ?> /> <br />
167 Ski <input type="checkbox" name="hobby[]" value="ski" <?php if
168 (isset($formData["hobby"]) && in_array('ski', $formData["hobby"]))
169 echo 'checked="checked"' ?> /> <br />
170 Alergat <input type="checkbox" name="hobby[]" value="alergat" <?php
171 if (isset($formData["hobby"]) && in_array('alergat',
172 $formData["hobby"])) echo 'checked="checked"' ?> /> <br />
173 Cantat <input type="checkbox" name="hobby[]" value="cantat" <?php
174 if (isset($formData["hobby"]) && in_array('cantat',
175 $formData["hobby"])) echo 'checked="checked"' ?> /> <br />
176 <br />
177
178 Limbi straine vorbite <br />
179
180 <select name="limbi_straine[]" multiple="multiple">
181 <option value="ro" <?php if (isset($formData["limbi_straine"])
182 && in_array('ro', $formData["limbi_straine"])) echo
183 'selected="selected"' ?> >Romana</option>
<option value="en" <?php if (isset($formData["limbi_straine"])
&& in_array('en', $formData["limbi_straine"])) echo
'selected="selected"' ?> >Engleza</option>
<option value="es" <?php if
(isset($formData["limbi_straine"]) && in_array('es',
$formData["limbi_straine"])) echo 'selected="selected"' ?>
>Spaniola</option>
<option value="de" <?php if
(isset($formData["limbi_straine"]) && in_array('de',
$formData["limbi_straine"])) echo 'selected="selected"' ?>
>Germana</option>
</select>

<br /><br />


Mesaj <br />
<textarea name="mesaj" cols="20" rows="20"><?php echo
$formData["mesaj"] ?></textarea>

<br /><br />


<input type="submit" name="buton" value="Trimite" />

<br />

</form>

6.6.4. Pastrarea datelor in formular 2


In subcapitolul anterior am invatat despre pastrarea datelor in formular in momentul cand formularul este trimis dar se reafiseaza datorita unor erori la
input. Insa, asa cum ati vazut in scriptul inregistrare.php este un efort destul de mare (este mult de tastat) pentru a obtine acest lucru. Din acest motiv, e
mult mai simplu, si se practica folosirea unor functii pentru generarea elementelor de formular.

Varianta imbunatatita a formularului o gasiti aici: inregistrare2

Functiile pentru generarea elementelor de formular le gasiti in common/f-forms.php. Sunt functii generale, pot fi folosite la orice proiect .php aveti nevoie
de formulare. In definitiile functiilor apar mai multi sau mai putini parametri, dar in general sunt urmatorii:

 $name - va fi numele elementului respectiv.

 $value - apare la generarea unui element de tip checkbox sau buton, si este informatia atributului value a campului respectiv

 $elementData - apare la majoritatea elementelor si este o valoare (sau un array) cu ce a completat sau a ales utilizatorul in/din campul
respectiv. Prin urmare este informatia ce vine de la utilizator, se transmite prin POST sau GET la reincarcarea formularului, si este folosita
pentru a repopula elementul respectiv cu informatie. Pentru ca $formData este in general POST sau GET, valoarea acestui parametru provine
din $formData["nume_element"]. Pe baza acestui element se genereaza elementele cu checked="checked" (bifate) sau optiunile cu
selected="selected".

 params - un string cu atribute optionale de tip html ce pot fi inserate in interiorul elementului respectiv (in interiorul tagului de inceput).

6.7. Tema
Tema6-1
Folositi un array similar cu:
$persoane = array(
8 => array (
'username' => 'ion',
'email' => 'ion@gmail.com',
'varsta' => 29
),

10 => array (
'username' => 'maria',
'email' => 'maria@gmail.com',
'varsta' => 53
),
....

);
completati array-ul $persoane cu inca 2-3 elemente (array-uri cu informatii despre persoane).

Realizati:
1. O functie care ia ca parametru id-ul, si array-ul $persoane si returneaza tabelul cu datele persoanei respective.

Ex: afiseazaPersoana($persoane, 8) va returna


username ion
email ion@gmail.com
varsta 29

2. O functie care ia ca parametru doar array-ul $persoane si le afiseaza pe toate. Ex: afiseazaPersoane($persoane) va returna:
username email varsta Detalii
ion ion@gmail.com 29 Detalii
maria maria@gmail.com 53 Detalii

....

3. Daca se incarca fisierul pagina.php prima data (fara parametru in get), se afiseaza toate persoanele. In momentul cand dati click pe Detalii in dreptul
unei persoane, se incarca fisierul .php cu parametrul id respectiv transmis prin url.

4. Daca se incarca pagina.php?id=8 , afisati doar detaliile persoanei cu id-ul 8. Aveti aici un link "Back" catre pagina fara nici un parametru in get, care
afiseaza toate persoanele.

Tema6-2

Construiti un formular html ce are cate un camp din fiecare tip: input text, input password, checkbox, radio, select, textarea.
Tineti cont de urmatoarele:

- nu folositi campurile exemplelor din curs


- validati datele din formular (acolo unde este cazul)
- completarea fiecarui camp este obligatorie
- reafisati formularul, cu datele completate, si cu erorile respective (daca sunt erori sau campuri necompletate)
- daca s-a apasat formularul si nu sunt erori, afisati intr-un tabel datele completate

CAP.7. Baze de date. MySQL.


7.1 Introducere
7.2 Despre SQL. Despre MySQL
7.3 Clienti MySQL
7.4 Crearea unei baze de date. Organizarea informatiei in tabele
7.5 Design-ul unei baze de date
7.6 Elemente de baza ale SQL
7.7 Tipuri de date
7.8 Atribute ale unei coloane
7.9 Indecsi
7.10 DDL (Data Definition Language)
7.11 DML (Data Manipulation Language)
7.12 Tema

7.1. Introducere
Ce sunt bazele de date ?
O baza de date este o colectie de inregistrari sau de informatii introduse si stocate intr-un calculator intr-un mod sistematic (structurat). O baza de date
poate fi interogata (intrebata) de catre noi sau de catre un program prin intermediul unui limbaj relativ simplu (in general SQL) si raspunde cu informatie
valoroasa, in functie de care se iau decizii. Pentru valorificarea informatiei ce poate fi extrasa dintr-o baza de date, este esential modul in care organizam
si stocam datele intr-o baza de date.
Aplicatii ale bazelor de date pe Web
Orice site care are un modul de login sau inregistrare utilizatori, orice magazin virtual, catalog de produse, forum, sistem de newsletter, articole, stiri, etc.
are in mod sigur o baza de date in care este tinuta informatia in mod structurat. Cea mai mare parte a site-urilor de pe Internet care trec de nivelul de site
de prezentare, si vand produse, servicii sau continut informational (cursuri, articole) catre utilizatorii site-ului folosesc baze de date. De exemplu, capitolele
si subcapitolele acestui curs precum si datele utilizatorilor, datele despre examene, etc. sunt tinute intr-o baza de date.
Aplicatii ale bazelor de date in alte domenii
O mare parte din aplicatiile software existente foloseste baze de date pentru stocarea si extragerea informatiilor. Datele tale si istoria platilor la telefonia
mobila, electricitate, telefonie fixa, internet, etc. sunt tinute in mod structurat in bazele de date ale furnizorilor la care esti abonat. In Statele Unite,
informatiile medicale, istoria creditelor, istoria angajarilor, precum si alte informatii apartinand unei persoane, se pot obtine de institutiile guvernamentale,
pe baza numarului de asigurare sociala al persoanei respective (SSN - social security number). Recensamantul, rezultatele la vot, plus alte informatii
sociale, sunt tinute in baze de date. Aceste baze de date se interogeaza ulterior pentru obtinerea de diverse statistici.
DBMS - Database Management System
Software-ul (aplicatia) care este folosit pentru a realiza, a administra si a interoga o baza de date este numit DBMS - Database Management System.
Modelul unei baze de date este o specificatie tehnica acceptata de mai multi furnizori de programe de baze de date (DBMS) ce se refera la modul in care
sunt stocate informatiile in baza de date si modul in care sunt folosite. Exemple de modele sunt: modelul relational, modelul orientat-obiect, modelul
ierarhic, etc. Cel mai raspandit in mod curent este modelul relational. Bazele de date relationale au informatiile organizate in tabele, iar intre informatiile
din aceste tabele pot fi stabilite legaturi. Primele sisteme de baze de date relationale au aparut in 1970. DBMS relationale populare sunt: Oracle, Microsoft
SQL Server, MySQL. Toate aceste sisteme de baze de date relationale au in comun limbajul standard de interogare a bazei de date numitSQL.

7.2. Despre SQL. Despre MySQL


Despre limbajul SQL
SQL - Structured Query Language este un limbaj de baze de date realizat pentru a extrage informatii si a administra bazele de date relationale.
Limbajul SQL a devenit standard ANSI (American National Standards Institute) in 1986.
Fiecare RDBMS (Relational Database Management System) comercial are propria versiune de limbaj SQL, bazata pe standardul SQL.
Astfel, limbajul SQL folosit in MySQL (un RDBMS) fata de limbajul SQL folosit in PostgreSQL sau Oracle (alte RDBMS), desi asemanatoare, au elemente
distincte, specifice acelui RDBMS.
In continuare, in acest curs, vom invata limbajul SQL din MySQL.
Despre MySQL
MySQL este o aplicatie comerciala pentru managementul bazelor de date relationale (pe scurt un RDBMS) foarte populara, mai ales in dezvoltarea
aplicatiilor web. MySQL a fost dezvoltata de firma suedeza MySQL AB ce a fost intre timp cumparata de Sun Microsystems. In anul 2010 Oracle
achizitioneaza Sun deci MySql este un produs Oracle.
Echipele ce au dezvoltat limbajul PHP si baza de date MySQL au colaborat cu succes de-a lungul timpului pentru a oferi o interoperabilitate foarte ridicata
intre cele doua programe, astfel incat prima preferinta a dezvoltatorilor in PHP pentru baze de date este MySQL. Cu toate astea, PHP are extensii (set de
functii) pentru a lucra si cu alte baze de date: PostgreSQL, Oracle, SQL Server, etc.
7.3. Clienti MySQL
Sistemele de baze de date sunt concepute intr-o arhitectura client-server. Astfel, serverul de baze de date este programul principal ce stocheaza si
manipuleaza datele, si raspunde clientilor (programe de tip client) ce se conecteaza la acesta pentru a cere informatii sau pentru a trimite cereri de alta
natura (adaugari, modificari, etc).
Serverul MySQL si clientul MySQL folosit pentru interogare pot fi instalate pe acelasi calculator, dar nu neaparat. Daca lucram local (pe calculatorul
propriu) si folosim un program ca WAMP server, atat serverul MySQL cat si clientul MySQL pe care-l alegem, vor fi instalate pe calculatorul nostru. In
momentul cand mutam baza de date pe un server de web hosting, serverul MySQL va fi pe acel server de web hosting iar clientul MySQL poate fi tot pe
acel server (de exemplu phpMyAdmin) sau ne putem conecta cu un client MySQL instalat pe calculatorul nostru (phpMyAdmin, MySQL Query Browser).

Pentru a administra o baza de date MySQL, un developer are in general urmatoarele optiuni:

1. phpMyAdmin este unul dintre cei mai folositi clienti MySQL. Este web-based (disponibil in interfata web), usor de folosit, si instalat implicit pe marea
majoritate a serverelor de gazduire. Astfel, un programator web ce a instalat aplicatia WAMP Server (vezi 1.2 Instalare si configurare) pe calculatorul
local, are automat instalat si phpMyAdmin.

2. Executabilul mysql este un client fara interfata grafica, folosit din linia de comanda. Aceasta varianta de administrare si folosire a MySQL este folosita
mai putin de web developeri insa sunt unele cazuri cand se dovedeste superioara celorlalte variante. Pentru a executa mysql din linia de comanda
parcurgeti urmatorii pasi:

 Mergeti in Start -> Run, tastati cmd apoi Enter


 Aici, daca tastati mysql si nu este recunoscuta comanda trebuie sa continuati cu pasii urmatori, sa adaugati folderul in care se afla binarul
mysql in variabila Path

 Mergeti in Control Panel - System - Advanced - Environment Variables - System Variables, click Path - Edit si adaugati calea catre folderul
respectiv, la "Variable value", folosind punct si virgula inaintea ei astfel: ;c:\wamp\bin\mysql\mysql5.0.51b\bin

 Redeschideti un terminal (linie de comanda) si ar trebui cand tastati mysql sa intrati in linia de comanda mysql ca-n printscreen-ul urmator

 Pentru a avea drepturi depline, va puteti conecta cu root, folosind sintaxa: mysql -u root -p

3. MySQL GUI Tools este o suita compusa din 3 aplicatii cu interfata grafica (ce se instaleaza pe calculatorul local) pentru administrarea MySQL. Cele 3
aplicatii sunt: MySQL Administrator , MySQL Query Browser, MySQL Migration Toolkit.

7.4. Crearea unei baze de date. Organizarea informatiei in tabele


Nota
In exemplele practice din acest curs, pentru administrarea unei baze de date MySQL sau pentru executarea de instructiuni SQL voi
folosiphpMyAdmin.

Urmarind un exemplu simplu, vom vedea cum este organizata informatia in MySQL (sau in alte baze de date relationale).

1. Baza de date - serverul MySQL contine mai multe baze de date. In functie de privilegiile cu care clientul MySQL se conecteaza la server, pot
avea acces la toate bazele de date sau doar la o parte din ele. De cele mai multe ori o aplicatie (web) foloseste o singura baza de date la care
se conecteaza pentru a actualiza sau extrage informatii. Insa, aplicatiile mai complexe pot folosi mai multe baze de date la care se conecteaza
simultan sau pe rand.

Folosind phpMyAdmin, o baza de date (goala, fara tabele) se creeaza simplu, scriind numele bazei de date in campul "Create new database"
si apasand pe butonul "Create". Baza de date pe care o realizam in acest exemplu se numeste "mysite".

2. Tabelul - o baza de date este compusa din mai multe tabele. Intr-o aplicatie pot avea cate un tabel pentru: utilizatori, produse, categorii de
produse, incasari, etc. Si, de exemplu, daca am 100 de utilizatori, voi avea 100 de inregistrari (randuri) in tabelul utilizatori. Nu voi intra in
detalii deocamdata referitor la sintaxa sql de creare a unui tabel sau la posibilitatile interfetei phpMyAdmin.
Pentru realizarea celor doua tabele ale acestei baze de date, alegeti baza de date "mysite", apasati pe linkul (butonul) SQL din meniul de sus,
si executati (prin copy-paste sau browse) codul sql din fisierul mysite.sql. Aceste instructiuni sql vor realiza doua tabele in baza de
date mysite, numite utilizatori simesaje si introduc cateva randuri in fiecare din aceste
tabele.
3. Randurile si coloanele.
Un tabel al unei baze de date relationale, are randuri si coloane. Avand in phpMyAdmin baza de date mysite selectata, pentru a vedea

inregistrarile (informatiile) din tabelul utilizatori, faceti click pe iconita din stanga tabelului in lista de tabele ( ) sau pe linkul
(butonul) Browse din meniul de sus. Apasand linkul Structure din meniu, puteti vedea coloanele sau structura tabelului respectiv, precum si
tipul de date si atributele fiecarei coloane in parte.

Inregistrarile (randurile) din tabelul utilizatori - vazute in phpMyAdmin

Important
Inregistrarile (sau randurile) dintr-un tabel al unei baze de date relationale reprezinta o colectie de date pentru o anumita categorie de
entitati. De exemplu, un tabel numit persoane poate tine mai multe inregistrari, cate una pentru o persoana. Un tabel numit produse va avea
o inregistrare pentru fiecare produs. Fiecare din aceste inregistrari are acelasi set de atribute (coloanele tabelului), aceste atribute
desemnand structura tabelului. Astfel, inregistrarile/randurile unui tabel inseamna informatii, iar atributele/coloanele unui tabel (sau unei
inregistrari) inseamna meta-informatie sau structura informatiei.
In tabelul utilizatori avem atributul/coloana utilizator de tip-ul varchar(20). Asta inseamna ca pentru fiecare inregistrare trebuie sa am o
informatie pentru acest atribut, informatie ce va desemna numele de utilizator, de tip sir de caractere, ce va avea maxim 20 de caractere.
Intersectia dintre o coloana si un rand il numim campul unei inregistrari. Exemplu, campul username al primei inregistrari este: "horatiu".
Structura (descrierea atributelor) tabelului utilizatori in phpMyAdmin

7.5. Design-ul unei baze de date


Nota
In aceasta documentatie, voi folosi urmatorii termeni:

 query - instructiune sql

 insert - instructiune sql sau operatiune ce desemneaza adaugarea unei inregistrari intr-un tabel

 update - instructiune sql sau operatiune ce desemneaza actualizarea unei inregistrari intr-un tabel

 delete - instructiune sql sau operatiune ce desemneaza stergerea unei inregistrari intr-un tabel

Design-ul unei baze de date relationale consta in organizarea informatiilor in tabele astfel incat informatiile sa poata fi extrase, sa nu existe redundanta
informatiilor (sau sa fie foarte mica), sa nu existe asa-numitele anomalii de introducere, actualizare sau stergere de inregistrari. Acest proces, de
optimizare sistematica a design-ului a unei baze de date, a fost studiat si documentat de-a lungul timpului, si denumit normalizare (sau database
normalization).
Acest subiect (design-ul bazelor de date relationale) este extrem de larg, si este tratat in carti intregi.
In termeni populari, normalizarea unei baze de date inseamna "spargerea" informatiilor in tabele astfel incat datele sa fie usor de extras prin queriuri si sa
se evite redundanta si anomaliile operatiilor: insert , update si delete.
Voi ilustra acest concept intr-un exemplu simplu, folosind baza de date mysite.

Organizarea informatiilor intr-un singur tabel

Teoretic, ar fi posibil sa organizam informatiile unor baze de date relationale intr-un singur tabel. Daca am face acest lucru pentru baza de date mysite,
acel tabel ar arata astfel:

Informatiile pentru utilizatori si mesaje intr-un singur tabel

username email anNastere sex dataAdaugarii subiect mesaj dataMesaj


2009-04-25
horatiu horatiu23@gmail.com 1981 m 2009-04-22 salut Bine-ati venit pe forum !
15:00:18

Salut,
2009-04-26
raluca raluca.v@gmail.com 1978 f 2009-04-23 salut si aici
Eu sunt Raluca, ma bucur sa va cunosc. 15:01:21
Am multe intrebari pentru voi.

care-i 2009-04-27
ion ion@yahoo.com 1969 m 2008-09-01 despre ce se vorbeste aici ?
treaba ? 00:02:20

vorbim despre baze de date. mai precis 2009-04-27


horatiu horatiu23@gmail.com 1981 m 2009-04-22 despre...
despre mysql. 09:02:20

2009-04-27
horatiu horatiu23@gmail.com 1981 m 2009-04-22 inca ceva de fapt despre php si mysql...
09:05:20

Informatia din tabelul de mai sus este nenormalizata, si in folosirea ei in practica intr-o baza de date relationala apar urmatoarele probleme:

 Probleme de logica si extragere a informatiei. Este ilogic sa avem informatiile a doua entitati distincte (utilizator si mesaj) intr-un singur
mesaj. Nu putem de exemplu numara printr-un query simplu utilizatorii inscrisi, pentru ca numarul de randuri din acest tabel indica de fapt
numarul de mesaje. Nu pot realiza printr-un query simplu media varstei utilizatorilor acestui forum. etc.

 Probleme de redundanta (duplicare a informatiei). Duplicarea informatiei genereaza nu doar anomaliile de mai jos si alte probleme de
logica, ci si probleme de spatiu de stocare pentru aceasta baza de date. Ganditi-va la un site de succes ce adaposteste un forum cu mii de
utilizatori si sute de mii de mesaje. Pentru fiecare mesaj trimis, se stocheaza in baza de date si toate datele utilizatorului respectiv. Spatiul
necesar stocarii acestei baze de date ar fi mult mai mare decat in mod normal, si orice operatii asupra bazei de date ar fi mult mai incete.

 Anomalie de update - de fiecare data cand utilizatorul horatiu scrie un mesaj, ii scriem toate datele din nou, e posibil sa gresim datele lui la
un moment dat. Astfel, baza de date devine inconsistenta, adica unele randuri arata anumite informatii despre acest utilizator, alte randuri
arata informatii gresite. In plus, daca dorim sa actualizam o informatie legata de un utilizator, sa zicem ca horatiu isi schimba emailul, trebuie
sa cautam in acest tabel toate aparitiile lui horatiu si sa facem actualizarea in mai multe locuri.

 Anomalie de insert - avem poate utilizatori ce nu vor sa scrie nici un mesaj, si atunci nu putem tine datele despre ei pentru ca nu au scris
nici un mesaj iar acest tabel asa cum e compus cere si datele unui mesaj. Am putea sa adaugam un rand cu datele utilizatorului si cu date
goale pentru mesaj dar atunci am avea alte probleme (de aplicatie) cum ar fi de exemplu prezenta pe forum a unui mesaj gol (fara subiect,
fara text, etc).

 Anomalie de delete - daca stergem toate mesajele lui horatiu, pierdem automat si informatia acestui utilizator

Normalizarea bazei de date - "spargerea" informatiei in mai multe tabele


Avand problemele de mai sus, optim este sa organizez informatia in doua tabele: utilizatori si mesaje. Fiecarui tabel i-am adaugat o coloana de tip intreg,
ce identifica in mod unic randul respectiv prin atribuirea unui numar. De atribuirea si pastrarea unicitatii acestui numar se ocupa serverul MySQL prin
setarea atributului AUTO_INCREMENT pentru aceasta coloana. Pentru tabelul mesaje acea coloana este mesajId, iar pentru utilizatori este utilizatorId.
Intr-o baza de date relationala, este foarte indicat (chiar obligatoriu in practica) sa existe o astfel de coloana care sa nu aiba valori nule si sa nu aiba
valori ce se repeta deci sa determine in mod unic o inregistrare. Aceasta coloana se numeste cheie primara (sau primary key sau PK). Ea nu trebuie
neaparat sa fie de tip intreg, desi in general asa este optim si se obisnuieste. Observam deci ca fiecare utilizator are un id (un numar unic). In tabelul
mesaje, pentru a sti ce utilizator a postat un anume mesaj, trebuie sa adaugam o coloana in care sa tinem valoarea id-ului unui utilizator, astfel incat sa
facem legatura logica cu tabelul de utilizatori. Astfel, toate mesajele trimise de horatiu, vor avea in dreptul coloanei utilizatorId valoarea 1, id-ul
corespunzator acestui utilizator. Aceasta coloana se numeste cheie straina (sau foreign key sau FK) si indica prezenta in alt tabel a valorilor unei
coloane ce e cheie primara intr-un tabel initial.

Resurse
http://en.wikipedia.org/wiki/Database_normalization

7.6. Elemente de baza ale SQL


SQL (Structured Query Language) este limbajul ce lucreaza cu bazele de date relationale. Instructiunile SQL pot fi impartite in 3 categorii in functie de
efectul lor:

 operatiuni de manipulare a datelor. Parte a limbajului ce se numeste si DML (Data Manipulation Language). Sunt acele operatiuni
referitoare la introducerea, actualizarea, stergerea si cautarea datelor. Instructiunile SQL de baza din aceasta categorie sunt: INSERT,
UPDATE, DELETE, SELECT

 operatiuni de schimbare a structurii datelor. Operatiuni incadrate in DDL (Data Definition Language). Instructiunile de baza din aceasta
categorie sunt: CREATE, ALTER, RENAME, TRUNCATE, DROP si se refera la schimbarea structurii unui tabel (modificarea coloanelor sau
numarului de coloane, adaugarea de indecsi) sau la schimbarea bazei de date

 administrarea privilegiilor asupra bazei de date. Aceasta categorie din limbaj este denumita DCL (Data Control Language), iar
instructiunile de baza sunt: GRANT (pentru acordarea de drepturi) si REVOKE (pentru stergerea drepturilor)

Nota
Instructiunile SQL pot fi testate atat in consola (se executa comanda mysql si se intra in linia de comanda mysql) cat si in phpMyAdmin, sau in orice
alt client MySQL
Numele bazelor de date, tabelelor si coloanelor
Pot avea litere si cifre (caractere alfanumerice) sau "_". Pot contine si caractere speciale (de exemplu spatiu) insa atunci trebuie incluse intre ` ` (back
quotes). De preferat este insa sa nu folositi spatii (sau alte caractere speciale) in denumirile bazelor de date, tabelelor sau coloanelor, pentru ca va fi mai
simplu ulterior sa le folositi. E bine sa respectati un standard usor de tinut minte, cum ar fi camel-case (incepe cu litera mica, si daca e compusa din mai
multe cuvinte, fiecare incepe cu litera mare). De exemplu: idProdus sau numePersoana.

Exemplu:

In mod normal, intr-o sesiune de lucru (sau cand execut din PHP instructiuni sql) voi
selecta o baza de date pe care lucrez, altfel trebuie sa preced numele de tabele cu numele
bazei de date.
1 USE mysite; #selectez baza de date mysite
2 SELECT email FROM utilizatori; #afisez coloana email din tabelul
utilizatori
Fiecare instructiune sql se termina in punct si virgula (;).
Comentarii
Comentariile in MySQL pot fi:

 comentarii de o linie - introduse de caracterul # sau -- (doua cratime si spatiu)

 comentarii de mai multe linii, intre /* si */

1 SELECT mysite.utilizatori.email FROM mysite.utilizatori; -- numele


tabelului este precedat de baza de date, daca nu am selectat o baza de
date curenta
Reprezentarea valorilor in SQL

Valorile ce au ca tip de date un sir de caractere sau data calendaristica, trebuie incluse intre ghilimele simple ' si ' sau ghilimele duble " sau " .
1 SELECT * FROM utilizatori WHERE anNastere > 1977 AND dataAdaugarii >
'2009-04-01'
Nota
Desi nu este obligatoriu, se foloseste standardul conform caruia cuvintele cheie SQL se scriu uppercase (cu litere mari) pentru a le diferentia mai
usor de numele de tabele, coloane, valori, etc.
Valoarea NULL
Valoarea NULL indica lipsa unei valori in campul respectiv. Ea este diferita fata de 0 (zero) pentru numere, sau sirul gol ('') pentru siruri de caractere. Se
poate specifica pentru anumite coloane faptul ca nu accepta aceasta valoare prin atributul NOT NULL.

7.7. Tipuri de date


Tipurile de date in MySQL se impart in urmatoarele categorii:

 numerice - pentru reprezentarea numerelor intregi sau fractionare

 data/timp - pentru reprezentarea datei calendaristice sau timpului

 sir de caractere - pentru stocarea sirurilor de caractere sau bytes (octeti) cu lungime fixa sau variabila

 liste de optiuni - ENUM si SET

Tipurile de date numerice


Tipurile de date pentru a memora intregi sunt: TINYINT, SMALLINT, MEDIUMINT, INTEGER, BIGINT
Numerele cu zecimale sunt:
1. Exacte: DECIMAL
2. Aproximative (cu o anumita precizie): FLOAT, DOUBLE
INT este sinonim cu INTEGER, si DEC este sinonim cu DECIMAL.
Tipurile de date numerice pot fi cu semn sau fara. Cu semn, inseamna ca accepta valori pozitive si negative. Pentru a stabili daca tipul de date folosit in
coloana curenta nu are semn, folosim atributul UNSIGNED la definirea coloanei. Tipul de date TINYINT de exemplu, poate stoca valori intregi intre -128 si
127. Insa TINYINT avand atributul UNSIGNED (deci fara semn), stocheaza valori intre 0 si 255. Deci, pentru numerele intregi, capatul superior al
intervalului se dubleaza, iar capatul inferior este 0. Pentru a vedea exact limitele tipurilor de date, accesati primul link din sectiunea Resurse de mai
jos.

La definirea tipului de date al unei coloane, se poate specifica un numar (sau doua separate prin virgula) intre paranteze rotunde. Exemplu: INT(10) sau
DECIMAL(4,2).
Aceste numere inseamna:
- pentru numere intregi, numarul din paranteze inseamna numarul minim de caractere returnat de MySQL. De exemplu, INT(10) inseamna ca pentru orice
numar intreg ce are mai putin de 10 cifre, va fi completat cu spatii in partea din stanga. Daca coloana respectiva are setat atributul ZEROFILL, va fi
completat cu 0 (zero).
- similar la numerele cu virgula, DECIMAL(4,2) specifica faptul ca se vor returna maxim 4 caractere din care 2 caractere pentru partea zecimala.

Nota
Specificarea numarului din paranteza nu afecteaza in nici un fel domeniul de valori pentru acel tip de date. De exemplu, SMALLINT(3) are acelasi
interval de valori posibile, intre -32768 si 32767

Tipuri de date pentru data calendaristica / timp

 DATE - este tipul de date folosit pentru memorarea datei calendaristice. In baza de date formatul datei este YYYY-MM-DD (Y - year (an) , M -
month (luna), d - day (zi)). Ex: 2015-02-26 Valoarea goala (empty) pentru acest tip de date este '0000-00-00'.

 DATETIME - similara cu DATE, insa stocheaza data si ora exacta, la secunda, deci inclusiv timpul. Ex: 2015-02-26 14:50:56. Valoarea goala
pentru acest tip de date este 0000-00-00 00:00:00
 TIMESTAMP - formatul este similar cu DATETIME, insa are un interval de valori mai mic (poate tine date intre 1970-01-01 00:00:01 si 2038-
01-09 03:14:07). Diferenta mai importanta este ca are capacitatea de actualizare automata la operatii de INSERT si UPDATE. Daca vrem ca
valoarea sa se actualizeze cu data curenta doar la INSERT, specificam atributul DEFAULT CURRENT_TIMESTAMP. Daca dorim sa se actualizeze
si la UPDATE putem specifica atributul ON_UPDATE CURRENT_TIMESTAMP. Daca nu specificam nici unul din aceste atribute, se considera
ambele, deci se stocheaza data curenta atat la insert cat si la update.

 TIME - formatul este HH:MM:SS . Ex: 14:50:56. Pot fi specificate si intervale mai mari de 24h. Ex: 98:59:59 (98 de ore, 59 de minute si 59
de secunde).

 YEAR - formatul este YYYY daca este declarat YEAR(4) sau YY daca este declarat YEAR(2).

Tipuri de date pentru siruri de caractere sau octeti (bytes)


Sirurile de caractere, sau sirurile de octeti sunt discutate impreuna pentru ca sunt asemanatoare ca tipuri de date avand insa urmatoarea diferenta: pentru
coloanele ce contin siruri de caractere se specifica un set de caractere (charset) si un mod de comparare si ordonare (collation). Sirurile de octeti sunt
comparate pe baza valorii numerice a octetilor respectivi.
Cele doua grupe de tipuri de date sunt urmatoarele:

 CHAR, VARCHAR, TINYTEXT, TEXT, MEDIUMTEXT si LONGTEXT - pentru siruri de caractere

 BINARY, VARBINARY, TINYBLOB, BLOB, MEDIUMBLOB si LONGBLOB - pentru siruri de octeti (bytes)

In continuare voi prezenta diferentele intre CHAR si VARCHAR.

 CHAR si VARCHAR sunt tipuri de date folosite pentru memorarea sirurilor de caractere. CHAR(30) de exemplu, inseamna ca in acel camp se
pot memora maxim siruri de 30 de caractere. Similar si cu VARCHAR(30).
Exista insa urmatoarele diferente intre CHAR SI VARCHAR:
- lungimea (atat in bytes cat si in caractere) continutului dintr-o coloana avand tipul CHAR este fixa. De exemplu, daca tin sirul 'ab' intr-o
coloana cu CHAR(30), vor fi completate restul de 28 de caractere cu spatii. Insa, cand extragem datele din baza de date acele spatii sunt in
general sterse, deci vom obtine tot 'ab'. Scopul este sa se optimizeze cautarea, coloana de tip CHAR avand acelasi nr de octeti pentru fiecare
inregistrare, va optimiza timpul de cautare pentru o valoare in cadrul acestor campuri
- lungimea (in bytes) a spatiului ocupat de un continut cu tipul VARCHAR, depinde de valoarea memorata. Se mai aloca 1 sau 2 bytes pentru
a memora lungimea campului respectiv
- intr-un camp de tip CHAR se pot memora siruri de maxim 255 de caractere
- lungimea unui camp VARCHAR este limitata de marimea posibila a unui rand, adica 65535 bytes

Nota
Atat pentru CHAR cat si pentru VARCHAR marimea in octeti (bytes) a unui caracter depinde de CHARSET-ul folosit. Astfel, pentru latin1
de exemplu, 1 caracter ocupa 1 byte. Pentru utf-8, 1 caracter poate ocupa de la 1 la 4 bytes

ENUM si SET
Aceste doua tipuri de date contin tot siruri de caractere, dar in forma unor optiuni.

 ENUM - tip de date ce permite memorarea unei valori dintr-o lista predefinita. Pot fi definite maxim 65535 valori distincte. Daca aceasta
coloana permite valoarea NULL, atunci valoarea NULL este si cea implicita. Altfel, se poate specifica o valoare implicita ca fiind una dintre
valorile listei. In caz ca nu se specifica o valoare implicita, si nu se completeaza o valoare la insert, in mod implicit se va alege prima valoare
din lista.

 SET - asemanator cu ENUM doar ca se poate memora orice combinatie dintre elementele unei liste predefinite

Resurse
http://dev.mysql.com/doc/refman/5.1/en/numeric-types.html
http://dev.mysql.com/doc/refman/5.1/en/date-and-time-types.html
http://dev.mysql.com/doc/refman/5.1/en/string-types.html

7.8. Atribute ale unei coloane


In momentul realizarii unui tabel, in afara tipului de date putem specifica anumite atribute pentru o coloana. De exemplu, sintaxa pentru crearea

tabelului mesaje din baza de date mysite arata astfel:


1 CREATE TABLE `mesaje` (
2 `mesajId` int(11) UNSIGNED NOT NULL auto_increment,
3 `utilizatorId` int(11) UNSIGNED NOT NULL,
4 `subiect` varchar(255) NOT NULL DEFAULT 'fara subiect',
5 `mesaj` text NOT NULL,
6 `dataMesaj` datetime NOT NULL,
7 PRIMARY KEY (`mesajId`)
8 ) ENGINE=MyISAM;

NULL versus NOT NULL


Este posibil atunci cand adaugam inregistrari intr-un tabel (deci la operatiunea de insert), pe pozitia unei anumite coloane sa nu introducem nici o valoare.
In mod normal se memoreaza in baza de date valoarea speciala NULL care indica lipsa informatiei in campul respectiv. Daca insa nu vreau sa accept valori
nule pentru coloana respectiva, folosesc la definirea coloanei atributul NOT NULL. In acest caz, daca tot nu precizez o valoare pentru campul respectiv la
operatiunea de INSERT, se introduce valoarea implicita, specificata cu atributul DEFAULT. Daca nu am atribut DEFAULT pentru coloana respectiva, se auto-
completeaza o valoare goala (sau valoare "zero" cum mai este numita) pentru campul respectiv de date.

Nota
Valoarea goala (sau valoarea "zero") pentru string-uri este sirul gol (''), pentru DATE este '0000-00-00', pentruDATETIME este '0000-00-00
00:00:00', pentru numere este 0
DEFAULT
In lipsa unei valori la INSERT pentru coloana respectiva, se memoreaza automat valoarea ce urmeaza dupa atributul DEFAULT
UNSIGNED si ZEROFILL
Coloanele cu tipuri de date numerice pot avea atributul UNSIGNED (fara semn) ce arata faptul ca se stocheaza doar valori pozitive (si pentru intregi se
dubleaza valoarea maxima stocata). ZEROFILL completeaza cu 0 un numar astfel incat sa ajunga la x cifre: daca atribuim coloanei de exemplu INT(x).
AUTO_INCREMENT
Atributul AUTO_INCREMENT poate fi adaugat unei coloane de tip numeric. Cand nu se specifica o valoare pentru coloana respectiva la operatia de
INSERT (sau valoarea specificata este 0), atunci coloana se auto-completeaza cu MAX + 1 unde MAX este cea mai mare valoare pentru acea coloana din
toate inregistrarile de pana atunci. Astfel, aceasta coloana va avea ca valori numere intregi, consecutive, insa daca se sterge unul din randuri, celelalte nu-
si vor modifica valorile pentru aceasta coloana, deci numerele nu vor mai fi consecutive. Acest atribut se specifica in mod clasic pentru coloana de tip id, ce
va fi sicheie primara a tabelului respectiv.
CHARACTER SET si COLLATE
Pentru coloane de tip sir de caractere (CHAR, VARCHAR, TEXT, etc) se poate specifica un set de caractere (ex: latin1 sau utf8) cu ajutorul atributului
CHARACTER_SET. Atributul COLLATE specifica ceea ce se numeste "collation", termen ce desemneaza modul in care sunt comparate si ordonate
caracterele dintr-un set de caractere.

Resurse
http://dev.mysql.com/doc/refman/5.1/en/adding-collation.html
http://dev.mysql.com/doc/refman/5.1/en/create-table.html

7.9. Indecsi
Indecsii sunt structuri de date apartinand unui tabel, si sunt folositi de MySQL pentru a mari viteza de cautare, sau de ordonare dupa anumite coloane. De
exemplu, daca folosim frecvent cautari dupa coloana "nume" dintr-un tabel "persoane", e optim sa adaugam un index pentru aceasta coloana. Fara index,
MySQL va cauta valoarea respectiva in fiecare rand din tabelul nostru, rand cu rand, operatie numita "full table scan", foarte costisitoare ca timp. Cu
ajutorul unui index, serverul de baze de date foloseste structura de date aditionala (ca un fel de tabel suplimentar) pentru a memora intr-o ordine precisa
valorile coloanei respective, si pentru a ajunge la randul corespunzator valorii cautate mult mai rapid. Un index poate fi adaugat atat pentru o coloana cat
si pentru 2 sau mai multe coloane simultan ("column indexes" si "multiple column indexes").

Exista urmatoarele tipuri de indecsi in MySQL:

 Index simplu - folosind cuvantul cheie INDEX sau KEY (sinonime)


Acest index nu impune nici o constrangere asupra valorilor acestei coloane, insa optimizeaza (ca orice index) pentru ordonare si cautare.

 Index unic - folosind cuvintele UNIQUE INDEX sau UNIQUE KEY


Folosind acest index impunem ca valorile acestei coloane sa fie unice. De exemplu, daca avem in tabelul nostru o coloana numita "email", un
index unic pe aceasta coloana nu va permite existenta unor inregistrari cu aceeasi valoare pentru coloana "email". Exceptia de la aceasta
regula este atunci cand o coloana nu are atributul NOT NULL (deci implicit are NULL) si poate aparea valoarea NULL de mai multe ori in cadrul
acestei coloane.

 Cheie primara - PRIMARY KEY - index ce forteaza atat unicitatea valorilor acestei coloane cat si prezenta unei valori (nu se accepta
valoarea NULL). In mod optim, orice tabel are o coloana cu index-ul cheie primara, iar acea coloana este intreg si are in plus
atributul AUTO_INCREMENT

Exista urmatoarele modalitati prin care se creeaza un index:

 folosind sintaxa CREATE TABLE in momentul cand realizam tabelul

 ALTER TABLE...ADD INDEX

 folosind CREATE INDEX (similar cu ALTER TABLE... ADD INDEX) insa folosind CREATE INDEX nu se poate adauga cheie primara

Exemple:

1 -- realizeaza tabelul utilizatori, cu 3 indecsi:


2 -- cheie primara pentru utilizatorId
3 -- index unic pentru username
4 -- index simplu pentru email
5
6 CREATE TABLE `utilizatori` (
7 `utilizatorId` int(11) unsigned NOT NULL auto_increment,
8 `username` varchar(20) NOT NULL,
9 `email` varchar(25) NOT NULL,
10 `anNastere` smallint(4) unsigned default NULL,
11 `sex` enum('m','f') NOT NULL,
12 `dataAdaugarii` date NOT NULL,
13 PRIMARY KEY (`utilizatorId`),
14 UNIQUE KEY `username` (`username`),
15 KEY `email` (`email`)
16 ) ;

1 -- realizeaza tabelul utilizatori, doar cu indexul cheie primara


2 -- foloseste apoi sintaxa ALTER TABLE pentru a adauga un index unic
3 pentru username si unul simplu pentru email
4
5 CREATE TABLE utilizatori (
6 utilizatorId int(11) unsigned NOT NULL auto_increment,
7 username varchar(20) NOT NULL,
8 email varchar(25) NOT NULL,
9 anNastere smallint(4) unsigned default NULL,
10 sex enum('m','f') NOT NULL,
11 dataAdaugarii date NOT NULL,
12 PRIMARY KEY (utilizatorId)
13 ) ;
14
15
16 ALTER TABLE utilizatori ADD UNIQUE (username);
17 ALTER TABLE utilizatori ADD KEY(email);
18
19 -- indecsii astfel adaugati vor optimiza cautari gen:
20 SELECT * FROM utilizatori WHERE email = 'john.s@gmail.com';
SELECT * FROM utilizatori WHERE username = 'john.s';
Resurse
http://dev.mysql.com/doc/refman/5.1/en/mysql-indexes.html
http://dev.mysql.com/doc/refman/5.1/en/create-index.html
http://www.sitepoint.com/article/optimizing-mysql-application/

7.10. DDL (Data Definition Language)


7.10.1 Comenzi legate de baza de date
7.10.2 Crearea unui tabel MySQL
7.10.3 Modificarea structurii unui tabel MySQL
7.10.4 Stergerea unui tabel MySQL

7.10.1. Comenzi legate de baza de date


Crearea unei baze de date:
1 -- creez o baza de date cu numele 'mysite'
2 CREATE DATABASE mysite

Stergerea unei baze de date:


1 -- ATENTIE ! informatiile acestei baze de date sunt pierdute
2 definitiv.
DROP DATABASE mysite;

Setarea bazei de date curente:


1 -- selectez mysite ca baza de date curenta
2 USE mysite;

7.10.2. Crearea unui tabel MySQL


Sintaxa (in pseudocod) pentru crearea unui tabel arata astfel:
Pseudocod
CREATE TABLE nume_tabel (
nume_coloana1 tip_date1[(lungime)] [atribute_extra],
nume_coloana2 tip_date2[(lungime)] [atribute_extra],
.....
[UNIQUE | PRIMARY] KEY nume_index (coloana)

);
Nota
Sintaxa CREATE TABLE poate fi mult mai complexa, avand si alte optiuni (vezi linkul din sectiunea Resurse). In sintaxa descrisa mai sus am
evidentiat lucrurile de baza care apar in orice creare de tabel: specificarea coloanelor, tipul de date si atributelor fiecarei coloane, precum si
specificarea indecsilor

Avem mai jos codul sql complet pentru crearea tabelului utilizatori:
1
2 CREATE TABLE utilizatori (
3 utilizatorId int(11) unsigned NOT NULL auto_increment,
4 username varchar(20) NOT NULL,
5 email varchar(25) NOT NULL,
6 varsta tinyint(4) unsigned default NULL,
7 sex enum('m','f') NOT NULL,
8 dataAdaugarii date NOT NULL,
9 PRIMARY KEY (utilizatorId),
10 UNIQUE KEY username (username),
11 KEY email (email)
12 );
Observam urmatoarele:

 fiecare definitie a unei coloane incepe cu numele coloanei, continua cu tipul de date, si apoi cu atributele suplimentare. ex:utilizatorId int(11)
unsigned NOT NULL auto_increment,

 dupa fiecare definitie a unei coloane, se pune virgula

 sunt tipuri de date care au lungimea specificata intre paranteze, ex: int(11), varchar(25), si tipuri de date la care intre paranteze sunt valorile
posibile ( set si enum ) ex: enum('m', 'f')

 majoritatea coloanelor au atributul NOT NULL. folosirea acestui atribut in majoritatea cazurilor este o preferinta a programatorului. cand un
camp are atributul NOT NULL setat, si totusi la insert nu primeste o valoare, el va primi valoarea goala pentru acel tip (sirul vid '' pentru
string-uri, 0 pentru numere, etc)

 la sfarsitul tabelului, sau definit trei indecsi: PRIMARY KEY (cheie primara) pentru utilizatorId, UNIQUE (cheie unica) pentru username si KEY
(index simplu) pentru email

7.10.3. Modificarea structurii unui tabel MySQL


Modificarea structurii unui tabel SQL se realizeaza cu instructiunea ALTER si se refera la:

 redenumirea tabelului sql


1 ALTER TABLE mesaje RENAME forum

 schimbarea definitiei unei coloane; prin acesta instructiune se poate schimba atat
numele coloanei, cat si restul definitiei: tip de date, atribute extra, index
1 ALTER TABLE utilizatori CHANGE sex gen ENUM( 'm', 'f' ) DEFAULT NULL

 adaugarea unei coloane; la sfarsitul acestei instructiuni indic locul in care adaug
coloana respectiva. "AFTER email" inseamna ca noua coloana se adauga dupa
coloana cu numele email; adaugarea coloanei pe prima pozitie o indic folosind
cuvantul cheie "FIRST".
1 ALTER TABLE utilizatori ADD telefon VARCHAR( 20 ) NOT NULL AFTER
email;

 stergerea unei coloane


1 ALTER TABLE utilizatori DROP COLUMN telefon
Resurse
http://dev.mysql.com/doc/refman/5.1/en/alter-table.html

7.10.4. Stergerea unui tabel MySQL


Nota
Stergerile ce afecteaza structura unei baze de date sau tabel, se efectueaza cu instructiuni de tip DROP. Cu DROPstergem o baza de date, un
tabel, sau o coloana. Stergerile ce se refera la datele (inregistrarile) dintr-un tabel, se vor face cu instructiunea DELETE.

Important
Intotdeauna faceti backup (arhiva, copie de siguranta) bazelor de date de care aveti nevoie. In mod normal, furnizorul de gazduire web trebuie sa puna la
dispozitia clientului un sistem de backup automat saptamanal sau lunar. Asigurati-va ca acest backup functioneaza. In caz contrar, luati masuri pentru
realizarea backup-ului automat, la un interval scurt (o zi, o saptamana) al bazei de date. In phpMyAdmin, backup-ul se poate realiza, folosind butonul
Export din meniul bazei de date. Click aici pentru printscreen-ul ecranului de backup/export.

Stergerea unui tabel sql se face astfel:


1 DROP TABLE forum;

Nota
Daca ati exersat aceste instructiuni pe baza de date mysite, si doriti sa o aduceti la forma originala, o puteti sterge, apoi o creati din nou, si
executati codul sql pentru crearea tabelelor: mysite.sql

DML (Data Manipulation Language)


7.11.1 INSERT
7.11.2 SELECT
7.11.3 UPDATE
7.11.4 DELETE

7.11.1. INSERT
Instructiunea INSERT adauga inregistrari intr-un tabel sql.
Exista doua forme in care se foloseste aceasta instructiune:

1. Forma completa - in aceasta forma sunt specificate atat coloanele in care introducem date cat si valorile introduse. Insert-ul va "cupla" de la stanga la
dreapta numele coloanelor cu valorile respective astfel incat in coloana1 va fi adaugata valoare1, in coloana2 valoare2, etc. Din aceasta forma deducem ca
putem specifica doar cateva coloane din tabelul "nume_tabel", deci nu toate coloanele. In cazul in care omitem anumite coloane de la insert, in ele se va
adauga valoarea NULL daca atributele coloanei permit, sau valoarea DEFAULT implicita (specificata in definitia coloanei folosind atributul DEFAULT) sau
cea explicita adica valoarea goala pentru acel tip de date.
Pseudocod
INSERT INTO nume_tabel (coloana1, coloana2, ...) VALUES (valoare1, valoare2, ...)

Instructiunea INSERT asupra tabelului utilizatori


1 INSERT INTO utilizatori (username, email, anNastere, gen,
dataAdaugarii) VALUES ('vasile', 'vasile@yahoo.com', 1949, 'm', '2008-
10-01');
Observam ca la insert-ul in tabelul utilizatori am omis coloana utilizatorId. Acest lucru este chiar indicat, pentru ca fiind coloana cu atributul
AUTO_INCREMENT, valoarea acestei coloane este generata automat la fiecare insert. La fel s-ar fi comportat daca incercam introducerea valorii NULL.

2. Forma scurta - in aceasta forma a instructiunii sunt specificate doar valorile pe care le introducem. Din acest motiv, numarul de valori introduse
trebuie sa fie egal cu numarul coloanelor tabelului. Instructiunea INSERT va incerca introducerea valorii1 in prima coloana, valorii2 in a doua coloana, etc.
Pseudocod
INSERT INTO nume_tabel VALUES (valoare1, valoare2, ...)

1 INSERT INTO utilizatori VALUES (NULL, 'anamaria',


'anamaria23@gmail.com', 1986, 'f', '2008-11-13');

Resurse
http://dev.mysql.com/doc/refman/5.1/en/insert.html

7.11.2. SELECT
Cu ajutorul instructiunii SELECT extragem, cautam si ordonam informatie (inregistrari) din tabelele sql.

Sintaxa (simplificata) este:


Pseudocod
SELECT lista_coloane FROM tabel [WHERE conditie] [ORDER BY coloana1,...] [LIMIT a,b]

lista_coloane poate fi de fapt una din urmatoarele expresii:

 o lista de coloane separate prin virgula;

 * simbol ce semnifica selectarea tuturor coloanelor din tabel

 , aplicate unor coloane sau nu neaparat. Prezenta acestora se poate


functii SQL predefinite

combina (sau nu) cu prezenta altor coloane in lista selectului.


1 SELECT username, email FROM utilizatori;
2
3 SELECT * FROM utilizatori;
4
5 SELECT MIN(anNastere) FROM utilizatori;
Clauza WHERE
Cu ajutorul clauzei WHERE filtram (sau cautam) informatiile dorite. Un tabel dintr-o baza de date poate avea de la cateva inregistrari, pana la miliarde de
inregistrari. Cu ajutorul clauzei WHERE obtinem doar inregistrarea sau inregistrarile dorite. Uneori, pentru a obtine inregistrarile dorite este necesar sa o

Inregistrarile returnate de instructiunea SELECT sunt cele


combinam cu clauzele ORDER BY si/sau LIMIT.

pentru care clauza WHERE este adevarata.


1 SELECT * FROM utilizatori WHERE anNastere > 1970; -- se pot folosi
2 operatorii de comparatie: =, !=, <, >, <=, >=
3 SELECT username,email, anNastere FROM utilizatori WHERE sex = 'm';
SELECT * FROM mesaje WHERE utilizatorId != 1; -- selecteaza toate
mesajele care au coloana utilizatorId diferita de valoarea 1

Se pot folosi operatorii booleni (AND, OR, XOR, NOT) precum si paranteze rodunde
pentru evaluarii clara a expresiei boolene.
1 SELECT * FROM utilizatori WHERE anNastere > 1965 AND sex = 'm';

cautam inregistrarile ce au pe coloana respectiva valori nule


Cu ajutorul operatorilor IS NULL si IS NOT NULL

sau dimpotriva, valori diferite de NULL.


1 INSERT INTO utilizatori VALUES (NULL, 'test', 'test@yahoo.com', 1918,
2 NULL, now());
SELECT * FROM utilizatori WHERE sex IS NULL

Cu ajutorul operatorului LIKE putem face cautari/filtrari pe baza unor portiuni dintr-un
string. In folosirea operatorului LIKE, expresia cu care se compara coloana de tip string
poate contine simbolurile % ce reprezinta orice caracter de oricate ori, sau simbolul _ ce
semnifica orice caracter ce apare o singura data.
1 INSERT INTO utilizatori (username, email, anNastere, sex,
2 dataAdaugarii) VALUES ('ionitza', 'ionitza112@gmail.com', 1989, 'm',
3 now());
4
5
6 /*
7 cauta inregistrari ce contin in campul username string-ul "ion".
8 Caracterul % ce incadreaza expresia "ion" semnfica prezenta oricaror
9 si oricator caractere
10 inainte sau dupa acest string.
11 */
12 SELECT * FROM utilizatori WHERE username LIKE '%ion%'

SELECT * FROM utilizatori WHERE username = 'ion' -- gaseste


inregistrarile ce au valoarea exacta "ion" pentru campul username

Nota
Cautarile de tip text (cautarea unui cuvant sau unei portiuni dintr-un string in coloane de tip string (char, varchar, text)) se realizeaza in mod
eficient cu ajutorul unui index de tip FULLTEXT pe coloana (coloanele) respective, si cu o sintaxa speciala (MATCH...AGAINST) - vezi sectiunea
Resurse.

Clauza ORDER BY
Implicit se ordoneaza crescator
Cuvantul cheie ORDER BY este urmata de coloanele dupa care ordonam, separate prin virgula.

dupa coloanele respective (ca si cum ar fi prezent cuvantul cheie ASC), dar putem ordona
descrescator folosind cuvantul cheie DESC.
1 SELECT * FROM utilizatori ORDER BY anNastere;
2
3 /*
4 efectul se observa doar daca exista mai multe inregistrari cu aceeasi
5 valoare pentru anNastere
6 si atunci, in acele inregistrari, se ordoneaza si descrescator dupa
7 username
*/
SELECT * FROM utilizatori ORDER BY anNastere, username DESC;
Clauza LIMIT
LIMIT are doua forme:

 LIMIT m - selecteaza n inregistrari

 LIMIT n,m - selecteaza m inregistrari incepand cu inregistrarea numarul n (numerotarea incepe de la 0). ex: LIMIT 1, 5 selecteaza 5
inregistrari excluzand prima inregistrare. (se porneste de la inregistrarea 1, dar prima inregistrare este inregistrarea 0)

pentru a forma top-uri. Exemplu: cei mai


Clauza ORDER BY se foloseste de multe ori impreuna cu LIMIT

tineri 10 utilizatori, primii 3 cel mai bine platiti angajati dintr-o firma, clientii ce
au generat incasarile cele mai mari pentru o firma (top clienti), etc.
1 SELECT username, anNastere FROM utilizatori ORDER BY anNastere DESC
2 LIMIT 3 -- top 3: cei mai tineri utilizatori
SELECT username, anNastere FROM utilizatori ORDER BY anNastere DESC
LIMIT 2, 3 -- cei mai tineri 3 utilizatori (insa excluzand primii 2 =
incepand cu inregistrarea 2)

INNER JOIN si LEFT JOIN - SELECT din mai multe tabele


De multe ori avem nevoie in aceeasi clauza SELECT sa extragem si sa filtram informatii din mai multe tabele sql. Acest lucru il facem cu ajutorul

. In cazul cel mai simplu, folosind doua tabele, sintaxa JOIN ne


sintaxei INNER JOIN sau LEFT JOIN

permite sa extragem intr-o singura inregistrare o combinatie intre coloanele unei


inregistrari din primul tabel, si coloanele unei inregistrari din cel de-al doilea tabel.
Trebuie sa folosim insa o conditie conform careia se combina inregistrarile din primul
tabel cu cele din cel de-al doilea tabel. Daca nu folosim aceasta conditie (nu folosim
sintaxa JOIN), SELECT-ul returneaza fiecare inregistrare din primul tabel combinata cu
fiecare inregistrare din cel de-al doilea tabel (adica produs cartezian), operatie pe care de
obicei nu-o dorim.
1 /*
2 fara a folosi sintaxa JOIN, se extrag informatii din ambele tabele,
3 fara nici o conditie.
4 fiecare inregistrare din primul tabel este combinata cu o inregistrare
5 din cel de-al doilea
*/
SELECT * FROM mesaje, utilizatori

Folosind sintaxa INNER JOIN, extragem fiecare inregistrare din primul tabel ce are ca pereche o inregistrare din cel de-al doilea tabel
conform unei conditii. De obicei, conditia folosita este: valoarea cheii primare din primul tabel (sa zicem coloana utilizatorId) este egala cu
valoarea aceleiasi coloane (cheie straina) din al doilea tabel (coloana utilizatorId din al doilea tabel)
1 SELECT
2 *
3 FROM
4 mesaje m
5 INNER JOIN utilizatori u ON m.utilizatorId = u.utilizatorId
6
7 ORDER BY m.dataMesaj DESC
Observatii:

 exemplul extrage toate inregistrarile din primul tabel, combinate cu cel de-al doilea tabel, pe baza conditiei ce urmeaza cuvantului cheie ON.
Conditia este m.utilizatorId = u.utilizatorId. Deci, inregistrarile sunt formate din acele inregistrari care au aceeasi valoare pentru coloana
utilizatorId in primul tabel si in al doilea tabel. Concret, sunt extrase mesajele din primul tabel, iar la fiecare inregistrare pentru un mesaj se
"alipeste" inregistrarea utilizatorului care a trimis mesajul. Astfel, informatia "sparta" in tabele la normalizare, capata acum sens: horatiu a
trimis mesajul cu subiectul "salut", apoi raluca a trimis mesajul cu subiectul "salut si aici"... etc

 folosirea sintaxei JOIN nu exclude posibiltatea folosirii clauzei WHERE, ORDER BY, etc. Aceste clauze folosesc coloane din tabelele prezente in
JOIN.

 observam la denumirea tabelelor sintaxa "mesaje m" sau "utilizatori u". Numele tabelului poate fi urmat de o litera (sau mai multe), ce
constituie o denumire prescurtata, un "nickname" al tabelului. Aceasta denumire prescurtata este apoi folosita in apelarea coloanelor din cele
doua tabele: m.utilizatorId, u.utilizatorId, m.dataMesaj

 am folosit ordonarea descrescatoare dupa dataMesaj, pentru a vizualiza mesajele in ordinea cronologica a trimiterii lor - cu cele mai recente
sus

Nota
Instructiunile ce au sintaxa SELECT mai complexe, cu mai multe clauze sau folosind sintaxa JOIN, prefer sa le scriu intr-un format ceva mai
"aerisit", ca in exemplul de mai sus: SELECT are propria linie, apoi fiecare coloana are propria linie, fiecare tabel din JOIN e pe propria linie, la fel cu
clauzele WHERE si ORDER BY. Acest standard de scriere a instructiunilor sql este folosit si in manualul MySQL pentru instructiunile SELECT mai
complexe. Ca si curiozitate, manualul MySQL prezinta o instructiune SELECT complexa, cu JOIN din mai multe tabele. Aceasta instructiune a fost
folosita in practica, intr-un studiu medical despre gemeni, si poate fi gasit aici: MySQL manual - Find All Non-distributed Twins

Sintaxa LEFT JOIN difera de INNER JOIN prin faptul ca selecteaza toate inregistrarile din primul tabel, indiferent ca au corespondent in cel de-al doilea
sau nu.

se foloseste conditia de combinare a inregistrarilor din primul tabel cu cele


Similar cu INNER JOIN

din al doilea tabel, dar daca nu este gasita o inregistrare corespondenta in al doilea tabel
se va afisa inregistrarea din primul tabel iar pe pozitiile campurilor din al doilea tabel se
va afisa valoarea NULL.
1 /*
2 adaug intai un mesaj ce nu are corespondenta in tabelul utilizatori
3 pentru coloana utilizatorId = 999
4 */
5 INSERT INTO mesaje (mesajId, utilizatorId, subiect, mesaj, dataMesaj)
6 VALUES (NULL, 999, 'subiect test', 'mesaj test', now());
7
8
9 SELECT
10 *
11 FROM
12 mesaje m
13 LEFT JOIN utilizatori u ON m.utilizatorId = u.utilizatorId

ORDER BY m.dataMesaj DESC


Daca ati pastrat datele din sql-ul initial pentru baza de date mysql, si ati executat INSERT-ul si SELECT-ul de mai sus, rezultatul SELECT-ului va arata ca
in acest printscreen. Observati ca pentru mesajul cu id-ul 6, nu s-a gasit un corespondent in tabelul utilizatori cu utilizatorId = 999. Astfel, in locul
campurilor pentru inregistrarea corespondenta din tabelul utilizatori, a fost returnata valoarea NULL.

Alte exemple folosind INNER JOIN si LEFT JOIN :


1 /*
2 cu ajutorul LEFT JOIN vrem sa gasim DOAR inregistrarile din primul
3 tabel ce nu au corespondenta in al doilea tabel folosind operatorul
4 IS NULL
5 Putem folosi acest query pentru a identifica si a sterge mesajele
6 utilizatorilor ce nu mai sunt in baza de date.
7 Desi, in mod normal, cand stergem un utilizator, trebuie sa cautam si
8 sa stergem si mesajele aferente (de exemplu, stergem utilizatorul
9 cu utilizatorId = 999, apoi stergem din tabelul mesaje toate mesajele
10 ce au utilizatorId = 999
11 */
12
13 SELECT
14 m.*,
15 u.utilizatorId
16
17 FROM
18 mesaje m
19 LEFT JOIN utilizatori u ON m.utilizatorId = u.utilizatorId
20
21 WHERE
22 u.utilizatorId IS NULL
23
24 /*
25 extragem doar numele de utilizator, subiectul si corpul mesajului
26 vrem doar mesajele scrise dupa anumita data
27 */
28
29 SELECT
30 u.username,
31 m.subiect,
32 m.mesaj
33
34 FROM
35 mesaje m
36 INNER JOIN utilizatori u ON m.utilizatorId = u.utilizatorId
37
WHERE
m.dataMesaj > '2009-04-01'

ORDER BY
m.dataMesaj DESC

Resurse
http://dev.mysql.com/doc/refman/5.1/en/non-typed-operators.html
http://dev.mysql.com/doc/refman/5.0/en/join.html
Articol Full-Text Search - Zend.com
Articol Full-Text Search - Devshed.com
Fulltext Search - Manual MySQL

7.11.3. UPDATE
Instructiunea UPDATE modifica inregistrari intr-un tabel sql. Se poate modifica un camp, sau mai multe campuri ale unei inregistrari.

Nota
In general instructiunea UPDATE este urmata de clauza WHERE pentru a identifica o inregistrare sau doar un set de inregistrari pentru care facem
modificarile resepctive. Daca nu folosim clauza WHERE modificarea va afecta TOATE inregistrarile din tabel. Inainte sa folositi sau sa testati
instructiunea un UPDATE pe o baza de date cu informatii reale, asigurati-va ca aveti un backup (copie) recent.

Sintaxa este:
Pseudocod
UPDATE tabel SET coloana1=valoare1, coloana2=valoare2... WHERE ...

Exemplu pe tabelul utilizatori :


1 UPDATE utilizatori SET username='test_modificat', email =
'test_modificat@yahoo.com' WHERE utilizatorId = 6;

7.11.4. DELETE

Instructiunea DELETE sterge inregistrari din tabele sql.


Nota
DELETE se foloseste cu o clauza WHERE pentru a sterge doar o inregistrare sau un anumit set de inregistrari din tabel. Daca omitem clauza WHERE
se sterg toate inregistrarile din tabel.

Exemplu:
1 DELETE FROM utilizatori WHERE utilizatorId = 6;
2 DELETE FROM mesaje WHERE subiect LIKE '%test%';

7.12. Tema
Tema 7-1
1. Construiti o baza de date cu un singur tabel, numit clienti, care sa
tine urmatoarele informatii:
- clientId (cheia primara)
- prenume client
- nume client
- sex
- varsta
- email
- incasari totale -> reprezinta o suma cu incasarile totale de la acest
client. Tipul de date care se preteaza la coloanele ce tin informatii
financiare este decimal.
Puteti pune aici decimal (10, 2)
- data adaugarii
- domeniu activitate -> faceti o lista de cateva domenii de activitate,
3-4. Ex: Agricultura, It...

* nu uitati sa adaugati o cheie primara pentru acest tabel, si sa fie


auto_increment
** campurile le denumiti fara spatii (folosind underscore sau camelcase)

2. Scrieti manual codul sql pentru cel putin 5 insert-uri in acest


tabel.

3. Dupa ce ati realizat baza de date, tabelul, si aveti si informatii in


tabel (ati facut cele 5 inserturi sau mai multe) faceti doua exporturi
in 2 fisiere diferite:
- intr-un fisier sa se tina structura tabelului
- in alt fisier sa se tina informatiile din tabel

Salvati aceste fisiere cu extensia .sql

4. Scrieti codul sql care:


- extrage toti clientii ordonati dupa nume crescator, si varsta
descrescator
- extrage toti clientii care au string-ul "ion" in nume, sau in prenume
- numara cate persoane de sex feminin sunt si cate de sex masculin
(SELECT count(*)...)
- calculeaza totalul incasarilor pentru toate persoanele de sex feminin
si pentru toate persoanele de sex masculin (SELECT SUM(coloana1) GROUP
BY coloana2...)
- extrage primii 3 cei mai tineri clienti
- extrage toate persoanele de sex masculin peste 30 de ani

5. Scrieti codul sql care:


- sterge inregistrarea cu un anumit id, pe care-l alegeti voi
6. Scrieti codul sql care:
- modifica varsta, emailul si data adaugarii cu valori noi, pentru o
inregistrare cu un anumit id

7. Salvati codul sql de la pasii 3, 4 si 5 intr-un fisier cu extensia


.sql. Fiecare instructiune sql trebuie sa aiba punct si virgula la
sfarsit ";"

8. Tot ce ati lucrat se va afla in fisierele salvate la pasul 3 si


fisierul salvat la pasul 6.

Tema 7-2
1. Adaugati la baza de date de la exercitiul anterior un tabel incasari
cu urmatoarele campuri:
- incasareId (cheia primara)
- clientId
- data incasarii
- suma
- modalitate plata - ENUM: banca, numerar, alta

2. Stergeti coloana ce reprezinta incasarile totale din primul tabel.

3. Folositi INSERT pentru a adauga randuri in acest tabel ce vor


corespunde clientilor din primul tabel, dar si cateva randuri ce nu au
corespondent in primul tabel.
Adaugati cel putin 2 inregistrari pentru fiecare client.

4. Folositi un query de tip JOIN (vezi documentatia despre join din


subcapitolul SELECT) astfel incat sa extrageti inregistrari cu
urmatoarele informatii:
prenume client, nume client, data incasarii, suma incasata, modalitate
plata. Datele sa fie ordonate cronologic, cele mai recente incasari sus.

5. Folositi clauza GROUP BY


(http://dev.mysql.com/doc/refman/5.1/en/select.html si
http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html)
astfel incat sa extrageti primii trei clienti in ordinea totalului de
incasari. Informatia selectata trebuie sa contina: prenume, nume,
sumaTotala.
Exemplu group by dintr-un singur tabel: SELECT SUM(suma) FROM incasari
GROUP BY clientId;

6. Introduceti cateva randuri in "incasari" ce nu au corespondent in


"clienti". Realizati apoi un LEFT JOIN care sa scoata in evidenta aceste
randuri.

7. Extrageti (cu select) suma incasarilor dintr-o anumita zi. Ex: 2009-
03-20. Trebuie sa aveti macar 2 incasari in ziua respectiva, sa
verificati daca functioneaza.

Tema 7-3
1. Descarcati data.php.zip , un tablou cu date de test ce contine 123 de
elemente.

2. Alcatuiti un script ce afiseaza un tabel cu 2 coloane (username si


varsta) si doar 10 randuri din tabloul de 123 de elemente.

3. Alegerea celor 10 elemente afisate se va face pe baza a doua


variabile:
3.1 o variabila definita in scriptul vostru ce reprezinta numarul de
elemente afisate. Ex: $rowsPerPage = 10;
3.2 o variabila ce se transmite prin get, numita from, ce stie de la al
catelea element se porneste afisarea.
Daca $_GET['from'] nu e definit sau este 0, se porneste de la prima
inregistrare.
Daca $_GET['from'] este 10, se afiseaza de la a 11-a inregistrare
(inregistrarea cu index-ul 10). samd.

3.3. Generati automat linkuri de next si previous (sau pagina


anterioara pagina urmatoare) pentru transmiterea parametrului from si
navigarea prin rezultate.

3.4. Prima pagina nu trebuie sa aiba Previous. Ultima pagina nu trebuie


sa aiba Next.

CAP.8. PHP si MySQL


8.1 Introducere
8.2 Extensia mysql
8.3 Extensia mysqli
8.4 Mini aplicatie
(select, insert, update, delete)
8.5 Tema

8.1. Introducere
Exista in mod curent in limbajul PHP trei seturi de functii (sau clase) pentru lucrul cu MySQL. Aceste seturi de functii, mai sunt numite si extensii. Toate
aceste extensii ajuta interogarea si administrarea unei baze de date MySQL prin intermediul PHP-ului.

 extensia mysql - este prima extensie folosita pentru lucrul cu MySQL din PHP, din acest motiv probabil este inca cea mai raspandita in
scripturile deja dezvoltate. Extensia MySQL contine doar functii (interfata procedurala) nu si clase (interfata orientata pe obiect) si este
recomandata doar pentru versiuni de MySQL mai vechi de 4.1.3. Elementele avansate de MySQL (prezente in versiuni ulterioare versiunii
4.1.3) nu sunt disponibile in aceasta extensie. Din acest motiv, aceasta extensie nu mai este dezvoltata in mod activ, iar echipa PHP
recomanda folosirea celorlalte doua extensii (mysqli sau PDO) in locul acesteia.

 extensia mysqli - a urmat extensiei mysql si contine atat functii (interfata procedurala) cat si un set de clase (interfata orientata obiect)
pentru operatiile uzuale cu MySQL. Aceasta extensie este mai avansata decat extensia mysql, (mysqli este prescurtarea de la mysql
improved) si introduce noi facilitati prezente in versiunile peste MySQL 4.1.3 - lucrul cu tranzactii, interogari multiple, stored procedures, etc.

 extensia PDO (PHP Data Objects) este ceea ce se numeste o "database abstraction layer"; Adica, PDO contine o interfata orientata obiect
(set de clase si metode) pentru lucrul in mod unitar cu o bazele de date din PHP. Concret, metodele folosite cu PDO sunt aceleasi fie ca
folosim o baza de date MySQL, Oracle, Firebird, PostgreSQL, etc. Deci, putem schimba sistemul de baze de date pentru aplicatia noastra
(bineinteles cu una din bazele de date suportate de aceasta extensie), fara sa schimbam codul PHP, sau cu schimbari minore. Acelasi lucru nu
se intampla cu extensiile mysql sau mysqli deoarece acestea contin functii specifice pentru lucrul cu MySQL. Dezavantajul principal
al PDO este faptul ca nu se pot folosi cateva din facilitatile foarte specifice si avansate ale unui sistem de baze de date MySQL, sau alt DBMS.

Nota
In acest curs se va prezenta in detaliu extensia mysql pentru ca este destul de raspandita si probabil cel mai simplu de folosit pentru inceput. Apoi
insa, prezint extensia mysqli, diferentele ce apar fata de extensia mysql, iar in continuare in exemplele din curs se va lucra cu extensia mysqli,
fiind cea recomandata si de echipa PHP.Trecerea de la mysql la mysqli este simpla, pentru ca cele doua extensii se aseamana destul de mult.

Resurse
http://www.php.net/manual/en/mysqli.overview.php

8.2. Extensia mysql


8.2.1 Conectarea la serverul MySQL
8.2.2 Selectarea bazei de date
8.2.3 Executarea unei instructiuni sql
8.2.4 Instructiuni de actualizare - insert, update, delete
8.2.5 Extragerea informatiilor - select
8.2.6 Alte functii mysql

8.2.1. Conectarea la serverul MySQL


Pentru a accesa o baza de date MySQL din PHP, scriptul nostru in PHP va indeplini rolul de client si se va conecta la un serverMySQL pentru ca ulterior sa
comunice cu acesta si sa-i trimita instructiuni sql. Conexiunea la serverul MySQL se face cu ajutorul functiei mysql_connect() si este pastrata intr-o
variabila de tip resource, variabila returnata de mysql_connect().

Aceasta variabila (denumita uneori $link) reprezinta conexiunea la baza de date si va fi folosita ulterior (implicit sau explicit) de alte functii mysql pentru a
trimite instructiuni prin aceasta conexiune, stabilita la primul pas (conectarea la baza de date).

Semnatura (putin simplificata) a functiei mysql_connect() este:


Pseudocod
resource mysql_connect (string $server, string $username, string $password [, bool $new_link= false] )

Pentru conectarea la un server MySQL avem deci nevoie de 3 parametri (informatii):

 $server - numele sau ip-ul serverului respectiv. In general, acesta va fi localhost. Cuvantul localhost identifica intotdeauna calculatorul
local, adica cel pe care se afla scriptul de la care ne conectam. Indiferent ca testam site-ul offline (la noi pe calculator) sau online (pe serverul
de gazduire), localhost isi pastreaza semnificatia pentru ca este acelasi calculator cu cel pe care avem scriptul PHP. Insa, daca avem script-ul
PHP pe un calculator, si serverul MySQL pe altul, putem specifica un nume de domeniu sau IP ca $server. In plus, optional, putem specifica si
port-ul pe care ne conectam (Ex: www.mysite.ro:3307).

 $username - accesul (privilegiile) la resursele unui server de baze de date este acordat pe baza utilizatorului ce se conecteaza la acel server.
Cand lucrez local, probabil voi folosi utilizatorul cu drepturi depline, si anume: root. Online (pe serverul de gazduire) voi realiza un utilizator
cu acces limitat si-l voi utiliza pe acela pentru conectarea din scripturile php.

 $password - parola cu care se autentifica $username

Parametrul $new_link (de tip boolean) este implicit false. Daca il folosim si e true, fiecare nou apel al functiei mysql_connect() cu aceiasi parametri va
deschide o noua conexiune catre baza de date in loc sa foloseasca conexiunea existenta. In cele mai multe cazuri nu avem nevoie de acest lucru.

conectare.php
1 <?php
2 mysql_connect('localhost', 'root', '') or die('Eroare la
3 conectare !');
?>

Nota
Sintaxa nume_functie() or die('Eroare...') sau $rezultat = nume_functie() or die('Eroare') este intalnita des in PHP iar explicatia este urmatoarea:

 or este un operator logic, si ca toti operatorii logici actioneaza cu "scurt-circuitare"; adica, este evaluat operandul din stanga, si anume
apelul nume_functie(). Daca acesta returneaza true, nu se va mai evalua die('Eroare'); pentru ca poate determina faptul ca rezultatul
operatiei este true. Daca in schimb apelul functiei returneaza false (sau 0), atunci se evalueaza die('Eroare'), instructiune ce va opri
executia script-ului curent, afisand mesajul: Eroare.

 motivul pentru care se foloseste or si nu || este ca or are o prioritate mai mica fata de "=". Prin urmare, variabilei $rezultat ii va fi
atribuit rezultatul apelului nume_functie() si apoi se va executa operatia logica or

Vezi si subcapitolul Operatori logici


Schimbati in script-ul de conectare parametrii de conectare la baza de date, pentru a testa diferitele erori.

Alte exemple de conectare (ce difera mai mult in stilul de lucru) sunt:

conectare2.php
1 <?php
2 /*
3 in cazul in care conectarea se face cu succes, conexiunea se
4 pastreaza in variabila de tip resursa $link
5 */
6
7 $link = mysql_connect('localhost', 'root', '') or die('Eroare la
8 conectare !');
9
10 // puteti verifica prezenta unei valori de tip resursa in variabila
$link
// var_dump($link);
?>
In acest al 3-lea exemplu, tin informatiile de conectare la baza de date in variabile (recomandat), pe care le transmit apoi ca parametri functiei
mysql_connect(). Folosesc operatorul @ ce are ca efect ignorarea mesajelor de eroare generate de o functie, astfel incat sa captez eroarea ulterior, cu
ajutorul functiei mysql_error();

conectare3.php
1 <?php
2 $db_host = 'localhost';
3 $db_user = 'root';
4 $db_pass = '';
5
6 $link = @mysql_connect($db_host, $db_user, $db_pass);
7 //var_dump($link); // pentru debug
8
9 if (!$link) {
10 die('Eroare la conectare: ' . mysql_error());
11 }
12 ?>

8.2.2. Selectarea bazei de date


Semnatura functiei este:
Pseudocod
bool mysql_select_db ( string $database_name [, resource $link_identifier ] )
Parametri:

 $database_name - numele bazei de date pe care o selectam

 $link_identifier - variabila ce reprezinta conexiunea la serverul de baze de date. Aceasta variabila este returnata de mysql_connect() si este
de tipul resource. Pentru aceasta functie, acest parametru este optional... PHP-ul va folosi ultima conexiune deschisa

Daca nu se afiseaza nimic in browser, in urma exemplului de mai jos, inseamna ca totul e bine, a fost deschisa conexiunea la serverul MySQL si s-a
selectat o baza de date.

conectare.php
1 <?php
2 $db_host = 'localhost';
3 $db_user = 'root';
4 $db_pass = '';
5
6 $link = @mysql_connect($db_host, $db_user, $db_pass);
7
8 if (!$link) {
9 die('Eroare la conectare: ' . mysql_error());
10 }
11
12 mysql_select_db('mysite') or die(mysql_error());
13
14 ?>

8.2.3. Executarea unei instructiuni sql


In continuare, pentru a urmari exemplele ce folosesc instructiuni catre serverul de baze de date, trebuie sa includeti codul dinconectare.php pentru a va
putea conecta la baza de date si selecta o baza de date pe care lucrati. Acest lucru se poate face si cu copy-paste in fiecare script in care lucrati, dar e mai
simplu sa includeti fisierul cu conectarea la baza de date cu ajutorul instructiunilor include sau require (vezi: include, require).
Trimiterea unei instructiuni sql catre serverul MySQL se face cu ajutorul functiei mysql_query(), care are urmatorul prototip:
Pseudocod
resource mysql_query ( string $query [, resource $link_identifier ] )

 $query - va fi instructiunea sql. Ex: 'SELECT * FROM utilizatori'. Se poate trimite o singura instructiune sql o data, si NU este urmata de
punct si virgula.

 $link_identifier - parametru optional ce reprezinta conexiunea catre serverul MySQL. Daca nu este specificata, se foloseste conexiunea
curenta

Valoarea returnata de mysql_query()


Valoarea returnata de mysql_query() depinde de tipul de instructiune sql folosita. Sa presupunem ca pastram valoarea returnata intr-o variabila numita
$result. ($result = mysql_query(...)).

Se disting doua cazuri:


1. Instructiunea sql este de tipul - INSERT, UPDATE, DELETE, DROP. In acest caz, $result este true daca instructiunea s-a executat cu succes,
sau false daca MySQL a intalnit o eroare in executarea instructiunii sql.

2. Instructiunea sql este de tipul - SELECT, sau alte instructiuni sql ce returneaza inregistrari. In acest caz, $result este o variabila de tip resource ce
contine setul de inregistrari returnat de server in urma executarii instructiunii sql. In cazul in care s-a primit o eroare la executarea instructiunii sql ,
$result va fi false. Important este ca, in cazul unei instructiuni SELECTexecutata cu succes, valoarea returnata de mysql_query() (variabila $result in
cazul nostru) va contine inregistrarile returnate in urma query-ului sql, inregistrari ce pot fi extrase din aceasta variabila cu ajutorul unor functii
specializate:mysql_fetch_row(), mysql_fetch_assoc(), mysql_fetch_array(). Trebuie deci sa retinem ca datele din $result nu pot fi vizualizate altfel
decat prin extragerea lor cu functiile de mai sus.

8.2.4. Instructiuni de actualizare - insert, update, delete


Nota
In faza de testarea sau constructie a unui script PHP ce trimite instructiuni catre un server MySQL, verificam dupa rularea scriptului cu un client
MySQL (de exemplu phpMyAdmin) daca au fost inserate, actualizate sau sterse inregistrarile respective, realizand un SELECT (sau apasand butonul
Browse) pe tabelul/tabelele respective.

Exemplu executare INSERT cu mysql_query():

1 <?php
2 include("conectare.php");
3
4 $sql = "INSERT INTO utilizatori (username, email, anNastere, sex,
5 dataAdaugarii) VALUES ('dan', 'dan23@gmail.com', 1981, 'm', now()) ";
6 //echo $sql;
7 mysql_query($sql) or die(mysql_error());
8
9
?>

Referitor la exemplul de mai sus:

 instructiunea echo $sql; are doar rol de debug. Este foarte util de multe ori sa afisam in browser exact instructiunea sql ce va fi executata cu
PHP si eventual sa o copiem si sa o testam manual in phpMyAdmin. Mai ales cand aceasta instructiune va fi formata dinamic, cu ajutorul
variabilelor, asa cum vom vedea mai tarziu.

 instructiunea care trimite codul sql catre serverul MySQL este: mysql_query($sql). In caz ca aceasta esueaza, cu ajutorul
functiei mysql_error() voi afisa eroarea returnata de serverul mysql. Functia die() va afisa eroarea si va opri executia scriptului.

 valorile de tip string sau date din mysql, sunt scrise intre ghilimele. Ca sa nu inchidem string-ul deschis in php cu ghilimele duble, voi folosi
pentru ghilimele simple in instructiunea sql. Se poate si invers.

 in caz ca executati a doua oara acest exemplu, veti obtine o eroare gen: "Duplicate entry 'dan' for key 2"; datorita faptului ca avem un index
unic pentru coloana username

Exemplu executare UPDATE cu mysql_query():

1 <?php
2 include("conectare.php");
3
4 $sql = "UPDATE utilizatori SET email = 'ion_popescu@yahoo.com' WHERE
5 utilizatorId = 3";
6 mysql_query($sql) or die(mysql_error());
7
8 echo 'Randuri afectate de query: ' . mysql_affected_rows();
?>

Daca am nevoie sa stiu cate randuri au fost afectate de ultima instructiune insert, update sau delete pot folosi functiamysql_affected_rows() Astfel,
daca rulez prima data exemplul respectiv (si inregistrarea e modificata), numarul returnat de mysql_affected_rows() este 1. Cand rulez exemplul ulterior,
MySQL detecteaza faptul ca nu s-a modificat nici o inregistrare din tabel, iar mysql_affected_rows() va returna 0.

Exemplu executare DELETE cu mysql_query():

1 <?php
2
3 $sql = ' DELETE FROM utilizatori WHERE utilizatorId > 6';
4 mysql_query($sql) or die(mysql_error());
5
6 echo 'Randuri sterse: ' . mysql_affected_rows();
7
8 ?>

8.2.5. Extragerea informatiilor - select


Executarea cu mysql_query() a unei instructiuni de tip SELECT va returna o valoare de tip resource ce contine setul de date extras din baza de date.
Setul de inregistrari aflate in variabila returnata de mysql_query() va fi extras cu ajutorul urmatoarelor functii:

 array mysql_fetch_row ( resource $result ) - returneaza inregistrarea curenta sub forma unui tablou cu chei numerice, astfel: prima coloana
din setul de rezultate va avea index-ul 0, a doua coloana 1, etc.

 array mysql_fetch_assoc ( resource $result ) - returneaza inregistrarea curenta sub forma unui tablou asociativ - avand ca si chei, numele
coloanelor din setul de inregistrari

 array mysql_fetch_array ( resource $result [, int $result_type= MYSQL_BOTH ] ) - in mod implicit aceasta functie returneaza un tablou cu
chei atat numerice cat si de tip string pentru valorile dintr-o inregistrare. Asta inseamna ca valorile campurilor unei inregistrari sunt duplicate
in acest tablou, pentru a fi accesate folosind atat chei numerice cat si chei de tip string. Al doilea parametru (optional, implicit este constanta
MYSQL_BOTH) poate fi constanta MYSQL_ASSOC caz in care aceasta functie este similara cu mysql_fetch_assoc(), sau poate fi constanta
MYSQL_NUM, caz in care functia este similara cu mysql_fetch_row().

select.php
1 <?php
2 include("conectare.php");
3
4 $sql = 'SELECT utilizatorId, username, email FROM utilizatori ORDER
5 BY utilizatorId DESC LIMIT 3';
6 $result = mysql_query($sql) or die(mysql_error());
7
8 while ($d = mysql_fetch_row($result)) {
9 print_r($d);
10 }
11
?>

In exemplul select.php inlocuiti functia mysql_fetch_row() cu mysql_fetch_assoc() si apoi cu mysql_fetch_array() si observati diferentele tabloului $d. Va
reamintesc, pentru a observa mai bine afisarea unui tablou cu functia print_r() trebuie sa va uitati in sursa browser-ului, pentru a vedea fiecare element
pe cate o linie.

In functie si de inregistrarile pe care le aveti in tabel, veti obtine ceva similar cu:
mysql_fetch_row() mysql_fetch_assoc() mysql_fetch_array()

Array Array Array


( ( (
[0] => 5 [utilizatorId] => 5 [0] => 5
[1] => anamaria [username] => [utilizatorId] => 5
[2] => anamaria [1] => anamaria
anamaria23@gmail.com [email] => [username] =>
) anamaria23@gmail.com anamaria
Array ) [2] =>
( Array anamaria23@gmail.com
[0] => 4 ( [email] =>
[1] => vasile [utilizatorId] => 4 anamaria23@gmail.com
[2] => [username] => )
vasile@yahoo.com vasile Array
) [email] => (
Array vasile@yahoo.com [0] => 4
( ) [utilizatorId] => 4
[0] => 3 Array [1] => vasile
[1] => ion ( [username] =>
[2] => [utilizatorId] => 3 vasile
ion_popescu@yahoo.com [username] => ion [2] =>
) [email] => vasile@yahoo.com
ion_popescu@yahoo.com [email] =>
) vasile@yahoo.com
)
Array
(
[0] => 3
[utilizatorId] => 3
[1] => ion
[username] => ion
[2] =>
ion_popescu@yahoo.com
[email] =>
ion_popescu@yahoo.com
)

Obtin deci exact informatiile pe care intentionam sa le obtin cu instructiunea sql respectiva. Cateva explicatii referitoare la ceea ce se intampla in
scriptul select.php:

 mysql_query() returneaza o valoare de tip resource, ce contine setul de inregistrari, si pastram aceasta valoare in variabila $result

 ganditi-va la $result ca la un tabel temporar (cu coloane si linii) ce poate fi accesat doar prin functiile mysql_fetch_row(),
mysql_fetch_assoc(), mysql_fetch_array()

 "tabelul temporar" sau setul de inregistrari tinut in $result, are exact atatea coloane cate am specificat in clauza SELECT, si atatea randuri cat
ne returneaza query-ul (instructiunea sql) respectiva, in functie de clauza WHERE sau LIMIT pe care o specificam. Deci nu neaparat are
numarul de coloane (sau randuri) al tabelului original.

 functiile de tip mysql_fetch_*() au urmatoarea proprietate: de fiecare data cand se apeleaza, extrag sub forma de tablou doar o inregistrare
(un rand) din setul de inregistrari, incepand cu prima inregistrare. Dupa ce a fost extrasa o inregistrare, pointerul intern al variabilei $result
inainteaza la urmatoarea inregistrare (similar cu functia next() de la tablouri). La urmatoarea apelare, extrage intr-un tablou urmatoarea
inregistrare, muta pointer-ul....etc. Astfel, daca stim sigur ca avem un singur rezultat (o singura inregistrare) obtinut prin instructiunea sql,
putem folosi direct $d = mysql_fetch_assoc($result). Daca avem mai multe randuri, trebuie sa folosim constructia while ($d =
mysql_fetch_assoc($result)) {...

 explicatia constructiei while ($d = mysql_fetch_assoc($result)) { este urmatoarea: desi poate la prima vedere ar trebui sa se foloseasca
operatorul de comparare "==" si nu cel de atribuire "=", aici nu se intentioneaza comparatia lui $d cu mysql_fetch_assoc($result) ci se
atribuie rezultatul lui mysql_fetch_assoc($result) variabilei $d. Astfel, $d devine prima inregistrare, se executa bucla, $d devine a doua
inregistrare, etc. In momentul cand pointer-ul din $result ajunge la sfarsit, mysql_fetch_assoc($result) va returna false. In momentul cand
false este atribuit variabilei $d, valoarea expresiei $d = false este valoarea atribuita adica false; in acel moment bucla while se opreste.

Transformarea scriptului select.php din script didactic in script folositor, pe intelesul utilizatorului, este simpla:

select2.php
1 <?php
2 include("conectare.php");
3
4 $sql = 'SELECT utilizatorId, username, email FROM utilizatori ORDER
5 BY utilizatorId DESC LIMIT 3';
6 $result = mysql_query($sql) or die(mysql_error());
7
8 $str = '<table border="1" style="border-collapse: collapse;border:
9 1px solid gray;" cellpadding="3">';
10
11 $str .= '<tr>';
12 $str .= '<th>utilizatorId</th>';
13 $str .= '<th>username</th>';
14 $str .= '<th>email</th>';
15 $str .= '</tr>';
16
17
18 while ($d = mysql_fetch_assoc($result)) {
19 $str .= '<tr>';
20 $str .= '<td>' . $d["utilizatorId"] . '</td>';
21 $str .= '<td>' . $d["username"] . '</td>';
22 $str .= '<td>' . $d["email"] . '</td>';
23 $str .= '</tr>';
24 }
25
26 $str .= '</table>';
27
28 echo $str;

?>

8.2.6. Alte functii mysql


Obtinerea numarului de randuri dintr-un SELECT
Se poate face in doua moduri, in functie de ce avem nevoie:

1. Daca vrem sa obtinem informatie din tabelul respectiv, si sa numaram randurile din variabila $result obtinuta, putem folosimysql_num_rows() cu
urmatorul prototip:
int mysql_num_rows ( resource $result )

Exemplu:

select.php
1 <?php
2 include("conectare.php");
3
4 $sql = 'SELECT utilizatorId, username, email FROM utilizatori WHERE
5 sex = "m" ORDER BY utilizatorId ';
6 $result = mysql_query($sql) or die(mysql_error());
7
8 if (mysql_num_rows($result) > 0) {
9 $str = 'Am obtinut <b>' . mysql_num_rows($result). ' </b> rezultate
10 <br />';
11
12 $str .= '<table border="1" style="border-collapse: collapse;border:
13 1px solid gray;" cellpadding="3">';
14
15 $str .= '<tr>';
16 $str .= '<th>utilizatorId</th>';
17 $str .= '<th>username</th>';
18 $str .= '<th>email</th>';
19 $str .= '</tr>';
20
21
22 while ($d = mysql_fetch_assoc($result)) {
23 $str .= '<tr>';
24 $str .= '<td>' . $d["utilizatorId"] . '</td>';
25 $str .= '<td>' . $d["username"] . '</td>';
26 $str .= '<td>' . $d["email"] . '</td>';
27 $str .= '</tr>';
28 }
29
30 $str .= '</table>';
31
32 } else {
33 $str = 'Nu am obtinut nici un rezultat';
34 }
35
echo $str;

?>
2. Daca vrem doar sa numaram randurile obtinute printr-un SELECT, optim este sa obtinem numarul de randuri direct din MySQL cu sintaxa SELECT
count(*) ...

1 <?php
2 include("conectare.php");
3
4 $sql = 'SELECT COUNT(*) FROM utilizatori WHERE sex = "m" ORDER BY
5 utilizatorId ';
6 $result = mysql_query($sql) or die(mysql_error());
7
8 /*
9 folosim mysql_fetch_row() pentru ca setul de inregistrari are o
10 singura coloana si un singur rand.
11 $d[0] este informatia cautata
12 */
13
14 $d = mysql_fetch_row($result);
15
echo 'Am gasit <b>' . $d[0] . '</b> inregistrari. ' ;
?>

Obtinerea numarului de randuri afectate de un UPDATE, SELECT, INSERT, DELETE


Reamintim functia mysql_affected_rows() cu urmatorul prototip:
Pseudocod
int mysql_affected_rows ([ resource $link_identifier ] )
Parametrul primit de aceasta functie este optional, reprezinta conexiunea catre baza de date, in lipsa acestui parametru se foloseste conexiunea curenta.
Returneaza numarul de randuri afectate de ultimul query trimis catra baza de date respectiva. Query-ul trebuie sa fie de tipul: UPDATE, SELECT, INSERT,
DELETE.

Obtinerea numelor si numarului de coloane din $result


Uneori, vrem sa obtinem in mod dinamic numele coloanelor dintr-un set de inregistrari. Apelam functia mysql_field_name($result, $index), unde $result
este bineinteles rezultatul apelarii unui query de tip SELECT cu mysql_query() si $index este pozitia coloanei din setul de inregistrari. Numarul coloanelor il
obtinem cu mysql_num_fields($result).

1 <?php
2 include("conectare.php");
3
4 $sql = 'SELECT utilizatorId, username, email FROM utilizatori WHERE
5 sex = "m" ORDER BY utilizatorId ';
6 $result = mysql_query($sql) or die(mysql_error());
7
8 echo '<table border="1">';
9 echo '<tr>';
10
11 for ($i = 0; $i < mysql_num_fields($result); $i++) {
12 $numeCamp = mysql_field_name($result, $i);
13 echo '<th>'.$numeCamp.'</th>';
14 }
15
16 echo '</tr>';
17
18 echo '</table>'
19
?>

Obtinerea in PHP a structurii unui tabel MySQL


Desi mai rar, avem poate uneori nevoia sa obtinem informatiile despre coloanele unui tabel MySQL. Putem folosi instructiunea sql 'SHOW COLUMNS
FROM nume_tabel' si voi obtine un set de inregistrari cu o inregistrare pentru fiecare coloana a tabelului.

1 <?php
2 include("conectare.php");
3
4 $sql = 'SHOW COLUMNS FROM utilizatori';
5 $result = mysql_query($sql) or die(mysql_error());
6
7 while ($d = mysql_fetch_assoc($result)) {
8 print_r($d);
9 }
10 ?>

Folosirea functiei mysql_real_escape_string()


Folosirea acestei functii (sau altor functii similare) ne fereste de atacurile tip "SQL Injection Attack" prin care atacatorul completeaza anumite valori in
formularele HTML (sau parametri GET) astfel incat samodifice instructiunea sql folosita de noi in script. Aceasta functie anuleaza orice caracter special
(ghilimea simpla ('), dubla ("), newline (\n) ) din string-ul respectiv prin adaugarea caracterului backslash (\) in fata acestor caractere. Astfel, in
instructiunea sql orice caractere speciale isi pierd semnificatia. Daca tabelul nostru ar avea o coloana de parola, o instructiune sql pentru autentificare
(gasirea unui utilizator cu un username si o parola) ar arata astfel:

1 <?php
2 include("conectare.php");
3
4 $username = $_POST["username"];
5 $parola = $_POST["parola"];
6
7
8 if (get_magic_quotes_gpc()) {
9 $username = stripslashes($username);
10 $parola = stripslashes($parola);
11 }
12
13 $username = mysql_real_escape_string($username);
14 $parola = mysql_real_escape_string($parola);
15
16 $sql = "SELECT * FROM utilizatori WHERE username = '$username' AND
17 parola = '$parola' ";
18 echo $sql;
19 $result = mysql_query($sql) or die(mysql_error());
20
21 while ($d = mysql_fetch_assoc($result)) {
22 print_r($d);
23 }
?>

Nota
Exista o setare in php.ini (fisierul de configurare al PHP-ului) numita magic_quotes_gpc. Aceasta setare nu poate fi modificata cu ajutorul functiei
ini_set() deci este in controlul celui care administreaza serverul respectiv (desi pot fi gasite metode "pe langa", vezi Resurse). Aceasta setare a
devenit invechita, insa este folosita inca implicit pe serverele de gazduire la configurarea PHP-ului. Cand este setata (are valoarea 1), toate
informatiile ce ajung de la utilizator (din get, post sau cookie) vor fi modificate astfel incat sa aiba backslash (\) in fata caracterelor ghilimea simpla
('), ghilimea dubla (") sau NULL. Puteti verifica daca aceasta setare este activa folosind functia get_magic_quotes_gpc(). Daca returneaza 1,
inseamna ca setarea este activa, si pentru a obtine string-ul initial trebuie sa-i aplicati functia stripslashes() ce scoate backslash-urile. Apoi, daca
folositi valorile respective in instructiuni sql, le puneti la loc dar cu mysql_real_escape_string().

Nota
Subiectele "SQL Injection Attack", si "escape-ul" sirurilor de caractere primite de la utilizator este ceva mai amplu si nu vor fi dezbatute pe larg aici.
Puteti consulta linkurile din sectiunea Resurse pentru mai multa informatie.

Resurse
http://www.php.net/manual/en/info.configuration.php#ini.magic-quotes-gpc
http://www.php.net/manual/en/security.database.sql-injection.php
http://www.php.net/manual/en/security.magicquotes.php

8.3. Extensia mysqli


8.3.1 Functiile mysqli_*
8.3.2 Folosirea tranzactiilor cu MySQL din PHP
8.3.3 Folosirea "prepared statements"
8.3.4 Interfata obiectuala a mysqli
8.3.1. Functiile mysqli_*
Extensia mysqli contine atat interfata procedurala (set de functii) cat si interfata orientata obiect (clase si metode) pentru lucrul cu MySQL din PHP. Deci
aceeasi functionalitate este oferita de fiecare din modalitatile de lucru alese (cu functii sau cu clase si metode), alegerea este a programatorului.
In continuare voi prezenta principalele functii din extensia mysqli, ce sunt foarte asemanatoare (ca nume si functionalitate) cu cele din extensia mysql,
cu urmatoarele diferente de retinut:

 numele functiilor incep cu mysqli_

 mysqli_connect() primeste un al patrulea argument - numele bazei de date selectate astfel incat sa nu mai fie nevoie apelarea functiei
mysqli_select_db()

 variabila ce pastreaza conexiunea la baza de date (returnata de functia mysqli_connect()), denumita in general $link, va fi necesara ca prim
argument la functii ce au nevoie de o conexiune activa, cum ar fi mysqli_query(). In functiile din extensiamysql acest argument era pe a 2-a
pozitie pentru mysql_query() si era optional.

 exista doua functii suplimentare pentru detectarea erorilor, mai precis pentru detectarea erorilor la conectare. Acestea sunt
mysqli_connect_error() - returneaza mesajul erorii, si mysqli_connect_errno(). Celelalte functii ce returneaza ultima eroare generata de
serverul MySQL sunt similare, si anume: mysqli_error() si mysqli_errno().

 functia mysqli_query() primeste un al treilea parametru, constanta MYSQLI_USE_RESULT (implicit) sau MYSQLI_STORE_RESULT.

o daca este folosit MYSQLI_STORE_RESULT setul de rezultate este extras integral in memoria calculatorului pe care ruleaza PHP
dar permite un acces rapid la inregistrari

o daca este folosit MYSQLI_USE_RESULT inregistrarile din setul de rezultate sunt extrase din serverul MySQL pe masura ce sunt
accesate in PHP. Acest mod de lucru este potrivit pentru seturi mari de inregistrari, caz in care informatia nu trebuie stocata
integral in memorie.

Codul de conectare la baza de date folosind functia mysqli_connect() ar putea arata astfel:

conectare.php
1 <?php
2
3 $db_host = 'localhost';
4 $db_user = 'root';
5 $db_pass = '';
6 $db_name = 'mysite';
7
8
9 $link = @mysqli_connect($db_host, $db_user, $db_pass, $db_name);
10
11 if (!$link) {
12 die('Eroare la conectare: ' . mysqli_connect_error());
13 }
14
15 ?>

Functia mysqli_connect() va returna FALSE in cazul esuarii conexiunii, si un obiect de tip mysqli in caz de succes, sau mai simplu, o variabila ce reprezinta
conexiunea la serverul MySQL.

Scriptul prin care realizam un select dintr-un tabel, devine:

select.php
1 <?php
2
3 include("conectare.php");
4
5 $sql = 'SELECT * FROM utilizatori';
6 $result = mysqli_query($link, $sql);
7
8 while ($d = mysqli_fetch_assoc($result)) {
9 print_r($d);
10 }
11
12
13 ?>
Nota
Restul functiilor sunt si ele asemanatoare cu cele din extensia mysql: mysqli_fetch_row(), mysqli_fetch_array(), mysqli_num_rows(),
mysqli_affected_rows(), ....

Resurse
http://www.php.net/manual/en/book.mysqli.php
http://www.php.net/manual/en/mysqli.summary.php

8.3.2. Folosirea tranzactiilor cu MySQL din PHP


Ce sunt tranzactiile ?
In sistemele de baze de date tranzactiile sunt un concept important si foarte necesar in anumite cazuri. Tranzactiile inseamna suport din partea serverului
de baze de date pentru tratarea unei secvente de instructiuni sql ca un grup unitar. Practic, una din consecintele principale este ca aceste instructiuni sql
se executa toate cu succes, sau nici una.
Un exemplu usor de inteles pentru necesitatea tranzactiilor este cel in care lucram cu baza de date a unei banci, si avem un tabel conturi in care operam
mutarea unei sume dintr-un cont in altul.
Cele doua query-uri arata astfel:
query 1: UPDATE conturi SET sold = sold - 100 WHERE clientId = 23;
query 2: UPDATE conturi SET sold = sold + 100 WHERE clientId = 499;
Daca dintr-un motiv query 2 nu este executat (pana de curent, eroare de aplicatie, etc) atunci scade soldul primului client dar suma nu se muta in contul
celui de-al doilea client, lucru ce nu corespunde cu realitatea si apare astfel o inconsistenta a bazei de date. Grupand aceste doua query-uri intr-o
tranzactie, serverul MySQL executa aceste instructiuni dar nu le face permanente, astfel incat daca una din ele esueaza instructiunile pot fi anulate (un fel
de undo). Plus ca, in timp ce o tranzactie se desfasoara, ceilalti clienti ce se conecteaza la serverul MySQL nu citesc datele modificate decat daca tranzactia
este incheiata.

Tranzactiile in MySQL. Un simplu exemplu.


Tranzactiile au aparut in MySQL incepand cu versiunea 4.0 si sunt suportate de tipul de tabele InnoDB. In MySQL exista mai multe tipuri de tabele sau
"storage engines" cum le numeste echipa MySQL. Cele mai folosite sunt MyISAM, tipul implicit pentru tabelele noi create. InnoDB are ca principal avantaj
fata de MyISAM suportul pentru tranzactii. Pentru diferitele tipuri de "storage engines" si diferentele dintre ele consultati sectiunea Resurse. Deci, inainte
sa testati sau sa folositi tranzactiile, asigurati-va ca lucrati pe un tabel InnoDB. In MySQL exista urmatoarele instructiuni principale ce ne ajuta sa lucram
cu tranzactii:

 START TRANSACTION; sau BEGIN;- incepe o tranzactie

 COMMIT; - finalizeaza tranzactia curenta

 ROLLBACK - daca tranzactia nu s-a finalizat, putem sa anulam instructiunile executate pana atunci din cadrul tranzactiei

MySQL lucreaza in mod implicit in modul AUTOCOMMIT, adica automat fiecare instructiune ce nu face parte dintr-o tranzactie este finalizata (ca si cum am
specifica COMMIT; la sfarsitul ei). Pot sa schimb acest comportament cu instructiunea sql: SET AUTOCOMMIT = 0;
Pentru a vedea la un moment dat ce valoare are variabila AUTOCOMMIT (0 sau 1) pot folosi instructiunea: SELECT @@autocommit;

Utilizand baza de date mysite, si doua linii de comanda mysql (deci doi clienti MySQL conectati in acelasi timp la server) voi sterge utilizatorul horatiu,
avand utilizatorId = 1 din tabelul utilizatori, si mesajele corespondente din tabelul mesaje. Folosind tranzactii: am posibilitatea sa anulez oricand
instructiunile realizate inainte de finalizarea tranzactiei, si in plus, voi observa cum celalalt client conectat nu vede modificarea decat atunci cand tranzactia
este incheiata.

1. In prima etapa, in conexiunea principala (stanga) transform tabelele bazei de date mysite la tipul InnoDB, pentru a avea acces la lucrul cu tranzactii pe
aceste tabele.
Selectez apoi inregistrarile utilizatorului cu utilizatorId = 1 din ambele tabele.
2. Incep tranzactia, cu START TRANSACTION. Rezultatul query-urilor din tranzactie se vad in conexiunea principala (deci randurile sunt sterse), dar
conexiunea din dreapta nu vede efectul query-urilor din tranzactia in derulare.
3. Folosind instructiunea ROLLBACK am posibilitatea sa anulez query-urile din tranzactia respectiva (daca detectez de exemplu ca un query nu s-a
executat cu succes), pentru ca tranzactia nu a fost inca finalizata, deci modificarile nu au fost
permanente.
4. a. Reiau tranzactia, execut START TRANSACTION
b. Execut cele doua instructiuni DELETE
c. In conexiunea din dreapta realizez instructiunile SELECT, inregistrarile sunt inca acolo, pentru ca tranzactia din prima conexiune nu a fost finalizata
d. In conexiunea din stanga, execut COMMIT
e. Instructiunile au fost executate, sunt permanente, se vad si pentru celelalte conexiuni
Folosirea tranzactiilor in MySQL din PHP
Extensiile mysqli si PDO permit lucrul cu tranzactiile MySQL. Functiile mysqli pentru folosirea tranzactiilor sunt:

1. mysqli_autocommit - seteaza modul autocommit pentru conexiunea $link


Pseudocod
bool mysqli_autocommit ( mysqli $link , bool $mode )

2. mysqli_commit - echivalent cu instructiunea COMMIT - finalizeaza o tranzactie


Pseudocod
bool mysqli_commit ( mysqli $link )

3. mysqli_rollback - echivalent cu ROLLBACK - anuleaza tranzactia curenta si query-urile executate pana atunci
Pseudocod
bool mysqli_rollback ( mysqli $link )

Exemplu:

1 <?php
2 include("conectare.php");
3
4 $rollback = 0;
5
6 $sql[] = 'DELETE FROM utilizatori WHERE utilizatorId = 1';
7 $sql[] = 'DELETE FROM mesaje WHERE utilizatorId = 1';
8
9
10 mysqli_autocommit($link, false);
11
12 foreach ($sql as $s) {
13 $ok = mysqli_query($link, $s);
14
15 if ($ok === FALSE) $rollback = 1; // daca un query returneaza FALSE
16 (a esuat), variabila rollback devine 1
17
18 }
19
20 if ($rollback == 1) {
21 mysqli_rollback($link);
22 } else {
23 mysqli_commit($link);
24 }
?>

Nota
Desi tranzactiile reprezinta un element important al bazelor de date, intr-o aplicatia web medie probabil nu e nevoie in general de tranzactii. Daca in
schimb se lucreaza cu date financiare sau alte date sensibile in care e extrem important sa se pastreze consistenta datelor si baza de date (implicit
website-ul) este foarte accesata, si mai mult, exista probabilitatea reala ca mai multi utilizatori sa citeasca/modifice acelasi randuri dintr-un tabel
atunci tranzactiile devin necesare. Daca insa folositi tranzactii, trebuie sa lucrati cu tabele InnoDB.

Nota
Pentru alte exemple ce demonstreaza avantajele tranzactiilor, si pentru mai multe informatii, consultati linkurile din sectiunea Resurse

Resurse
http://dev.mysql.com/doc/refman/5.1/en/ansi-diff-transactions.html
http://dev.mysql.com/doc/refman/5.1/en/storage-engines.html
http://dev.mysql.com/doc/refman/5.1/en/commit.html
http://www.databasejournal.com/features/mysql/article.php/10897_3382171_1/Transactions-in-MySQL.htm
http://www.devshed.com/c/a/MySQL/Using-Transactions-In-MySQL-Part-1/

8.3.3. Folosirea "prepared statements"


Utilizarea "prepared statements" (procedurilor stocate) permite refolosirea unei instructiuni MySQL cu argumente diferite , si prezinta urmatoarele
avantaje:

 in general sunt mai rapide decat varianta clasica (trimiterea unei instructiuni sql complete catre MySQL) datorita faptului ca instructiunea sql
a fost deja compilata pe server MySQL, si nu se transmit spre server decat parametrii necesari

 sunt mai sigure pentru ca parametrii folositi in query, trimisi catre server, sunt automat verificati, iar toate caracterele speciale sunt anulate,
precedate de backslash. Este ca si cum valorile primite de server ar fi trecute prin functia mysql_real_escape_string

Exemplu:

1 <?php
2 include("conectare.php");
3
4 $sql = 'SELECT subiect, mesaj, dataMesaj FROM mesaje WHERE
5 DATE_FORMAT(dataMesaj, "%Y-%m-%d") = ? AND utilizatorId = ? ORDER BY
6 dataMesaj DESC';
7 $stmt = mysqli_prepare($link, $sql);
8
9
10 $dataMesaj = '2009-04-27';
11 $utilizatorId = 1;
12
13 mysqli_stmt_bind_param($stmt, 'sd', $dataMesaj, $utilizatorId);
14 mysqli_stmt_execute($stmt);
15
16 mysqli_bind_result($stmt, $subiect, $mesaj, $dataMesaj);
17
18 echo '<table border="1">';
19 while (mysqli_stmt_fetch($stmt)) {
20 // vezi capitolul Tipuri de date - string - heredoc
21 echo <<<A
22 <tr>
23 <td>$subiect</td>
24 <td>$mesaj</td>
25 <td>$dataMesaj</td>
26 </tr>
27 A;
28
29 } /// while
30
31 echo '</table>';

?>

Functiile folosite in acest exemplu sunt:

 mysqli_prepare - primeste ca parametru o variabila a conexiunii la baza de date ($link) si o instructiune sql ($query) ce reprezinta
procedura stocata ("the prepared statement"). In aceasta instructiune sql, parametrii sau valorile pe care vrem sa le transmitem ulterior, sunt
inlocuite cu semnul intrebarii (?) . Functia returneaza o variabila (obiect) de tip mysqli_stmt.

Pseudocod

mysqli_stmt mysqli_prepare ( mysqli $link , string $query )

 mysqli_bind_param - primeste ca prim parametru o variabila de tip mysqli_stmt (returnata de mysqli_prepare), apoi un string format din
litere ce reprezinta tipul parametrilor transmisi catre instructiunea sql, astfel: i pentru integer, d pentru double, s pentru string, b pentru blob.
De la al treilea parametru in sus, se primesc numele variabilelor al caror continut va fi transmis catre server pentru a inlocui simbolul ? in
procedura stocata. Astfel, daca vreau sa trimit un string si un intreg, functia va fi apelata de exemplu: mysqli_stmt_bind_param($stmt, 'si',
$nume, $varsta);

Pseudocod

bool mysqli_stmt_bind_param ( mysqli_stmt $stmt , string $types , mixed &$var1 [, mixed &$... ] )

 mysqli_stmt_execute - executa o variabila de tip mysqli_stmt, deci o "prepared statement", sau procedura stocata. Procedura a fost initial
pregatita (trimisa catre server) cu mysqli_prepare(), apoi au fost trimise si valorile parametrilor prin mysqli_bind_param. la apelarea acestei
functii, instructiunea este executata pe serverul MySQL.

Pseudocod

bool mysqli_stmt_execute ( mysqli_stmt $stmt )

 mysqli_bind_result - "leaga" numele unor variabile de valorile aflate la un moment dat intr-o inregistrare din setul de inregistrari

Pseudocod

bool mysqli_stmt_bind_result ( mysqli_stmt $stmt , mixed &$var1 [, mixed &$... ] )

 mysqli_stmt_fetch - extrage cate o inregistrare din setul de inregistrari obtinut prin executia query-ului, si la fiecare apelare (presupunem
ca o folosim intr-un while) va returna valorile obtinute pentru fiecare camp in variabilele "legate" cu mysqli_bind_result. Daca nu mai sunt
randuri in setul de inregistrari, va returna NULL.

Pseudocod

bool mysqli_stmt_fetch ( mysqli_stmt $stmt )

8.3.4. Interfata obiectuala a mysqli


Nota
Folosirea claselor si a altor concepte ale programarii orientate obiect vor fi explicate in detaliu in capitolul "Clase si obiecte".

Metodele clasele extensiei mysqli se regasesc si in interfata procedurala, dar bineinteles, putin modificate, in general cu mai putini parametri. In
documentatia oficiala PHP, sunt tratate in paralel. Exista 3 clase principale ale extensiei mysqli.

 mysqli - obiectele din aceasta clasa reprezinta conexiuni la serverul de baze de date.

 mysqli_stmt - reprezinta o procedura stocata (prepared statement)

 mysqli_result - obiectele contin rezultatele obtinute in urma executarii unui query. Metodele din aceasta clasa corespund functiilor
mysqli_fetch_row(), mysqli_fetch_array() si mysqli_fetch_assoc() si extrag informatiile din rezultatul executiei.
1 <?php
2
3 $db_host = 'localhost';
4 $db_user = 'root';
5 $db_pass = 'iesire';
6 $db_name = 'mysite';
7
8 $mysqli = @new mysqli($db_host, $db_user, $db_pass, $db_name);
9
10 if (mysqli_connect_error()) {
11 die('Eroare conexiune: ' . mysqli_connect_error());
12 }
13
14 $sql = 'SELECT * FROM utilizatori';
15 $result = $mysqli->query($sql);
16
17 while ($d = $result->fetch_assoc()) {
18 print_r($d);
19 }
20
21 ?>

Resurse
http://www.php.net/manual/en/book.mysqli.php
http://www.php.net/manual/en/mysqli.connect.php
http://www.php.net/manual/en/mysqli.query.php
http://www.php.net/manual/en/mysqli-result.fetch-assoc.php

8.4. Mini aplicatie

(select, insert, update, delete)


8.4.1 Adauga (insert)
8.4.2 Actualizeaza (update)
8.4.3 Afiseaza (select)
8.4.4 Sterge (delete)
8.4.5 Descarca arhiva aplicatie

Voi continua cu prezentarea unei simple aplicatii ce realizeaza operatiile de baza asupra unui tabel numit utilizatori, din PHP. Prin aceasta aplicatie oferim o
interfata pentru adaugarea, modificarea, sau stergerea utilizatorilor. Aceasta suita de operatii este foarte des intalnita in lucrul cu PHP si MySQL datorita
nevoii de administrare a datelor unui website.
Realizati in phpMyAdmin o baza de date numita myapp, si rulati codul sql pentru crearea tabelului utilizatori: myapp.sql

Inainte sa incepem, cateva lucruri:

 Puteti descarca direct aplicatia in ultimul subcapitol din aceasta serie

 Vor fi prezentate la fiecare script in parte doar elementele care sunt considerate mai dificile sau noi fata de a fost prezentat pana acum in curs

 Denumirea fisierelor, variabilelor a fost facuta in acest caz pe cat posibil in limba romana, pentru o asimilare mai usoara. Insa, in aplicatiile
mai complexe din curs se va trece la denumirea tabelelor, coloanelor, variabilelor, functiilor in limba engleza. Este un stil de lucru ce
incurajeaza colaborarea dintre programatori (lucrul in echipe), si externalizarea aplicatiei (folosirea sau modificarea codului de programatori
de alta nationalitate) atunci cand e nevoie. In plus, e mai usor de integrat cu alte librarii/functii/aplicatii care au denumiri tot in limba engleza.

 Referitor la structura aplicatiei:

o myapp

 site

 common

 f-forms.php

 f-url.php

 f-vars.php

 css
 global.css

 lib

 conectare.php

 f-html.php

 start.php

 adaugaUtilizator.php

 afiseazaUtilizatori.php

 sterge.php

 myapp.sql

- myapp - este folder-ul proiectului. Tot ce e legat de proiect va fi in acest folder


- site - aici stau doar fisierele ce formeaza site-ul sau aplicatia. Orice fisier ce nu face parte direct din site este in afara acestui folder.
mysite.sql de exemplu, nu trebuie sa fie accesat de utilizatorii web, nu are ce cauta in interiorul folderului site
- site - are in acest caz 3 foldere (common, css, lib), si fisierele aplicatiei
- common - este un folder in care pastrez functii (sau clase) comune proiectelor web, generale, nespecifice unei anumite aplicatii. Aceste
functii sunt organizate in mai multe fisiere.
- lib - in acest folder am fisiere utile si specifice acestei aplicatii, ce trebuiesc incluse la un moment dat
- css - un folder in care pastrez stilurile css

8.4.1. Adauga (insert)

Adauga Utilizator.php este o continuare naturala a scriptului ce valideaza si pastreaza datele intr-un formular, prezentat insubcapitolul 6.6.4. Foarte
important, folosim scriptul adaugareUtilizator.php atat pentru adaugarea utilizatorilor cat si pentru modificarea lor datorita faptului ca cele doua operatii
(adaugare si modificare) au urmatoarele lucruri in comun:
- formularul html
- validarea datelor
- pastrarea datelor in formular
In momentul cand procesam formularul, in loc sa construim un mesaj pentru utilizator, de data asta redirectam catre scriptul de afisare al utilizatorilor.
Acest script php (ca si altele de altfel) nu trebuie vazut ca realizand un singur lucru, el executa diferite instructiuni in functie de ce parametri (din get sau
post) primeste. Astfel, se disting urmatoarele 3 cazuri (in cazul in care NU primim utilizatorId prin GET, si deci facem insert):

1. Se incarca adaugaUtilizator.php , fara nici un parametru in get sau post, deci formularul nu a fost apasat .
In acest caz, se executa instructiunea ce include start.php, se initializeaza variabilele $utilizatorId = '', $ceFacem = 'insert', $proceseaza = 0, $erori =
array() si $formFields avand campurile formularului. $formData este setat din POST, dar POST nu are date, astfel ca prin fragmentul de mai jos,

29 <?php
30 foreach ($formFields as $field) {
31 if (!isset($formData[$field]))
32 $formData[$field] = '';
33 }
34 ?>

initializam toate elementele $formData['campFormular'] cu sirul gol ''.


isset($formData["btnSubmit"]) in acest caz returneaza false, deci nu se executa instructiunile din acest if. In continuare, se apeleaza
functia html_start() ce incepe sa formeze codul html. Apoi, se construieste formularul, si cu ajutorul functiilor din common/f-forms.php

2. Se incarca adaugaUtilizator.php in momentul cand utilizatorul a apasat pe butonul de submit, avand elementele din POST. Si sunt
erori $formData este POST, doar elementele nesetate (ce au o cheie in $formFields dar nu in POST) devin sirul gol. In acest
caz isset($formData["btnSubmit"]) este true, deci intra in if. Detecteaza erorile, construieste variabila $erori, si NU proceseaza formularul. Apoi, intre liniile
179 si 189 se afiseaza erorile.
Pe baza array-ului $formData se construieste formularul deja completat cu informatiile tastate anterior de utilizator.

3. Utilizatorul a apasat pe submit, nu sunt erori. isset($formData["btnSubmit"]) este true, deci $proceseaza devine 1, si cum $ceFacem ='insert',
executam codul pentru adaugarea in baza de date:

155 <?php
156 if ($ceFacem == 'insert') {
157 // insert in baza de date
158 $sql = "INSERT INTO utilizatori (prenume, nume, utilizator,
159 parola, email, hobby, limbiStraine, mesaj, dataAdaugarii) VALUES
160 ('$prenume', '$nume', '$utilizator', '$parola', '$email', '$hobby',
161 '$limbiStraine', '$mesaj', now())";
mysqli_query($link, $sql);
} else {
?>
Apoi, cu ajutorul functiei redirect(), prezenta in common/f-url.php , redirectam catre afisarea utilizatorilor.

adaugaUtilizator.php
1 <?php
2 include("lib/start.php");
3
4
5 getpost('utilizatorId'); // functie ce preia variabila utilizatorId
6 din get sau post, indiferent de unde vine
7
8 // daca avem variabila utilizatorId setata, facem update
9 if (!isset($utilizatorId)) {
10 $utilizatorId = '';
11 $ceFacem = 'insert';
12 } else {
13 $ceFacem = 'update';
14 }
15
16
17 // variabile initiale
18 $proceseaza = 0;
19 $erori = array();
20 $formFields = array('prenume', 'nume', 'utilizator', 'parola',
21 'email', 'hobby', 'limbiStraine', 'mesaj');
22
23 /*
24 formData este de fapt informatia primita de la utilizator prin
25 formular si in plus informatia ce populeaza formularul
26 dar ca sa nu lucrez cu $_GET sau $_POST, voi lucra peste tot cu
27 formData
28 */
29 $formData = $_POST;
30
31 /*
32 orice camp din formular care nu este setat in $formData, va fi
33 initializat la sirul empty
34 */
35 foreach ($formFields as $field) {
36 if (!isset($formData[$field]))
37 $formData[$field] = '';
38 }
39
40
41 /*
42 in cazul in care facem update, si nu avem datele din post (deci am
43 incarcat formularul prima data),
44 populam formData din baza de date, cu informatiile utilizatorului
45 utilizatorId a fost extras din get cu ajutorul functiei getpost
46 */
47 if ($ceFacem == 'update' ) {
48
49 if (!isset($formData["btnSubmit"])) {
50 $sql = 'select * from utilizatori where utilizatorId = ' .
51 $utilizatorId;
52 $result = mysqli_query($link, $sql);
53 $dbData = mysqli_fetch_assoc($result);
54 $dbData["limbiStraine"] = explode(',',
55 $dbData["limbiStraine"]); // transformam din string avand cuvinte
56 separate prin virgula, in array -> pentru compatibilitate cu
57 formData si pentru generarea formularului
58 $dbData["hobby"] = explode(',', $dbData["hobby"]);
59 $formData = $dbData;
60 }
61
62 }
63
64 /*
65 echo 'POST: ';
66 echo '<pre>';
67 print_r($_POST);
68 echo '</pre>';
69 echo '<br />';
70 echo '<br />';
71 echo 'formData: ';
72 echo '<pre>';
73 print_r($formData);
74 echo '</pre>';
75 */
76
77
78 // initData este un array cu informatii pentru popularea unor
79 elemente din formularul initial
80 // (cum ar fi select-ul) pentru limbi straine
81
82 $initData["limbiStraine"] = array(
83 'Romana' => 'Romana',
84 'Engleza' => 'Engleza',
85 'Spaniola' => 'Spaniola',
86 'Germana' => 'Germana'
87 );
88
89
90 if (isset($formData["btnSubmit"])) { // daca s-a apasat butonul de
91 submit
92
93
94 // preluarea variabilelor din formData
95 $prenume = $formData["prenume"];
96 $nume = $formData["nume"];
97 $utilizator = $formData["utilizator"];
98 $parola = $formData["parola"];
99 $email = $formData["email"];
100 $hobby = $formData["hobby"];
101 $limbiStraine = $formData["limbiStraine"];
102 $mesaj = $formData["mesaj"];
103
104 // verificarea erorilor
105
106 if (!$prenume) {
107 $erori[] = 'Completeaza prenume';
108 } else if (!preg_match('/^[a-zA-Z\-\s\']{2,20}$/', $prenume)) {
109 $erori[] = 'Prenume invalid';
110 }
111
112
113 if (!$nume) {
114 $erori[] = 'Completeaza nume';
115 } else if (!preg_match('/^[a-zA-Z\-\s\']{2,20}$/', $nume)) {
116 $erori[] = 'Nume invalid';
117 }
118
119
120 if (!$utilizator) {
121 $erori[] = 'Completeaza utilizator';
122 } else if (!preg_match('/^[a-zA-Z\-0-9]{4,15}$/', $utilizator)) {
123 $erori[] = 'Utilizator invalid';
124 }
125
126 if (!$parola) {
127 $erori[] = 'Completeaza parola';
128 } else if (preg_match('/[\'\"]/', $parola)) {
129 $erori[] = 'Parola contine caractere invalide';
130 }
131
132
133 if (!$email) {
134 $erori[] = 'Completeaza emailul';
135 } else if (!preg_match('/(?i)[a-z0-9\.\-_\+]+@[a-z0-9\-]+\.([a-z0-
136 9\-]+\.)*+[a-z]{2}/', $email)) {
137 $erori[] = 'Email incorect';
138 }
139
140
141
142 if (!is_array($hobby)) {
143 $erori[] = 'Completeaza cel putin un hobby';
144 }
145
146
147 if (!is_array($limbiStraine)) {
148 $erori[] = 'Completeaza cel putin o limba straina';
149 }
150
151
152 // daca nu sunt erori, variabila $proceseaza devine 1
153 if (!count($erori)) {
154 $proceseaza = 1;
155 }
156
157
158 // daca variabila proceseaza este 1, procesam -> in cazul nostru
159 compunem mesajul de afisat pentru utilizator si-l tinem in variabile
160 $mesaj pentru afisarea lui ulterioara
161 if ($proceseaza) {
162 if (is_array($hobby)) {
163 $hobby = join(',', $hobby);
164 }
165
166 if (is_array($limbiStraine)) {
167 $limbiStraine = join(',', $limbiStraine);
168 }
169
170
171 if ($ceFacem == 'insert') {
172 // insert in baza de date
173 $sql = "INSERT INTO utilizatori (prenume, nume, utilizator,
174 parola, email, hobby, limbiStraine, mesaj, dataAdaugarii) VALUES
175 ('$prenume', '$nume', '$utilizator', '$parola', '$email', '$hobby',
176 '$limbiStraine', '$mesaj', now())";
177 mysqli_query($link, $sql);
178 } else {
179 // update in baza de date
180 $sql = "UPDATE utilizatori SET prenume='$prenume',
181 nume='$nume', utilizator='$utilizator', parola='$parola',
182 email='$email', hobby='$hobby', limbiStraine='$limbiStraine',
183 mesaj='$mesaj', ultimaModificare=now() WHERE utilizatorId =
184 $utilizatorId";
185 mysqli_query($link, $sql);
186 }
187
188 redirect('afiseazaUtilizatori.php');
189
190 } /// end if proceseaza
191
192
193 } /// end if (isset($formData["buton"])) {
194
195
196 html_start();
197
198 echo '<a href="afiseazaUtilizatori.php">Afiseaza
199 utilizatori</a><br />';
200
201 // daca sunt erori, le afisam
202 if (isset($erori) && is_array($erori) && count($erori)) {
203
204 echo '<br />';
205 echo '<div class="errors">';
206 foreach ($erori as $eroare) {
207 echo $eroare;
208 echo '<br />';
209 } /// end foreach
210 echo '</div>';
211
212 } //// end if(isset($erori))
213
214
215 if (!$proceseaza) { ?>
216
217 <br /><br />
218
219 <!-- begin form -->
220 <form method="post" action="">
221 <?php if ($ceFacem == 'update') echo form_hidden('utilizatorId',
222 $utilizatorId); ?>
223
224 <table border="0" cellspacing="0" cellpadding="3">
225 <tr>
226 <td>Prenume</td>
227 <td><?php echo form_input('prenume', $formData["prenume"]) ?
228 ></td>
229 </tr>
230 <tr>
231 <td>Nume</td>
232 <td><?php echo form_input('nume', $formData["nume"]) ?></td>
233 </tr>
234 <tr>
235 <td>Utilizator</td>
236 <td><?php echo form_input('utilizator',
237 $formData["utilizator"]) ?></td>
238 </tr>
239 <tr>
240 <td>Parola</td>
241 <td><?php echo form_pass('parola', $formData["parola"]) ?
242 ></td>
243 </tr>
244 <tr>
245 <td>Email</td>
246 <td><?php echo form_input('email', $formData["email"]) ?
247 ></td>
248 </tr>
249 <tr>
250 <td>Hobby</td>
251 <td>
Inot <?php echo form_ck('hobby', 'inot', $formData["hobby"]); ?
>
Ski <?php echo form_ck('hobby', 'ski', $formData["hobby"]); ?>
Alergat <?php echo form_ck('hobby', 'alergat',
$formData["hobby"]); ?>
Cantat <?php echo form_ck('hobby', 'cantat',
$formData["hobby"]); ?>
</td>
</tr>
<tr>
<td>Limbi straine</td>
<td>
<?php echo form_select('limbiStraine', 'multiple',
$initData["limbiStraine"], $formData["limbiStraine"], 'size="4"') ?>
</td>
</tr>
<tr>
<td>Mesaj</td>
<td><?php echo form_textarea('mesaj', 20, 20,
$formData["mesaj"]); ?></td>
</tr>
<tr>
<td></td>
<td><br /><br /><?php echo form_button('btnSubmit',
'Trimite'); ?></td>
</tr>

</table>
</form>
<!-- end form -->

<?php } /// if !proceseaza ?>

<?php echo html_end(); ?>

8.4.2. Actualizeaza (update)

Acelasi script este si pentru update. Insa, aici avem alte trei cazuri, pornind de la primirea parametrului utilizatorId prin GET. Exemplu:
adaugaUtilizator.php?utilizatorId=3

1. 1. Se incarca adaugaUtilizator.php?utilizatorId=3 si in acest caz avem doar informatie din GET..


- linia 5: getpost('utilizatorId') va fi echivalent in acest caz cu $utilizatorId = $_GET["utilizatorId"]; deci preluam valoarea parametrului get in variabila
$utilizatorId
- linia 12: variabila $ceFacem devine 'update';
- in fragmentul urmator de cod:

40 <?php
41 if ($ceFacem == 'update' ) {
42
43 if (!isset($formData["btnSubmit"])) {
44 $sql = 'select * from utilizatori where utilizatorId = ' .
45 $utilizatorId;
46 $result = mysqli_query($link, $sql);
47 $dbData = mysqli_fetch_assoc($result);
48 $dbData["limbiStraine"] = explode(',',
49 $dbData["limbiStraine"]); // transformam din string avand cuvinte
50 separate prin virgula, in array -> pentru compatibilitate cu formData
51 si pentru generarea formularului
52 $dbData["hobby"] = explode(',', $dbData["hobby"]);
53 $formData = $dbData;
}

}
?>

se vor executa instructiunile din interiorul acestor if-uri, pentru ca ambele conditii se respecta (facem update si nu s-a apasat inca pe submit). Aceste
instructiuni extrag datele pentru acel utilizatorId din tabelul utilizatori, sub forma variabilei de tip array $dbData. $dbData["limbiStraine"] si
$dbData["hobby"] sunt transformate in array, din string. Astfel, $formData devine $dbData, si va fi folosit de functiile formularului pentru a "umple"
formularul cu informatia din baza de date.
isset($formData["btnSubmit"]) nu este true, pentru ca formularul nu s-a apasat, deci nu intra in if.
Se construieste apoi formularul, folosind datele din $formData. Insa, un lucru foarte important, de data asta apare un camp in plus, un camp de tip
hidden, pentru a transmite mai departe (adica prin POST) variabila utilizatorId a carei valoare a fost initial obtinuta din GET.

2. Utilizatorul apasa pe butonul formularului, si sunt erori.


La aceasta incarcare a scriptului, se primesc doar date din POST, dar spre deosebire de insert, acum se primeste si utilizatorId din campul hidden generat
la cazul 1.
- linia 5: getpost('utilizatorId') va fi echivalent acum cu $utilizatorId = $_POST["utilizatorId"]
- linia 12: $ceFacem devine si de data asta 'update'
- liniile 44-49: instructiunile din interiorul acestui if nu se executa, pentru ca s-a apasat pe butonul formularului; prin urmare, $formData ramane cu
informatiile din POST cum era si normal, pentru ca desi facem update, utilizatorul a modificat informatiile din formular, si le-a retrasnmis. -
isset($formData["btnSubmit"]) este TRUE, intra in if-ul respectiv, daca sunt erori se construieste variabila $erori si apoi se afiseaza erorile si formularul.
$formData este folosit pentru a "umple" formularul de data asta nu cu informatiile din baza de date ci cu cele din POST.

3. Utilizatorul apasa pe butonul formularului, si NU sunt erori.


Similar cu pasul 2, dar de data asta intra in if (isset($formData["btnSubmit"])), $proceseaza devine 1, si se executa codul pentru update:

160 <?php
161 // update in baza de date
162 $sql = "UPDATE utilizatori SET prenume='$prenume',
163 nume='$nume', utilizator='$utilizator', parola='$parola',
164 email='$email', hobby='$hobby', limbiStraine='$limbiStraine',
165 mesaj='$mesaj', ultimaModificare=now() WHERE utilizatorId =
$utilizatorId";
mysqli_query($link, $sql);
}
?>

Apoi, utilizatorul este redirectat catre pagina de afisare.

adaugaUtilizator.php
1 <?php
2 include("lib/start.php");
3
4
5 getpost('utilizatorId'); // functie ce preia variabila utilizatorId
6 din get sau post, indiferent de unde vine
7
8 // daca avem variabila utilizatorId setata, facem update
9 if (!isset($utilizatorId)) {
10 $utilizatorId = '';
11 $ceFacem = 'insert';
12 } else {
13 $ceFacem = 'update';
14 }
15
16
17 // variabile initiale
18 $proceseaza = 0;
19 $erori = array();
20 $formFields = array('prenume', 'nume', 'utilizator', 'parola',
21 'email', 'hobby', 'limbiStraine', 'mesaj');
22
23 /*
24 formData este de fapt informatia primita de la utilizator prin
25 formular si in plus informatia ce populeaza formularul
26 dar ca sa nu lucrez cu $_GET sau $_POST, voi lucra peste tot cu
27 formData
28 */
29 $formData = $_POST;
30
31 /*
32 orice camp din formular care nu este setat in $formData, va fi
33 initializat la sirul empty
34 */
35 foreach ($formFields as $field) {
36 if (!isset($formData[$field]))
37 $formData[$field] = '';
38 }
39
40
41 /*
42 in cazul in care facem update, si nu avem datele din post (deci am
43 incarcat formularul prima data),
44 populam formData din baza de date, cu informatiile utilizatorului
45 utilizatorId a fost extras din get cu ajutorul functiei getpost
46 */
47 if ($ceFacem == 'update' ) {
48
49 if (!isset($formData["btnSubmit"])) {
50 $sql = 'select * from utilizatori where utilizatorId = ' .
51 $utilizatorId;
52 $result = mysqli_query($link, $sql);
53 $dbData = mysqli_fetch_assoc($result);
54 $dbData["limbiStraine"] = explode(',',
55 $dbData["limbiStraine"]); // transformam din string avand cuvinte
56 separate prin virgula, in array -> pentru compatibilitate cu
57 formData si pentru generarea formularului
58 $dbData["hobby"] = explode(',', $dbData["hobby"]);
59 $formData = $dbData;
60 }
61
62 }
63
64 /*
65 echo 'POST: ';
66 echo '<pre>';
67 print_r($_POST);
68 echo '</pre>';
69 echo '<br />';
70 echo '<br />';
71 echo 'formData: ';
72 echo '<pre>';
73 print_r($formData);
74 echo '</pre>';
75 */
76
77
78 // initData este un array cu informatii pentru popularea unor
79 elemente din formularul initial
80 // (cum ar fi select-ul) pentru limbi straine
81
82 $initData["limbiStraine"] = array(
83 'Romana' => 'Romana',
84 'Engleza' => 'Engleza',
85 'Spaniola' => 'Spaniola',
86 'Germana' => 'Germana'
87 );
88
89
90 if (isset($formData["btnSubmit"])) { // daca s-a apasat butonul de
91 submit
92
93
94 // preluarea variabilelor din formData
95 $prenume = $formData["prenume"];
96 $nume = $formData["nume"];
97 $utilizator = $formData["utilizator"];
98 $parola = $formData["parola"];
99 $email = $formData["email"];
100 $hobby = $formData["hobby"];
101 $limbiStraine = $formData["limbiStraine"];
102 $mesaj = $formData["mesaj"];
103
104 // verificarea erorilor
105
106 if (!$prenume) {
107 $erori[] = 'Completeaza prenume';
108 } else if (!preg_match('/^[a-zA-Z\-\s\']{2,20}$/', $prenume)) {
109 $erori[] = 'Prenume invalid';
110 }
111
112
113 if (!$nume) {
114 $erori[] = 'Completeaza nume';
115 } else if (!preg_match('/^[a-zA-Z\-\s\']{2,20}$/', $nume)) {
116 $erori[] = 'Nume invalid';
117 }
118
119
120 if (!$utilizator) {
121 $erori[] = 'Completeaza utilizator';
122 } else if (!preg_match('/^[a-zA-Z\-0-9]{4,15}$/', $utilizator)) {
123 $erori[] = 'Utilizator invalid';
124 }
125
126 if (!$parola) {
127 $erori[] = 'Completeaza parola';
128 } else if (preg_match('/[\'\"]/', $parola)) {
129 $erori[] = 'Parola contine caractere invalide';
130 }
131
132
133 if (!$email) {
134 $erori[] = 'Completeaza emailul';
135 } else if (!preg_match('/(?i)[a-z0-9\.\-_\+]+@[a-z0-9\-]+\.([a-z0-
136 9\-]+\.)*+[a-z]{2}/', $email)) {
137 $erori[] = 'Email incorect';
138 }
139
140
141
142 if (!is_array($hobby)) {
143 $erori[] = 'Completeaza cel putin un hobby';
144 }
145
146
147 if (!is_array($limbiStraine)) {
148 $erori[] = 'Completeaza cel putin o limba straina';
149 }
150
151
152 // daca nu sunt erori, variabila $proceseaza devine 1
153 if (!count($erori)) {
154 $proceseaza = 1;
155 }
156
157
158 // daca variabila proceseaza este 1, procesam -> in cazul nostru
159 compunem mesajul de afisat pentru utilizator si-l tinem in variabile
160 $mesaj pentru afisarea lui ulterioara
161 if ($proceseaza) {
162 if (is_array($hobby)) {
163 $hobby = join(',', $hobby);
164 }
165
166 if (is_array($limbiStraine)) {
167 $limbiStraine = join(',', $limbiStraine);
168 }
169
170
171 if ($ceFacem == 'insert') {
172 // insert in baza de date
173 $sql = "INSERT INTO utilizatori (prenume, nume, utilizator,
174 parola, email, hobby, limbiStraine, mesaj, dataAdaugarii) VALUES
175 ('$prenume', '$nume', '$utilizator', '$parola', '$email', '$hobby',
176 '$limbiStraine', '$mesaj', now())";
177 mysqli_query($link, $sql);
178 } else {
179 // update in baza de date
180 $sql = "UPDATE utilizatori SET prenume='$prenume',
181 nume='$nume', utilizator='$utilizator', parola='$parola',
182 email='$email', hobby='$hobby', limbiStraine='$limbiStraine',
183 mesaj='$mesaj', ultimaModificare=now() WHERE utilizatorId =
184 $utilizatorId";
185 mysqli_query($link, $sql);
186 }
187
188 redirect('afiseazaUtilizatori.php');
189
190 } /// end if proceseaza
191
192
193 } /// end if (isset($formData["buton"])) {
194
195
196 html_start();
197
198 echo '<a href="afiseazaUtilizatori.php">Afiseaza
199 utilizatori</a><br />';
200
201 // daca sunt erori, le afisam
202 if (isset($erori) && is_array($erori) && count($erori)) {
203
204 echo '<br />';
205 echo '<div class="errors">';
206 foreach ($erori as $eroare) {
207 echo $eroare;
208 echo '<br />';
209 } /// end foreach
210 echo '</div>';
211
212 } //// end if(isset($erori))
213
214
215 if (!$proceseaza) { ?>
216
217 <br /><br />
218
219 <!-- begin form -->
220 <form method="post" action="">
221 <?php if ($ceFacem == 'update') echo form_hidden('utilizatorId',
222 $utilizatorId); ?>
223
224 <table border="0" cellspacing="0" cellpadding="3">
225 <tr>
226 <td>Prenume</td>
227 <td><?php echo form_input('prenume', $formData["prenume"]) ?
228 ></td>
229 </tr>
230 <tr>
231 <td>Nume</td>
232 <td><?php echo form_input('nume', $formData["nume"]) ?></td>
233 </tr>
234 <tr>
235 <td>Utilizator</td>
236 <td><?php echo form_input('utilizator',
237 $formData["utilizator"]) ?></td>
238 </tr>
239 <tr>
240 <td>Parola</td>
241 <td><?php echo form_pass('parola', $formData["parola"]) ?
242 ></td>
243 </tr>
244 <tr>
245 <td>Email</td>
246 <td><?php echo form_input('email', $formData["email"]) ?
247 ></td>
248 </tr>
249 <tr>
250 <td>Hobby</td>
251 <td>
Inot <?php echo form_ck('hobby', 'inot', $formData["hobby"]); ?
>
Ski <?php echo form_ck('hobby', 'ski', $formData["hobby"]); ?>
Alergat <?php echo form_ck('hobby', 'alergat',
$formData["hobby"]); ?>
Cantat <?php echo form_ck('hobby', 'cantat',
$formData["hobby"]); ?>
</td>
</tr>
<tr>
<td>Limbi straine</td>
<td>
<?php echo form_select('limbiStraine', 'multiple',
$initData["limbiStraine"], $formData["limbiStraine"], 'size="4"') ?>
</td>
</tr>
<tr>
<td>Mesaj</td>
<td><?php echo form_textarea('mesaj', 20, 20,
$formData["mesaj"]); ?></td>
</tr>
<tr>
<td></td>
<td><br /><br /><?php echo form_button('btnSubmit',
'Trimite'); ?></td>
</tr>

</table>
</form>
<!-- end form -->

<?php } /// if !proceseaza ?>

<?php echo html_end(); ?>

8.4.3. Afiseaza (select)


Codul este simplu si clar. Extrag din tabelul utilizatori toate inregistrarile si le afisez. In plus, la fiecare inregistrare afisez un link Edit si Delete care trimite
catre scripturile respective, cu parametrul GET utilizatorId avand valoarea din baza de date pentru campul utilizatorId.

afiseazaUtilizatori.php
1 <?php
2 include("lib/start.php");
3
4 $sql = ' SELECT * FROM utilizatori';
5 $result = mysqli_query($link, $sql);
6
7
8 html_start();
9
10 echo '<a href="adaugaUtilizator.php">Adauga utilizator</a><br
11 /><br />';
12
13
14 if (mysqli_num_rows($result)) {
15
16 $str = '<table class="tdata">';
17
18 $str .= '
19
20 <tr>
21 <td class="thead">utilizatorId</td>
22 <td class="thead">prenume</td>
23 <td class="thead">nume</td>
24 <td class="thead">utilizator</td>
25 <td class="thead">parola</td>
26 <td class="thead">email</td>
27 <td class="thead">hobby</td>
28 <td class="thead">limbiStraine</td>
29 <td class="thead">mesaj</td>
30 <td class="thead">dataAdaugarii</td>
31 <td class="thead">ultimaModificare</td>
32 <td class="thead">Edit</td>
33 <td class="thead">Delete</td>
34 </tr>
35
36 ';
37
38
39 while ($d = mysqli_fetch_assoc($result)) {
40 $str .= '
41 <tr>
42 <td>'.$d["utilizatorId"].'</td>
43 <td>'.$d["prenume"].'</td>
44 <td>'.$d["nume"].'</td>
45 <td>'.$d["utilizator"].'</td>
46 <td>'.$d["parola"].'</td>
47 <td>'.$d["email"].'</td>
48 <td>'.$d["hobby"].'</td>
49 <td>'.$d["limbiStraine"].'</td>
50 <td>'.nl2br($d["mesaj"]).'</td>
51 <td>'.$d["dataAdaugarii"].'</td>
52 <td>'.$d["ultimaModificare"].'</td>
53 <td><a href="adaugaUtilizator.php?utilizatorId='.
54 $d["utilizatorId"].'">Edit</a></td>
55 <td><a href="sterge.php?ce=utilizator&utilizatorId='.
56 $d["utilizatorId"].'">Delete</a></td>
57 </tr>
58 ';
59 }
60
61 $str .= '</table>';
62
63 } else {
64 $str = 'Nu exista utilizatori in baza de date';
65 }
66
67 echo $str;

html_end();
?>

8.4.4. Sterge (delete)


Acest script este denumit sterge.php si nu stergeUtilizatori.php pentru ca poate fi un script general de stergere, si in functie de parametrul GET numit "ce"
sa stearga dintr-un tabel sau altul (in cazul in care aplicatia noastra ar fi fost ceva mai complexa, si ar fi avut si alte tabele).
Dupa executarea stergerii, redirectam utilizatorul inapoi la pagina de afisare.

sterge.php
1 <?php
2 include("lib/start.php");
3
4
5 $ce = $_GET["ce"];
6
7
8 if ($ce == 'utilizator') {
9
10 $utilizatorId = (int)($_GET["utilizatorId"]);
11 $sql = ' DELETE FROM utilizatori WHERE utilizatorId = '.
12 $utilizatorId.'';
13 mysqli_query($link, $sql);
14 redirect('afiseazaUtilizatori.php');
15 }
16
17
18
19
20
?>

8.4.5. Descarca arhiva aplicatie


Descarca codul aplicatiei aic

8.5. Tema
Tema 8-1

Folosind o baza de date compusa din cele doua tabele de la temele 7-1 si
7-2, adica un tabel de clienti si un tabel de incasari,
realizati aplicatia web care sa contina:

1. Adaugare clienti
2. Update clienti
3. Listare clienti
4. Stergere clienti

5. Adaugare incasare - cum o incasare este legata de clienti prin


coloana clientId din tabelul incasari, fiecare client in parte trebuie
sa aiba un link
numit "Adauga incasare", prin care sa transmiteti deja clientId-ul
incasarii pe care o adaugati
6. Lista incasari pe client - la fel, link pentru fiecare client in
parte.
7. Update incasare
8. Stergere incasare
9. Listare incasari in ordine invers cronologica (cele mai recente sus)
pentru toti clientii. Sa apara in tabel atat datele de baza ale
clientului (nume, prenume, email) cat si datele incasarii.
In acest tabel, folositi cate o culoare de background pentru fiecare tip
de incasare (Numerar, Banca, Alta .. sau ce aveti acolo).

Tema 8-2
1. Link de cautare clienti. In pagina respectiva e un input text, simplu
si un buton cauta.
In pagina in care se face cautarea, realizati un query folosind
operatorul sql LIKE.
Recomandat sa folositi pagina de Listare clienti de la tema anterioara
pentru listarea rezultatelor. Transmiteti parametrul de cautare prin
GET.
2. Clasament clienti - listarea clientilor in ordinea totalului
incasarilor. Prenume client, nume client, email, total incasari.
3. Introduceti incasari astfel incat sa aveti cateva incasari (1-3) pe
fiecare luna, mai multe luni consecutive.
Realizati la acest punct un tabel cu luna, si totalul de incasari.
Ex:

Ianuarie 1200 RON


Februarie 1320 RON
Martie 4200 RON
4. Folosind o imagine de un pixel de o singura culoare (bineinteles
folositi width si height pentru aceasta imagine), realizati un grafic
simplu
cu coloane care sa reflecte comparatia incasarilor pe luni.

CAP.9. Lucrul cu fisiere din PHP


9.1 Problema permisiunilor
9.2 Upload de fisiere
9.3 Deschiderea fisierelor
9.4 Citirea fisierelor
9.5 Scrierea in fisiere
9.6 Alte operatii cu fisiere
9.7 Operatii cu directoare
9.8 Tema

9.1. Problema permisiunilor


In manipularea fisierelor si directoarelor cu PHP apare deseori problema permisiunilor, problema spinoasa pentru programatorii PHP aflati la inceput si
nefamiliarizati cu sistemul de operare Unix/Linux. Aceasta problema este dificila din doua cauze principale: una, nu apare tot timpul. De exemplu, nu apare
daca setarile de permisiuni implicite se potrivesc cu scopul programatorului, si acesta are acces la resursele dorite; si a doua, multi programatori lucreaza
doar in Windows dar proiectul web este gazduit pe un server ce are sistemul de operare Unix/Linux.
Ca sa rezolvam aceasta problema, voi explica principiile de baza ale sistemului de permisiuni sub Unix.
In Unix, permisiunile fisierelor se acorda unor utilizatori sau grupuri de utilizatori de pe acel calculator.
Astfel, un fisier are urmatoarele informatii specifice:
- owner - utilizatorul ce detine acel fisier - implicit este utilizatorul ce a creat fisierul, dar poate fi schimbat
- group - grupul de utilizatori ce detine acel fisier - implicit grupul utilizatorului ce a creat fisierul
Restul utilizatorilor, sunt considerati din punct de vedere al permisiunilor, other. Cu alte cuvinte nu sunt owner si nici nu fac parte din group
Pentru fiecare din aceste categorii de utilizatori, owner, group sau other, fisierul are un set de 3 permisiuni:
- read - dreptul de citire
- write - dreptul de scriere
- execute - dreptul de executie

exista urmatoarele diferente intre felul in care functioneaza


Referitor la permisiunile read, write, si execute

aceste permisiuni pentru fisiere si pentru directoare:


Permisiune Fisier Director

dreptul de citire al continutului


read dreptul de a afisa continutul directorului
fisierului

dreptul de modificare al continutului dreptul de a modifica continutul directorului(stergere, creare, redenumire fisiere/directoare continute
write
fisierului in director) impreuna cu x

execute dreptul de a executa fisierul acces la fisierele continute. dreptul de a ne muta in director.

Nota
Daca un director contine dreptul de scriere ( w) pentru o anumita categorie de user ( owner, group sau other), acea categorie are dreptul de
a modifica continutul directorului chiar daca pentru acele fisiere nu exista drepturi. Modificarea continutului directorului inseamna:
stergerea sau mutarea fisierelor din el sau in el, stergerea de directoare din acest director, sau mutarea de directoare din el; practic tot ce modifica
lista continutului acelui director.

Pentru a modifica continutul directorului trebuie sa avem atat w cat si x.

Exprimarea permisiunilor

Deci, fiecare categorie de utilizatori, (owner, group sau other) poate avea sau nu fiecare din drepturile: read, write, execute. Permisiunile pot fi exprimate
printr-un sir de litere: r pentru read, w pentru write, si x pentru execute. De exemplu, un fisier cu permisiunile rwx rw- r-- are drepturile read, write si
execute pentru owner (primul grup de litere rwx) , are drepturile read si write pentru group (al doilea grup de litere rw-), si doar dreptul read (r--) pentru
other. In acest sistem de reprezentare sunt in total noua caractere, primul grup de trei caractere reprezinta permisiunile pentru owner, al doilea grup
pentru group, al treilea pentru other.
Permisiunile unui fisier pot fi exprimate si in modul octal, printr-un numar format din 3 cifre in baza 8.
Prima cifra exprima permisiunile pentru owner, a doua pentru group, a treia pentru other. Exemplul de mai sus, rwxrw-r-- in octal este 764. Fiecare
permisiune (read, write sau execute) este reprezentata de o cifra, (4 pentru read, 2 pentru write si 1 pentru execute) iar suma celor trei cifre exprima
permisiunile pentru grupul respectiv.

Privind in paralel cele doua sisteme de reprezentare, pentru exemplul de mai sus, arata
astfel:
owner group other

r w x r w - r - -

4 2 1 4 2 - 4 - -

7 6 4
Deci, reprezentarea in octal este 764, adica owner are toate drepturile (read, write, execute), group are dreptul read si write, iar other are doar dreptul
read.

Problemele cele mai des intalnite pe serverul de gazduire


In general, cand o functie php incearca sa modifice sau sa citeasca un fisier sau director in care nu are acces, functia respectiva genereaza un Warning ca
de exemplu:
Warning: fopen(fisiere/a.txt) [function.fopen]: failed to open stream: Permission denied in /home/exemplu/www/test.php on line 3

Problemele de permisiuni (dar nu din php) le putem considera si cazurile cand nu aveti drepturi de a modifica/sterge un director sau fisier din contul de
gazduire prin intermediul clientului de FTP. Aceste doua tipuri de probleme se leaga de multe ori.
Cateva din cazurile cel mai des intalnite sunt:

1. Nu ai permisiunea sa creezi cu PHP un fisier sau un director.


Presupunem ca site-ul la care lucrezi se afla pe server in locatia /home/dan/public_html/. Aceasta tip de cale este frecvent intalnita pe Unix, /home/dan/
fiind folderul userului dan, si public_html fiind Document Root, sau locatia in care trebuie sa se afle fisierele siteului. Realizez un script ce creaza (sau
incearca) un folder numit mydir1.
Astfel, in /home/dan/public_html/t1.php avem:

1 <?php
2 mkdir('mydir1');
3
4 ?>

Acest apel al functiei mkdir() este probabil sa esueze datorita lipsei de permisiuni pentru crearea folderului. Asa cum vedem in partea teoretica a
capitolului, nu putem modifica continutul directorului /home/dan/public_html/ , deci nu putem realiza un nou folder, daca nu avem
permisiunile w si x pentru utilizatorul ce incearca acest lucru.

Permisiunile folderului /home/dan/public_html/ ar arata astfel:


drwxrwxr-x 2 dan dan ... public_html

Adica owner si group este dan, si avem permisiunile 775. In mod clasic, scriptul php ruleaza cu utilizatorul Apache-ului, de cele mai multe ori cu
utilizatorul nobody, adica alt utilizator decat dan. nobody nu este nici dan nici nu face parte din grupuldan, deci nefiind nici owner nici group, intra in
categoria other. Dupa cum vedem, other are permisiunea r-x (sau 5). Deci nu are drept de scriere (w) pe public_html. Adica nu-i poate altera continutul,
deci nu poate creea/sterge foldere sau fisiere in acest director.
O solutie ar fi sa schimbam cu un client ftp (sau prin ssh pe server daca avem acces) permisiunile pentru public_html in 777. Astfel, si other ar avea rwx,
deci si permisiunea de a altera continutul. Insa, e mai sigur sa NU oferim permisiuni complete pentru public_html, in schimb sa realizam (prin ftp) un
subfolder in acesta, il denumim de exemplu users, schimbam in 777 permisiunile pentru acest folder, iar script-ul t1.php va incerca realizarea folderului
mydir1 in /home/dan/public_html/users/. Astfel, /home/dan/public_html/t1.php devine:

1 <?php
2 mkdir('users/mydir1');
3
4 ?>

Cu Filezilla, mouse-dreapta pe directorul respectiv (users in cazul nostru), accesam File Permissions obtinem o fereastra ca-n imaginea de mai jos de unde
putem schimba permisiunile:
Ruland acum scriptul t1.php, voi obtine realizarea folderului mydir1 in folderul users.
Aceeasi solutie se aplica in momentul cand vrem sa creem un fisier, sau sa stergem un fisier dintr-un folder.

2. Creezi un fisier cu un script PHP, si nu-l poti suprascrie prin FTP.


Presupunem ca ai creat prin PHP un fisier numit a.txt in folderul /home/dan/public_html/users/. Fisierele noi create au in general permisiunile 644 (sau rw-
r--r--). Fisierele PHP nu au nevoie sa fie executabile. In plus, in mod implicit ele nu trebuie sa poata fi scrise de other. Daca fisierul a fost creat cu un
script PHP, el va fi detinut de nobody. Deci owner va fi nobody, si grup la fel, nobody. Astfel, dan, utilizatorul ce acceseaza fisierul prin ftp nu are drept
de scriere asupra lui (pentru ca othernu are w in acest caz).
Cand un client FTP (Filezilla de exemplu) realizeaza o suprascirere (overwrite) pentru un fisier, va incerca sa-i schimbe de fapt continutul, deci sa scrie in
el, si bineinteles nu va avea acces pentru ca incearca accest lucru cu user-ul dan. Insa, a.txt de exemplu, poate fi sters cu clientul FTP, pentru ca dan are
acces la stergerea lui (modificarea continutului pentru folderul parinte, users), si apoi poate fi copiat alt a.txt in aceeasi locatie.

Exista si alte variante de probleme cu permisiuni intalnite in scripturile PHP sau in lucrul cu FTP, insa informatiile despre permisiuni si exemplele de mai sus
te pot ghida spre rezolvarea acestora.

9.2. Problema permisiunilor


In manipularea fisierelor si directoarelor cu PHP apare deseori problema permisiunilor, problema spinoasa pentru programatorii PHP aflati la inceput si
nefamiliarizati cu sistemul de operare Unix/Linux. Aceasta problema este dificila din doua cauze principale: una, nu apare tot timpul. De exemplu, nu apare
daca setarile de permisiuni implicite se potrivesc cu scopul programatorului, si acesta are acces la resursele dorite; si a doua, multi programatori lucreaza
doar in Windows dar proiectul web este gazduit pe un server ce are sistemul de operare Unix/Linux.
Ca sa rezolvam aceasta problema, voi explica principiile de baza ale sistemului de permisiuni sub Unix.
In Unix, permisiunile fisierelor se acorda unor utilizatori sau grupuri de utilizatori de pe acel calculator.
Astfel, un fisier are urmatoarele informatii specifice:
- owner - utilizatorul ce detine acel fisier - implicit este utilizatorul ce a creat fisierul, dar poate fi schimbat
- group - grupul de utilizatori ce detine acel fisier - implicit grupul utilizatorului ce a creat fisierul
Restul utilizatorilor, sunt considerati din punct de vedere al permisiunilor, other. Cu alte cuvinte nu sunt owner si nici nu fac parte din group
Pentru fiecare din aceste categorii de utilizatori, owner, group sau other, fisierul are un set de 3 permisiuni:
- read - dreptul de citire
- write - dreptul de scriere
- execute - dreptul de executie

exista urmatoarele diferente intre felul in care functioneaza


Referitor la permisiunile read, write, si execute

aceste permisiuni pentru fisiere si pentru directoare:


Permisiune Fisier Director

dreptul de citire al continutului


read dreptul de a afisa continutul directorului
fisierului

dreptul de modificare al continutului dreptul de a modifica continutul directorului(stergere, creare, redenumire fisiere/directoare continute
write
fisierului in director) impreuna cu x

execute dreptul de a executa fisierul acces la fisierele continute. dreptul de a ne muta in director.
Nota
Daca un director contine dreptul de scriere ( w) pentru o anumita categorie de user ( owner, group sau other), acea categorie are dreptul de
a modifica continutul directorului chiar daca pentru acele fisiere nu exista drepturi. Modificarea continutului directorului inseamna:
stergerea sau mutarea fisierelor din el sau in el, stergerea de directoare din acest director, sau mutarea de directoare din el; practic tot ce modifica
lista continutului acelui director.

Pentru a modifica continutul directorului trebuie sa avem atat w cat si x.

Exprimarea permisiunilor

Deci, fiecare categorie de utilizatori, (owner, group sau other) poate avea sau nu fiecare din drepturile: read, write, execute. Permisiunile pot fi exprimate
printr-un sir de litere: r pentru read, w pentru write, si x pentru execute. De exemplu, un fisier cu permisiunile rwx rw- r-- are drepturile read, write si
execute pentru owner (primul grup de litere rwx) , are drepturile read si write pentru group (al doilea grup de litere rw-), si doar dreptul read (r--) pentru
other. In acest sistem de reprezentare sunt in total noua caractere, primul grup de trei caractere reprezinta permisiunile pentru owner, al doilea grup
pentru group, al treilea pentru other.
Permisiunile unui fisier pot fi exprimate si in modul octal, printr-un numar format din 3 cifre in baza 8.
Prima cifra exprima permisiunile pentru owner, a doua pentru group, a treia pentru other. Exemplul de mai sus, rwxrw-r-- in octal este 764. Fiecare
permisiune (read, write sau execute) este reprezentata de o cifra, (4 pentru read, 2 pentru write si 1 pentru execute) iar suma celor trei cifre exprima
permisiunile pentru grupul respectiv.

Privind in paralel cele doua sisteme de reprezentare, pentru exemplul de mai sus, arata
astfel:
owner group other

r w x r w - r - -

4 2 1 4 2 - 4 - -

7 6 4

Deci, reprezentarea in octal este 764, adica owner are toate drepturile (read, write, execute), group are dreptul read si write, iar other are doar dreptul
read.

Problemele cele mai des intalnite pe serverul de gazduire


In general, cand o functie php incearca sa modifice sau sa citeasca un fisier sau director in care nu are acces, functia respectiva genereaza un Warning ca
de exemplu:
Warning: fopen(fisiere/a.txt) [function.fopen]: failed to open stream: Permission denied in /home/exemplu/www/test.php on line 3

Problemele de permisiuni (dar nu din php) le putem considera si cazurile cand nu aveti drepturi de a modifica/sterge un director sau fisier din contul de
gazduire prin intermediul clientului de FTP. Aceste doua tipuri de probleme se leaga de multe ori.
Cateva din cazurile cel mai des intalnite sunt:

1. Nu ai permisiunea sa creezi cu PHP un fisier sau un director.


Presupunem ca site-ul la care lucrezi se afla pe server in locatia /home/dan/public_html/. Aceasta tip de cale este frecvent intalnita pe Unix, /home/dan/
fiind folderul userului dan, si public_html fiind Document Root, sau locatia in care trebuie sa se afle fisierele siteului. Realizez un script ce creaza (sau
incearca) un folder numit mydir1.
Astfel, in /home/dan/public_html/t1.php avem:

1 <?php
2 mkdir('mydir1');
3
4 ?>

Acest apel al functiei mkdir() este probabil sa esueze datorita lipsei de permisiuni pentru crearea folderului. Asa cum vedem in partea teoretica a
capitolului, nu putem modifica continutul directorului /home/dan/public_html/ , deci nu putem realiza un nou folder, daca nu avem
permisiunile w si x pentru utilizatorul ce incearca acest lucru.

Permisiunile folderului /home/dan/public_html/ ar arata astfel:


drwxrwxr-x 2 dan dan ... public_html

Adica owner si group este dan, si avem permisiunile 775. In mod clasic, scriptul php ruleaza cu utilizatorul Apache-ului, de cele mai multe ori cu
utilizatorul nobody, adica alt utilizator decat dan. nobody nu este nici dan nici nu face parte din grupuldan, deci nefiind nici owner nici group, intra in
categoria other. Dupa cum vedem, other are permisiunea r-x (sau 5). Deci nu are drept de scriere (w) pe public_html. Adica nu-i poate altera continutul,
deci nu poate creea/sterge foldere sau fisiere in acest director.
O solutie ar fi sa schimbam cu un client ftp (sau prin ssh pe server daca avem acces) permisiunile pentru public_html in 777. Astfel, si other ar avea rwx,
deci si permisiunea de a altera continutul. Insa, e mai sigur sa NU oferim permisiuni complete pentru public_html, in schimb sa realizam (prin ftp) un
subfolder in acesta, il denumim de exemplu users, schimbam in 777 permisiunile pentru acest folder, iar script-ul t1.php va incerca realizarea folderului
mydir1 in /home/dan/public_html/users/. Astfel, /home/dan/public_html/t1.php devine:

1 <?php
2 mkdir('users/mydir1');
3
4 ?>

Cu Filezilla, mouse-dreapta pe directorul respectiv (users in cazul nostru), accesam File Permissions obtinem o fereastra ca-n imaginea de mai jos de unde
putem schimba permisiunile:
Ruland acum scriptul t1.php, voi obtine realizarea folderului mydir1 in folderul users.
Aceeasi solutie se aplica in momentul cand vrem sa creem un fisier, sau sa stergem un fisier dintr-un folder.

2. Creezi un fisier cu un script PHP, si nu-l poti suprascrie prin FTP.


Presupunem ca ai creat prin PHP un fisier numit a.txt in folderul /home/dan/public_html/users/. Fisierele noi create au in general permisiunile 644 (sau rw-
r--r--). Fisierele PHP nu au nevoie sa fie executabile. In plus, in mod implicit ele nu trebuie sa poata fi scrise de other. Daca fisierul a fost creat cu un
script PHP, el va fi detinut de nobody. Deci owner va fi nobody, si grup la fel, nobody. Astfel, dan, utilizatorul ce acceseaza fisierul prin ftp nu are drept
de scriere asupra lui (pentru ca othernu are w in acest caz).
Cand un client FTP (Filezilla de exemplu) realizeaza o suprascirere (overwrite) pentru un fisier, va incerca sa-i schimbe de fapt continutul, deci sa scrie in
el, si bineinteles nu va avea acces pentru ca incearca accest lucru cu user-ul dan. Insa, a.txt de exemplu, poate fi sters cu clientul FTP, pentru ca dan are
acces la stergerea lui (modificarea continutului pentru folderul parinte, users), si apoi poate fi copiat alt a.txt in aceeasi locatie.

Exista si alte variante de probleme cu permisiuni intalnite in scripturile PHP sau in lucrul cu FTP, insa informatiile despre permisiuni si exemplele de mai sus
te pot ghida spre rezolvarea acestora.

9.3. Deschiderea fisierelor

Unele functii pentru citirea sau scrierea fisierelor in PHP cer ca acestea sa fie inainte deschise sau creeate. Deschiderea sau creearea unui fisier nou se face
cu functia fopen($filename, $mode)
- $filename - fisierul ce trebuie deschis
- $mode - modul in care e deschis fisierul. Vezi semnificatia in tabelul de mai jos

Posibilitati pentru $mode

'r' Fisierul este deschis doar pentru citire. Pointerul este la inceputul fisierului

'r+' Fisierul este deschis pentru citire si scriere. Pointerul este la inceputul fisierului

'w' Fisierul este deschis doar pentru scriere. Daca fisierul nu exista, el este creat. Daca exista, se sterge tot din fisier, pointerul fiind plasat la inceput

'w+' Ca 'w', insa fisierul este deschis pentru citire si pentru scriere

'a' Deschis pentru scriere. Daca fisierul nu exista, el este creat. Pointerul este plasat la sfarsit.

'a+' La fel ca 'a' dar este deschis atat pentru scriere cat si pentru citire.

'x' Creeaza si deschide un fisier pentru scriere. Daca fisierul exista, functia returneaza FALSE, si genereaza un Warning

'x+' La fel ca 'x' insa deschide fisierul si pentru citire

$filename poate fi :

 O cale relativa la scriptul php. De exemplu: fisiere/a.txt


 O cale absoluta catre un fisier

 un url. Ex: http://www.exemplu.com/a.txt. In acest caz, setarea allow_url_fopen din php.ini trebuie sa fie On. Aceasta setare se poate
schimba conform setarii PHP_INI_SYSTEM , adica doar de administratorul serverului in php.ini sau in httpd.conf

Valoarea returnata de fopen() este FALSE in cazul in care apare o eroare in deschiderea fisierului specificat sau o valoare de tip resursa in caz de succes.
Aceasta variabila de tip resursa (denumita deseori $fp sau $handle ) este folosita ulterior de functii precum fread() sau fwrite() pentru citirea sau scrierea
in fisier.

1 <?php
2 /*
3 Daca unul din apelurile fopen() esueaza, este generat un Warning, iar
4 var_dump($fp) returneaza bool(false).
5 Altfel var_dump va returna un string asemanator cu: resource(x) of
6 type (stream)
7 */
8
9 $fp = fopen('fisier.txt', 'w+');
10 var_dump($fp);
11
12 $fp = fopen('http://www.google.com/', 'r');
13 var_dump($fp);
14
15 $fp = fopen('c:/www/alt_fisier.txt', 'a');
16 var_dump($fp);

?>

Cele mai intalnite probleme ce pot aparea in deschiderea unui fisier din PHP sunt:

 Problema de permisiuni. Nu aveti de exemplu drept de scriere (w) pe folderul respectiv, si deci nu puteti creea un fisier in acel folder. Sau
nu puteti deschide un fisier din acel folder pentru ca nu aveti dreptul x asupra folderului respectiv, ce va permite accesul la fisierele din folder.

 Deschideti un url si allow_url_fopen in php.ini este off

 setarea open_basedir ce indica faptul ca scripturile php nu pot deschide fisiere decat din directoarele specificate in aceasta setare; setare ce
sta la indemana administratorului serverului respectiv. Poate fi schimbata in php.ini sau in httpd.conf

Inchiderea fisierelor
Pentru a elibera resursele (variabila de tip resource) si pentru a redeschide eventual fisierul respectiv daca e necesar, pointerul catre fisier trebuie inchis.
Astfel, daca $fp reprezinta variabila returnata de fopen, inchiderea lui se face cu fclose($fp);

9.4. Citirea fisierelor


file_get_contents()
file_get_contents($filename) este cea mai simpla functie pentru citirea intregului continut al unui fisier intr-un string.

Exemplu:

1 <?php
2
3 $str = file_get_contents('fisier.txt');
4 echo $str;
5
6 ?>

file()
Functia file($filename) este foarte utila, permite citirea intregului continut al unui fisier, si returnarea lui intr-un array. Fiecare element al array-ului este
o linie din fisierul respectiv.

In exemplul urmator, deschidem un fisier printr-un URL, si printam numarul fiecarei linii si continutul ei. Fiind cod html, daca vrem sa-l afisam in browser
trebuie sa folosim functia htmlspecialchars() ce transforma caracterele ce au inteles in HTML in entitati HTML (caractere speciale, ce nu sunt interpretate
de browser).
Sursa script Vizualizare in browser
1 <?php
2
3 $lines =
4 file('http://www.invata-
5 online.ro/xhtml.html');
6
7 foreach ($lines as $no => $line)
8{
9 echo ++$no;
10 echo ' ';
11 echo htmlspecialchars($line);
echo '<br />'."\n";
}
?>

Folosind functia file() putem sa citim usor doar primele sau ultimele n linii din fisier, puteam sa pastram doar liniile ce contin un anumit subsir, etc. Apoi,
daca vrem sa afisam continutul array-ului $lines asa cum era in fisier, pot folosi functia implode("\n", $lines);
fread()
Functia fread($fp, $length) este folosita pentru a citi $length bytes dintr-un fisier si returneaza FALSE in caz de eroare sau string-ul citit.

1 <?php
2
3 $fp = fopen('fisier.txt', 'r');
4 $str = fread($fp, 100); // citeste primii 100 bytes din fisier
5 echo $str;
6
7 ?>

In exemplul de mai jos, folosim functia filesize() pentru a determina marimea fisierului in bytes si citim cu fread() un nr de bytes egal cu marimea lui,
adica tot continutul.

1 <?php
2
3 $filename = "fisier.txt";
4 $fp = fopen($filename, "r");
5 $contents = fread($fp, filesize($filename));
6 fclose($fp);
7
8 echo $contents
9
10 ?>

readfile()
readfile($filename) va citi fisierul $filename, si ii va afisa continutul (trimite catre browser).

1 <?php
2
3 readfile('fisier.txt');
4
5 ?>
9.5. Scrierea in fisiere
fwrite()
Prototip
int fwrite ( resource $handle , string $string [, int $length ] )
 $handle - este o variabila de tip resursa, returnata de fopen()

 $string - sirul de caractere (sau bytes) scris in fisier

 $length - argument optional. Daca este furnizat, scrierea in fisier se opreste cand apare prima data unul din cele doua evenimente: se
termina string-ul sau cand string-ul scris ajunge la lungimea $length

 returneaza numarul de bytes scrisi in fisier

1 <?php
2 // $newline = "\n"; // unix
3 $newline = "\r\n"; // windows
4
5 $filename = "fisier.txt";
6 $fp = fopen($filename, "w"); // daca nu exista, creeaza fisierul.
7 daca exista, sterge tot din el
8
9 fwrite($fp, "salut");
10 fwrite($fp, $newline);
11 fwrite( $fp, "Ce faci ?");
12
13 fclose($fp);
?>

file_put_contents()
Prototip
int file_put_contents ( string $filename , mixed $data [, int $flags= 0 [, resource $context ]] )

Functia file_put_contents() simplifica scrierea in fisiere, apelarea sa fiind echivalenta cu a apela fopen(), fwrite() si apoi fclose(). Primul parametru este
numele fisierului ce va fi deschis pentru scriere, apoi urmeaza informatia ce o scriem in fisier, iar al treilea parametru $flags, consta intr-o constanta sau
combinatie de constante ce modifica optiunile functiei. Folosind constanta FILE_APPEND , determinam adaugarea textului la sfarsitul fisierului la fiecare
apelare a functiei si nu golirea (trunchierea) lui inainte de scriere asa cum ar fi fost implicit.

1 <?php
2 $newline = "\r\n"; // windows
3 $filename = "persoane.txt";
4
5 file_put_contents($filename, 'John Smith' . $newline, FILE_APPEND);
6
7 ?>

9.6. Alte operatii cu fisiere


Nota
In prototipul functiilor cu fisiere, in general, $filename desemneaza calea catre fisierul relativ. Aceasta cale poate fi relativa la scriptul din care se
apeleaza functia sau calea absoluta a fisierului pe harddisk.

filesize()
filesize($filename) verifica si returneaza lungimea in bytes a fisierului.

file_exists()
Verifica existenta unui fisier sau a unui director.
Prototip
bool file_exists ( string $filename )

1 <?php
2 $filename = 'c:/www/fisier.txt';
3 // $filename = 'fisier.txt'; // sau cale relativa
4
5 if (file_exists($filename)) {
6 echo 'da';
7 } else {
8 echo 'nu';
9 }
10
11 ?>

is_file()
Verifica daca un fisier exista (si este fisier), spre deosebire de file_exists() care verifica existenta unui fisier sau director.
Prototip
bool is_file ( string $filename )

is_readable() si is_writable()
Cele doua functii, is_readable($filename) si is_writable($filename) verifica daca scriptul respectiv are permisiunea de a citi respectiv de a scrie in fisierul
respectiv.

copy()
Prototip
bool copy ( string $source , string $dest )
Copiaza fisierul dintr-o locatie ($source) in alta locatie ($dest). Returneaza TRUE pentru succes, altfel FALSE.

rename()
Prototip
bool rename ( string $oldname , string $newname )

rename($filename) muta sau redenumeste fisierul primit ca argument. Se pot folosi de asemenea cai relative sau absolute.

1 <?php
2 rename('fisier.txt', '../fisier.txt'); // muta fisierul pe acelasi
3 nivel cu directorul parinte
4
5 rename('c:/alt_fisier.txt', 'c:/www/other_file.txt'); // foloseste cai
6 absolute
7
rename('fisier.txt', 'fisier2.txt'); // doar ii schimba numele, dar
ramane in acelasi director
?>

unlink()
Prototip
bool unlink ( string $filename )

unlink($filename) sterge fisierul respectiv. Pentru stergerea directoarelor se foloseste rmdir()

basename()
Prototip
string basename ( string $path [, string $suffix ] )
Returneaza numele fisierului dintr-o cale completa. Numele fisierului este returnat cu tot cu extensie, exemplu fisier.txt insa daca specificam al doilea
parametru, $suffix, functia va sterge string-ul $suffix de la sfarsitul denumirii fisierului.

1 <?php
2 $path = 'c:/www/fisier.txt';
3
4 echo basename($path); // output: fisier.txt
5 echo '<br />';
6 echo basename($path, '.jpg'); // output: fisier.txt - nu gaseste .jpg
7 la sfarsitul fisierului
8 echo '<br />';
9 echo basename($path, '.txt'); // output: fisier
10
?>

pathinfo()
Pseudocod
mixed pathinfo ( string $path )
Functia primeste o cale catre un fisier, si returneaza intr-un array componentele ei.

Sursa script Sursa HTML in browser


1 <?php 1 Array
2 2(
3 $path = 'c:/www/fisier.txt'; // 3 [dirname] => c:/www
4 o cale in Windows 4 [basename] => fisier.txt
5 //$path = 5 [extension] => txt
6 '/home/stefan/fisier.txt'; // o 6 [filename] => fisier
7 cale in Unix 7)
8
9 $info = pathinfo($path);
10
print_r($info);

?>

Resurse
http://www.php.net/manual/en/ref.filesystem.php

9.7. Operatii cu directoare


mkdir()
Prototip
bool mkdir ( string $pathname [, int $mode= 0777 [, bool $recursive= false ]] )

Creeaza un director in locatia specificata de $pathname. $pathname este calea catre directorul ce trebuie creat. Daca $pathname cuprinde mai multe
nivele de directoare ce nu exista, trebuie sa folosesc al treilea parametru avand valoarea truece indica crearea tuturor directoarelor din $pathname. Al
doilea parametru, este un numar in octal (numerele in baza 8 in php trebuie scrise cu 0 in fata), ce reprezinta permisiunile pentru acel director. Acest
parametru, $mode, este ignorat in Windows.

1 <?php
2
3 mkdir('mydir'); // creeaza folderul mydir in directorul scriptului
4 curent
5
6 mkdir('mydir2/ceva3/ceva4/', 0755, true); // creeaza atat mydir2 cat
7 si directoarele sale. 0755 echivalent cu rwxr-xr-x
8
9 mkdir('c:/www/test', 0777); // creeaza folderul test in c:/www , cu
drepturile 0777

?>

rmdir()
Prototip
bool rmdir ( string $dirname )

Sterge directorul $dirname, daca scriptul are permisiunile necesare, si daca directorul este gol. Pentru a sterge un director care nu e gol, trebuie
realizata o functie utilizator, ce sterge in mod recursiv subdirectoarele si fisierele din directorul $dirname, si in final sa stearga si $dirname.

Iterarea intr-un director - listarea fisierelor dintr-un director


Putem sa listam continutul unui director pentru a-i afisa fisierele sau directoarele componente, sau pentru a le procesa intr-un anume fel. De exemplu,
stergem toate fisierele de tip .gif dintr-un director, sau mutam fisierele de tip txt din acel director in alta locatie, etc.
Pentru aceasta operatie folosim functiile opendir(), readdir() si apoi inchiderea directorului cu closedir():

1 <?php
2 $dir = 'c:/www';
3
4 $d = opendir($dir) or die('Eroare');
5
6 while (false !== ($f = readdir($d))) {
7 echo $f;
8 echo '<br />';
9}
10
11 closedir($d);
12
13
14 ?>

 opendir($dir) - deschide directorul $dir si returneaza o variabila de tip resursa, $d , cu ajutorul careia citim directorul

 readdir($d) - citeste o intrare in lista directorului reprezentat de $d, si returneaza numele intrarii respective. O intrare poate fi un fisier, un
director, sau fisierele speciale "." si ".." ce reprezinta directorul curent respectiv directorul parinte. Daca a ajuns la sfarsit, readdir() va
returna FALSE, si atunci stim ca am terminat de listat continutul directorului. Insa intotdeauna trebuie sa comparam valoarea returnata de
readdir() din punct de vedere identic cu FALSE, sa ne asiguram ca returneaza intr-adevar FALSE si nu o valoare ce se converteste automat la
FALSE cum ar fi 0 (in caz ca un fisier se numeste 0).

 instructiunea $f = readdir($d) va atribui rezultatul lui readdir($d), deci numele fisierului curent, variabilei $f. Rezultatul acestei instructiuni
este bineinteles valoarea atribuita, care trebuie sa fie diferita (!==) de FALSE.

Un script care ar face o filtrare dupa extensie de exemplu arata astfel:

1 <?php
2 $dir = 'c:/www/';
3
4 $d = opendir($dir) or die('Eroare');
5
6 while (false !== ($f = readdir($d))) {
7 $caleCompleta = $dir . $f;
8
9 if (is_file($caleCompleta) && $f != '.' && $f != '..') {
10 $info = pathinfo($f);
11 // print_r($info); // primul pas, verificam ce am obtinut pana
12 acum in $info
13 if (strtolower($info["extension"]) == 'txt') {
14 $fisiere[] = $caleCompleta;
15 }
16 }
17
18 }
19
20 closedir($d);
21
22 if (isset($fisiere)) {
23 print_r($fisiere);
24 }
25
26
?>

In verificarea is_file($filename) folosesc ca argument calea completa catre fisier si nu doar numele fisierului pentru ca posibil sa nu se afle in acelasi
director cu scriptul meu; desi pot folosi si o cale relativa. Foarte important, $dir trebuie sa se termine in slash, astfel incat la concatenarea cu $f calea sa
aiba continuitate, sa fie despartit directorul de fisier. Exclud intrarile "." si ".." apoi extrag cu pathinfo() componentele caii respective printre care si
extensia. Aplic functia strtolower() pentru a transforma toate extensiile in litere mici astfel incat sa fie egale cu sirul 'txt' si sirurile 'TXT', 'Txt', etc.
Rezultatele gasite, caile complete catre fisierele gasite le pastrez in tabloul $fisiere pentru a le folosi ulterior.

Resurse
http://www.php.net/ref.dir
http://www.php.net/opendir
http://www.php.net/readdir
http://www.php.net/class.dir
9.8. Tema
Tema 9-1
Realizati o functie care sterge un director si continutul acestuia (subdirectoare, fisiere, etc). Functia trebuie sa fie recursiva - se auto-apeleaza.

Tema 9-2
Modificati functia astfel incat sa primeasca inca un parametru optional, care sa precizeze intr-un array extensii de fisiere, astfel incat functia sa stearga
doar fisierele respective.

CAP.10. Cookies. Sesiuni


10.1 Introducere
10.2 Pastrarea informatiilor intre cererile HTTP
10.3 Cookies
10.4 Sesiuni
10.5 Mini-aplicatie login

10.1. Introducere

Intelegerea conceptelor cookies si sesiuni se bazeaza pe cunoasterea modului in care functioneaza comunicatia intre clientul web si serverul web, si
rolul headerelor http in aceasta comunicatie. Voi continua discutia deschisa in subcapitolul 6.1 despre cereri http, raspunsuri http si headere http.
Cand un utilizator tasteaza o adresa web in browser, de exemplu www.invata-online.ro, clientul web (browser-ul) gaseste si contacteaza serverul web si ii
adreseaza o cerere http de tip GET. In cererile HTTP, vor fi transmise headere HTTP si eventualele date de la utilizator (prin GET sau POST), desi in
aceasta prima cerere nu e cazul. Headerele sunt despartite de valorile lor prin ":".
Headerele unei cereri HTTP pentru www.invata-online.ro arata astfel. In aceasta cerere, exista headere ce ofera informatii despre clientul web,
precum User-Agent sau headere precum Host ce ofera serverului web informatii despre resursa cautata. Comanda "GET / HTTP/1.1\r\n" cere de fapt
serverului web resursa (fisierul) dorit, si anume / ce reprezinta "radacina directorului" intr-o cale reprezentata prin serverul web.

Astfel, serverul web va cauta un fisier de tip index.php sau index.html in radacina site-ului (Document Root), si va returna acel fisier intr-un http
response, ce arata astfel.
Raspunsul HTTP consta in 2 grupuri de informatii separate:
1. Headerele HTTP de raspuns
Cum ar fi Date, Server, Set-Cookie, Content-Type, etc.
2. Continutul efectiv al resursei cerute
Aici, sursa html a paginii index.php.

Intr-un raspuns http, headerele sunt separate de continutul efectiv al raspunsului printr-o linie goala (\r\n), si intotdeauna trebuiesc trimise toate
headerele inainte sa se trimita continutul.

Nota
Faptul ca sunt trimise intai headerele http si apoi continutul paginii este foarte important pentru ca setarea cookie-urilor precum si pornirea unei
sesiuni implica asa cum vom vedea trimiterea unui header http de catre server, deci trebuiesc realizate inainte de trimiterea oricarui continut (fie el
si un spatiu sau o linie goala) al paginii web.

In timp ce incarca pagina index.php, browserul va trimite cereri http pentru celelalte fisiere cerute de sursa html a paginii. Cand intalneste un tag img, sau
un tag ce va cere un fisier css extern, browserul va trimite o cerere http pentru fiecare din aceste fisiere, si le va primi de la server prin raspunsuri http. In
momentul cand navigam pe o alta pagina, se initiaza o noua cerere http pentru pagina respectiva php/html ce va initia alt lant de cereri HTTP.
Functiile PHP pentru lucrul cu headere
In PHP, exista urmatoarele functii in legatura cu headerele HTTP:

 header() - cu ajutorul acestei functii indicam serverului ce headere HTTP sa trimita catre client

 headers_sent() - returneaza true headerele au fost deja trimise catre clientul web, caz in care nu putem adauga un nou header. Returneaza
false daca headerele nu au fost trimise, si putem adauga propriul header

 headers_list() - returneaza un array cu lista de headere ce au fost trimise sau vor fi trimise catre client

Prototip
void header ( string $string [, bool $replace= true [, int $http_response_code ]] )

In exemplul urmator, voi trimite headerul Location ce are ca efect redirectarea clientului web spre un nou URL.

headers1.php
1 <?php
2 Header("Location: http://www.google.com");
3 ?>

Este ceva mai greu de observat, insa, in acest exemplu am introdus un spatiu inaintea deschiderii tagului <?php.
Fie ca e un simplu spatiu, newline, cod html, text simplu, text afisat cu echo in php sau orice alta modalitate de a trimite output catre serverul
web, NU trebuie trimis inaintea trimiterii headerelor. Acest cod, pe un server de gazduire in productie, de cele mai multe ori va genera un Warning:
Pseudocod
Warning: Cannot modify header information - headers already sent by (output started at C:\www\test.php:1) in C:\www\test.php on line 2

Nota
Pe platforma WAMP, pe Windows, este foarte probabil sa nu intalniti aceasta eroare, prin urmare functia header() sa se execute cu succes. Acest
lucru se intampla datorita unei setari implicite din php.ini instalat de WAMP, si anume, output_buffering = 4096. Inlocuiti cu output_buffering = Off
si veti obtine eroarea "headers already sent". Este mai bine sa lucrati astfel, pentru ca mutand site-ul pe serverul de gazduire nu veti obtine un
comportament diferit, si veti trimite headerele intotdeauna inainte de generarea oricarui output.
output_buffering e capacitatea PHP-ului de a stoca output (rezultatul text al programului) un anumit timp (sau un anumit numar de bytes), si apoi
a-l trimite impreuna cu headerele dar aranjate in ordinea corecta: headerele pe primul loc.
Nota
Nu confundati spatiile, liniile goale sau textul din afara tagurilor php - care inseamna output al programului cu spatiile sau liniile goale din interiorul
tagului php care nu formeaza output, fac parte din codul PHP

Corect:

headers2.php
1 <?php
2
3 Header("Location: http://www.google.com");
4
5 // spatii, text, cod html, apelarea lui echo.... vin dupa
6 trimiterea headerelor
7 echo 'orice';
8 ?>
9
10 <html>
11
12 <head>
13 </head>
14
<body>

Nota
Outputul nedorit poate aparea de multe ori in fisierele pe care le includem in fisierul nostru cu constructiile include saurequire

Resurse
http://en.wikipedia.org/wiki/List_of_HTTP_headers
http://php.net/header

10.2. Pastrarea informatiilor intre cererile HTTP


Se spune despre HTTP ca este un protocol "stateless"; adica, fiecare cerere este tratata in mod independent fata de alte cereri anterioare. Pentru un server
web nu conteaza ca vin mai multe cereri de la un client el nu face diferenta intre clienti, si nici nu-si aminteste (fara ajutor) informatii (gen preferinte,
setari ale utilizatorului) din cererile anterioare.
O serie de perechi cerere-raspuns http de la mai mult clienti arata astfel:
Insa, cu ajutorul sistemului de cookies si/sau sesiuni, in aplicatia web pe care o dezvoltam putem diferentia cererile http (accesarile paginilor noastre) si
chiar le putem grupa pe utilizatori:

In aceasta a doua imagine, serverul web poate diferentia cererile 1 si 3 ca apartinand unui client, si 2 si 4 altui client.

Resurse
http://en.wikipedia.org/wiki/HTTP

10.3. Cookies
10.3.1 Cum functioneaza
10.3.2 Setarea unei cookie din PHP
10.3.3 Citirea informatiilor din cookie
10.3.4 Stergerea unui cookie

10.3.1. Cum functioneaza


In primul rand, ce sunt aceste "cookies" ?

Definitie
Un cookie este o informatie de forma nume=valoare setata intr-un raspuns http (de catre serverul web), si stocata de catre browserul web pe calculatorul
utilizatorului, pe harddisk, sub forma unui fisier de tip text. De fiecare data cand utilizatorul web se intoarce la pagina web pentru care a fost setat acel
cookie, browserul trimite inapoi catre server cookie-ul, de forma nume=valoare, astfel incat in aplicatia web sa avem acces la aceste informatii, anterior
setate, despre utilizator.
Browser-ul web va trimite cookie-ul inapoi pentru o pagina web, atat timp cat cookie-ul nu este expirat. De exemplu, pentru a evidentia in statisticile
website-ului nostru comportamentul vizitatorilor (cand a vizitat prima data site-ul, pe ce pagini a fost, care e rata vizitatorilor ce se intorc pe site-ul nostru,
etc), trebuie sa diferentiem cererile http - accesarile paginilor din site. Cu ajutorul unei baze de date (camp de tip auto_increment) putem genera un id
unic la prima vizita a unui utilizator, si apoi la vizitele ulterioare, pentru ca ne-a trimis cookie-ul cu informatia anterioara (id_user), il recunoastem, si nu
generam un id nou.

Schematic, 4 vizite a 2 utilizatori web ai unei pagini ce seteaza un cookie numit id_user arata astfel:
HTTP lucreaza cu cookies prin headerul Set-Cookie header ce apare in raspunsurile ce seteaza un cookie , si prin headerulCookie prin care se returneaza
cookie-ul in cererile http ulterioare.

Daca analizam cu un program special (vezi resurse) vizitele unui singur utilizator, headerele HTTP arata astfel:

 request 1 - este ceruta resursa / (index) si nu este setat nici un cookie

 response 1 - serverul raspunde cu headere, urmate de resursa ceruta. Sunt setate doua cookie-uri:site cu valoarea m98k.... si id_user cu
valoarea 568804

 request 2 - clientul cere o noua resursa, /css/global.css, si returneaza cookie-urile site si id_user

 request 3 - similar pentru alte request-uri ale aceleiasi pagini web, sunt returnata cookie-urile active.

Nu am inclus in acest exemplu response2 si response3 pentru ca nu erau relevante. In aceste doua raspunsuri nu se seteaza cookie-uri. Un cookie odata
setat intr-un raspuns, el este doar returnat in cererile ulterioare.

Alte utilizari
Cookie-urile pot fi folosite si pentru alte scopuri decat de a grupa vizitele site-ului nostru pe utilizatori ca in exemplul de mai sus. Putem de exemplu sa
avem un site cu continut in 3 limbi straine si la prima vizita sa setam un cookie cu limba preferata in functie de ce limba alege utilizatorul. Apoi, la vizitele
pe alte pagini, sau chiar cand vizitatorul revine cateva zile mai tarziu (daca nu a expirat cookie-ul), ii citim in PHP acel Cookie, care ne este trimis de catre
browser, si ii afisam continutul in limba dorita. Similar, un vizitator poate alege o tema a site-ului vostru (presupunem ca aveti cateva teme de culori), si
de fiecare data cand revine, site-ul se deschide in tema dorita. La fel, cu ajutorul cookie-urilor, un utilizator poate fi logat timp de cateva zile (sau mai
mult), chiar daca inchide browser-ul/calculatorul.
Schema vizitelor unui utilizator caruia ii setam doua cookie-uri, tema_site si lang, arata

astfel:

Dezavantaje cookies
Cookie-urile sunt foarte utile in programarea web si de multe ori fac aplicatiile web mai usor de folosit. Putem sa le folosim in aplicatia noastra atata timp
cat intelegem faptul ca nu ne putem baza 100% pe faptul ca sunt acceptate de browser-ul utilizatorului sau ca utilizatorul nu le sterge inainte de data lor
de expirare. Pentru ca, fiind pe harddisk-ul sau, si mai mult browser-ul avand interfata pentru stergerea lor, utilizatorul poate sterge oricand cookie-urile.
Sau poate folosi alt browser pentru accesarea ulterioara a paginii voastre si fiecare browser are cookie-urile sale. Sau pur si simplu isi reinstaleaza sistemul
de operare, si implicit nu mai are nici fisierele de cookies. Deci, ca programatori web, nu ne putem baza pe existenta unui cookie pana la data lui de
expirare.
Poate va intrebati, "La ce bun atunci sa le folosim ?"
Scenariile in care se folosesc, iau in calcul si uneori chiar nu sunt afectate de aceste neajunsuri. De exemplu, un utilizator caruia i s-a setat un cookie cu
tema site-ului si cu limba aleasa va vedea site-ul la vizite succesive cu o anumita schema de culori si in limba respectiva. Daca isi sterge cookie-ul, va
trebui sa-si seteze din nou aceste preferinte. E normal, si nu e o problema majora. In exemplul cu statisticile web, bineinteles ele introduc o mica eroare in
sensul ca un utilizator daca isi sterge cookie-urile, in statistici va aparea ca un utilizator nou nu ca unul care revine. Dar statistic vorbind, eroarea
respectiva nu influenteaza prea mult datele finale ale statisticii. La fel, putem folosi cookie-urile pentru a "tine logat" un utilizator. Pentru el e mai simplu,
nu trebuie sa mai tasteze de fiecare data user si parola.
Daca isi sterge cookie-urile, va trebui sa le tasteze din nou.
Deci atat timp cat suntem constienti de "perisabilitatea" cookie-urilor, le putem folosi in consecinta.

Resurse
Wireshark
Live HTTP Headers - Mozilla plugin
http://en.wikipedia.org/wiki/HTTP_cookie

10.3.2. Setarea unei cookie din PHP


Un cookie este setat din PHP cu ajutorul functiei setcookie(). Setarea unui cookie inseamna de fapt trimiterea cookie-ului respectiv de catre serverul web
catre client, sau modificarea unui cookie existent.
Pseudocod
bool setcookie ( string $name [, string $value [, int $expire= 0 [, string $path [, string $domain [, bool $secure= false [, bool $httponly=
false ]]]]]] )

Functia setcookie() returneaza TRUE daca a setat cookie-ul, sau FALSE daca a fost trimit output anterior apelarii acestei functii, deci functia va genera si
un Warning, iar cookie-ul nu va fi trimis. Faptul ca setcookie() returneaza TRUE nu e o garantie ca browser-ul utilizatorului a acceptat acel cookie.
Parametri principali:

 $name - numele cookie-ului; devine ulterior cheie a superglobalului $_COOKIE

 $value - informatia pastrata de cookie; valoarea cookie-ului

 $expire - momentul de expirare al cookie-ului, exprimat in Unix Timestamp (nr de secunde de la 1 Ianuarie 1970). Adaugam numarul de
secunde peste care vrem sa expire cookie-ul la rezultatul functiei time() (nr de secunde pana in prezent). Daca nu specificam acest
parametru, si implicit el va fi 0, cookie-ul expira la inchiderea browser-ului.

 $path - cale web, relativa la radacina site-ului. calea in care va fi valabil cookie-ul respectiv, in cadrul domeniului $domain. De exemplu
"/users/", cookie-ul va fi valabil doar pentru www.exemplu.com/users/ si toate subfolderele de sub aceasta cale. "/" semnifica intreg domeniul

 $domain - subdomeniul in care este activ cookie-ul respectiv. Implicit va fi domeniul curent. Exemplu: ".users.example.com" , sau
".example.com".

Acesti parametri sunt specifici cookie-urilor folosite prin HTTP in general, nu doar functiei setcookie() din PHP. Deci indiferent cu ce setam un cookie
(JavaScript, ASP, etc) pe calculatorul utilizatorului, acest cookie va avea asociate aceste informatii ce determina felul in care acest cookie functioneaza.

1 <?php
2 // se seteaza doua cookie-uri, color si lang
3 // aceste doua cookie-uri expira la inchiderea browserului
4 setcookie('color', 'blue');
5 setcookie('lang', 'ro');
6
7
8 // se seteaza un alt cookie (id_user), ce expira peste aproximativ 3
9 luni
10 $secunde = 60 * 60 * 24 * 30 * 3; // 60*60 = 1 ora. 24h * 30 = 1 luna
11 *3 = 3 luni
12 setcookie('id_user', 234, time() + $secunde);
13
14 // seteaza un cookie care expira tot peste 3 luni, dar e valabil doar
15 intr-un anumit subfolder, pe un anumit domeniu (mysite.com)
setcookie('x', 1, time() + $secunde, '/admin/', '.mysite.com');

?>

Setarea unui cookie ca array


Folosind notatia cu paranteze patrate [], se poate seta un cookie ca array astfel:

1 <?php
2
3 setcookie('preferinte[culoare]', 'rosu');
4 setcookie('preferinte[meniu]', 'sus');
5 setcookie('preferinte[logat]', 'da');
6
7
8 if (isset($_COOKIE["preferinte"])) {
9 print_r($_COOKIE);
10 }
11 ?>

Apoi, valoarea $_COOKIE["preferinte"] extrasa in PHP va fi un array. De fapt, folosind aceasta notatie sunt setate mai multe cookie-uri, cate unul pentru
fiecare element al array-ului.

Resurse
http://www.php.net/setcookie

10.3.3. Citirea informatiilor din cookie

Asa cum se observa si in schema de mai sus, cookie-urile sunt trimise de client la cereri ulterioare raspunsului in care s-a setat cookie-ul. Deci in prima
cerere (in prima incarcare a paginii), informatia din cookie nu va fi disponibila aplicatiei php.
Dar, incepand cu cererea 2, informatiile din cookie sunt disponibile in array-ul asociativ $_COOKIE , variabila de tip superglobal.
Cea mai simpla modalitate sa verificam ce cookie-uri au fost setate, este print_r($_COOKIE). Informatia din $_COOKIE va fi bineinteles disponibila la
primul refresh al paginii.
1 <?php
2 // se seteaza doua cookie-uri, tema_site si lang
3 // aceste doua cookie-uri expira la inchiderea browserului
4 setcookie('tema_site', 'blue');
5 setcookie('lang', 'ro');
6
7
8 // se seteaza un alt cookie (id_user), ce expira peste aproximativ 3
9 luni
10 $secunde = 60 * 60 * 24 * 30 * 3; // 60*60 = 1 ora. 24h * 30 = 1 luna
11 *3 = 3 luni
12 setcookie('id_user', 234, time() + $secunde);
13
14
print_r($_COOKIE);
?>

In mod normal, setam cookie-urile intr-o pagina (sa zicem pagina catre care utilizatorul a trimis un formular cu preferinte), si le citim in celelalte pagini. In
celelalte pagini nu mai e necesar sa setam acele cookie-uri, doar ne folosim de informatia lor. Exemplu:

pagina1.php
1 <?php
2
3 if (isset($_GET["buton"])) {
4
5 $secundeZi = 60 * 60 * 24;
6 $secunde = 90 * $secundeZi;
7
8 setcookie('tema_site', $_GET["tema_site"]);
9 setcookie('lang', $_GET["lang"]);
10 setcookie('id_user', 234, time() + $secunde);
11
12
13 Header("Location: pagina2.php");
14 }
15
16
17 ?>
18 <form method="get">
19 Tema site:
20 <select name="tema_site">
21 <option value="Blue">Albastru</option>
22 <option value="Red">Rosu</option>
23 </select>
24
25 <br />
26
27 Limba:
28 <select name="lang">
29 <option value="Romana">Romana</option>
30 <option value="English">English</option>
31 </select>
32
33 <br /><br />
34
35 <input type="submit" name="buton" value="Trimite" />
36
37 </form>

pagina2.php
1 <?php
2 if (isset($_COOKIE["tema_site"])) {
3 echo 'Ai ales tema_site: ' . $_COOKIE["tema_site"];
4 }
5
6 echo '<br />';
7
8 if (isset($_COOKIE["lang"])) {
9 echo 'Ai ales limba: ' . $_COOKIE["lang"];
10 }
11
12 echo '<br />';
13
14 if (isset($_COOKIE["id_user"])) {
15 echo 'Esti utilizatorul cu id_user: ' . $_COOKIE["id_user"];
16 }
17
18
19
20 ?>

Daca stergeti cookie-urile, si incarcati direct pagina2.php, nu o sa se afiseze nimic pentru ca browser-ul nu trimite nici un cookie catre server. Daca setati
preferintele in pagina1, si apasati Trimite, se va face o noua cerere catre pagina1 cu preferintele setate in $_GET. Drept raspuns, serverul va seta cookie-
urile cu valorile din GET si va trimite browserului o instructiune de redirectare. La noua cerere, catre pagina2.php, browserul va trimite si cookie-urile
setate, si acestea vor fi disponibile in $_COOKIE. Daca inchideti browserul, si apoi il deschideti si reveniti in pagina2.php, va fi afisat doar cookie-ul
id_user, pentru ca e setat sa expire peste 90 de zile, celelalte expira la inchiderea browserului.

Este posibil sa vrem sa setam acelasi cookie indiferent pe ce pagina aterizeaza un nou utilizator (id_user de exemplu). In acest caz probabil voi include
codul respectiv cu o instructiune include. Insa, odata acest cookie setat, nu vreau sa-l setez si la accesarea altor pagini, sau la refresh-ul acestei pagini.
Daca as genera un id unic pentru fiecare vizitator nou, atunci de fiecare data cand acel vizitator nou ar accesa si alte pagini (in care presupunem ca avem
inclus codul cu setcookie() si cu generarea id-ului), i-am seta cookie-ul id_user cu o valoare noua, si astfel fiecare vizita statisticile noastre ar insemna un
vizitator nou, ceea ce e gresit. Atunci, trebuie sa verificam daca utilizatorul are setat acel cookie, si doar daca NU il are, sa il setam. Exemplu:

1 <?php
2
3
4 // setam cookie-ul DOAR daca utilizatorul nu are acel cookie
5
6 if (!isset($_COOKIE["id_user"])) {
7 /*
8 Daca am fi inserat un rand intr-un tabel de statistici, am fi obtinut
9 ultima valoare din campul AUTO_INCREMENT
10 ar fi returnata de mysqli_insert_id()
11 */
12
13 /*
14 ...
15 aici ar fi codul de conectare la db, si apoi insertul
16 */
17
18 //$id_user = mysqli_insert_id($link); // se genereaza un id nou doar
19 daca nu are setat cookie-ul id_user, deci e vizitator nou
20
21 $id_user = 234; // pentru simplificare
22
23
24
25 $secundeZi = 60 * 60 * 24;
26 $secunde = 90 * $secundeZi;
27 setcookie('id_user', $id_user, time() + $secunde);
28 echo 'setez cookie'; // pentru debug
29 }
30
31 echo '<br /><br />';
print_r($_COOKIE);
?>

Resurse
http://www.php.net/manual/en/reserved.variables.cookies.php

10.3.4. Stergerea unui cookie


Un cookie se sterge folosind aceeasi parametri ca la setare, insa cu o data de expirare in trecut. E de preferat ca data de expirare sa fie mult in trecut,
pentru ca posibil ca timpul de pe server sa fie diferit de timpul de pe client. In plus, valoarea ei poate fi setata ca sirul gol "" sau valoarea booleana FALSE.

pagina1.php
1 <?php
2 $day = 60 * 60 * 24;
3
4 if (!isset($_COOKIE["nume"])) {
5 setcookie('nume', 'Stefan', time() + 30 * $day);
6 }
7
8 ?>

pagina2.php
1 <?php
2 $day = 60 * 60 * 24;
3 setcookie('nume', 'Stefan', time() - 30 * $day);
4
5 // unset($_COOKIE['nume']);
6
7 print_r($_COOKIE);
8 ?>

La prima incarcare a fisierului pagina2.php , observam ca inca se afiseaza valoarea arrayului $_COOKIE. Acest lucru se intampla pentru ca in acest raspuns
se trimite catre browser cererea de stergere a cookie-ului si abia la accesarea viitoare $_COOKIE nu va contine informatiile din acel cookie. Daca in scriptul
nostru avem nevoie inca din cererea respectiva sa ne bazam pe absenta cookie-ului din $_COOKIE, putem sterge intrarea respectiva cu
unset($_COOKIE['nume_cookie']);

10.4. Sesiuni
10.4.1 Sesiunile in PHP
10.4.2 Inceputul unei sesiuni
10.4.3 Transmiterea id-ului prin GET
10.4.4 Transmiterea id-ului prin cookies
10.4.5 Setarile sesiunii
10.4.6 Incheierea unei sesiuni
10.4.1. Sesiunile in PHP
O sesiune http inseamna un grup de cereri http ce sunt recunoscute in aplicatia web (pe serverul web) ca apartinand aceluiasi vizitator in cadrul unei
vizite curente. Aceasta vizita curenta, adica o succesiune de cereri din partea acelui utilizator, incepe cand se deschide sesiunea, si se termina cand se
incheie sesiunea. Chiar daca vizitatorul continua sa acceseze paginile site-ului dar sesiunea a expirat sau a fost inchisa, pentru noi (in aplicatia web),
cererile sale sunt din nou anonime, nu apartin unei sesiuni sau unui vizitator anume.
Gruparea acestor accesari intr-o sesiune, ce apartine unui utilizator, se realizeaza generand un session ID unic pentru fiecare sesiune deschisa. Cand avem
un vizitator nou, pe o pagina pe care deschidem sesiunea, ii generam un session ID si i-l oferim, de obicei printr-un cookie. La vizitele sale ulterioare, el va
trimite acel session ID, astfel noi il recunoastem, si ii continuam sesiunea.

Ne punem in mod normal intrebarea, cu ce difera atunci sesiunile de cookies ?


Crearea si managementul sesiunilor sunt de data asta in responsabilitatea limbajului PHP si a serverului web.
Exista doua elemente principale in lucrul cu sesiuni:
1. Id-ul de sesiune (session ID), ce este generat de motorul PHP, sau poate fi generat de programator, la inceputul deschiderii unei sesiuni.
2. Continutul sesiunii (session data). Continutul sesiunii reprezinta ca si in cazul cookie-urilor informatie legata de utilizatorul respectiv dar de data
asta continutul de sesiune este stocat pe server, intr-un fisier. La incheierea scriptului .php, se salveaza informatiile sesiunii in fisierul respectiv, si la
inceperea rularii unui nou script .php interpretorul PHP citeste din fisierul respectiv datele sesiunii curente (daca exista o sesiune curenta si exista date
pentru ea) si le incarca in variabila superglobala $_SESSION. Informatiile sunt tot perechi nume=valoare. Putem numi o astfel de pereche nume=valoare o
variabila de sesiune, desi tehnic este un element in array-ul $_SESSION.

Prin urmare, fiecare sesiune are fisierul propriu pe server cu datele sesiunii respective, atat timp cat sesiunea este activa. Datele respective sunt incarcate
in $_SESSION cat timp browserul unui utilizator trimite un id de sesiune corect.

10.4.2. Inceputul unei sesiuni


Deschiderea unei sesiuni se realizeaza cu functia session_start().
Prototip
bool session_start ( void )

session_start() are de fapt doua comportamente:


1. Daca primeste un id valid de sesiune de la client (prin url sau prin cookie), va continua sesiunea respectiva. Deci id-ul de sesiune ramane
neschimbat.
2. Daca nu primeste un id de sesiune de la client, sau id-ul respectiv nu corespunde unei sesiuni active pe server, va deschide o noua sesiune, deci se
genereaza un nou id.

Cuvantul "void" in lista de argumente al prototipului inseamna ca functia nu primeste nici un parametru. session_start() returneaza TRUE daca sesiunea a
fost pornita cu succes, FALSE in caz contrar.
Id-ul de sesiune poate fi transmis de la o cerere la alta nu doar prin cookie ci si prin GET (sau POST) asa cum vom vedea mai tarziu.
Orice sesiune in PHP are un nume. Numele sesiunii este de fapt numele cookie-ului ce reprezinta id-ul de sesiune, sau numele parametrului GET daca id-ul
de sesiune se transmite prin GET.

Nota
Desi in un id de sesiune poate fi primit de aplicatia web atat prin get cat si prin post, voi vorbi in general despre GET, adica transmiterea prin url,
atunci cand nu vorbim despre cealalta varianta, transmiterea prin cookie

Numele sesiunii este returnat de functia session_name(). session_name() poate primi un parametru caz in care setam noi numele sesiunii. Similar cu
functia session_id(), returneaza id-ul sesiunii. Daca insa vrem sa setam noi id-ul sesiunii, trebuie sa-l transmitem ca parametru functiei session_id().

1 <?php
2 // in acest caz numele sesiunii va fi cel implicit: PHPSESSID
3 // id-ul sesiunii va fi generat de php
4
5 session_start();
6
7
8 echo 'Sesiunea curenta se numeste: ' . session_name();
9 echo '<br />';
10 echo 'Id-ul sesiunii curente este: ' . session_id();
11 ?>

1 <?php
2 session_name('mysession'); // numim sesiunea: mysession
3 session_start();
4
5
6 echo 'Sesiunea curenta se numeste: ' . session_name();
7 echo '<br />';
8 echo 'Id-ul sesiunii curente este: ' . session_id();
9 ?>

Interpretorul PHP se ocupa de unicitatea id-ului de sesiune , deci in general nu avem nevoie sa setam noi un id de sesiune. Unicitatea id-ului de sesiune
inseamna ca din momentul in care s-a generat prima sesiune, pe parcursul "vietii" unui site sa nu existe 2 sesiuni cu acelasi id. In acelasi timp, un id de
sesiune trebuie sa fie "greu de ghicit", din acest motiv contine litere, cifre, si nu este scurt.
Exista cateva preferinte ale sesiunilor in PHP ce pot fi setate, si schimbate fata de cele implicite, dar trebuie schimbate inainte de pornirea sesiunii. Cateva
din aceste preferinte sunt optiuni in php.ini, ce pot fi schimbate insa prin functia ini_set(). Foarte important, trebuie sa ne decidem cum vrem sa
transmitem id-ul sesiunii pe care o deschidem, prin URL (GET) sau prin cookie.

Setarea session.use_cookies poate fi 0 sau 1. Daca este 1, atunci se vor trimite cookie-uri pentru transmiterea id-ului de sesiune. Insa, poate fi transmis in
acelasi timp si prin GET; Deci incadrul unei sesiuni cu setarea session.use_cookies 1, daca primeste prin GET id-ul sesiunii, aplicatia va continua sesiunea.
Insa, setarea session.use_only_cookies daca este setata cu 1 (sau On), va permite propagarea id-ului de sesiune doar prin cookie. Aceasta setare la
valoarea 1 este implicita incepand cu PHP 6. Transmiterea id-ului doar prin cookies este considerata mai sigura, si ceva mai simplu de aplicat, deci in
general este cea preferata.

Nota
Toate optiunile sesiunii trebuie sa le setam inainte de apelarea functiei session_start()

$_SESSION
Indiferent cum este transmis id-ul de sesiune (url sau cookies), scopul final al unei sesiuni este de a salva la un moment initial datele unui utilizator, si cat
timp navigheaza intr-o sesiune activa pe site-ul nostru sa extragem datele de care avem nevoie. Altfel, ar fi foarte dificil sa transmitem datele respective
de la o pagina la alta. $_SESSION este un tablou superglobal, cu ajutorul caruia salvam datele unei sesiuni, si apoi extragem aceste date cand avem
nevoie de ele.

Nota
In toate exemplele cu sesiuni, observati id-ul de sesiune generat initial. Daca la navigarea in alta pagina (sau la refresh) id-ul sesiunii se schimba,
inseamna ca sesiunea initiala a expirat sau s-a inchis dintr-un motiv sau altul, si a fost generata o noua sesiune, cu un nou id.

pagina1.php
1 <?php
2 ini_set('session.use_cookies', 1);
3 session_name('mysession'); // numim sesiunea: mysession
4 session_start();
5
6
7 $_SESSION["username"] = 'ion';
8 $_SESSION["email"] = 'ion@gmail.com';
9
10
11 ?>
12 <a href="pagina2.php">pagina2</a>

pagina2.php
1 <?php
2 ini_set('session.use_cookies', 1);
3 session_name('mysession'); // numim sesiunea: mysession
4 session_start();
5
6 echo $_SESSION["username"];
7 echo '<br />';
8 echo $_SESSION["email"];
9
10
11 ?>
12 <br /><br />
13 <a href="pagina1.php">pagina1</a>

Resurse
http://php.net/session_name
http://www.php.net/manual/en/session.configuration.php

10.4.3. Transmiterea id-ului prin GET


In exemplul urmator, intre pagina1.php si pagina2.php id-ul sesiunii se propaga prin url. Este responsabilitatea noastra ca programator sa adaugam in
linkurile din site parametrul ?nume_sesiune=id_sesiune astfel incat la cererile ulterioare ale vizitatorului, browserul web sa ne ofere prin URL id-ul de
sesiune. In acest fel, sesiunea se regenereaza pentru acel utilizator. Ca sa nu scriem linkurile folosind variabile pentru numele sesiunii curente si pentru id-
ul sesiunii curente, gen echo '<a href="pagina.php?'.$session_name.'='.$session_id.'">pagina</a>' ... php-ul ne ofera ca "scurtatura" constanta SID ce
contine sirul nume_sesiune_curenta=id_sesiune_curenta. Acest SID exista doar daca setarea session.use_cookies este 0.

pagina1.php
1 <?php
2 ini_set('session.use_cookies', 0);
3 ini_set('session.use_only_cookies', 0);
4 session_name('mysession'); // numim sesiunea: mysession
5 $t = session_start();
6
7 if ($t) {
8 echo 'Sesiunea a fost (re)pornita';
9 echo '<br />';
10 echo 'Nume sesiune: ' . session_name();
11 echo '<br />';
12 echo 'Id sesiune: ' . session_id();
13
14 // salvam date in aceasta sesiune
15 $_SESSION["username"] = 'ion';
16 $_SESSION["uid"] = 33;
17 }
18
19
20 ?>
21 <br /><br />
22 <a href="pagina2.php?<?php echo SID ?>">pagina2</a>

pagina2.php
1 <?php
2 ini_set('session.use_cookies', 0);
3 ini_set('session.use_only_cookies', 0);
4 session_name('mysession'); // numim sesiunea: mysession
5 $t = session_start();
6
7 if ($t) {
8 echo 'Sesiunea a fost (re)pornita';
9 echo '<br />';
10 echo 'Nume sesiune: ' . session_name();
11 echo '<br />';
12 echo 'Id sesiune: ' . session_id();
13 echo '<br /><br />';
14 print_r($_SESSION);
15 }
16
17
18
19
20 ?>
21 <br /><br />
22 <a href="pagina1.php?<?php echo SID ?>">pagina1</a>

Exista o posibilitate mai simpla de a transmite id-ul de sesiune de la o pagina la alta prin url. Si anume, activand optiuneasession.use_trans_sid cu
ini_set(). Daca aceasta optiune este setata, interpretorul PHP adauga automat id-ul de sesiune si valoarea sa la toate linkurile din scripturile in care pornim
o sesiune.

pagina1.php
1 <?php
2 ini_set('session.use_cookies', 0);
3 ini_set('session.use_only_cookies', 0);
4 ini_set('session.use_trans_sid', 1);
5
6
7 session_name('mysession');
8 session_start();
9
10 echo session_id();
11 echo '<br />';
12
13 ?>
14 <a href="pagina2.php">pagina2</a>

pagina2.php
1 <?php
2 ini_set('session.use_cookies', 0);
3 ini_set('session.use_only_cookies', 0);
4 ini_set('session.use_trans_sid', 1);
5
6
7 session_name('mysession');
8 session_start();
9
10 echo session_id();
11 echo '<br />';
12
13 ?>
14 <a href="pagina1.php">pagina1</a>

10.4.4. Transmiterea id-ului prin cookies


Transmiterea id-ului de sesiune prin cookies este varianta optima si mai sigura fata de transmiterea prin url.
Setarile unei sesiuni se fac inaintea pornirii sesiunii. Prin urmare, voi incepe cu ini_set('session.use_only_cookies', 1). In acest caz,session_start() va
determina setarea unui cookie cu numele sesiunii, avand ca valoare id-ul sesiunii. De exemplu: mysession=d635d6db819084ebed17e9a907568b6a , sau
PHPSESSID=d635d6db819084ebed17e9a907568b6a.
Cookie-ul de sesiune, ca oricare alt cookie, are anumiti parametri ce pot fi setati sau obtinuti
prin session_set_cookie_params() sisession_get_cookie_params().
Prototip
void session_set_cookie_params ( int $lifetime [, string $path [, string $domain [, bool $secure= false [, bool $httponly= false ]]]] )
Parametrii sunt similari cu cei ai functiei setcookie() doar ca bineinteles nu apar $name si $value pentru ca numele si valoarea cookie-ului sunt deja
setate, fiind un cookie al id-ului de sesiune. Inca o diferenta, $lifetime aici este numarul de secunde in care expira cookie-ul de cand a fost setat. $path
implicit este "/" adica cookie-ul e valabil pe tot domeniul pe care a fost setat.
In exemplul urmator, cookie-ul sesiunii a fost setat sa expire la 5 secunde. Incarcati pagina1.php, observati id-ul sesiunii, dati click pe pagina2.php
observati ca sesiunea se continua (deci id-ul sesiunii ramane neschimbat). Daca au trecut 5 secunde de cand ati incarcat pagina, id-ul sesiunii se va
schimba. Prin urmare, cookie-ul ce reprezenta sesiunea initiala a expirat, si session_start() a generat un nou id de sesiune, deci a fost setat un alt cookie.
Acest lucru se intampla indiferent ca dati click pe pagina2 pana in 5 secunde si apoi pe pagina1, etc. Deci timpul de expirare al cookie-ului nu se modifica.

pagina1.php
1 <?php
2 ini_set('session.use_only_cookies', 1);
3
4 session_name('mysession');
5 session_set_cookie_params(5);
6
7 session_start();
8
9 echo session_id();
10 echo '<br />';
11
12
13 print_r(session_get_cookie_params());
14 ?>
15 <a href="pagina2.php">pagina2</a>

pagina2.php
1 <?php
2 ini_set('session.use_only_cookies', 1);
3
4 session_name('mysession');
5 session_set_cookie_params(5);
6
7 session_start();
8
9 echo session_id();
10 echo '<br />';
11
12
13 print_r(session_get_cookie_params());
14 ?>
15 <a href="pagina1.php">pagina1</a>

Este util uneori sa pastram sesiunea unui utilizator un timp (sa zicem 2 ore) de la ultima accesare, deci de la ultimul sau click, nu de cand a inceput
sesiunea (altfel poate fi delogat in timp ce navigheaza). In exemplele de mai jos, id-ul de sesiune se pastreaza atat timp cat navigarea de la pagina1 la
pagina2 si invers se face pana in 5 secunde. Daca stau pe o pagina mai mult de 5 secunde, la navigarea pe cealalta pagina id-ul sesiunii se schimba, deci
sesiunea anterioara a expirat. Pentru a prelungi astfel sesiunea de la ultimul click, trebuie sa apelam functia setcookie() pentru a seta din nou manual
cookie-ul de sesiune, pentru a prelungi data de expirare. Apelarea functiei setcookie() trebuie realizata aici dupa session_start(). Practic, modificam
cookie-ul initial setat de session_start(). Cookie-ul setat prin session_start() are implicit (daca nu setam altfel) calea "/". Din acest motiv, apelarea
functiei setcookie() trebuie sa aiba la parametrul $path tot "/" sau ce cale am setat pentru cookie-ul de sesiune.
Valoarea de 5 secunde este pentru teste, in mod normal puneti cateva ore.

pagina1.php
1 <?php
2 ini_set('session.use_only_cookies', 1);
3 $seconds = 3;
4
5 session_name('mysession');
6 session_set_cookie_params($seconds);
7
8 session_start();
9
10 setcookie(session_name(), session_id(), time() + $seconds, "/"); //
11 prelungeste viata cookie-ului de la ultimul click
12
13 echo session_id();
14 echo '<br />';
15
16
17 print_r(session_get_cookie_params());
18 ?>
<a href="pagina2.php">pagina2</a>

pagina2.php
1 <?php
2 ini_set('session.use_only_cookies', 1);
3 $seconds = 3;
4
5 session_name('mysession');
6 session_set_cookie_params($seconds);
7
8 session_start();
9
10 setcookie(session_name(), session_id(), time() + $seconds, "/"); //
11 prelungeste viata cookie-ului de la ultimul click
12
13 echo session_id();
14 echo '<br />';
15
16
17 print_r(session_get_cookie_params());
18 ?>
<a href="pagina1.php">pagina1</a>

Resurse
http://php.net/session_set_cookie_params
http://php.net/session_get_cookie_params

10.4.5. Setarile sesiunii


Lista preferintelor de sesiune este la adresa: http://www.php.net/manual/en/session.configuration.php. Aceste setari sunt prezente in fisierul de
configurare al PHP-ului, php.ini, dar se pot schimba si prin functia ini_set('optiune', valoare).
Setarile cookie-ului de sesiune (ex: session.cookie_lifetime, session.cookie_path) se pot schimba atat prin ini_set() cat si prin
functia session_set_cookie_params() prezentata anterior.

Important
De retinut ca toate optiunile unei sesiuni trebuie setate inainte de apelarea lui session_start(). Si de obicei e bine ca pe fiecare pagina in care deschidem
sesiunea respectiva sa o deschidem exact la fel, cu exact aceleasi setari. Deci codul de deschidere a unei sesiuni se scrie in cadrul unei functii sau se scrie
intr-un fisier inclus apoi in aplicatia noastra.

De cele mai multe ori, pe un server de gazduire Unix sunt gazduite mai multe website-uri, apartinand mai multor webmasteri. Toate fisierele de sesiune
pornite cu PHP vor fi salvate la un loc in folderul /tmp. Pentru a schimba directorul in care sunt salvate sesiunile aplicatiei tale, poti folosi
ini_set('session.save_path', '/home/dan/sesiuni/'); de exemplu pentru a specifica o cale absoluta, sau ini_set('session.save_path', '../sesiuni/'); pentru o
cale relativa. De preferat ca folderul de sesiuni sa fie in afara folderului public_html in care este site-ul, si care este accesibil prin http. Astfel, site-ul va fi
in /home/dan/public_html/ , iar folderul de sesiuni va fi /home/dan/sesiuni/.

10.4.6. Incheierea unei sesiuni


Discutam aici in principiu despre sesiunile ale caror id se transmite prin cookie. Inchiderea/expirarea unei sesiuni presupune unul din urmatoarele lucruri:

 cookie-ul de sesiune expira sau este sters de pe calculatorul utilizatorului

 fisierul ce contine datele sesiunii este sters de pe server

Daca unui cookie de sesiune nu-i setam data de expirare, in mod implicit cookie-ul are parametrul $expires = 0, deci expira la inchiderea browserului.
Putem insa seta sesiunea sa expire peste cat timp dorim asa cum am vazut anterior cu ajutorul functiei session_set_cookie_params() sau setand din nou
cookie-ul de sesiune cu setcookie().
Insa, exista problema cand fisierul de sesiune dispare de pe server inainte sa expire cookie-ul utilizatorului. Presupunand ca folosim sesiunea pentru login,
utilizatorul va fi atunci delogat pentru ca datele sesiunii (din $_SESSION) se pierd.
Cum dispare fisierul sesiunii de pe server ?
Interpretorul PHP ruleaza din cand in cand un program numit "garbage collector" care sterge fisierele "vechi" de sesiune de pe server. Cand ruleaza acest
program si cum se considera fisierele de sesiune "vechi" ? Exista trei setari (in php.ini, se pot schimba cu ini_set), ce au urmatoarele valori implicite:

session.gc_probability 1

session.gc_divisor 100

session.gc_maxlifetime 1440

Cand garbage collector ruleaza pe server, sterge fisierele de sesiune mai vechi de gc_maxlifetime secunde. Implicit pe cele mai vechi de 1440 secunde (24
minute). Acest program este setat sa ruleze cand se pornesc noi sesiuni sau se continua sesiuni existente cu session_start() insa nu de fiecare data ci cu o
frecventa de gc_probability/gc_divisor, implicit 1%, sau 0.01. Adica, cu setarile implicite, la 100 de apelari ale lui session_start() pe serverul respectiv se
va apela garbage collector o data. Daca aveam gc_probability 1 si gc_divisor 3, atunci la 1 din 3 porniri de sesiuni se rula si garbage collector.
In concluzie ce e important este ca atunci cand ruleaza garbage collector sterge fisiere de sesiune mai vechi de 1440 de secunde (sau de
gc_maxlifetime secunde).
Daca un fisier e mai vechi de gc_maxlifetime secunde nu inseamna deci ca el este imediat sters, poate fi sters dupa inca 2 ore, sau 2 zile, cand ruleaza
garbage collector dar nu va fi sters mai devreme. Daca insa dorim sa pastram utilizatorul logat 2 ore, si gc_maxlifetime este 1440 secunde (24 min), e
probabil ca la un moment dat garbage collector-ul sa stearga fisierele de sesiune mai devreme decat ne-am dori, si atunci sesiunea de login tine mai putin
de 2 ore. Din aceasta cauza gc_maxlifetime trebuie setat atat cat setam $lifetime pentru cookie. Sau chiar putin mai mult (datorita posibilelor diferente de
timp intre client si server). In acest fel ne asiguram ca sesiunea nu expira datorita stergerii inoportune a fisierului de sesiune de pe server, ci va expira in
mod normal, cand expira cookie-ul de sesiune.
Se intampla insa ca setarile sa fie corecte, si fisierul de sesiune sa fie totusi sters. Acest lucru se intampla frecvent pe serverele de gazduire shared (mai
multe aplicatii web pe acelasi server) datorita faptului ca fisierele de sesiune stau in acelasi folder, /tmp, si interpretorul PHP nu tine pentru fiecare sesiune
valori separate ale gc_probability, gc_divisor si gc_maxlifetime, si atunci alege valoarea cea mai mica pentru gc_maxlifetime, astfel fisierele aplicatiei
noastre pot fi sterse mult mai devreme independent de setarile pe care le-am facut. Acest lucru nu se intampla daca folosim setarea
ini_set('session.save_path', '/home/dan/sesiuni/') pentru a salva fisierele intr-un folder ce ne apartine. Acest folder trebuie sa aiba drept de scriere (w)
pentru user-ul serverului web.

Startul unei sesiuni care nu se termina mai devreme de $seconds ar deveni atunci:

1 <?php
2 $seconds = 60 * 60 * 2; // 2 ore
3
4 ini_set('session.use_only_cookies', 1);
5 ini_set('session.gc_maxlifetime', $seconds + 600); // ceva mai mare
6 decat expirarea cookie-ului
7 session_name('mysession');
8 session_set_cookie_params($seconds);
9
10 session_start();
11 setcookie(session_name(), session_id(), time() + $seconds); //
12 prelungeste viata cookie-ului de la ultimul click
13
14 echo session_id();
15 echo '<br />';
16
17 // setam doua variabile de sesiune
18 $_SESSION['username'] = 'dan';
19 $_SESSION['uid'] = 7;

?>

Cum incheiem totusi o sesiune ?


Mai sus, am tratat problema sesiunilor ce se pot termina mai devreme decat ne dorim. Daca insa dorim sa terminam o sesiune cand utilizatorul apasa pe
un buton de Logout ? Bineinteles, atunci trebuie sa fortam terminarea sesiunii, ce implica urmatoarele lucruri:

 pornirea sesiunii cu session_start(). Scriptul care distruge o sesiune trebuie intai sa o porneasca

 stergerea cookie-ului de sesiune; adica setarea lui intr-o data din trecut; e important sa setam aceeasi cale cu cea cu care a fost setat cookie-
ul de sesiune. implicit "/"

 stergerea datelor din tabloul de sesiune. $_SESSION = array(). Acest lucru s-ar fi intamplat oricum, dar abia la request-ul urmator. Este
necesar sa nu mai avem nici o informatie despre sesiunea respectiva in $_SESSION.

 session_destroy() sterge datele sesiunii (fisierul de sesiune)

pagina1.php
1 <?php
2 $seconds = 60 * 60 * 2; // 2 ore
3
4 ini_set('session.use_only_cookies', 1);
5 ini_set('session.gc_maxlifetime', $seconds + 600); // ceva mai mare
6 decat expirarea cookie-ului
7 session_name('mysession');
8 session_set_cookie_params($seconds);
9
10 session_start();
11 setcookie(session_name(), session_id(), $seconds, "/"); //
12 prelungeste viata cookie-ului de la ultimul click
13
14 echo session_id();
15 echo '<br />';
16
17 // setam doua variabile de sesiune
18 $_SESSION['username'] = 'dan';
19 $_SESSION['uid'] = 7;
20
21
22 print_r($_SESSION);
23 ?>

<a href="logout.php">logout</a>

logout.php
1 <?php
2 $seconds = 60 * 60 * 2; // 2 ore
3
4 ini_set('session.use_only_cookies', 1);
5 ini_set('session.gc_maxlifetime', $seconds + 600); // ceva mai mare
6 decat expirarea cookie-ului
7 session_name('mysession');
8 session_set_cookie_params($seconds);
9
10 session_start();
11
12 setcookie(session_name(), FALSE, 1, "/"); // sterge cookie-ul de
13 sesiune (1 reprezinta prima secunda din anul 1970, deci mult in
14 trecut)
15
16 $_SESSION = array(); // se sterg datele din $_SESSION
17
18 session_destroy(); // se sterg datele din fisierul de sesiune
19
20
?>

<a href="pagina1.php">pagina1</a>

10.4.6.. Incheierea unei sesiuni


Discutam aici in principiu despre sesiunile ale caror id se transmite prin cookie. Inchiderea/expirarea unei sesiuni presupune unul din urmatoarele lucruri:

 cookie-ul de sesiune expira sau este sters de pe calculatorul utilizatorului

 fisierul ce contine datele sesiunii este sters de pe server

Daca unui cookie de sesiune nu-i setam data de expirare, in mod implicit cookie-ul are parametrul $expires = 0, deci expira la inchiderea browserului.
Putem insa seta sesiunea sa expire peste cat timp dorim asa cum am vazut anterior cu ajutorul functiei session_set_cookie_params() sau setand din nou
cookie-ul de sesiune cu setcookie().
Insa, exista problema cand fisierul de sesiune dispare de pe server inainte sa expire cookie-ul utilizatorului. Presupunand ca folosim sesiunea pentru login,
utilizatorul va fi atunci delogat pentru ca datele sesiunii (din $_SESSION) se pierd.
Cum dispare fisierul sesiunii de pe server ?
Interpretorul PHP ruleaza din cand in cand un program numit "garbage collector" care sterge fisierele "vechi" de sesiune de pe server. Cand ruleaza acest
program si cum se considera fisierele de sesiune "vechi" ? Exista trei setari (in php.ini, se pot schimba cu ini_set), ce au urmatoarele valori implicite:

session.gc_probability 1

session.gc_divisor 100

session.gc_maxlifetime 1440

Cand garbage collector ruleaza pe server, sterge fisierele de sesiune mai vechi de gc_maxlifetime secunde. Implicit pe cele mai vechi de 1440 secunde (24
minute). Acest program este setat sa ruleze cand se pornesc noi sesiuni sau se continua sesiuni existente cu session_start() insa nu de fiecare data ci cu o
frecventa de gc_probability/gc_divisor, implicit 1%, sau 0.01. Adica, cu setarile implicite, la 100 de apelari ale lui session_start() pe serverul respectiv se
va apela garbage collector o data. Daca aveam gc_probability 1 si gc_divisor 3, atunci la 1 din 3 porniri de sesiuni se rula si garbage collector.
In concluzie ce e important este ca atunci cand ruleaza garbage collector sterge fisiere de sesiune mai vechi de 1440 de secunde (sau de
gc_maxlifetime secunde).
Daca un fisier e mai vechi de gc_maxlifetime secunde nu inseamna deci ca el este imediat sters, poate fi sters dupa inca 2 ore, sau 2 zile, cand ruleaza
garbage collector dar nu va fi sters mai devreme. Daca insa dorim sa pastram utilizatorul logat 2 ore, si gc_maxlifetime este 1440 secunde (24 min), e
probabil ca la un moment dat garbage collector-ul sa stearga fisierele de sesiune mai devreme decat ne-am dori, si atunci sesiunea de login tine mai putin
de 2 ore. Din aceasta cauza gc_maxlifetime trebuie setat atat cat setam $lifetime pentru cookie. Sau chiar putin mai mult (datorita posibilelor diferente de
timp intre client si server). In acest fel ne asiguram ca sesiunea nu expira datorita stergerii inoportune a fisierului de sesiune de pe server, ci va expira in
mod normal, cand expira cookie-ul de sesiune.
Se intampla insa ca setarile sa fie corecte, si fisierul de sesiune sa fie totusi sters. Acest lucru se intampla frecvent pe serverele de gazduire shared (mai
multe aplicatii web pe acelasi server) datorita faptului ca fisierele de sesiune stau in acelasi folder, /tmp, si interpretorul PHP nu tine pentru fiecare sesiune
valori separate ale gc_probability, gc_divisor si gc_maxlifetime, si atunci alege valoarea cea mai mica pentru gc_maxlifetime, astfel fisierele aplicatiei
noastre pot fi sterse mult mai devreme independent de setarile pe care le-am facut. Acest lucru nu se intampla daca folosim setarea
ini_set('session.save_path', '/home/dan/sesiuni/') pentru a salva fisierele intr-un folder ce ne apartine. Acest folder trebuie sa aiba drept de scriere (w)
pentru user-ul serverului web.

Startul unei sesiuni care nu se termina mai devreme de $seconds ar deveni atunci:

1 <?php
2 $seconds = 60 * 60 * 2; // 2 ore
3
4 ini_set('session.use_only_cookies', 1);
5 ini_set('session.gc_maxlifetime', $seconds + 600); // ceva mai mare
6 decat expirarea cookie-ului
7 session_name('mysession');
8 session_set_cookie_params($seconds);
9
10 session_start();
11 setcookie(session_name(), session_id(), time() + $seconds); //
12 prelungeste viata cookie-ului de la ultimul click
13
14 echo session_id();
15 echo '<br />';
16
17 // setam doua variabile de sesiune
18 $_SESSION['username'] = 'dan';
19 $_SESSION['uid'] = 7;

?>

Cum incheiem totusi o sesiune ?


Mai sus, am tratat problema sesiunilor ce se pot termina mai devreme decat ne dorim. Daca insa dorim sa terminam o sesiune cand utilizatorul apasa pe
un buton de Logout ? Bineinteles, atunci trebuie sa fortam terminarea sesiunii, ce implica urmatoarele lucruri:

 pornirea sesiunii cu session_start(). Scriptul care distruge o sesiune trebuie intai sa o porneasca

 stergerea cookie-ului de sesiune; adica setarea lui intr-o data din trecut; e important sa setam aceeasi cale cu cea cu care a fost setat cookie-
ul de sesiune. implicit "/"

 stergerea datelor din tabloul de sesiune. $_SESSION = array(). Acest lucru s-ar fi intamplat oricum, dar abia la request-ul urmator. Este
necesar sa nu mai avem nici o informatie despre sesiunea respectiva in $_SESSION.

 session_destroy() sterge datele sesiunii (fisierul de sesiune)

pagina1.php
1 <?php
2 $seconds = 60 * 60 * 2; // 2 ore
3
4 ini_set('session.use_only_cookies', 1);
5 ini_set('session.gc_maxlifetime', $seconds + 600); // ceva mai mare
6 decat expirarea cookie-ului
7 session_name('mysession');
8 session_set_cookie_params($seconds);
9
10 session_start();
11 setcookie(session_name(), session_id(), $seconds, "/"); //
12 prelungeste viata cookie-ului de la ultimul click
13
14 echo session_id();
15 echo '<br />';
16
17 // setam doua variabile de sesiune
18 $_SESSION['username'] = 'dan';
19 $_SESSION['uid'] = 7;
20
21
22 print_r($_SESSION);
23 ?>

<a href="logout.php">logout</a>

logout.php
1 <?php
2 $seconds = 60 * 60 * 2; // 2 ore
3
4 ini_set('session.use_only_cookies', 1);
5 ini_set('session.gc_maxlifetime', $seconds + 600); // ceva mai mare
6 decat expirarea cookie-ului
7 session_name('mysession');
8 session_set_cookie_params($seconds);
9
10 session_start();
11
12 setcookie(session_name(), FALSE, 1, "/"); // sterge cookie-ul de
13 sesiune (1 reprezinta prima secunda din anul 1970, deci mult in
14 trecut)
15
16 $_SESSION = array(); // se sterg datele din $_SESSION
17
18 session_destroy(); // se sterg datele din fisierul de sesiune
19
20
?>

<a href="pagina1.php">pagina1</a>

10.5. Mini-aplicatie login


Descarca aplicatia
Pentru setarea aplicatiei, citeste fisierul "citeste_ma.txt" din arhiva. Descarca aplicatia aici

Structura aplicatiei
Structura este asemanatoare cu cea a aplicatiei de la capitolul PHP si MySQL, cu cateva mici diferente. S-a folosit un fisier de configurare al
aplicatiei, lib/config.php ce pastreaza optiunile necesare intr-un array numit $siteGlobals. Acesta se formeaza diferit in functie de valoarea variabilei
$_SERVER['REMOTE_ADDR'] ce reprezinta adresa ip a serverului pe care ne aflam, si in functie de care ne putem da seama daca script-ul se ruleaza offline
sau online. sessions.php este un fisier ce tine functiile legate de sesiuni, de utilizatori.
Aplicatia are "paginile" index.php, login.php, logout.php, restricted1.php si restricted2.php.

 index.php este o pagina la care au acces atat utilizatorii logati (autentificati) cat si cei anonimi. Insa, putem servi continut diferit in functie
de cele doua categorii de utilizatori, cu ajutorul functiei is_logged() ce determina daca vizitatorul este logat sau nu.

 login.php - este script-ul de login (ce poate fi la un moment dat pus intr-o functie) - ce logheaza un utilizator si-l redirectioneaza intr-o
pagina restrictionata

 restricted1.php si restricted2.php sunt paginile la care au acces doar utilizatorii logati. La inceputul paginilor pe care vrem sa le
restrictionam, trebuie sa apelam functia authorize()

 logout.php - script-ul care distruge sesiunea (de-logheaza) si apoi redirecteaza la index

login.php
Ideea principala este sa verificam daca avem o singura inregistrare in tabelul users, ce se potriveste cu username-ul si parola completate de utilizator.
Ideal este sa facem o verificare mai riguroasa a utilizatorului si parolei (nr de caractere, caractere nepermise, etc) inainte sa facem verificarea in baza de
date. Acolo unde in script este verificarea simpla:

10 <?php
11
12 if (!$username or !$pw) {
13 $error = 1;
14 }
15 ?>

Apoi, daca au trecut de prima verificare, username-ul si parola sunt introduse in sql-ul ce cauta inregistrarea potrivita in tabelul users. Insa, username-ul
este trimis functiei mysql_real_escape_string(), functie ce precede cu backslash (\) caracterele cu inteles special in limbajul sql, evitand astfel posibilele
atacuri de tip "sql injection". Parola este transformata in hash, cu ajutorul functiei sha1(); pentru ca nu pastram in baza de date parolele in clar ci hash-ul
lor, un sir de 40 de caractere hexazecimale (in baza 16). Hash-ul este un cod, obtinut printr-o functie speciala, numita functie hash, aici sha1. Acest cod
are proprietatea ca nu va fi identic cu alt cod obtinut din alta informatie digitala. Si mai are proprietatea ca NU se poate obtine informatia originala doar
pe baza hash-ului. Deci, fiecare parola va avea codul ei, si nu se poate determina parola pe baza codului. Verificam deci daca exista o inregistrare pentru
utilizatorul introdus, si pentru hash-ul parolei introduse. Acest lucru presupune automat ca la inregistrare (insert-ul in baza de date), in loc sa introducem
parola, introducem hash-ul parolei.

17 <?php
18 $username = mysql_real_escape_string($username);
19 $pw = sha1($pw); // in baza de date va fi stocat hash-ul parolei,
20 nu parola insasi
21
22 $sql = ' SELECT uid, username FROM users WHERE username = "'.
23 $username.'" AND pw = "'.$pw.'" ';
24 //echo $sql;
25 $result = mysqli_query($link, $sql) or die(mysqli_error());
26
if (mysqli_num_rows($result) == 1) {
?>

Daca exista o inregistrare (daca exista mai multe inregistrari inseamna ca avem o problema destul de mare - mai multi utilizatori cu acelasi username si
aceeasi parola), inseamna ca utilizatorul nostru este autentificat, trebuie sa-i creem o sesiune si sa-i pastram datele de sesiune.
Functia my_session_start() contine setarile si codul necesar pornirii unei sesiuni bazate pe cookies, asa cum am discutat in subcapitolele anterioare. Aici
este singurul punct in care apelam my_session_start(1) avand parametrul 1, adica $regenerate_id = 1. In functia my_session_start(), daca
$regenerate_id este 1, "regeneram" id-ul. Aceasta functie, session_regenerate_id() genereaza un nou id pentru sesiunea curenta (deci un nou fisier de
sesiune), pastrand datele sesiunii existente. Este necesar acest lucru pentru a evita atacuri de gen Session fixation (vezi Resurse). Apoi, dupa ce
pornim sesiunea cu un nou id, pastram in variabile de sesiune valoarea uid-ului (uid - prescurtare de la userId) si username-ului pentru acel user, valori
extrase din baza de date.
Nu este necesar sa pastram toate valorile utilizatorului in variabilele de sesiune. Este de ajuns doar valoarea uid-ului din baza de date. Il putem folosi
atunci pentru a obtine ce informatii avem despre utilizator.

24 <?php
25 if (mysqli_num_rows($result) == 1) {
26 // do login
27 my_session_start(1);
28 $d = mysqli_fetch_assoc($result);
29 $_SESSION['uid'] = $d["uid"];
30 $_SESSION['username'] = $d["username"];
31
32 redirect('restricted1.php');
33 ?>

Functiile is_logged() si authorize()


Functia is_logged() decide de fapt daca utilizatorul ce ne viziteaza pagina este logat sau nu. Simpla verifica daca este setata variabila de sesiune
$_SESSION['uid'] este de ajuns. $_SESSION['uid'] va fi setat doar daca sesiunea pornita de php cu session id-ul primit de la utilizator prin cookie este o
sesiune activa pe server (exista fisierul de sesiune), si contine o valoare pentru uid.
In aplicatia noastra, setam $_SESSION['uid'] doar cand logam utilizatorul, deci, se creeaza un fisier de sesiune cu informatia respectiva pe server.

Un utilizator nu poate manipula tabloul $_SESSION generat de php, decat daca are acces
la fisierele de sesiune de pe server.

42 <?php
43 function is_logged()
44 {
45 if (isset($_SESSION['uid'])) {
46 return 1;
47 } else {
48 return 0;
49 }
50 }
51 ?>

Functia authorize() porneste o sesiune pentru orice vizitator (fie el logat sau nu), ca apoi sa verificam cu is_logged() daca sesiunea apartine unui
utilizator autentificat (exista uid) sau unui utilizator anonim. Astfel, sesiunile sunt pornite si pentru utilizatori neautentificati, dar in sesiunea respeciva nu

se pastreaza informatia "uid". Daca utilizatorul nu este autentificat, functia authorize() il redirectioneaza catre login.php

53 <?php
54 // (re)porneste sesiunea - my_session_start(). daca nu este logat, il
55 scoate din pagina, pentru ca nu are acces
56 function authorize()
57 {
58 my_session_start();
59
60 if (!is_logged()) {
61 redirect('login.php');
62 exit;
63 }
64 }
?>

Nota
Vezi sectiunea de resurse pentru masuri mai severe de securitate a sesiunilor: regenerarea id-ului de sesiune la fiecare request, comunicatia prin
HTTPS, etc.

Resurse
Articol SitePoint.com despre securitatea sesiunilor
http://en.wikipedia.org/wiki/Session_fixation
PHP Manual - session_regenerate_id()
http://en.wikipedia.org/wiki/Cryptographic_hash_function

CAP.11. Clase si obiecte (I)


11.1 Despre OOP. Conceptul de clasa, si obiect.
11.2 Sintaxa de baza
11.3 Atribute
11.4 Constante
11.5 Metode. Cuvantul cheie $this
11.6 public. private. protected
11.7 Constructor. Destructor
11.8 Metode getter si setter
11.9 Metodele magice
11.10 Atribuirea unui obiect unei variabile
11.11 Clonarea obiectelor
11.12 Cuvantul static
11.13 Functia __autoload
11.14 Type hinting
11.15 Operatorul instanceof
11.16 Functii pentru clase si obiecte
11.17 Composition - atribute de tip obiect
11.18 Tema

11.1. Despre OOP. Conceptul de clasa, si obiect.


OOP inseamna "Object-Oriented Programming" sau programare orientata pe obiecte. Exista mai multe modele de a programa, cele mai cunoscute fiind
cel procedural si cel orientat pe obiecte (OOP). Unele limbaje suporta ambele modele de programare, altele sunt construite pentru a suporta doar unul
din ele.
Limbaje ca C++, Python, PHP suporta programarea procedurala cat si cea orientata obiect. In Java totul este un obiect, deci suporta doar modelul OOP.
Limbajul C este un limbaj procedural.

Programarea procedurala presupune organizarea codului in functii, si variabile, fara a fi necesara gruparea si organizarea lor in structuri de date
complexe.

Pe de alta parte, programarea pe obiecte pleaca de la ideea organizarii unor concepte din lumea reala in anumite entitati separate - structuri de date
definite de programator.

O astfel de structura, este denumita clasa, si contine atat datele efective legate de acel concept cat si actiuni legate de conceptul respectiv.

Intalnim astfel in programarea OOP, spre deosebire de programarea procedurala (in care lucram cu functii si variabile) urmatorii termeni, concretizati in
facilitati suportate de limbaj:

 clasa - tipul de date sau structura definita de programator ce contine atribute(variabile) si metode(functii)

 obiect - obiectele se mai numesc instante ale clasei sau copii individuale ale clasei ce contin fiecare informatii proprii (diferite valori
ale atributelor) si respecta structura sablonului din care au fost create: clasa

 atribute (sau proprietati, campuri, sau "member variables") sunt datele, sau variabilele definite in clasa respectiva. In general, fiecare obiect
are propriile valori pentru aceste variabile. Similar cum diferite persoane au valori diferite pentru nume, prenume, varsta, etc.

 metode - reprezinta actiunile definite de clasa respectiva, adica functiile definite in clasa. Astfel, spre deosebire de programarea procedurala,
aici functiile nu sunt de sine statatoare, ele sunt definite in interiorul unei clase si vor fi apelate doar prin intermediul unui obiect din clasa
respectiva. (uneori prin intermediul clasei).

Deci, putem spune ca pe baza unei clase putem crea mai multe obiecte apartinand clasei respective, tot asa cum avand tipulint, putem crea mai multe
variabile din acest tip. O clasa contine atribute (variabile) si metode (functii) ce vor fi apoi specifice obiectelor create.

Nota
In unele documentatii, se foloseste terminologia "membru al clasei" pentru a desemna atributele. In alte documentatii, prin membru se poate
intelege atat un atribut cat si o metoda definita in clasa.

Desi denumirea variabilelor ce reprezinta instante ale claselor este de "obiecte" pentru asemanarea cu concepte din lumea reala, un "obiect" in programare
poate reprezenta: o tranzactie, un utilizator, un formular sau un element dintr-un formular, sau orice alta entitate cu care lucram in aplicatia noastra web.

Resurse
http://en.wikipedia.org/wiki/Object-oriented_programming

11.2. Sintaxa de baza


In PHP se defineste o clasa cu ajutorul cuvantului cheie class, urmat de numele clasei (pe care-l alegem in functie de ce reprezinta), si incadrand
continutul intre acolade.

1 <?php
2 class ClasaMea {
3
4}
5 ?>

Crearea de obiecte ce apartin acestei clase (instantierea clasei) se realizeaza cu ajutorul operatorului new urmat de numele clasei sub forma unei functii.

1 <?php
2 $x = new ClasaMea(); // x este un obiect (o instanta) al clasei
3 ClasaMea
4 $y = new ClasaMea(); // Y este alt obiect din aceeasi clasa
?>

Resurse
PHP Manual - Classes and Objects - The Basics

11.3. Atribute
Atributele unei clase sunt variabilele definite in interiorul functiei. Fiecare obiect creat din clasa respectiva va avea propriile valori ale atributelor respective.
Diferentele intre variabilele obisnuite si atribute sunt urmatoarele:

 atributele sunt definite in interiorul clasei

 atributele pot fi definite fara sa fie initializate cu o valoare anume

 la definire, atributele sunt precedate de unul din modificatorii de acces: public, protected, private

 daca sunt initializate, valorile primite de atribute trebuie sa fie valori propriu-zise, constante, nu sunt permise expresii, apeluri de functii, sau
alte variabile

1 <?php
2 class Persoana {
3 public $prenume;
4 public $nume;
5 private $adresa;
6
7
8}
9 ?>

Modificatorii de acces sunt cuvintele cheie public, protected sau private si preced atributele si (optional) metodele in momentul definirii, pentru a dicta
accesul la aceste variabile din afara clasei. Detalii intr-un subcapitol urmator.

In exemplul urmator, atributele $nume si $prenume au valori implicite (default) la definirea in interiorul clasei. Asta inseamna ca toate obiectele de tip
Persoana vor avea implicit la creare valorile respective pentru atributele $prenume si $nume.

1 <?php
2 class Persoana {
3 public $prenume = 'John';
4 public $nume = 'Doe';
5 private $adresa;
6
7}
8
9 ?>

Accesul la atribute
Accesul la atributele unui obiect se realizeaza cu ajutorul operatorului ->. Numele varibilei ce reprezinta obiectul precede ->, urmeaza apoi atributul ce
este citit sau modificat. Exemplu prin codul $p->nume accesam atributul nume al obiectului $p. Observati ca la accesarea prin intermediul unui obiect
semnul "$" nu se pune in fata atributului, doar in fata variabilei ce reprezinta obiectul. Insa la definirea in interiorul clasei, atributul este precedat de "$".

1 <?php
2
3 class Persoana {
4 public $prenume = 'John';
5 public $nume = 'Doe';
6 private $adresa;
7
8}
9
10 $p1 = new Persoana();
11 echo $p1->prenume; // John
12 $p1->prenume = 'Ion';
13 echo $p1->prenume; // Ion
14
15 $p2 = new Persoana();
16 $p2->prenume = 'Vasile';
17 $p2->nume = 'Petre';
18 echo $p2->prenume; // Vasile
19 echo strtoupper($p2->nume); // PETRE
20
21
22 ?>

Odata definit, putem folosi atributul unui obiect in orice loc am folosi o variabila: intr-o expresie, ca parametru pentru o functie, etc
Resurse
PHP Manual - Classes and Objects - The Basics

11.4. Constante
Constantele unei clase, similar cu constantele de sine statatoare, contin valori ce nu se schimba. Contantele au urmatoarele proprietati:

 se declara: const numeConstanta;

 sunt initializate obligatoriu in momentul cand sunt definite, cu o valoare constanta (nu expresie, variabila, etc) si de un tip scalar (deci nu
array)

 nu sunt precedate de modificatorii de acces, sunt automat publice

 constantele clasei exista intr-un singur exemplar, avand aceeasi valoare (si loc de memorie) pentru fiecare obiect al clasei.

 pot fi accesate cu operatorul ::


Din afara clasei prin NumeClasa::numeConstanta. Din interiorul clasei cu self:numeConstanta
self este un cuvant cheie ce reprezinta clasa curenta

1 <?php
2 class Newsletter {
3 const emailFrom = 'john@example.com';
4
5
6 function emailFrom()
7 {
8 return self::emailFrom;
9 }
10
11 }
12
13
14 echo Newsletter::emailFrom; // accesarea constantei din afara clasei
15 echo '<br />';
16 $n = new Newsletter;
17 echo $n->emailFrom(); // returnarea constantei de o metoda din clasa
18 ce o acceseaza folosind 'self'
19
20
?>

Resurse
PHP Manual - Class Constants

11.5. Metode. Cuvantul cheie $this

Metodele sunt functiile definite in interiorul clasei. O metoda poate fi precedata de un modificator de acces, public, protected sau private. Implicit
metodele sunt publice. Un exemplu simplu de definire a unei metode arata astfel:

1 <?php
2
3 class Persoana {
4 public $prenume;
5 public $nume;
6 private $adresa;
7
8 function getNume()
9 {
10
11 }
12
13 }
14 ?>

Metoda getNume() nu face deocamdata nimic pentru ca definitia ei nu contine instructiuni. Metodele au asemanari cu functiile obisnuite: primesc
parametrii, pot returna valori, pot fi apelate acolo unde poate fi apelata orice functie. Insa, din exteriorul clasei se apeleaza fiind precedate de un obiect, cu
ajutorul operatorului "->", similar cu accesarea atributelor.

1 <?php
2
3 class Persoana {
4 public $prenume;
5 public $nume;
6 private $adresa;
7
8 function getNume()
9 {
10
11 }
12
13 } /// end class
14
15
16 $p = new Persoana();
17 $p->getNume(); // apelarea functiei getNume() pentru obiectul $p
18 ?>

Spre deosebire de atribute, ce au valori diferite pentru fiecare obiect al clasei si au existenta independenta in memorie (practic sunt variabile diferite),
metodele au o singura existenta, atat in memorie cat si in logica programului, indiferent de obiectele create.
Cand sunt apelate, metodele stiu sa acceseze atributele obiectului curent. Pentru acest lucru, in interiorul metodelor trebuie sa folosim cuvantul
cheie $this in fata atributelor. Astfel, $this semnifica obiectul curent. In momentul cand apelez $p->spuneNume(), este ca si cum as transmite ca
parametru functiei spuneNume() obiectul $p, obiectul curent. Astfel, in interiorul metodei spuneNume() acest parametru devine $this, adica obiectul
curent, cel pentru care am apelat metoda. $this il folosim in interiorul metodelor atat pentru accesarea atributelor obiectului curent cat si pentru chemarea
altor metode din clasa respectiva. In acest exemplu, $this->prenume si $this->nume sunt atributele obiectului curent. Metoda afiseaza() nu opereaza cu
nici un atribut ce apartine vreunui obiect. Similar cu o functie, primeste un parametru ce devine apoi variabila locala pentru aceasta metoda. Ea poate fi
chemata cu acest parametru atat din alta metoda a clasei, cat si din exteriorul clasei (dar precedata de un obiect).

1 <?php
2
3 class Persoana {
4 public $prenume;
5 public $nume;
6 private $adresa;
7
8 function spuneNume()
9 {
10 $numeComplet = $this->prenume . ' ' . $this->nume;
11 $this->afiseaza($numeComplet);
12 }
13
14
15 function afiseaza($s)
16 {
17 echo $s;
18 echo '<br />';
19 }
20
21 } /// end class
22
23
24 $p = new Persoana();
25 $p->prenume = 'Rasmus';
26 $p->nume = 'Lerdorf';
27
28 $p->spuneNume();
29
30 $p->afiseaza('cineva');
31 ?>

Resurse
PHP Manual - Classes and Objects - The Basics

11.6. public. private. protected


Modificatorii de acces sunt cuvintele cheie "public", "private" si "protected" puse in fata atributelor sau metodelor unei clase pentru a regla vizibilitatea
acestora din afara clasei. In definirea variabilelor este obligatorie specificarea unui modificator de acces. In fata metodelor nu este obligatorie, in caz ca nu
specificam implicit se considera "public". Efectul acestora este urmatorul:

 public - membrul respectiv (atribut sau metoda) este vizibil complet in afara clasei

 protected - membrul respectiv este vizibil doar in clasele derivate (ce mostenesc) din aceasta clasa (mai multe detalii in capitolul despre
Inheritance)
 private - membrul respectiv nu este vizibil decat in alte metode din cadrul aceleiasi clase. Acest membru este "ascuns" in interiorul clasei, nu
poate fi accesat din exterior.

In exemplul urmator, atributul $adresa nu poate fi accesat din afara clasei, fiind privat. In schimb, il putem seta prin intermediul metodei publice
setAdresa() care are acces la acest atribut, fiind in interiorul aceleiasi clase.

1 <?php
2
3 class Persoana {
4 public $prenume;
5 public $nume;
6 private $adresa;
7 public $oras;
8
9 function spuneNume()
10 {
11 $numeComplet = $this->prenume . ' ' . $this->nume;
12 $this->afiseaza($numeComplet);
13 }
14
15 function setAdresa($a, $o)
16 {
17 $this->adresa = $a;
18 $this->oras = $o;
19 }
20
21
22 } /// end class
23
24
25 $p = new Persoana();
26 $p->prenume = 'Mihai';
27 $p->nume = 'Ionescu';
28 $p->adresa = 'Sos Mihai Bravu nr 33, Bucuresti'; // Fatal error:
29 Cannot access private property Persoana::$adresa
30
31 $p->setAdresa('Sos Mihai Bravu nr 33', 'Bucuresti');
32
?>

Resurse
PHP Manual - Visibility

11.7. Constructor. Destructor


Constructor
Se poate declara o metoda speciala numita constructor, in interiorul unei clase, ce trebuie denumita __construct (precedata de doua caractere underline),
metoda ce este executata la realizarea unui obiect nou. apartinand clasei respective. In general in aceasta metoda se pune cod de initializare a
obiectelor nou create, poate setarea unor valori implicite pentru atribute ale obiectului.

Nota
In PHP4 constructorul era o metoda ce avea acelasi nume cu al clasei. In PHP5, pentru compatibilitate, ramane inca aceasta posiblitate.

1 <?php
2
3 class Persoana {
4 public $prenume;
5 public $nume;
6 private $adresa;
7 public $oras;
8
9 // constructorul clasei Persoana
10 function __construct($p, $n)
11 {
12 $this->prenume = $p;
13 $this->nume = $n;
14 }
15
16
17 function spuneNume()
18 {
19 $numeComplet = $this->prenume . ' ' . $this->nume;
20 $this->afiseaza($numeComplet);
21 }
22
23 function afiseaza($s)
24 {
25 echo $s;
26 echo '<br />';
27 }
28
29
30 } /// end class
31
32
33 $p = new Persoana('Mihai', 'Ionescu');
34 $p->spuneNume();
35 ?>

Destructor
Destructorul este o metoda speciala executata in momentul cand se sterg referintele catre obiectul respectiv (cu functia unset() de exemplu). Toate
obiectele sunt automat "distruse" in momentul cand se incheie executia script-ului, si atunci este apelata si aceasta metoda. Este bineinteles optionala, si
se foloseste in cazurile cand avem activitati de "curatenie" cand dispare un obiect: de exemplu stergem un fisier/tabel temporar folosit de fisier, inchidem
o conexiune la baza de date, etc.

1 <?php
2
3 class Test {
4
5 function __destruct()
6 {
7 echo 'E sters';
8 }
9
10
11
12 }
13
14 $t = new Test();
15 unset($t);
16 ?>

Resurse
PHP Manual - Constructors and Destructors
11.8. Metode getter si setter
Deseori, in programarea orientata obiect, este de preferat sa stabilim metode separate pentru citirea sau modificarea anumitor atribute din clasa. Astfel,
codul client (partea din cod din afara clasei ce foloseste aceasta clasa) nu va avea acces direct la atributele respective, care in general sunt private, ci prin
intermediul acestor metode standard, numite "getter" si "setter".

 metode de tip getter - denumite si accesor - sunt destinate citirii unui atribut declarat private, care bineinteles nu poate fi accesat in mod
direct din afara clasei. Denumim aceste metode getAtribut() si in general nu primesc argument, si returneaza valoarea atributului respectiv

 metode de tip setter - denumite si mutator - sunt destinate modificarii unui atribut private. Aceste metode se
denumescsetAtribut($valoare), primind ca parametru valoarea cu care modificam atributul respectiv

Setarea acestor metode se face de catre programator, atunci cand simte nevoia sa ofere un acces controlat la anumite atribute ale clasei respective. La
accesarea unui astfel de atribut, cu o metoda tip getAtribut(), programatorul poate alege sa formateze, verifice sau sa schimbe forma atributului inainte
sa-l returneze codului client. Metodele de tip setAtribut($valoare) realizeaza o filtrare a valorii primite pentru setarea atributului respectiv. Programatorul
clasei are posibilitatea prin setters sa verifice validitatea datelor primite, sa le respinga, sa genereze o eroare, sau sa le modifice.

Un exemplu simplu, arata astfel:

1 <?php
2
3 class User {
4
5 private $email;
6
7
8 // getter pentru atributul $email
9 function getEmail()
10 {
11 return $this->email;
12 }
13
14
15 // setter pentru atributul $email
16 function setEmail($e)
17 {
18 $this->email = $e;
19 }
20
21 }
22
23
24 $a = new User();
25 $a->setEmail('john@gmail.com');
26
27 echo $a->getEmail();
28 ?>

11.9. Metodele magice


Exista un set de metode predefinite in PHP, ce pot fi folosite in interiorul unei clase, si al caror nume incepe cu "__" (dublu underscore). Cateva dintre
acestea sunt: __autoload(), __get(), __set(), __call(), __callStatic(), __toString, etc. In aceeasi categorie intra si __construct() si __destruct().
Aceste metode sunt denumite "magice" pentru ca sunt apelate automat de catre interpretorul PHP in diferite situatii: de exemplu cand creez un nou obiect
(__construct()), cand folosesc o clasa al carei cod nu este in fisierele deja incluse (__autoload()) sau cand citesc un atribut inaccesibil pentru clasa
respectiva (__get()).

Voi prezenta in acest subcapitol acele metode magice prin care tratam accesarea atributelor sau metodelor innacesibile.

Nota
Denumim atribute sau metode innacesibile (sau membri inaccesibili), acele atribute sau metode ce nu exista in clasa respectiva (nu au fost definite)
sau la care nu avem acces datorita modificatorilor de acces.

__get() si __set()

 __get($name) - daca se defineste aceasta metoda intr-o clasa, va fi apelata de fiecare data cand incercam citirea (nu si modificarea) unui
atribut inaccesibil. Va primi ca parametru ($name) numele atributului pe care incercam sa-l modificam
 __set($name, $value) - se apeleaza cand incercam modificarea unui atribut inaccesibil. $name este numele atributului, iar $value este
valoarea cu care incercam modificarea atributului respectiv

In primul rand, un exemplu didactic, prin care pun in evidenta functionarea acestor metode.

1 <?php
2
3 class Test {
4
5 private $atribut1;
6
7
8 function __get($name)
9 {
10 echo 'se executa __get('.$name.')';
11 echo '<br />';
12 }
13
14 function __set($name, $value)
15 {
16 echo 'se executa __set('.$name.', '.$value.')';
17 echo '<br />';
18 }
19
20
21 }
22
23
24 $t = new Test();
25 $x = $t->atribut1; // se executa __get('atribut1') - pentru ca
26 atribut1 este private
27 $t->atribut1 = 'a' ; // se executa __set('atribut1', 'a')
28
29
30 echo $t->atributInexistent; // __get('atributInexistent')
31 $t->atributInexistent = 'alta valoare'; // __set('atributInexistent',
32 'alta valoare')

?>

In acest exemplu, folosim method_exists($obiect, 'metoda') pentru a gasi metode de tip setter sau getter in aceasta clasa. Inlocuim apoi incercarea de
accesare directa a unor atribute de tip private cu apelarea metodelor setter respectiv getter.

1 <?php
2
3 class Persoana {
4 private $prenume;
5 private $nume;
6
7
8
9 function getPrenume()
10 {
11 return $this->prenume;
12 }
13
14
15 function setPrenume($prenume)
16 {
17 $this->prenume = ucfirst($prenume);
18 }
19
20
21 function __get($attr)
22 {
23 $metoda = 'get' . ucfirst($attr); // metoda devine getAttr()
24
25 // daca exista metoda getAttr(), apelam $this->getAttr()
26 if (method_exists($this, $metoda)) {
27 return $this->$metoda();
28 }
29 }
30
31
32
33 function __set($attr, $value)
34 {
35 $metoda = 'set' . ucfirst($attr); // metoda devine setAttr()
36
37 // daca exista metoda setAttr(),
38 if (method_exists($this, $metoda)) {
39 return $this->$metoda($value); // apelam $this->setAttr($value)
40 }
41 }
42
43
44
45
46 } /// end class
47
48
49 $p = new Persoana();
50 $p->prenume = 'vasile'; // prenume este private. prin __set apelam de
51 fapt $p->setPrenume('vasile')
52 echo $p->prenume; // apelam prin __get() $p->getPrenume()
53
?>

__call si __callStatic

 __call($method, $arguments) - daca o definim in clasa noastra, este apelata in momentul cand incercam apelarea unei metode
inaccesibile. $metod va deveni numele metodei pe care incercam sa o apelam, iar $arguments un tablou ce contine argumentele cu care am
apelat metoda respectiva

 __callStatic($metod, $arguments) - similar cu __call dar pentru metodele statice (vezi capitolul "Cuvantul static"). Aceasta metoda este
disponibila incepand cu 5.3.0

1 <?php
2
3
4 class Test {
5
6 function __call($method, $args)
7 {
8 echo $method . ' ';
9 print_r($args);
10 echo '<br />';
11 }
12
13 }
14
15
16 $t = new Test();
17 $t->metodaInexistenta();
18 $t->alteMetoda('ceva', 'alt parametru');
19
20 ?>

__toString()
Obiectele in mod implicit nu pot fi convertite la string (ex: afisate cu echo) decat daca implementam in clasa respectiva o metoda __toString prin care
hotaram cum se va face conversia la string

Resurse
PHP Manual - Magic Methods

11.10. Atribuirea unui obiect unei variabile

Atribuirea valorilor de tip simplu unor variabile, functioneaza diferit fata de atribuirea unor valori de tip obiect. Spre exemplu, daca am $a = 3; si $b =
$a; , $b si $a sunt independente, corespund unor locatii de memorie diferite. Adica modificarile ulterioare pentru o variabila nu o afecteaza pe cealalta. $a
= $b este atribuirea prin valoare.
Asa cum am vazut, la atribuirea prin referinta $b = &$a; variabilele $a si $b practic sunt una si aceeasi variabila - nume diferite pentru aceeasi locatie de
memorie.

1 <?php
2
3 $a = 4;
4 $b = &$a;
5
6 echo $b;
7 echo '<br />';
8
9 $a = 55;
10 echo $b;
11
12 ?>

Ceea ce se intampla insa la atribuirea unor valori de tip obiect, este diferit fata de cazurile de mai sus. Ceea ce se stocheaza intr-o variabile de tip obiect
este locatia catre zona de memorie in care e stocat obiectul, adica ceea ce este numit "object handle", si nu obiectul insusi. In momentul cand $a = new
Test(); si $b = $a; , variabila $b va indica acelasi obiect, insa prin alt object handle. Ca efect, obiectul respectiv nu este duplicat, $b si $a se refera la
acelasi obiect, insa, $b si $a nu sunt nume diferite ale aceleiasi zone de memorie, sunt variabile independente, astfel schimbarea valorii pentru $b nu va
afecta valoarea variabilei $a.

1 <?php
2
3 class Persoana {
4 public $prenume;
5
6
7}
8
9 $a = new Persoana();
10 $a->prenume = 'Ion';
11
12 $b = $a;
13
14 echo $b->prenume; // Ion
15 $a->prenume = 'Marian';
16 echo $b->prenume; // Marian - $b si $a se refera la acelasi obiect
17
18 $b = 5;
19 $a->prenume = 'Vasile';
20
21 echo $a->prenume; // $a ramane obiectul initial
22 echo $b->prenume; // Notice -> b este acum intreg-ul 5
23 var_dump($b); // int(5)
24
25
26 ?>

Resurse
PHP Manual - Objects and references

11.11. Clonarea obiectelor

Pentru a obtine o copie independenta a unui obiect - adica un obiect cu aceleasi atribute, dar diferit fata de primul - se foloseste cuvantul cheie clone.
Aplicarea acestui cuvant cheie, rezulta in crearea unui obiect identic, si apelarea metodei __clone() pentru obiectul nou creat. Implementarea unei metode
__clone() este optionala, necesara doar in cazul unor actiuni specifice in legatura cu obiectul nou creat.

1 <?php
2
3 class Test {
4 private $name;
5
6 function __construct($name)
7 {
8 $this->name = $name;
9 }
10
11
12 function setName($name)
13 {
14 $this->name = $name;
15 }
16
17
18 function getName()
19 {
20 return $this->name;
21 }
22
23 function __clone()
24 {
25 echo 'M-am clonat. Ma cheama ' . $this->name;
26 echo '<br />';
27 }
28
29
30 }
31
32 $t1 = new Test('t1');
33 $t2 = clone $t1; // M-am clonat. Ma cheama t1
34
35 $t2->setName('t2');
36 echo 'Acum sunt ' . $t2->getName(); // t2
37 ?>

Resurse
PHP Manual - Object cloning

11.12. Cuvantul static


Cuvantul cheie static poate fi folosit atat in fata atributelor cat si in fata metodelor, acestea devenind "statice". Atributele statice mai sunt numite si "class
variables" (variabilele clasei), iar metodele statice mai sunt denumite "class functions" (functiile clasei), asta pentru ca termenul de "static" se refera la
apartenenta la clasa, si nu la instantele (obiectele) create din clasa respectiva. Atributele statice apartin clasei, nu obiectelor create, si sunt deci apelate
prin intermediul numelui clasei, astfel:

 NumeClasa::$numeAtribut - din afara clasei

 self::$numeAtribut - din interiorul clasei. self fiind un cuvant cheie ce desemneaza clasa curenta

Nota
Observati ca semnul $ , ce desemneaza prezenta unei variabile, este de data asta folosit inainte de numele atributului, dupa operatorul ::

Atributele statice au o singura valoare, a clasei, indiferent de obiectele create. Ele nu pot fi apelate folosind variabile de tip obiect si operatorul ->.

1 <?php
2
3 class Test {
4
5 public static $obiecteCreate;
6
7 function __construct()
8 {
9 self::$obiecteCreate ++;
10 }
11
12 }
13
14
15 echo Test::$obiecteCreate; // '' -> NULL convertit la string.
16 $t1 = new Test();
17 echo Test::$obiecteCreate; // 1;
18 echo $t1->obiecteCreate; // Notice: Undefined property....
19
20
21
22 ?>

Metodele statice pot fi apelate atat prin sintaxa asemanatoare atributelor statice, (NumeClasa::metoda() sau self::metoda() din interiorul clasei) , insa
pot fi apelate si prin intermediul unui obiect. Metodele statice nu au acces la atribute si metode ce apartin obiectului curent (folosind sintaxa $this), dar au
acces la alte atribute si metode statice.

1 <?php
2
3 class Persoana {
4 public static $nrFemei;
5 public static $nrBarbati;
6 private $sex;
7 public $name;
8
9 function __construct($sex, $name)
10 {
11 $this->name = $name;
12 self::statistica($sex, 1);
13 }
14
15
16 public static function statistica($sex, $count)
17 {
18 if ($sex == 'm') {
19 self::$nrBarbati += $count;
20 } else {
21 self::$nrFemei += $count;
22 }
23 }
24
25 public static function getStatistica()
26 {
27 // echo $this->name; // Fatal error: Using $this when not in
28 object contex
29 return array(
30 'nrBarbati' => self::$nrBarbati,
31 'nrFemei' => self::$nrFemei
32 );
33 }
34
35 }
36
37 $p1 = new Persoana('m', 'ion');
38 $p2 = new Persoana('f', 'ana');
39 $p3 = new Persoana('f', 'maria');
40
41 print_r(Persoana::getStatistica());
42 // print_r($p3->getStatistica()); // ok si-asa
?>

Resurse
PHP Manual - Static keyword

11.13. Functia __autoload

Exista o functie "magica", numita __autoload(), ce poate fi definita de catre programator, (functie normala, nu depinde de o clasa anume) pentru
includerea automata a fisierelor ce contin definitii de clasa. Se practica in general pastrarea unui fisier pentru o definitie a unei clase. Daca lucram cu multe
clase, nu are rost sa scriem instructiuni include pentru toate fisierele cu clase ce ne-ar fi de folos, in schimb folosim aceasta functie.
Functia primeste ca parametru numele clasei a carei definitie este cautata de interpretorul php.

Nota
Datorita faptului ca include fisiere de pe harddisk, trebuie sa nu folosim input de la utilizator pentru formarea caii catre fisiere, pentru a nu avea
probleme de securitate prin introducerea caracterelor "../". Daca totusi folosim surse nesigure in aceasta functie, trebuie sa o verificam sa nu
contina astfel de caractere

In exemplul de mai jos, declaratia clasei Test1 este intr-un fisier numit Test1.php in folderul lib aflat pe acelasi nivel cu scriptul php.

1 <?php
2
3 function __autoload($className)
4{
5 require 'lib/'.$className.'.php';
6}
7
8 $t = new Test1();
9 ?>

11.14. Type hinting

Incepand cu PHP5, limbajul suporta ceea ce se numeste "type hinting", adica impunerea unor argumente primite de o functie sa fie un obiect dintr-o
anumita clasa, sau array. Limbajul nu permite fortarea argumentelor din tipurile primitive: int, string, etc. Aceasta facilitate functioneaza atat pentru
functiile normale cat si pentru metode.

1 <?php
2
3 class Persoana {
4 public $nume;
5
6 function __construct($nume)
7 {
8 $this->nume = $nume;
9 }
10
11 }
12
13
14
15 function afiseazaPersoana(Persoana $p)
16 {
17 echo '<b>' . $p->nume . '</b>';
18 }
19
20
21 $p1 = new Persoana('ion');
22
23 // afiseazaPersoana('ion'); // Catchable fatal error: Argument 1
24 passed to afiseazaPersoana() must be an instance of Persoana, string
25 given
26 // afiseazaPersoana(4); // Catchable fatal error: Argument 1 passed
27 to afiseazaPersoana() must be an instance of Persoana, integer given
28 // afiseazaPersoana(null); // Catchable fatal error: Argument 1
29 passed to afiseazaPersoana() must be an instance of Persoana, null
given
afiseazaPersoana($p1);

?>

In exemplul de mai sus, functia afiseazaPersoana(Persoana $p) asteapta un obiect de tip Persoana. In caz contrar, va genera o eroare de tip Catchable
fatal error. Putem atribui valoarea implicita NULL pentru un argument ce are un tip impus, caz in care argumentul poate fi doar un obiect avand tip-ul
respectiv sau NULL. In exemplul de mai sus, functia ar fi devenit afiseazaPersoana(Persoana $p = null) caz in care ar fi acceptat valori de tip NULL sau de
tip Persoana.
Fortarea unui argument de tip array
Argumentele unei functii pot fi fortate si la tipul de date array. In caz contrar, interpretorul arunca o eroare similara cu cele de mai sus.

1 <?php
2 $persoane = array('Ion', 'Marian', 'Vasile');
3
4 function listaPersoane(array $data)
5{
6
7 foreach ($data as $persoana) {
8 echo $persoana;
9 echo '<br />';
10 }
11 }
12
13
14 // listaPersoane('a'); // Catchable fatal error: Argument 1 passed to
15 listaPersoane() must be an array, string given
16 listaPersoane($persoane);
17
?>

Aceasta facilitate a limbajului, numita type hinting, este foarte importanta pentru ca economiseste efortul programatorului de a verifica in interiorul unor
functii ce primesc obiecte ca argumente daca argumentele sunt obiecte, din clasa corecta, inainte sa-i apeleze anumite metode sau atribute.

11.15. Operatorul instanceof

Operatorul instanceof verifica daca o variabila este o instanta (un obiect) a unei anumite clase, caz in care returneaza true. Operandul stang este
variabila ce este verificata, operandul drept este numele clasei.

1 <?php
2 class Test {
3
4}
5
6 $t = new Test();
7
8 var_dump($t instanceof Test); // bool(true)
9 var_dump($t instanceof AltaClasa); // bool(false)
10 ?>

Din punct de vedere OOP, un obiect apartine unei clasa (sa zicem clasa Parinte) nu doar daca este o instanta a clasei respective, ci si daca este o instanta
a unei clase derivate din clasa respectiva (Copil). Capitolul urmator trateaza pe larg subiectul mostenire/derivare, implementat prin cuvantul
extends. instanceof tine cont de acest lucru.

1 <?php
2 class Parinte {
3
4}
5
6
7 class Copil extends Parinte {
8
9}
10
11 $t = new Copil;
12
13 var_dump($t instanceof Copil); // evident, true
14 var_dump($t instanceof Parinte); // true. ce se naste din pisica...
15
16 ?>

Pentru a verifica ca un obiect NU apartine unei instante, folosim operatorul de negare "!"
Exemplu if (!($a instanceof MyClass)) . Acest if se executa daca $a nu este o instanta a clasei MyClass.
Asa cum am observat, instanceof este folosit cu un nume de clasa (nu string). Adica $a instanceof MyClass , si nu $a instanceof 'MyClass'. Insa, mai
poate fi folosit in urmatoarele doua variante:

 $x instanceof $a - unde $a este o instanta (un obiect) dintr-o anumita clasa. Este verificat daca $x face parte din clasa respectiva.

 $x instanceof $className - aici $className este o variabila de tip string, ce contine numele clasei pentru care se face verificarea

1 <?php
2 class A {
3
4}
5
6 class AltaClasa {
7
8}
9
10
11 $b = new A;
12 $x = new A;
13
14 $clasa = 'A';
15 $altceva = 'altceva';
16
17 var_dump($x instanceof $b); // true
18 var_dump($x instanceof $clasa); // true
19 var_dump($x instanceof $altceva); // false
20
21 ?>

11.16. Functii pentru clase si obiecte


Exista o serie de functii predefinite in PHP ce ofera informatii in legatura cu clasele sau obiectele definite. Lista completa o gasiti la resurse.
Cateva dintre ele sunt:

 bool class_exists ( string $class_name [, bool $autoload= true ] ) - returneaza true daca exista clasa $class_name , altfel false. Daca
$autoload este true, este apelata si functia __autoload() pentru gasirea clasei

 array get_declared_classes ( void ) - returneaza un array cu clasele definite. In functie de extensiile cu care este instalat PHP-ul pe
calculatorul pe care se executa scriptul, returneaza o serie de clase predefinite, in afara celor definite in script

 array get_class_methods ( mixed $class_name ) - returneaza un array cu numele metodelor pentru clasa $class_name. Argumentul
$class_name este un string cu numele clasei, sau un obiect al clasei respective

 array get_class_vars ( string $class_name ) - returneaza un array cu proprietatile accesibile ale clasei, si valorile lor implicite (valorile
stabilite la definirea proprietatilor)

 string get_class ([ object $object ] ) returneaza numele clasei pentru obiectul primit ca argument

 bool property_exists ( mixed $class , string $property ) - verifica daca proprietatea $property exista in clasa $class. Returneaza true chiar
daca in contextul dat proprietatea nu este accesibila (de exemplu folosim functia din afara clasei, si atributul/proprietatea este private.
Returneaza true si daca exista dar are valoare null, spre deosebire de isset($obiect->atribut) care ar fi returnat false daca atributul era
definit dar nu era initializat. $class si aici poate fi nume de clasa sau un obiect din clasa respectiva.

 bool method_exists ( mixed $object , string $method_name ) - similar cu property_exists

 bool is_a ( object $object , string $class_name ) - similara cu operatorul instanceof

Nota
O alta varianta, ceva mai bogata, de analiza a claselor si obiectelor este Reflection Api - vezi resurse.

11.17. Composition - atribute de tip obiect

In OOP, principalele obiective sunt reutilizarea codului, flexibilitatea si organizarea. Reutilizarea/refolosirea codului inseamna proiectarea codului astfel
incat o cat mai mare parte din el sa fie util si in alte aplicatii ce au nevoie de functionalitati similare. Flexibilitatea inseamna in plus posibilitatea de a
imbina obiectele/clasele existente intr-un mod cat mai eficient - cu un efort minim sa se obtina rezultatele dorite. In plus, o buna flexibilitate rezulta in
schimbari cat mai mici ale codului deja scris, pe masura ce aplicatia are nevoie de "ajustari", sau noi functionalitati.
Doua concepte de baza pentru combinarea obiectelor in OOP sunt: inheritance (mostenirea) si composition.
Pe scurt, inheritance descrie o relatie intre clase de tip "is a" (este). De exemplu un User este o Persoana. Sau unAutomobil este un Vehicul.
In timp ce conceptul composition descrie o relatie de tip "has a" (are). Exemplu: un User are un Privilegiu sau unAutomobil are o Roata.
Revenind la sintaxa, in momentul cand un atribut al unei clase ia ca valoare un obiect din alta clasa, realizam o compozitie. Deseori avem nevoie sa
folosim in lant operatorul "->" pentru a apela atributele sau metodele unui obiect care la randul lui este un atribut.

1 <?php
2 class User {
3 private $prenume;
4 private $nume;
5 private $email;
6 private $privilegiu;
7
8 function __construct($p, $n)
9 {
10 $this->prenume = $p;
11 $this->nume = $n;
12 }
13
14 function setPrivilegii(array $myPrivs)
15 {
16 $this->privilegiu = new Privilegiu();
17 $this->privilegiu->setPrivilegii($myPrivs);
18 }
19
20
21 function areAcces($pagina)
22 {
23 return $this->privilegiu->areAcces($pagina);
24 }
25
26 }
27
28
29 class Privilegiu{
30
31 private $privData;
32 private $myPrivs;
33
34 function __construct()
35 {
36 // De forma: page => numePriv
37 // privData este lista privilegiilor cerute de fiecare pagina in
38 parte. Fiecare pagina cere un anumit privilegiu
39 $this->privData = array(
40 'index.php' => 'normal',
41 'contact.php' => 'normal',
42 'members.php' => 'restricted',
43 'admin.php' => 'admin',
44 );
45 }
46
47 function setPrivilegii(array $privs)
48 {
49 // un array cu privilegiile curente
50 $this->myPrivs = $privs;
51 }
52
53 function areAcces($pagina)
54 {
55 // daca privilegiul cerut de pagina respectiva (obtinut din
56 privData pe baza paginii) este in lista myPrivs, atunci returneaza
57 true
58 $privRequired = $this->privData[$pagina];
59 $myPrivs = $this->myPrivs;
60
61 // print_r($myPrivs);
62 // print_r($privRequired);
63
64 if (is_array($myPrivs) && in_array($privRequired, $myPrivs)) {
65 return true;
66 }
67
68 return false;
69 }
70
71 } // privilegiu
72
73
74 $u = new User('Ion', 'Popescu');
75 $u->setPrivilegii(array('normal', 'restricted'));
76
var_dump($u->areAcces('index.php'));

?>

11.18. Tema
Tema11-1
Realizati o clasa ce va poate ajuta la realizarea formularelor html, la auto-completarea acestora si la validare.

Tema11-2
Folosind notiunile de la capitolul sesiuni, si cunostintele de pana acum OOP, realizati o clasa (sau mai multe) cu care sa realizati un sistem de login.
Exemplificati folosirea acestei clase intr-un script.

CAP. 12.Clase si obiecte (II)


12.1 Inheritance (mostenirea)
12.2 Inheritance si modificatorii de acces
12.3 Overriding - rescrierea metodelor
12.4 Polimorfism
12.5 Cuvantul cheie final
12.6 Metode si clase abstracte
12.7 Interfete. Implementarea interfetelor
12.8 Standard PHP Library (SPL)
12.9 Exceptii. Tratarea exceptiilor
12.10 Tema

12.1. Inheritance (mostenirea)


Asa cum am discutat in capitolul anterior, exista doua relatii de baza intre clasele ce interactioneaza intr-un program OOP. Una din ele este compozitia, sau
relatie de tip "has a" (are), in care un obiect detine ca atribute referinte catre alte obiecte. Cealalta este inheritance (mostenirea), ce implementeaza o
relatie de tip "is a" (este) prin care o clasa parinte este extinsa intr-o noua clasa, numita clasa copil, ce-i preia toate atributele si metodele, cu scopul de a
modifica functionalitatea existenta in clasa de baza sau de a a adauga functionalitate noua.

Terminologia intalnita pentru a descrie mostenirea este urmatoarea:


 clasa parinte - mai este numita si clasa de baza, sau superclasa

 clasa copil - cea care extinde clasa de baza, este denumita si clasa derivata, sau subclasa

 inheritance - procesul prin care clasa copil se extinde din clasa parinte se numeste inheritance, mostenire, derivare sau extindere

Important
Clasa derivata (clasa copil) va prelua automat toate atributele si metodele publice sau protected definite in clasa de baza. In PHP, realizarea unei clase
derivate dintr-o clasa parinte se face cu ajutorul cuvantului cheie extends

In exemplul de mai jos, clasa Om, mosteneste, sau deriva din clasa Animal. Cu alte cuvinte, un Om este un Animal.

1 <?php
2 class Animal {
3 public $name;
4
5
6 function comunica()
7 {
8 echo 'Sunt un simplu animal. Nu stiu sa comunic' . '<br />';
9 }
10
11 function deplaseaza()
12 {
13 echo 'Sunt un simplu animal. Nu stiu sa ma deplasez' . '<br />';
14 }
15
16 }
17
18
19
20 class Om extends Animal {
21
22 }
23
24
25 $a = new Animal();
26 $a->name = 'Tom';
27 $a->comunica();
28
29
30 $om = new Om();
31 $om->name = 'John';
32 $om->comunica();
33 echo $om->name;
34
35 ?>

Un obiect de tip Om, preia atributele si metodele clasei Animal. Din acest motiv, putem apela atributul $om->name sau metoda $om->comunica().

Folosim o clasa derivata cand avem nevoie de o clasa asemanatoare cu clasa de baza, ce
include o parte din functionalitatea clasei de baza, dar are elemente noi concretizate in
atribute si metode noi. Aceste atribute si metode noi vor fi implementate in clasa derivata.
Astfel, clasa derivata va avea acces atat la atributele si metodele mostenite din clasa de
baza, cat si la cele noi.

1 <?php
2 class Animal {
3 public $name;
4
5
6 function comunica()
7 {
8 echo 'Sunt un simplu animal. Nu stiu sa comunic' . '<br />';
9 }
10
11 function deplaseaza()
12 {
13 echo 'Sunt un simplu animal. Nu stiu sa ma deplasez' . '<br />';
14 }
15
16 } /// class Animal
17
18
19
20 class Om extends Animal {
21 public $address;
22 public $email;
23
24 function munceste()
25 {
26 echo 'Sunt un om, si muncesc' . '<br />';
27 }
28
29
30 } /// class Om
31
32
33
34 $om = new Om();
35 $om->name = 'John';
36 $om->address = '3623 W Sunset Blvd, Los Angeles, CA 90026';
37 $om->comunica();
38 $om->munceste();
39 echo $om->address;
40 ?>

12.2. Inheritance si modificatorii de acces


Reamintim modificatorii de acces in contextul mostenirii:

 public - membrul poate fi accesat oriunde: deci si din exteriorul clasei, si din alte clase

 protected - membrul este vizibil doar in clasa curenta si in clasele derivate din clasa in care a fost definit

 private - membrul este vizibil doar in clasa in care a fost definit

Deci clasa derivata preia atributele si metodele declarate "public" si "protected". Atributele si metodele preluate in clasa derivata isi pastreaza modificatorul
de acces, daca nu sunt redefinite.

1 <?php
2 class A{
3 public $x = 'public';
4 protected $y = 'protected';
5 private $z = 'private';
6
7
8
9}
10
11
12 class B extends A {
13
14 function test()
15 {
16 echo $this->x . ' ';
17 echo $this->y . ' ';
18 echo $this->z . ' '; // Notice Undefined property B::$z
19 }
20
21 }
22
23 $b = new B();
24 $b->test();
25 ?>

In exemplul urmator incercam apelarea din afara clasei a 3 metode declarate public protected si private printr-un obiect $b, ce mosteneste clasa A. Acelasi
lucru s-ar fi intamplat si la atribute, doar cel public este accesibil din afara.

1 <?php
2 class A{
3
4 public function mx() {
5 echo 'Metoda mx publica';
6 }
7
8 protected function my() {
9 echo 'Metoda my protected';
10 }
11
12 private function mz() {
13 echo 'Metoda mz private';
14 }
15
16 }
17
18
19 class B extends A {
20
21
22 }
23
24 $b = new B();
25 $b->mx();
26 $b->my(); // eroare. fiind protected, nu este disponibila din afara
27 clasei
28 $b->mz(); // este private, nu este disponibila din afara clasei
?>

In schimb, daca apelam metodele din interiorul clasei derivate (context 'B' cum e numit de interpetor), avem acces la metoda publica si la cea protected.

1 <?php
2 class A{
3
4 public function mx() {
5 echo 'Metoda mx publica';
6 }
7
8 protected function my() {
9 echo 'Metoda my protected';
10 }
11
12 private function mz() {
13 echo 'Metoda mz private';
14 }
15
16 }
17
18
19 class B extends A {
20
21 function test()
22 {
23 $this->mx(); // ok, mx() este publica
24 $this->my(); // ok, my() este protected, avem acces in clasele
25 derivate din clasa A unde a fost definita
26 $this->mz(); // Fatal error: Call to private method A::mz() from
27 context 'B'
28 }
29
30 }
31
32 $b = new B();
$b->test();
?>

Important
De retinut, putem redefini un membru (atribut sau metoda) intr-o clasa derivata, insa cu acelasi modificator de acces, sau cu unul mai slab (mai putin
restrictiv). De exemplu, daca un atribut este public in clasa de baza, trebuie sa fie public si in clasa derivata. Daca este protected in clasa de baza, poate fi
protected sau public in clasa derivata.

1 <?php
2 class A{
3 public $x = 'public';
4 protected $y = 'protected';
5 private $z = 'private';
6
7}
8
9
10 class B extends A {
11 // protected $x = 'alt x'; // Fatal error: Access level to B::$x
12 must be public (as in class A)
13 private $y = 'alt y'; // Fatal error: Access level to B::$y must
14 be protected (as in class A) or weaker
15 // public $y = 'acel alt y'; // ok
16
17
18 }
19
20 $b = new B();
echo $b->y;
?>

12.3. Overriding - rescrierea metodelor

In unul din exemplele anterioare, am vazut ca John, desi e om si munceste, pe de alta parte "este un simplu animal si nu stie sa comunice". Cu alte
cuvinte, metoda comunica() a clasei Animal trebuie reimplementata, deci rescrisa in clasa Om.
Aceasta actiune inlocuieste pur si simplu metoda mostenita din clasa derivata. Deci clasa derivata are functionalitate noua, metoda munceste(), si poate
schimba functionalitatea existenta metoda comunica().

1 <?php
2 class Animal {
3 public $name;
4
5 function __construct($name)
6 {
7 $this->name = $name;
8 }
9
10 function comunica()
11 {
12 echo 'Sunt un simplu animal. Nu stiu sa comunic' . '<br />';
13 }
14
15 function deplaseaza()
16 {
17 echo 'Sunt un simplu animal. Nu stiu sa ma deplasez' . '<br />';
18 }
19
20
21 function mananca()
22 {
23 echo 'Mananc ...';
24 }
25
26 } /// class Animal
27
28
29
30 class Om extends Animal {
31 public $address;
32 public $email;
33
34
35 function comunica()
36 {
37 echo 'Salut, numele meu este ' . $this->name. '<br />';
38 }
39
40
41 function mananca()
42 {
43 parent::mananca();
44 echo ' in general cu tacamuri.';
45 }
46
47
48 function munceste()
49 {
50 echo 'Sunt un om, si muncesc' . '<br />';
51 }
52
53
54 } /// class Om
55
56
57
58 $om = new Om('John');
59 $om->comunica();
60 $om->munceste();
61 $om->mananca();
62
63 ?>

Rescrierea metodelor si apelarea metodelor din clasa parinte


In exemplul de mai sus observam urmatoarele lucruri:

 metoda comunica() a fost rescrisa in clasa derivata. Procesul se numeste "overridden". Acceseaza atributul $name care a fost mostenit de la
clasa de baza.

 metoda mananca() a fost si ea rescrisa. Insa am folosit cuvantul cheie parent si operatorul :: pentru a apela metoda mananca() a clasei
parinte, continuand astfel functionalitatea ei. Astfel, in loc sa o rescriem complet, refolosim codul din aceasta metoda si il imbogatim.

 constructorul din clasa parinte (clasa Animal) a fost aici apelat automat cand am creat un obiect de tip Om, pentru ca in clasa derivata
(Om) NU am definit un constructor. Daca am fi definit aici un constructor, cel din clasa parinte NU ar fi fost apelat automat, in schimb ar fi
trebuit pentru apelare sa folosim parent::__construct()

1 <?php
2
3 class A {
4
5 function __construct() {
6 echo 'constructor A';
7 }
8
9}
10
11
12 class B extends A {
13
14 function __construct() {
15 // parent::__construct();
16 echo 'constructor B';
17 }
18
19 }
20
21
22 $b = new B(); // constructor B
23 ?>
12.4. Polimorfism

In OOP, termenul de polimorfism desemneaza capacitatea unor obiecte de fi folosite in locuri in care se asteapta obiecte din alte clase. Acest lucru se
evidentiaza atunci cand un obiect ce face parte dintr-o clasa, este tratat ca apartinand de fapt clasei parinte. Acest lucru este corect si logic, pentru ca o
clasa copil este inclusa intr-o clasa parinte, ii preia integral functionalitatea.
Exemplul in care putem evidentia aceasta proprietate foloseste functii ce au ca argumente obiecte din clasa parinte:

1 <?php
2
3 class Animal {
4 public $name;
5
6 function __construct($name)
7 {
8 $this->name = $name;
9 }
10
11
12 function mananca()
13 {
14 echo 'Mananc ...' . '<br />';
15 }
16
17
18 function doarme()
19 {
20 echo 'Dorm...' . '<br />';
21 }
22
23 } /// class Animal
24
25
26 class Caine extends Animal {
27
28 function mananca()
29 {
30 echo 'Mananc mancare pentru caini.'.'<br />';
31 }
32
33 }
34
35 class Om extends Animal {
36
37 function mananca()
38 {
39 echo 'Mananc o ciorba' . '<br />';
40 }
41
42 }
43
44 class HtmlElement {
45
46 }
47
48
49 function ceFace(Animal $a)
50 {
51 $a->mananca();
52 $a->doarme();
53 }
54
55 $a = new Animal('');
56 $c = new Caine('Scooby Doo');
57 $o = new Om('John');
58 $html = new HtmlElement();
59
60 ceFace($a); // $a este Animal
61 ceFace($c); // $c este Caine - derivat din Animal
62 ceFace($o); // $o este Om - derivat din Animal
63 ceFace($html); // Fatal Error...Argument 1 passed to ceFace() must be
64 an instance of Animal...
65
?>

Functia ceFace(Animal $a) accepta un argument de tipul Animal, in caz contrar va genera o eroare. Nu emite o eroare insa daca ii furnizam obiecte
derivate din animal, obiecte de tip Caine sau de tip Om. Pentru ca, amintind relatia dintre o superclasa si o subclasa, un Caine este un Animal. Si un Om
este un Animal. Deci, pastrand logica din exemplul de mai sus, orice face un Animal, poate sa faca si un Caine sau Om. Obiectul desi este tratat ca un
Animal, (i se apeleaza metode si atribute specifice obiectelor din clasa Animal), el reactioneaza normal, raspunzand cu metodele sau atributele din clasa
proprie daca acestea sunt redefinite (mananca() a fost reimplementat atat pentru Om cat si pentru Caine).

Invers nu este valabil, pentru ca un Animal nu este un Om (o superclasa nu este o subclasa).


Prin urmare, daca functia ceFace() ar fi cerut un argument de tip Om, ea nu ar fi acceptat argumente de tip Animal.

In concluzie, un grup de clase ce au un mostenitor comun, pot fi tratate unitar acolo unde este nevoie, ca obiecte ce fac parte din aceeasi superclasa.

12.5. Cuvantul cheie final


Cuvantul cheie final poate fi folosit in doua cazuri:

 in fata metodelor - ca efect, aceste metode nu pot fi suprascrise in clase derivate

 in fata unei clase - clasa respectiva nu poate fi derivata (nu poate avea subclase)

1 <?php
2 class A {
3
4 final public function a() {
5
6 }
7
8}
9
10 class B extends A {
11 function a()
12 {
13
14 }
15 }
16
17 // Fatal error: Cannot override final method A::a()
18
19 ?>

1 <?php
2 final class A {
3
4}
5
6 class B extends A {
7
8}
9
10 // Fatal error: Class B may not inherit from final class (A)
11 ?>

12.6. Metode si clase abstracte

1. Clasele abstracte (precedate de cuvantul cheie abstract) nu pot fi instantiate. Deci nu poate fi creat un obiect din clasa respectiva. Astfel,
programatorul poate doar sa extinda aceste clase. Deci sa completeze functionalitatea lor in clasele copii.

1 <?php
2 abstract class A {
3
4}
5
6 $a = new A(); // Fatal error: Cannot instantiate abstract class A
7
8 ?>

2. Si metodele pot fi declarate abstracte (precedate de cuvantul cheie abstract). O metoda abstracta nu poate oferi implementare, astfel corpul ei este
inlocuit de punct si virgula (;) ca in exemplul de mai jos. Astfel, pentru o metoda abstracta scriem doar semnatura metodei: numele si argumentele.

1 <?php
2
3 abstract class A {
4
5 abstract function test($a, $b);
6
7}
8
9 ?>

3. O clasa ce contine cel putin o metoda abstracta, trebuie declarata ca abstracta. Daca insa declaram o clasa ca abstracta, nu e obligatoriu sa avem
metode abstracte in ea.

4. In subclasele ce extind o clasa cu metode abstracte trebuie sa implementam, adica sa suprascriem (override) metodele abstracte din clasa de baza.
Sau, sa declaram la randul ei subclasa ca abstracta.

1 <?php
2
3 abstract class A {
4
5 abstract protected function test($a, $b);
6
7}
8
9
10 class B extends A { // Fatal error: Class B contains 1 abstract
11 method and must therefore be declared abstract or implement the
12 remaining methods (A::test
13
14 }

?>
In exemplul urmator, metoda abstracta test() a fost rescrisa in subclasa B. Fiind protected in clasa de baza ea poate fi redefinita tot ca protected sau ca
public ("same or weaker").

1 <?php
2
3 abstract class A {
4
5 abstract protected function test($a, $b);
6
7}
8
9
10 class B extends A {
11 protected function test($a, $b)
12 {
13 return $a + $b;
14 }
15 }
16
17 $b = new B();
18
19
20 ?>

Nota
Intr-o clasa abstracta, putem defini si metode ce nu sunt abstracte si ofera o implementare, inclusiv un constructor, chiar daca aceste clase nu
pot fi instantiate. Aceste definiri isi au rostul, pe de o parte pentru ca metodele sunt mostenite si preluate in subclasele ce extind clasa, iar
constructorul va fi chemat in mod implicit sau explicit cand se instantiaza un obiect dintr-o subclasa.

1 <?php
2 abstract class Animal {
3 public $name;
4
5 function __construct($name)
6 {
7 $this->name = $name;
8 }
9
10 abstract public function comunica();
11 abstract public function deplaseaza();
12
13 public function mananca() {
14 echo 'Mananc ' . '<br />';
15 }
16
17 }
18
19 class Caine extends Animal {
20 function comunica()
21 {
22 echo 'Ham ham ham ' . '<br />';
23 }
24
25 function deplaseaza()
26 {
27 echo 'Merg in patru labe. Pot si in doua, dar obosesc repede' .
28 '<br />';
29 }
30 }
31
32
33 class Om extends Animal {
34 public $address;
35 public $email;
36
37 function comunica()
38 {
39 echo 'Salut, numele meu este ' . $this->name.'. Despre ce vrei sa
40 vorbim ? ' . '<br />';
41 }
42
43 function deplaseaza()
44 {
45 echo 'Ma deplasez cu masina uneori. In rest merg in doua
46 picioare.' . '<br />';
47 }
48
49 function munceste()
50 {
51 echo 'Sunt om, si muncesc' . '<br />';
52 }
53
54 }
55
56
57 // $a = new Animal('Tom'); // Fatal error: Cannot instantiate
58 abstract class Animal
59
60 $b = new Om('John');
61 $b->comunica();
62 $b->munceste();
63
64 echo '<br />';
65
$c = new Caine('Buck');
$c->comunica();
$c->deplaseaza();
$c->mananca();
12.7. Interfete. Implementarea interfetelor
Interfetele sunt clase speciale urmatoarele caracteristici:

 sunt definite folosind cuvantul cheie interface

 interfetele pot fi privite ca si clase complet abstracte: nu pot fi instantiate, nu ofera implementare pentru nici o metoda (toate metodele sunt
automat abstracte)

 interfetele nu au atribute. Doar constante de clasa

 toate metodele din interfete sunt automat publice

1 <?php
2 interface A {
3
4}
5
6 $a = new A(); // Fatal Error
7
8 ?>

1 <?php
2 // Fatal error: Interface function A::test() cannot contain body
3
4 interface A {
5
6 public function test() {
7
8 }
9
10 }
11
12 ?>

Corect,

1 <?php
2
3 interface A {
4
5 public function test();
6
7}
8
9 ?>

Implementarea interfetelor
O clasa nu extinde o interfata ci o implementeaza, folosind cuvantul cheie implements. O clasa ce implementeaza o interfata este obligata sa suprascrie
toate metodele prezente in interfata (pentru ca sunt de fapt metode abstracte). Deci scopul unei interfete este de fapt sa creeze un schelet pe care sa se
construiasca clasele ce implementeaza aceasta interfata.
Important
O clasa poate implementa mai multe interfete in acelasi timp. Acestea se separa prin virgula. Clasa va fi nevoita sa rescrie toate metodele din interfetele
pe care le implementeaza

1 <?php
2 interface Animal {
3 function mananca();
4 function comunica();
5}
6
7 interface Mamifer {
8 function naste();
9}
10
11 class Girafa implements Animal,Mamifer {
12
13 }
14
15 // Fatal error: Class Girafa contains 3 abstract methods and must
16 therefore be declared abstract or implement the remaining methods
(Animal::mananca, Animal::comunica, Mamifer::naste)
?>

Corect este,

1 <?php
2 interface Animal {
3 function mananca();
4 function comunica();
5}
6
7 interface Mamifer {
8 function naste();
9}
10
11 class Girafa implements Animal,Mamifer {
12
13 function mananca()
14 {
15
16 }
17
18 function comunica()
19 {
20
21 }
22
23 function naste()
24 {
25
26 }
27
28 }
29
30
31 ?>

Important
O clasa poate extinde o alta clasa (inheritance), si in acelasi timp poate implementa una sau mai multe interfete

1 <?php
2 interface Animal {
3 function mananca();
4 function comunica();
5}
6
7 class Persoana {
8 protected $firstName;
9 protected $lastName;
10
11 function __construct($firstName, $lastName)
12 {
13 $this->firstName = $firstName;
14 $this->lastName = $lastName;
15 }
16
17 }
18
19 class User extends Persoana implements Animal {
20
21 function reseteazaParola($oldPass, $newPass)
22 {
23
24 }
25
26 function mananca()
27 {
28
29 }
30
31 function comunica()
32 {
33
34 }
35
36 }
37
38
39 $u = new User('John', 'Smith');
40
41 ?>

Extinderea interfetelor
Interfetele pot fi extinse, deci pot avea interfete copii, similar cu mostenirea claselor. Spre deosebire de clase, o interfata poate mosteni simultan de la mai
multe interfete, separate prin virgula.

 Mostenirea simpla (simple inheritance):

 interface X extends A {

 ...

 Mostenirea multipla (multiple inheritance):

 interface X extends A, B {

 ...

* Unde A si B sunt interfete. Interfata X, va mosteni definitiile metodelor din interfata A (respectiv A, B) si va putea adauga propriile metode abstracte.
Astfel, o clasa ce va implementa interfata X trebuie sa implementeze metodele abstracte mostenite din A (respectiv A,B) precum si metodele abstracte
definite in interfata X.

12.8. Standard PHP Library (SPL)


Standard PHP Library (SPL) cuprinde o serie de clase si interfete predefinite in PHP avand scopul de a oferi programatorilor solutii standard si usor de
implementat in unele probleme clasice.

Implementarea unor interfete din SPL obliga programatorul PHP sa ofere metodele din interfata in clasa respectiva, insa, in plus, limbajul PHP ofera
anumite facilitati pentru clasele ce implementeaza anumite interfete, cum ar fi folosirea obiectelor cu sintaxa pentru array, sau iterarea intr-un obiect cu
constructia foreach.

Libraria SPL contine numeroase interfete, si clase, (vezi resurse), voi prezenta aici cateva dintre ele:
Interfata ArrayAccess
Clasa ce implementeaza aceasta interfata permite accesarea atributelor unui obiect cu sintaxa destinata tablourilor - [].
Interfata ArrayAccess contine urmatoarele 4 metode:

 boolean offsetExists ( string $offset ) - functia trebuie sa returneze true daca $offset (cheia cautata) exista in array, in caz contrar false.
 void offsetUnset ( string $offset ) - functie chemata automat cand stergem cu unset() un element ce are cheia $offset

 mixed offsetGet ( string $offset ) - returneaza valoarea corespunzatoare cheii $offset. Chemata cand accesam un element folosind cheia
respectiva. $a['cheie']

 void offsetSet ( string $offset , string $value ) - seteaza elementul ce are cheia $offset cu valoarea $value.

Clasa ce implementeaza interfata ArrayAccess trebuie, bineinteles, sa ofere aceste metode. In exemplul urmator, putem folosi sintaxa [] langa un obiect
de tip Website pentru ca aceasta clasa implementeaza interfata ArrayAccess.

1 <?php
2 class Website implements ArrayAccess{
3
4 public $options;
5
6 function offsetExists($offset)
7 {
8 // echo __METHOD__ . '<br />';
9 return array_key_exists($offset, $this->options);
10 }
11
12
13 function offsetUnset($offset)
14 {
15 // echo __METHOD__ . '<br />';
16 unset($this->options[$offset]);
17 }
18
19
20 function offsetGet($offset)
21 {
22 // echo __METHOD__ . '<br />';
23 return $this->options[$offset];
24 }
25
26
27
28 function offsetSet($offset, $value)
29 {
30 // echo __METHOD__ . '<br />';
31 $this->options[$offset] = $value;
32 }
33
34
35 function listOptions()
36 {
37 foreach ($this->options as $k => $v) {
38 echo $k . ':' . $v;
39 echo '<br />';
40 }
41
42 }
43
44 }
45
46 $ws = new Website();
47
48
49 $ws["author"] = 'John'; // se apeleaza automat offsetSet
50 $ws["title"] = 'My website'; // se apeleaza automat offsetSet
51 $ws["debug"] = 1; // se apeleaza automat offsetSet
52
53 $ws->listOptions();
54
55 echo $ws["author"]; // se apeleaza automat offsetGet
56 echo '<br />';
57
58
59 if (isset($ws["altceva"])) { // se apeleaza automat offsetExists
60 echo 'nu ma afisez';
61 }
62 ?>

Interfata Iterator
Aceasta interfata este predefinita in PHP, si este interfata de baza folosita pentru iteratia simpla in obiecte. Aici, iteratia este un proces repetitiv ce permite
traversarea unei liste de elemente. Concret, interfata Iterator ne permite sa traversam un obiect cu sintaxa foreach, asa cum am traversa un simplu array.
Ce inseamna exact sa traversam obiectul respectiv, vom defini in metodele clasei ce implementeaza interfata. De cele mai multe ori vom traversa de fapt
unul din atributele obiectului respectiv, care este array.

Interfata predefinita Iterator arata astfel:

1 <?php
2
3
4 Iterator extends Traversable {
5 /* Methods */
6 abstract public mixed current ( void )
7 abstract public scalar key ( void )
8 abstract public void next ( void )
9 abstract public void rewind ( void )
10 abstract public boolean valid ( void )
11 }
12
13
14 ?>

Interfata Iterator nu trebuie sa o definim in scripturile noastre, ea e predefinita. Insa, e util sa stim cum arata pentru a o implementa si a-i rescrie
metodele.

 current() - metoda ce returneaza valoare elementul curent din array

 key() - returneaza cheia elementului curent

 next() - avanseaza la urmatorul element

 rewind() - revenirea la primul element din array

 valid() - verifica daca pozitia curenta este valida. Se apeleaza in general dupa rewind() sau next() pentru a verifica daca s-au depasit limitele
tabloului

1 <?php
2
3 class Website implements Iterator {
4 private $options;
5 private $key;
6
7 function __construct($options)
8 {
9 $this->options = $options;
10 }
11
12 function current() {
13 return current($this->options);
14 }
15
16 function next() {
17 next($this->options);
18 }
19
20 function rewind() {
21 reset($this->options);
22 }
23
24 function key() {
25 return key($this->options);
26 }
27
28
29 function valid() {
30 $current = current($this->options);
31 return (FALSE !== $current); // returneaza FALSE daca $curent e
32 FALSE; in caz contrar returneaza TRUE
33 }
34
35
36 }
37
38
39 $options = array('author' => 'John','title' => 'My website', 'debug'
40 => '1');
41 $ws = new Website($options);
42
43 foreach ($ws as $key => $value) {
44 echo $key.':'.$value;
45 echo '<br />';
46 }
47

?>

Implementarea acestor metode sunt legate de sintaxa foreach pentru ca sintaxa foreach apeleaza aceste metode pentru a efectua iteratia. Ceea ce am
facut mai sus cu foreach este echivalent cu:

1 <?php
2
3 /*
4
5 .... definitia clasei Website ...
6
7 */
8
9
10 // Resetam iteratorul - foreach face acest lucru automat
11 $ws->rewind();
12
13 // Iteram atat timp cat este valid
14 while ( $ws->valid() ) {
15
16 echo $ws->key().": ".$ws->current()."<br>"; // extragem cheia si
17 elementul curent
18 $ws->next(); // trecem la elementul urmator
19
20 }
21
?>

Clasa DirectoryIterator
Clasa DirectoryIterator, este o clasa predefinita in PHP, si faciliteaza accesul simplu, orientat obiect la continutul unui director. Clasa DirectoryIterator
extinde clasa SplFileInfo si implementeaza doua interfete: Iterator si Traversable. In listarea continutului unui director, sistemul de operare va returna
implicit directorul curent "." si directorul parinte "..". Metoda isDot() ne ajuta sa identificam aceste directoare si sa le excludem.

1 <?php
2
3 $path = new DirectoryIterator('C:/www/');
4
5
6
7 foreach ($path as $file) {
8
9 if (!$file->isDot()) {
10 echo $file->getFilename() . " ";
11 echo $file->getSize() . ' ';
12 echo $file->getRealPath() . ' ';
13 echo '<br />';
14 }
15
16 }
17
18 ?>

$file este un obiect de tip DirectoryIterator, respectiv SplFileInfo, astfel ii putem apela metodele si atributele publice (vezi Resurse)

Resurse
PHP Manual - SPL
PHP Manual - Predefined Interfaces
PHP Manual - Iterators
PHP Manual - The DirectoryIterator class
PHP Manual - The SplFileInfo class
Sitepoint.com article - PHP5 Standard Library
Devshed.com article - Iterators in the Simplest Sense...
devzone.zend.com - The Standard PHP Library
7. Exceptii. Tratarea exceptiilor
12.9.1 Executia unui script
12.9.2 Exceptiile in PHP. Aruncarea unei exceptii
12.9.3 Blocurile try catch
12.9.4 Extinderea clasei Exception

12.9.1. Executia unui script


Este necesar sa intelegem exact modul si ordinea instructiunilor in care interpretorul PHP executa un script. Pentru acest simplu exemplu, executia
scriptului PHP va avea loc in urmatorii pasi:

 linia 2 - se realizeaza instructiunea de atribuire. $i devine 4

 linia 4 - se evalueaza expresia $i == 5, rezulta false. Instructiunile din interiorul constructiei if NU sunt executate, executia sare direct la linia
8

 linia 8 - se executa instructiunea de afisare echo $i;

1 <?php
2 $i = 4;
3
4 if ($i == 5) {
5 echo 'sunt in if';
6}
7
8 echo $i;
9 ?>

Prin urmare, asa cum este si intuitiv, executia se realizeaza de sus in jos, instructiune cu instructiune, tinand cont de structurile decizionale (if , if else,
switch) care decid daca anumite blocuri de cod se executa sau nu, de instructiunile repetitive (for, while, do while) care decid de cate ori se repeta
executia anumitor blocuri de cod, etc.

Ce se intampla insa in cazul functiilor sau metodelor ?

Avem mai jos un simplu exemplu, ce ajuta sa intelegem modul in care se executa programul atunci cand apar functiile.

Sursa script Vizualizare in browser


inainte de a()
1 <?php a1
2 function a() b1
c1
3{ c2
b3
4 echo 'a1' . '<br />'; a2
5 b(); dupa a()

6 echo 'a2' . '<br />';


7}
8
9 function b()
10 {
11 echo 'b1' . '<br />';
12 c();
13 echo 'b3' . '<br />';
14 }
15
16 function c()
17 {
18 echo 'c1' . '<br />';
19 echo 'c2' . '<br />';
20 return;
21 echo 'c3' . '<br />';
22 d();
23 }
24
25 function d()
26 {
27 echo 'nu ma execut';
28 }
29
30
31 echo 'inainte de a()' .
32 '<br />';
33 a();
34 echo 'dupa a()' . '<br />';
35
?>

Acest program se executa astfel:

 liniile 2, 9, 16, 25 - interpetorul se opreste la aceste linii pentru a citi semnatura functiilor

 linia 31 - executia propriu-zisa incepe in programul principal (contextul main() cum mai este numit), cu prima linie. Se afiseaza in browser
"inainte de a()"

 linia 32 - se executa aceasta linie, care este o apelare de functie (function call). Executia programului tine minte in call stack(concept
explicat in paragraful urmator) locatia in care se afla instructiunea imediat urmatoare apelarii functiei a(). In acest caz, se tine minte locatia
instructiunii de pe linia 33. Aceasta locatie este tinuta minte de executia programului pentru ca atunci cand se termina cu executia functiei
a(), programul trebuie sa se intoarca la locul in care a fost apelata functia a() si sa execute instructiunea urmatoare. Interpetorul va sari
acum in corpul functiei a(), pentru a executa instructiunile din aceasta functie.

 linia 4 - executia sare in corpul functiei a(), (function body) si se executa prima instructiune din functie

 linia 5 - urmatoarea instructiune din interiorul functiei a() este un apel al functiei b(). Programul tine minte in call stackinstructiunea imediat
urmatoare apelarii functiei b() (instructiunea de pe linia 6), pentru a continua executia cu instructiunea respectiva dupa terminarea executiei
functiei b().

 linia 11 - se executa prima linie din functia b()

 linia 12 - se apeleaza functia c(). similar, programul tine minte unde a ramas (adauga locatia instructiunii de pe linia 13 in call stack) si sare
la executia instructiunilor din c()

 linia 18, linia 19 - se executa cele doua instructiuni din c()

 linia 20 - instructiunea return are ca efect iesirea dintr-o functie. Interpretorul iese dintr-o functie cand intalneste return sau cand se
termina de executat toate instructiunile din functie. In acest program, linia 21 nu este executata niciodata, nici linia 22 si nici corpul functiei
d().

 linia 13 - programul a terminat executia functiei c(), se intoarce deci la instructiunea tinuta minte in call stack (vezi linia 12), adica
instructiunea imediat urmatoare apelului functiei

 linia 14 - interpretorul intalneste simbolul "}" ce indica terminarea functiei b().

 linia 6 - executia s-a intors la instructiunea tinuta minte in call stack (vezi linia 5), adica instructiunea imediat urmatoare apelului functiei b()

 linia 7 - incheierea functiei a()

 linia 33 - executia se intoarce la instructiunea imediat urmatoare apelului functiei a()

Notiunea call stack


Call stack, (stiva de apeluri) este o structura folosita de executia programului pentru a tine minte locatiile in care trebuie sa se intoarca programul dupa
ce termina executia unei functii. In plus, cand programul se executa in interiorul unei functii, se spune ca se afla intr-un alt context, contextul functiei
respective. In contextul unei functii (sau metode), nu sunt vizibile toate variabilele programului. Sunt vizibile doar cele locale functiei, argumentele primite
de functie, precum si variabilele globale (importate in contextul functiei cu cuvantul cheie global). In cazul metodelor, este vizibil si obiectul curent prin
intermediul cuvantului cheie $this.
Conceptul call stack ne ajuta sa intelegem ca executia programului se afla la un moment dat "in adancime", in interiorul unei functii ce a fost apelata de
alta functie, ce la randul ei a fost apelata de alta, etc. Ultima functie apelata (in exemplul nostru functia c()) va fi ultima functie adaugata in stiva, urmeaza
apoi b(), apoi a() (prima functie apelata), apoi contextul main() adica programul principal.

Call stack afisata de un program de debug pentru scriptul din exemplu, atunci cand executia se afla in interiorul functiei c() arata astfel:
Tabelul ne arata locatia in care se afla executia la un moment dat (in interiorul functiei c() ), linia pe care s-a apelat fiecare functie si momentul de timp in
care s-a apelat functia respectiva. De exemplu, functia b() a fost apelata pe linia 5, la 0.0008 secunde de la inceputul scriptului.

12.9.2. Exceptiile in PHP. Aruncarea unei exceptii


Exceptiile reprezinta un concept de tratare a erorilor in mod organizat, in programarea OOP, si au aparut ca facilitate de limbaj in PHP5.
O exceptie este o situatie neobisnuita (poate fi privita ca o eroare, dar nu neaparat grava) intalnita de executia programului, situatie ce poate fi create
chiar de programator pentru a semnala de exemplu un input gresit al utilizatorului, sau o situatie in care in mod normal programul n-ar fi trebuit sa ajunga
- din acest motiv se numeste exceptie.

O exceptie are urmatoarele caracteristici:

 o exceptie apare la un moment dat in cod, ca urmare a unei erori, sau este generata de programator pentru a trata o situatie neobisnuita a
programului

 o exceptie este un obiect, din clasa Exception - clasa predefinita in PHP. Acest obiect contine informatii detaliate despre exceptia respectiva;
unele informatii sunt furnizate automat de script (de ex: linia si fisierul in care a aparut exceptia) , altele pot fi furnizate de programator
(mesajul si codul exceptiei).

 aparitia unei exceptii schimba "curgerea" normala a executiei. In functie de modul in care "tratam" exceptia respectiva, programatorul poate
decide recuperarea mai eleganta si eficienta decat in cazul unei erori clasice

 presupunand ca exceptia apare intr-o functie, instructiunile de dupa generarea exceptiei nu se executa, si executia "sare" acolo unde a fost
apelata functia curenta, apoi sare si in functia parinte, si asa mai departe pana ajunge in main si genereaza o eroare fatala. Acest lucru se
intampla doar in cazul in care exceptia nu este "prinsa" cu ajutorul unui bloc try...catch. Exceptia de fapt parcurge acest drum prin call
stack, stiva de apeluri.

Cuvantul cheie throw


Se spune despre o exceptie ca este "aruncata" ("bubble up"), pentru ca ea parcurge acest drum prin stiva de apeluri, pana la "suprafata" scriptului.
"Aruncarea" unei exceptii se realizeaza cu ajutorul cuvantului cheie throw. Acest cuvant cheie este urmat de obiectul ce reprezinta exceptia, generat ca
orice obiect cu ajutorul operatorului new. Constructorul clasei Exception primeste doi parametri optionali, primul este mesajul exceptiei, al doilea este un
cod furnizat de programator.

Modificam exemplul din capitolul anterior, pentru a genera o exceptie folosind instructiunea throw new Exception('Am intalnit o exceptie', 1); , in interiorul
functiei c(). Aceasta exceptie nu este "prinsa" in nici un punct al scriptului, ca urmare, din momentul in care a aparut exceptia scriptul se executa astfel:

 linia 19 - este generata/aruncata exceptia. Restul liniilor din aceasta functie nu mai sunt executate

 exceptia este "propagata" in functia b(), locul in care a fost apelata functia c(). Nici aici nu este "prinsa" prin urmare instructiunile urmatoare
(linia 13) nu sunt executate, si se propaga in mai departe in stiva de apeluri, in interiorul functiei a()

 nici in interiorul functiei a() exceptia nu este tratata ("prinsa") prin urmare executia nu continua nici in aceasta functie, si exceptia se propaga
in main(), in programul principal, acolo unde a fost apelata functia a(), si genereaza o eroare fatala. Prin urmare, nici linia 34 nu este
executata.

1 <?php
2 function a()
3{
4 echo 'a1' . '<br />';
5 b();
6 echo 'a2' . '<br />';
7}
8
9 function b()
10 {
11 echo 'b1' . '<br />';
12 c();
13 echo 'b3' . '<br />';
14 }
15
16 function c()
17 {
18 echo 'c1' . '<br />';
19 throw new Exception('Am intalnit o exceptie', 1);
20 echo 'c2' . '<br />';
21 return;
22 echo 'c3' . '<br />';
23 d();
24 }
25
26 function d()
27 {
28 echo 'nu ma execut';
29 }
30
31
32 echo 'inainte de a()' . '<br />';
33 a();
34 echo 'dupa a()' . '<br />';
35
36 ?>
12.9.3. Blocurile try catch
Nota
Instructiunea ce apeleaza o functie sau o metoda se numeste cod client fata de functia sau metoda respectiva.

Avantajele exceptiilor, fata de erorile clasice, sunt:

 obiectul erorii contine informatie structurata, si detaliata despre eroarea respectiva

 nu trebuie sa transmitem erorile de la o functie la alta prin parametri sau valori de return. Exceptiile se propaga automat. Fiecare functie,
daca genereaza o exceptie, anunta functia parinte despre eroarea respectiva - ii paseaza exceptia. Flexibilitatea consta in faptul ca putem
"prinde" exceptia atat in contextul in care a fost generata cat si in oricare din functiile parinte regland astfel executia programului in orice
moment ni se pare potrivit.

 acelasi bloc de cod, poate genera mai multe tipuri de exceptii. Putem scrie cod ce reactioneaza diferit in functie de tipul de exceptie generat

Prinderea exceptiilor se realizeaza cu ajutorul blocurilor de tip try catch. Atat try, cat si catch, delimiteaza un bloc de cod. Blocul de cod delimitat de try
este calea normala a scriptului, in care insa e posibil sa apara o exceptie. Daca una din instructiunile din try genereaza o exceptie, indiferent ca este in acel
bloc sau "la adancime" in apelul unei functii ce s-a facut pornind din acest bloc, aceasta exceptie va fi in mod normal prinsa de blocul catch, sau de unul
din blocurile catch, in functie de tipul exceptiei asa cum vom vedea.

Un bloc try catch arata astfel:

1 <?php
2
3 try {
4 $j = 0;
5
6 if ($j == 0) throw new Exception('Impartire la 0', 1); // primul
7 argument este mesajul exceptiei, al doilea argument este codul
8 exceptiei
9 $i = 1 / $j;
10
11 } catch (Exception $e) {
12 echo 'Mesaj exceptie: ' .$e->getMessage() . '<br />';
13 echo 'Cod exceptie: ' .$e->getCode() . '<br />';
14 echo 'Fisier: ' .$e->getFile() . '<br />';
15 echo 'Linie: ' .$e->getLine() . '<br />';
16 echo 'Stiva de apeluri: ' .$e->getTraceAsString() . '<br />';
17 }

?>

In acest exemplu incercam executia unei impartiri. Daca insa $j este 0, generam o exceptie cu ajutorul cuvantului cheie "throw". Codul urmator exceptiei
din interiorul blocului try nu se mai executa. Insa, exceptia este prinsa in interiorul bloculuicatch. catch este urmat de paranteze rotunde si de clasa
exceptiei precum si de o variabila in care se va pastra obiectul exceptiei. Aceasta sintaxa este asemanatoare cu cea de la subcapitolul Type hinting in
care fortam tipul unui argument ce-l poate primi o functie. Obiectul $e apartine clasei Exception, din acest motiv ii putem apela metode prin care sa
obtinem informatii despre eroarea respectiva, inclusiv stiva de apeluri (vezi Resurse: PHP Manual - Exception).
Bineinteles, unele informatii nu trebuie afisate utilizatorului, ci scrise intr-un log de erori.

In urmatorul exemplu, vom "prinde" exceptia in alt loc fata de locul in care este generata.

1 <?php
2
3 function imparte($i, $j)
4{
5 if ($j == 0) throw new Exception('Impartire la 0', 1);
6 echo 'nu se executa';
7}
8
9
10 try {
11
12 $i = 1;
13 $j = 0;
14 imparte($i, $j);
15 echo 'nici aici nu se executa';
16
17 } catch (Exception $e) {
18 echo 'Mesaj exceptie: ' .$e->getMessage() . '<br />';
19 echo 'Cod exceptie: ' .$e->getCode() . '<br />';
20 echo 'Fisier: ' .$e->getFile() . '<br />';
21 echo 'Linie: ' .$e->getLine() . '<br />';
22 echo 'Trace (stiva de apeluri): <pre>' .nl2br($e-
23 >getTraceAsString()) . '</pre>';
24 }
25
26 echo ' insa scriptul poate continua dupa blocul try catch ce a prins
27 exceptia';

?>

Exceptia a fost generata in interiorul functiei imparte, prin urmare nu se executa restul codului din aceasta functie. Este prinsa in main(), acolo unde a fost
apelata functia, intr-un bloc catch. Instructiunile din blocul try ce urmeaza apelului functiei ce a generat exceptia (linia 15) nu se executa. Insa, dupa ce
exceptia a fost prinsa intr-un bloc catch scriptul isi continua executia cu instructiunile ce urmeaza acestui bloc. Deci linia 25 si eventualele instructiuni
urmatoare, se executa.

Reluand (putin modificat) exemplul initial, cu functiile a(), b() si c() (in care a() apeleaza b() care la randul ei apeleaza functia c()) generam o exceptie in
interiorul functiei c(), o lasam sa se propage prin b(), si o prindem in a().

1 <?php
2 function a()
3{
4 echo 'a1' . '<br />';
5
6 try {
7
8 b();
9 echo 'a2' . '<br />';
10
11 } catch (Exception $e) {
12
13 echo '<b>Exceptie: </b>' . $e->getMessage() . '<br />';
14
15 }
16 echo 'a3' . '<br />';
17
18 } /// a()
19
20
21 function b()
22 {
23 echo 'b1' . '<br />';
24 c();
25 echo 'b3' . '<br />';
26 }
27
28 function c()
29 {
30 echo 'c1' . '<br />';
31
32 if (!function_exists('ceva')) throw new Exception('Functie
33 inexistenta', 3);
34
35
36 echo 'c2' . '<br />';
37 return;
38
39 echo 'c3' . '<br />';
40 d();
41 }
42
43 function d()
44 {
45 echo 'nu ma execut';
46 }
47
48
49 echo 'inainte de a()' . '<br />';
50 a();
51 echo 'dupa a()' . '<br />';
52
?>

Ordinea executiei este urmatoarea:

 linia 48

 linia 49 - se apeleaza functia a()

 linia 4 - se executa prima instructiune din functia a()

 linia 8 - se prima instructiune din din blocul try - apelul functiei b()

 linia 23, 24 - se executa cele doua instructiuni din b(). Pe linia 24 se apeleaza functia c()

 linia 30

 linia 32 - se determina faptul ca nu exista functia ceva(), prin urmare generam o exceptie

 exceptia se propaga prin call stack, prin functia b() (fara sa se mai execute nimic din aceasta functie), pana in interiorul functiei a(). Din
punctul de vedere al functiei a(), codul care a generat eroarea este apelul functiei b(); prin urmare, instructiunea urmatoare (linia 9) nu se
executa; executia sare in interiorul blocului catch, la linia 13. Se afiseaza mesajul exceptiei.

 linia 16, pentru ca exceptia a fost prinsa, se continua cu executia codului ce urmeaza blocului catch(), si anume linia 16.

 linia 50 - executia continua in mod normal, se revine la locul in care a fost apelata functia a() si se executa instructiunea urmatoare

Concluzie
1. O exceptie poate fi prinsa atat in locul in care a fost generata, cat si in oricare din functiile parinte. Daca nu este prinsa cu un bloc try catch va genera
o eroare de tip Fatal Error.

2. Pentru a retine modul in care se modifica executia programului cand apare o exceptie, este suficient sa ne gandim ca executia codului nu continua
decat dupa blocul catch care a prins exceptia

12.9.4. Extinderea clasei Exception

Clasa Exception, ca orice clasa, poate fi extinsa. Putem face acest lucru in momentul cand vrem sa adaugam metode noi clasei Exception, si vrem sa avem
eventual mai multe clase ce extind clasa Exception ce reactioneaza diferit in functie de erorile intalnite. Atunci cand aruncam o exceptie "custom", adica
dintr-o clasa creata de noi ce extinde clasa Exception, putem prinde exceptia intr-un bloc catch (Exception $e) sau intr-un bloc catch ce precizeaza clasa
noastra catch (MyException $e).
Daca o portiune de cod poate arunca mai multe tipuri de exceptii, este posibil sa specificam mai multe ramuri pentru blocul catch (similar cu constructia
switch), astfel incat sa directionam exceptia noastra in ramura dorita. Exceptia va cauta ramura din catch ce se potriveste clasei din care face parte sau
unei clase parinte. In cazul nostru, daca se arunca o exceptie de tip WrongInput, aceasta va fi prinsa de } catch (WrongInput $e) {. Daca aceasta
ramura catch n-ar fi fost prezenta, exceptia WrongInput ar fi fost prinsa de catch (Exception $e).

1 <?php
2 class DbException extends Exception {
3 const ERROR_FILE = 'c:/www/error_log';
4
5 function logError()
6 {
7 error_log(
8 $this->getMessage() . "\t" .
9 $this->getFile() . "\t" .
10 $this->getLine() . "\t\n", 3, self::ERROR_FILE);
11 }
12 }
13
14 class WrongInput extends Exception {
15
16 }
17
18
19 function dbConnect()
20 {
21 $db_host = 'localhost';
22 $db_user = 'root';
23 $db_pass = '';
24 $db_name = 'mysite';
25
26
27 $link = @mysqli_connect($db_host, $db_user, $db_pass, $db_name);
28
29 if (!$link) {
30 throw new DbException('Eroare la conectare', 1);
31 }
32
33 return $link;
34
35 }
36
37 function getInfo($utilizatorId) {
38 global $link;
39
40 if (!is_numeric($utilizatorId)) {
41 throw new WrongInput('Id-ul furnizat este nu este numeric', 3);
42 }
43
44 $sql = ' SELECT * FROM utilizatori WHERE utilizatorId = '.
45 $utilizatorId;
46 $result = mysqli_query($link, $sql);
47
48 if (mysqli_num_rows($result) == 1) {
49 $d = mysqli_fetch_assoc($result);
50 return $d;
51 } else {
52 throw new WrongInput('Nu au fost gasiti utilizatori pentru id-ul'
53 . $utilizatorId, 2);
54 }
55
56 }
57
58
59 try {
60
61 $link = dbConnect(); // -> in caz ca nu reuseste conectarea la baza
62 de date -> DbException
63 // $utilizator = getInfo('asdf'); -> WrongInput exception
64 // $utilizator = getInfo(1234); -> WrongInput exception
65 $utilizator = getInfo(1);
66
67
68 foreach ($utilizator as $k => $v) {
69 echo $k.' : ' . $v;
70 echo '<br />';
71 }
72
73
74 } catch (DbException $e) {
75 $e->logError();
76 echo $e->getMessage();
77 } catch (WrongInput $e) {
78 echo $e->getMessage();
79 } catch (Exception $e) {
80 echo $e->getMessage();
81 die();
82 }
83
echo '<br /><br />continuare script...<br /><br />';

?>

12.10. Tema
Tema 12-1
Realizati, cu ajutorul OOP, o librarie (o clasa, combinatie de clase, interfete, etc) cu ajutorul careia sa realizati paginarea rezultatelor extrase dintr-o baza
de date. Spre exemplu, daca un rand are 100 de inregistrari, utilizatorul vede doar 10 inregistrari pe pagina, si poate naviga inainte, inapoi, la prima
pagina, la ultima etc. Realizati o mini-aplicatie in care sa demonstrati folosirea acestei librarii.

Tema 12-2
Realizati, in stilul OOP, propria librarie pentru lucrul cu MySQL, astfel incat sa faciliteze operatiile comune cu baza de date: extragerea unui rand, mai
multor randuri, insert, update, extragerea informatiilor despre coloane, aflarea cheii primare, extragerea unui rand pe baza valorii cheii primare, etc

CAP. 13. Diverse


13.1 Date/time in PHP
13.2 Trimiterea unui email din PHP
13.3 Informatiile afisate de phpinfo()
13.4 Setarea optiunilor/directivelor PHP
13.5 Informatii utile in $_SERVER
13.6 Managementul erorilor
13.7 Imbinarea tehnologiei Ajax cu PHP
13.8 PHP si fisierele XML
13.9 Lucrul cu sabloane html. Clasa Template
13.10 Despre reinventarea rotii. Un exemplu: libraria PEAR
13.11 Bancuri in PHP
13.12 Tema

13.1. Date/time in PHP


Deseori intalnim nevoia in scripturile noastre sa extragem data curenta, sa afisam intr-un anumit format data curenta, sau sa facem diferite operatii cu
datele calendaristice. Voi prezenta in acest subcapitol functiile de baza si exemple in utilizarea acestora. Cand vorbim despre data curenta, ne referim la
data serverului pe care ruleaza scriptul php.
date()
Functia date() accepta doi parametri, al doilea fiind optional: date($format, $timestamp). Pentru inceput, sa analizam primul parametru.

$format este un string conform caruia se va formata data pe care vrem sa o afisam. Diferite litere in acest string au inteles special. Cateva din cele mai
folosite litere:

 d - numarul zilei din luna - cu zero inainte

 m - numarul lunii - cu zero inainte

 Y - anul - 4 cifre

 H - ora in format 24 de ore, cu zero inainte

 i - minute, cu zero inainte

 s - secunde, cu zero inainte

 l (L mic) - numele zilei saptamanii

 j - ziua din luna - fara zero inainte

 n - numarul lunii - fara zero inainte

Lista continua, restul optiunilor le gasiti in documentatia oficiala a acestei functii (vezi Resurse).

Daca al doilea parametru ($timestamp) nu este furnizat, date() ne returneaza data curenta:

1 <?php
2
3 echo date('d.m.Y H:i:s');
4 echo '<br />';
5
6 echo date('d/m/Y');
7 echo '<br />';
8
9 echo date('l');
10 echo '<br />';
11
12 ?>

mktime()
O serie de functii din PHP returneaza sau lucreaza cu o valoare numita timestamp. Aceasta valoare e folosita pentru a indica o anumita data, indiferent de
formatul ei. Este o valoare de tip intreg, si reprezinta numarul de secunde ce au trecut de la 1 ianuarie 1970 ora 00:00.

mktime(), fara nici un argument, returneaza timestamp-ul datei curente.

Prototipul functiei mktime arata astfel:


Pseudocod
int mktime ([ int $hour= date("H") [, int $minute= date("i") [, int $second= date("s") [, int $month= date("n") [, int $day= date("j") [, int $year=
date("Y")]]]]]] )
Adica toti parametrii functiei sunt optionali, dar intr-o anumita ordine. Daca prezicam primul parametru el va indica ora, iar restul parametrilor sunt:
minutul curent, secunda curenta, luna curenta, ziua curenta, anul curent. Daca precizam al doilea si al treilea parametru (reprezentand o ora si un minut),
restul valorilor, similar, sunt cele curente. Astfel, daca folosim functia date() pentru fiecare din parametrii, obtinem timestamp-ul datei curente.
Acest lucru ne ajuta sa calculam o data in trecut sau in viitor cu un anumit numar de ore, minute secunde, zile, luni, ani, sau cu orice combinatie dintre
acestea. Valoarea returnata de mktime(), timestamp-ul, il pasam apoi ca al doilea argument functiei date() pentru a formata data.

De exemplu:

1 <?php
2 $ts = mktime(0, 0, 0, date('n'), date('j'), date('Y')); // obtinem
3 timestamp-ul zilei de azi, ora 00:00
4 echo date('d.m.Y H:i:s', $ts);
5
6 echo '<br />';
7
8
9 $ts = mktime(date('H'), date('i'), date('s'), date('n'), date('j'),
10 date('Y')); // obtinem timestamp-ul pentru data curenta, inclusiv ora
11 echo date('d.m.Y H:i:s', $ts);
12
13 echo '<br />';
14
15
16 $ts = mktime(date('H'), date('i'), date('s'), date('n'), date('j') +
17 200, date('Y')); // relativ la data si ora curenta, obtinem data de
18 peste 200 de zile
19 echo date('d.m.Y H:i:s', $ts);
20
21 echo '<br />';
22
23
24 $ts = mktime(date('H'), date('i'), date('s'), date('n') + 3,
25 date('j') - 5, date('Y')); // obtinem data de peste 3 luni fara 5
26 zile
27 echo date('d.m.Y H:i:s', $ts);
28
29 echo '<br />';
30
31
32
33 $ts = mktime(date('H') + 1000, date('i'), date('s'), date('n'),
date('j'), date('Y') + 1); // obtinem data de peste 1 an si 1000 de
ore
echo date('d.m.Y H:i:s', $ts);

echo '<br />';

?>

strtotime()
strtotime() este o functie foarte utila ce returneaza de asemenea un timestamp.
Prototip
int strtotime ( string $time [, int $now ] )

Stringul $time este o data in limba engleza, cu un format destul de liber, care trebuie experimentat. strtotime() este folosit atat pentru extragerea datei
curente cat si pentru a calcula date in trecut sau viitor, similar cu mktime(). Daca folosim un string similar cu o data, data respectiva trebuie sa fie in
format englezesc, mm/dd/yyyy.

Voi folosi in exemple strtotime() in colaborare cu date(), pentru a vizualiza data returnata de strtotime().

1 <?php
2 function test_strtotime($str)
3{
4 $ts = strtotime($str);
5 echo date('d.m.Y H:i:s', $ts);
6 echo ' = ';
7 echo $str;
8
9 echo '<br />';
10 }
11
12
13 test_strtotime('now');
14 test_strtotime('tomorrow');
15 test_strtotime('+1 day');
16 test_strtotime('+20 days');
17 test_strtotime('+3 weeks 2 days 7 hours');
18 test_strtotime('-1 week +1 day');
19 test_strtotime('+3 Monday');
20 test_strtotime('next Thursday');
21 test_strtotime('03/23/2010 14:08:01'); // daca furnizam o data in
22 format englezesc, strtotime() reactioneaza corect
23 test_strtotime('03/23/2010 14:08:01 + 3 day');
24
25
?>

Al doilea parametru acceptat de strtotime() este optional, si reprezinta un timestamp fata de care se calculeaza datele relative. Acel timestamp poate fi
obtinut prin orice metoda: mktime(), tot strtotime(), obtinut din MySQL, etc
Compararea a doua date
Pentru a compara doua date, este necesar sa le reducem la "numitorul comun", la timestamp

1 <?php
2 if (strtotime('now') < strtotime('09/23/2011')) {
3 echo 'Inca mai e timp';
4}
5
6 ?>

13.2. Trimiterea unui email din PHP


Trimiterea unui email din scripturile PHP se realizeaza cu ajutorul functiei mail().
Pseudocod
bool mail ( string $to , string $subject , string $message [, string $additional_headers ] )

 $to - emailul destinatarului

 $subject - subiectul emailului

 $message - mesajul emailului

 $additional_headers - headere aditionale transmise serverului de email

Singurul lucru care cere lamuriri suplimentare este conceptul de "headers". Transmiterea emailului prin Internet de la un utilizator la celalalt se realizeaza
pe baza unor standarde. Aceste standarde cer ca emailul, in afara de subiect si mesaj, sa contina o sectiune denumita "headers", folosita de serverele si
clientii de email pentru a trimite/primi corect emailul. Fiecare header este un string, separat de celelalte headere prin caracterul CRLF (\r\n), adica
"newline". Va amintiti ca in PHP caracterele de control (newline, tab, etc) pot fi scrise doar intre ghilimele duble. Un header consta intr-o pereche Camp:
Valoare. De exemplu, Cc: webmaster@invata-online.ro
Pentru campurile Cc (carbon copy), Bcc (blind carbon copy), se poate specifica un nume de utilizator, urmat de adresa efectiva de email intre < si >.

1 <?php
2
3 $to = 'stefan@crystalmind.ro';
4
5 $subject = 'Salut';
6
7 $body = "Salut \n
8 \n
9 Doar testam sa vedem daca merge";
10
11 $headers = '';
12
13 /* observati in liniile urmatoare, ghilimelele duble la \r\n */
14 $headers .= 'From: Eu <eu@example.com>' . "\r\n"; // neaparat trebuie
15 specificat headerul From - indica expeditorul emailului
16
17
18 $headers .= 'Cc: Webmaster IO <webmaster@example.com>' . "\r\n"; //
19 acest header e bineinteles optional - carbon copy trimite o copie
20 catre o alta adresa
21 $headers .= 'Bcc: Mie imi <eu@example.com>' . "\r\n"; // la fel,
22 optional - blind carbon copy trimite o copie catre alta adresa fara
23 ca ceilalti destinatari sa vada
24

mail($to, $subject, $body, $headers);

?>

Pentru a trimite un email in format html, trebuie in plus sa adaugam urmatorul header:

1 <?php
2
3 $headers .= 'Content-type: text/html; charset=utf-8' . "\r\n";
4
5 ?>

13.3. Informatiile afisate de phpinfo()

Functia phpinfo() este deosebit de utila pentru aflarea de informatii detaliate despre php, serverul pe care ruleaza, optiunile de configurare, si nu numai.
In dezvoltarea cu php, atat pe calculatorul local - mediul in care dezvoltam, cat si pe serverul web - mediul de productie, programatorul web foloseste
phpinfo() atunci cand are nevoie sa stie de exemplu ce versiune de php ruleaza, sau care este calea fizica in sistemul de fisiere a scriptului curent, sau
care este DOCUMENT ROOT (calea radacinii serverului web), sau ce valori au anumite optiuni din php.ini (cum ar fi session.save_path), si exemplele pot
continua.

Nota
Informatiile pe care le afiseaza phpinfo() sunt destinate programatorului web si in nici un caz utilizatorilor. Afisarea informatiilor din phpinfo() catre
utilizatori este considerat un risc de securitate, din acest motiv functia phpinfo() este dezactivata pe unele servere de gazduire.

Apelata fara nici un parametru, phpinfo() afiseaza toate informatiile. Insa, poate primi ca argument un intreg (specificat sub forma unei constante) ce
afiseaza categoria de informatii ce ne intereseaza.

O clasificare a informatiilor din phpinfo() ar fi urmatoarea:

 informatii despre versiunea de PHP instalata, si despre modul in care a fost compilat
Stim ca, de la PHP4 la PHP5 - de la o versiune majora la alta - sunt diferente destul de mari, mai ales in sintaxa OOP, dar si de la o versiune
minora la cealalta (de exemplu de la PHP 5.1 la PHP 5.3) apar diferente ce pot influenta scriptul, daca folosim exact lucrurile care s-au
schimbat.

Prin urmare, este necesar sa stim versiunea pe care dezvoltam in PHP, si ideal ar fi sa avem aceeasi versiune, cu optiuni si extensii cat mai
asemanatoare atat in mediul de dezvoltare (local) cat si in cel de productie (online) pentru a minimiza diferentele de comportament ale
aplicatiei in rularea pe cele doua medii.

Aceste informatii le obtinem cu phpinfo(INFO_GENERAL);

 informatii referitoare la extensiile cu care PHP este instalat


Extensiile sunt "portiuni" ale limbajului destinate sa lucreze cu un set specific de operatiuni sau resurse. Unele extensii fac parte din limbajul
PHP si sunt instalate odata cu acesta. De exemplu mysql - extensie destinata legaturii intre PHP si MySQL, mysqli si PDO - extensii cu acelasi
scop dar functionalitate diferita, Reflection - extensie destinata introspectiei claselor, SPL extensia cu interfete si clase standard, dom, libxml,
pdf, etc.
Cu phpinfo(INFO_MODULES) aflam ce extensii sunt instalate cu versiunea noastra de PHP, precum si optiunile si alte informatii referitoare
la aceste extensii.

 informatii despre variabilele predefinite in PHP

Aceasta sectiune printeaza informatiile stocate in variabilele predefinite, in principal organizate in tablourile "superglobals": $_GET, $_POST,
$_COOKIE, $_REQUEST (contine toate informatiile venite de la utilizator, deci combinatia dintre tablourile $_GET, $_POST si $_COOKIE) ,
$_SERVER, $_ENV, $_FILES, $_SESSION, $GLOBALS (un tablou cu toate variabilele globale). Aici (in $_SERVER si $_ENV) avem informatii
importante despre caile in sistemul de fisiere - atat cai in sistemul de fisiere, cat si cai http (relative la document root). De asemenea sunt
informatii despre sistemul de operare, serverul web, etc.

Aceasta categorie poate fi afisata cu phpinfo(INFO_VARIABLES).

 informatii despre optiunile PHP - valoarea curenta si valoarea din php.ini Aceasta sectiune, poate fi afisata
cuphpinfo(INFO_CONFIGURATION), si printeaza informatii despre optiunile PHP-ului, optiuni ce sunt initial specificate prin fisierul de
configurare (php.ini) dar pot fi schimbate in scriptul curent cu ini_set(). Local Value este valoarea optiunii din scriptul curent, iar Master
Value este valoarea originala a optiunii - preluata din php.ini

Nota
Multe optiuni de configurare utile (de ex session.save_path) sunt specifice unei anumite extensii, prin urmare sunt afisate cu INFO_MODULES, nu
cu INFO_CONFIGURATION.
Din acest motiv, e mai simplu uneori sa afisam toata informatia cu phpinfo() si sa cautam cu ajutorul browserului textul/optiunea care ne
intereseaza.

13.4. Setarea optiunilor/directivelor PHP


Printre primele lucruri afisate cu phpinfo(), si uneori foarte util, este locatia fisierului de configurare al php-ului, php.ini.
Pe un sistem Unix arata
astfel:

Pe Windows, bineinteles va fi o cale ce incepe cu "C:\...". In php.ini sunt scrise optiunile (directivele) cu care ruleaza PHP, optiuni ce modifica esential
aspecte ale rularii unui script, si pe care deseori trebuie sa le schimbam. Local, avem acces la php.ini, pe un server de gazduire "shared" in mod sigur nu o
sa avem acces, deci trebuie sa gasim alte modalitati de a schimba aceste optiuni, sau macar o parte din ele.

Aceste optiuni, asa cum am vazut, sunt afisate si cu phpinfo(). Un exemplu ar fi optiunea session.save_path , pe care, asa cum spuneam, e o idee buna sa
o schimbam astfel incat sesiunile sa nu fie salvate "la gramada" cu cele ale altor site-uri.

In phpinfo optiunea arata astfel:

Prima coloana (stanga) este "Local Value", valoarea pentru scriptul curent, a doua este "Master Value", valoarea preluata din php.ini. In acest caz, Local
Value si Master Value au aceeasi valoare: /var/lib/php5.

In lista optiunilor prezenta in manualul PHP la List of php.ini directives , avem in dreptul fiecarei optiuni una din urmatoarele 3 constante:

 PHP_INI_ALL - indica faptul ca optiunea respectiva poate fi schimbata de oriunde (php.ini , ini_set(), .htaccess...)

 PHP_INI_PERDIR - optiunea ce are in dreptul ei aceasta constanta poate fi schimbata in fisiere .htaccess (bineinteles poate fi schimbata si
din php.ini)

 PHP_INI_SYSTEM - optiunea poate fi schimbata doar in php.ini si httpd.conf (fisierul de configurare al Apache-ului)

ini_set() si ini_get()
Continuand exemplul cu session.save_path , in dreptul acestei optiuni avem PHP_INI_ALL , deci putem sa o schimbam in scripturile noastre cu ini_set().
ini_set() are urmatorul prototip:

string ini_set ( string $varname , string $newvalue )

Primul string este optiunea pe care o modificam, al doilea este valoare corespunzatoare optiunii respective. Putem verifica apoi cu phpinfo() sau cu
ini_get($varname) noua valoare setata.

Nota
Optiunile php.ini de tip boolean se pot seta cu valorile "on" / "off" respectiv "1" / "0". In lista de directive php.ini

1 <?php
2 ini_set('session.save_path', 'c:/www/myproject/sessions');
3
4 //echo ini_get('session.save_path');
5
6 phpinfo();
7
8 ?>

Verificand outputul functiei phpinfo() vom obtine in dreptul optiunii session.save_path la Local Value valoarea setata de noi in script, si la Master Value
valoarea originala a
optiunii.

PHP_INI_PERDIR si .htaccess
In gazduirea shared, nu avem in general acces la httpd.conf si la php.ini. Daca optiunea noastra este in categoria PHP_INI_PERDIR, putem incerca
schimbarea optiunii printr-un fisier denumit .htaccess, plasat in directorul curent. Acest tip de fisier este citit de Apache pentru a adauga optiuni de
configurare la nivel de director.

In lista optiunilor de configurare (List of php.ini directives), unele optiuni au link catre o explicatie mai detaliata, in care aflam si tipul de date acceptat de
optiunea respectiva.

Exista doua modalitati de a schimba o optiune php din .htaccess.

1. Daca optiunea respectiva este de tip string, sau intreg:


php_value name value

2. Daca optiunea respectiva este de tip boolean:


php_flag name on|off

Exemplu continut .htaccess


php_value post_max_size "24M"
php_value upload_max_filesize "24M"
php_flag magic_quotes_gpc off

Dupa ce includem un fisier .htaccess avand optiunile modificate, trebuie sa verificam cu phpinfo() sau ini_get() daca valoarea optiunilor a fost intr-adevar
schimbata.

Important
Fisierele .htaccess au efect doar daca configuratia serverului Apache, in httpd.conf permite acest lucru cu directiva AllowOverride Options sau
AllowOverride All.

Nota
Constantele existente in PHP si in php.ini (exemplu: E_ALL , E_NOTICE) nu exista in afara limbajului php, deci nu au sens in .htaccess. In locul lor
trebuie sa folosim valoarea propriu-zisa, pe care o putem obtine din documentatie sau cu echo CONSTANTA; intr-un script

13.5. Informatii utile in $_SERVER


Exista mai multe tipuri de cai (paths) cu care lucreaza un browser web, un server web, sau interpretorul PHP pentru a gasi un fisier/director. La inceput,
acestea se pot uneori confunda, sau folosi gresit.
In functie de context, unele cai nu se pot folosi in anumite cazuri, sau nu sunt recomandate.

1. Calea relativa
Atat browserul web, cat si interpretorul PHP, inteleg acest tip de cale si este poate cea mai folosita. In dese cazuri, este singura recomandata.
Este o cale in sistemul de fisiere (de pe harddisk), in care resursa ceruta (fisier sau director) este relativa la fisierul html sau scriptul php curent.

Nota
Simpla chemare a unui fisier cu numele lui (ex: <img src="poza.jpg".. sau fopen('a.txt', 'w+') ) este o cale relativa, fisierul fiind cautat in acelasi
director cu scriptul curent

 exemplu in html:
Daca intr-un fisier html (sau script php) scriu codul html de mai jos pentru afisarea unei imagini in browser, browserul cauta pe harddiskul
local (sau cere serverului web) un fisier numit poza.jpg aflat in directorul img de pe acelasi nivel cu fisierul html. Cu alte cuvinte, calea
img/poza.jpg este relativa la fisierul .html in care am folosit aceasta cale.

fisier.html

<img src="img/poza.jpg" border="0" alt="" />

Se pot bineinteles folosi cai gen ../dir1/dir2/a.jpg pentru a urca in directorul parinte.

 exemplu in php:

1 <?php
2 include("lib/f-date.php"); // interpretorul php cauta fisierul f-
3 date.php in directorul lib de pe acelasi nivel cu scriptul curent
4
5 fopen('tmp.txt', 'a+'); // este cautat tmp.txt in directorul curent
6
7 include("../config/config.php"); // in folderul config cu un nivel mai
sus, se cauta config.php
?>

Nota
Caile relative NU sunt precedate de slash "/" .

2. Calea absoluta in sistemul de fisiere (Filesystem path)

In Windows arata astfel: c:\www\myproject\site\index.php . In Unix, poate fi: /home/myproject/site/index.php.

In nici un caz nu se foloseste in codul html cand realizam un link sau includem o imagine. Se foloseste rareori si in PHP, pentru ca "leaga" aplicatia web de
sistemul de fisiere al unui calculator. Insa, exista cazuri cand e necesar sa o folosim. Functiile din PHP ce folosesc fisiere (include, fopen(),
file_get_contents() ) accepta o astfel de cale absoluta, precum si o cale relativa.
In cazurile in care avem nevoie sa folosim aceste cai, e bine sa le compunem dinamic folosind $_SERVER['DOCUMENT_ROOT'] urmat de o cale in
webspace.

3. Calea in webspace sau calea relativa la document root


Este calea pe care o intelege serverul web, atunci cand ii cerem o resursa. Aceasta cale incepe cu slash / si reprezinta o resursa relativa la setarea
DocumentRoot a serverului web. Aceasta cale poate fi privita in general si ca relativa la domeniul cu care accesam site-ul. Depinde in ce context o folosim.
Mai precis, daca cer serverului web calea /img/poza.jpg pe un server ce are configurata setarea DocumentRoot /home/example/www , serverul va adauga
la DocumentRoot calea /img/poza.jpg pentru a gasi fisierul cerut pe harddisk. Aceeasi resursa, /img/poza.jpg este disponibila in browser sub forma
http://www.example.com/img/poza.jpg
Astfel, urmatoarele resurse sunt echivalente (desi in sisteme diferite):

Cale in webspace Cale absoluta in sistemul de fisiere URL

/img/poza.jpg /home/example/www/img/pozajpg http://www.example.com/img/poza.jpg

Se aseamana cu calea absoluta (in filesystem) din Unix, insa se folosesc in situatii diferite, astfel nu exista riscul ca un program sa le confunde. De
exemplu, nu putem folosi aceasta cale cu functiile PHP ce lucreaza cu fisiere. Acestea vor accepta o cale relativa sau o cale in sistemul de fisiere, pentru ca
in aceste cazuri lucreaza direct cu sistemul de operare, fara o legatura cu serverul web.

Se poate folosi aceasta cale in html:


fisier.html
<img src="/img/poza.jpg" border="0" alt="" />
Va fi cautata resursa img/poza.jpg relativa la DocumentRoot, asa cum s-a aratat mai sus.

Exista anumite valori ale tabloului $_SERVER ce returneaza calea in webspace. Putem folosi acest concept in scripturile noastre

4. URL
De forma: http://www.example.com/img/poza.jpg

Se poate folosi atat in html pentru referirea diferitelor fisiere (imagini, fisiere css, fisiere js) dar si in PHP cu include, require, fopen, file_get_contents, etc,
daca optiunile allow_url_fopen si allow_url_include sunt on.

$_SERVER
Manualul PHP ne avertizeaza ca in $_SERVER obtinem informatiile pe care ni le ofera serverul web, si, bineinteles unele pot fi disponibile altele nu, in
functie de server. In acest array superglobal, sunt informatii cu diferite cai din sistemul de fisiere (sau relative la document root) , sunt informatii despre
serverul web , sau despre conexiunea http curenta.

Pentru a intelege mai bine cateva elemente din arrayul $_SERVER, presupunem ca accesam
http://www.example.com/test/t.php?userId=7&page=display si avem Document Root in /home/example/www

Elementele din superglobalul $_SERVER sunt:

Element $_SERVER Exemplu Explicatii

Setarea DocumentRoot a serverului web. Cale absoluta, in sistemul de


$_SERVER["DOCUMENT_ROOT"] /home/example/www
fisiere

calea in webspace (relativa la DocumentRoot sau relativa la domeniu)


catre scriptul curent. Daca aveti nevoie sa obtineti calea absoluta catre
$_SERVER['PHP_SELF'] /test/t.php
fisierul curent, se poate folosi variabila predefinita __FILE__ (dublu
underscore)

calea absoluta catre fisierul curent executat. Diferenta intre


$_SERVER["SCRIPT_FILENAME"] si __FILE__ se poate testa astfel:
realizati un fisier f.php, in care includeti un fisier numit f_inclus.php, in
care sa afisati atat $_SERVER["SCRIPT_FILENAME"] cat si __FILE__ .
Rulati apoi in browser f.php. Veti observa ca f_inclus.php ne arata calea
$_SERVER["SCRIPT_FILENAME"] /home/example/www/test/t.php
absoluta catre f.php cu $_SERVER["SCRIPT_FILENAME"] si calea absoluta
catre f_inclus.php in __FILE__ . In concluzie, __FILE__ contine numele
fisierului curent (chiar daca acesta este inclus, nu executat direct) in timp
ce $_SERVER["SCRIPT_FILENAME"] este fisierul care a fost cerut
serverului web.

similar cu o cale in webspace, insa include si query string-ul (parametrii


$_SERVER["REQUEST_URI"] /test/t.php?userId=7&page=display
get). Acest tip de resursa se numeste URI.
$_SERVER["QUERY_STRING"] userId=7&page=display Valoarea query string-ului, daca acesta exista

Aceasta informatie este un header al cererii HTTP, deci este transmis de


Mozilla/5.0 (X11; U; Linux i686; en-US; client (browser), si este un sir de informatii cu care browserul se
$_SERVER["HTTP_USER_AGENT"] rv:1.9.0.3) Gecko/2008092510 identifica. Aceste informatii includ de obicei tipul si versiunea browserului,
Ubuntu/8.04 (hardy) Firefox/3.0.3 sistemul de operare pe care e instalat browserul (deci sistemul de operare
al utilizatorului), etc

$_SERVER["REMOTE_ADDR"] 81.122.169.117 Adresa IP a vizitatorului

In caz ca vizitatorul a ajuns la aceasta pagina prin click pe un link,


$_SERVER["HTTP_REFERER"] http://www.altsite.com browserul e posibil sa trimita prin headere HTTP_REFERER, adica URL-ul
prin care s-a ajuns la aceasta pagina

$_SERVER["REQUEST_METHOD"] GET GET sau POST

Numele serverului web pentru scriptul curent asa cum este configurat in
$_SERVER["SERVER_NAME"] www.example.com
httpd.conf. In general, in gazduirea shared, este numele domeniului

$_SERVER["SERVER_ADDR"] 80.96.148.194 Adresa ip a serverului web

13.6. Managementul erorilor


13.6.1 Tipurile de erori
13.6.2 Optiunea error_reporting
13.6.3 Afisarea sau logarea erorilor
13.6.4 set_error_handler()
13.6.5 Tratarea erorilor ca exceptii

13.6.1. Tipurile de erori

Lasand la o parte erorile de logica, si exceptiile, erorile generate de PHP se impart in mai
multe tipuri, in functie de tip si nivel de severitate. Fiecarui tip de eroare ii corespunde un
numar intreg, sau o constanta predefinita (cu valoarea numarului respectiv).

Cele mai importante / intalnite tipuri de erori generate de interpretorul PHP sunt:
Erori fatale (Fatal Error) in executia scriptului. De exemplu, apelam o functie care nu exista, sau includem un fisier inexistent
E_ERROR
cu require, sau scriptul consuma toata memoria etc. Executia scriptului este oprita in punctul in care eroare e intalnita

Erori de tip Warning (atentionare) in executia scriptului. De exemplu, incercam sa scriem intr-un fisier in care n-avem acces, sau
E_WARNING apelam o functie cu numar gresit de parametri, sau incercam sa includem un fisier inexistent cu include, etc.
Warning-urile sunt mai putin severe decat erorile fatale, si NU opresc executia scriptului.

Erori de o severitate mai scazuta, ce pot reprezenta sau nu o problema, dar merita atentia programatorului. Exemplu cel mai des
E_NOTICE intalnit de notice apare cand folosim in expresii variabile nedefinite.
Ele NU opresc executia scriptului. In mod normal, in dezvoltarea unei aplicatii web, notice-urile trebuiesc afisate, si inlaturate.

PHP5 a venit si cu cateva noi tipuri de erori, printre care si E_STRICT. Acest tip de erori ofera sfaturi pentru a pastra un cod cat mai
E_STRICT
compatibil cu versiunile viitoare de PHP

Introdus in php 5.3.0 , ca nivel de severitate similar cu notice-urile, afiseaza mesaje de atentionare in legatura cu codul invechit
E_DEPRECATED
(deprecated).

Alte tipuri de erori existente:

 E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE, E_USER_DEPRECATED similare in comportament si afisare cu E_ERROR,


E_WARNING... insa sunt declansate de utilizator cu functia trigger_error($error_msg, $error_type); unde $error_type este constanta tipului
erorii, si implicit este E_USER_NOTICE

 E_PARSE - erori de sintaxa, la compilare (inainte de rularea scriptului)

 E_COMPILE_ERROR si E_COMPILE_WARNING pot aparea in faza de compilare, generate de Zend Scripting Engine (nucleul PHP-ului).

 E_CORE_ERROR si E_CORE_WARNING - pot aparea in momentul cand este pornit prima data interpretorul PHP. Aceste erori pot fi
generate de exemplu de anumite setari incorecte din php.ini.

 E_RECOVERABLE_ERROR - sau Catchable fatal error, are un nivel de severitate similar cu E_ERROR (Fatal Error), insa poate fi "tratata"
cu set_error_handler().

 E_ALL - este o constanta ce include toate tipurile de erori reunite, cu exceptia E_STRICT

1 <?php
2 error_reporting(E_ALL);
3
4 // functia_mea_nedefinita(); // Fatal Error - aceasta linie trebuie
5 comentata, astfel incat scriptul sa continue, sa puteti vedea si
6 celelalte erori
7
8 fopen(); // Warning...
9
10 $j = $i * 2; // Notice
11
12 trigger_error('Mesaj warning...', E_USER_WARNING); // warning generat
13 de mine
14
15
16 trigger_error('Mesaj eroare... ?', E_USER_ERROR); // fatal error
17 generat de mine
18

echo 'Text';

?>

13.6.2. Optiunea error_reporting

error_reporting este o optiune PHP ce determina tipurile de erori raportate de PHP in timpul rularii unui script.
Directiva error_reporting este "changeable" PHP_INI_ALL deci poate fi schimbata inclusiv cu ini_set() la inceputul executiei scriptului. Insa, se poate
folosi functia error_reporting() in loc de ini_set().

Indiferent cum se schimba aceasta directiva (php.ini , ini_set(), error_reporting()), accepta ca valoare un numar intreg determinat prin operatiile binare
intre constantele tipurilor de erori.
Astfel, operatorul "|" (SAU binar) folosit intre constante ne ajuta sa grupam mai multe tipuri de erori, in timp ce CONSTANTA1 & ~CONSTANTA2 ("&" - SI
binar, "~" not binar) ia in calcul CONSTANTA1, dar fara CONSTANTA2.

La inceputul scriptului, putem decide ce tipuri de erori dorim sa fie raportate de PHP combinand constantele cu operatorii binari. Aveti cateva exemple mai
jos:

1 <?php
2
3 error_reporting(0); // nu se vor raporta nici un fel de erori
4
5 error_reporting(E_ALL); // se vor raporta toate erorile (cu exceptia
6 E_STRICT).
7
8 error_reporting(E_ALL | E_STRICT); // raporteaza toate erorile, si
9 cele E_STRICT
10
11 error_reporting(E_ALL & ~E_NOTICE); // raporteaza toate erorile cu
12 exceptia celor de tip E_NOTICE
13
14 error_reporting(E_ALL & ~E_USER_ERROR & ~E_USER_WARNING &
15 ~E_USER_NOTICE); // raporteaza fara erorile din familia E_USER
16
error_reporting(E_COMPILE_ERROR | E_RECOVERABLE_ERROR | E_ERROR |
E_CORE_ERROR); // raporteaza doar erorile cu o severitate grava - ce
intrerup executia scriptului

?>

In general, error_reporting() este apelat o singura data, la inceputul scriptului, in functie de politica de raportare a erorilor pe care o stabiliti pentru
scriptul (aplicatia) respectiv. Insa, poate fi uneori de dorit sa schimbati nivelul de raportare doar pe o anumita portiune de cod. Acest lucru este posibil
datorita faptului ca error_reporting() returneaza valoarea initiala (inainte de schimbare) a acestei optiuni, astfel incat sa poata fi schimbata la loc, ulterior
in script.

1 <?php
2 error_reporting(E_ALL);
3
4 echo $a; // Notice
5
6 $err_rep = error_reporting(0);
7
8 fopen(); // Warning...
9
10 $j = $i * 2; // Notice
11
12 error_reporting($err_rep);
13
14 trigger_error('Mesaj warning...', E_USER_WARNING); // user warning
15
16
17 echo 'Text';
18 ?>

13.6.3.Afisarea sau logarea erorilor


Daca suntem in mediul de dezvoltare - pe calculatorul local, dezvoltam sau intretinem aplicatia web - avem o alta abordare in tratarea erorile fata de cazul
in care aplicatia web ruleaza "in productie", online.
In general, cand dezvoltam vrem sa afisam erorile (si sa nu le pastram intr-un log neaparat), iar online vrem sa nu afisam erorile, dar sa le logam, si
eventual sa fim anuntati pe email.
Erorile de PHP in general nu trebuie afisate utilizatorului din cel putin doua motive: primul, eroarea poate oferi informatii sensibile despre server, si in al
doilea rand, este inestetic.

Nota
Nu trebuie sa schimbam setarile de fiecare data cand copiem website-ul online. Putem avea ambele setari in ramuri diferite ale unei structuri if,
prin care determinam daca aplicatia este offline sau online. Acest lucru il putem face pe baza valorii din $_SERVER["SERVER_ADDR"] , sau
$_SERVER["SERVER_NAME"].
Optiunile din php.ini ce controleaza afisarea erorilor sunt display_errors si display_startup_errors. Sunt de tip boolean, pot fi setate deci cu
valorile on sau off. Cand sunt off, erorile nu sunt afisate in browser (chiar daca ele sunt raportate cu error_reporting()).

Astfel, cand dezvoltam avem:

1 <?php
2
3 error_reporting(E_ALL);
4 ini_set('display_startup_errors', 'on');
5 ini_set('display_errors', 'on');
6
7 echo $i; // Notice
8 fopen(); // Warning
9
10 echo '<br /><b>Welcome to my website</b>';
11
12 ?>

Iar "in productie" avem acelasi lucru, dar cu setarile display_errors si display_startup_errors avand valoarea off.

Optiunile log_errors si error_log


Aceste optiuni (php.ini sau ini_set()) determina daca si unde sa se scrie (logheze) erorile:

 log_errors - de tip boolean (primeste "on" sau "off", echivalent cu "1" sau "0"). Daca este on, adauga erorile intr-un fisier text.

 error_log - primeste ca valoare calea (absoluta sau relativa) catre fisierul in care dorim scrierea erorilor

Local, se potrivesc urmatoarele setari:

1 <?php
2
3 error_reporting(E_ALL);
4 ini_set('display_startup_errors', 'on'); // afisam erorile
5 ini_set('display_errors', 'on'); // afisam erorile
6 ini_set('log_errors', 'off'); // nu are neaparat rost sa le logam
7
8
9
10 echo $i; // Notice
11 fopen(); // Warning
12
13 echo '<br /><b>Welcome to my website</b>';
14
15 ?>

Iar online, pe un server in productie:

1 <?php
2
3 error_reporting(E_ALL);
4 ini_set('display_startup_errors', 'off'); // nu afisam erorile
5 ini_set('display_errors', 'off'); // nu afisam erorile
6 ini_set('log_errors', 'on'); // in schimb le scriem in log
7 ini_set('error_log', '../fisier_erori.txt'); // aici
8
9
10 echo $i; // Notice
11 fopen(); // Warning
12
13 echo '<br /><b>Welcome to my website</b>';
14
15 ?>
13.6.4. set_error_handler()

Erorile sunt implicit "manuite" (handled) de interpetorul PHP. Acesta le afiseaza intr-un anumit fel, atunci cand apar, si tine cont de optiunea
error_reporting pentru a raporta doar anumite tipuri de erori.
Daca dorim mai mult control asupra erorilor, putem sa definim o functie, create de noi ce trateaza erorile. Numele functiei definite de noi trebuie sa fie
primita ca parametru de functia set_error_handler()
Cu ajutorul functiei set_error_handler() indicam ce tipuri de erori vrem sa tratam, si cu ce functie.

mixed set_error_handler ( callback $error_handler [, int $error_types= E_ALL | E_STRICT ]

Callback este un pseudo-tip de date folosit in documentatia PHP pentru a indica un string ce reprezinta numele unei functii definite de utilizator. Astfel,
parametru $error_handler va contine numele functiei pe care o definim sa se ocupe de erori. $error_types, implicit E_ALL | E_STRICT, reprezinta (similar
cu valoarea pentru error_reporting) combinatia de constante ce regleaza tipurile de erori preluate de acest "handler", adica de functia noastra.
Important
Sunt cateva tipuri de erori (in general cele severe) pe care nu le putem trata cu functia noastra. Printre ele sunt: E_ERROR, E_PARSE. Prin urmare, o
eroare fatala va fi tratata de PHP independent de functia noastra.

Nota
Setarea error_reporting nu mai efect, in sensul ca nu putem ignora de exemplu erorile E_NOTICE cu error_reporting daca le-am pasat functiei
set_error_handler prin al doilea parametru. Insa, in interiorul functiei definite de noi (callback) pentru tratarea erorilor, putem citi valoarea setata in
error_reporting.

Functia definita de noi (handler) pentru a trata erorile, va primi ca parametri: $errno (nivelul erorii), $errstr (mesajul erorii), $errfile (fisierul in care a
aparut eroarea), $errline (linia pe care a aparut eroarea). Optional, al cincilea parametru, $errcontext contine un array cu toate variabilele si valorile sale
definite in contextul si momentul cand a aparut eroarea.
Denumirea parametrilor unei functii callback poate fi oricare (in cazul nostru nu trebuie sa denumim parametrii $errno, $errstr, etc.), ordinea parametrilor
este cea importanta. Primului parametru ii va fi trimisa automat valoarea ce reprezinta numarul erorii, in al doilea parametru se va stoca mesajul erorii,
etc.

In exemplul de mai jos, in myErrorHandler() in principal ma ocup de doua lucruri:


1. afisez in mod personalizat erorile
2. le scriu intr-un log
Bineinteles, functia poate fi schimbata in functie de preferintele voastre. Unele erori pot sa nu fie afisate (doar logate), afisarea erorilor se poate schimba,
se pot apela si alte functii pentru anumite tipuri de erori (trimiterea unui email, redirectare, etc).
Exista cazul cand am nevoie ca scriptul meu sa reactioneze si in cazul erorilor fatale (E_ERROR...) ce nu sunt trimise functiei myErrorHandler(). In acest
caz, pot folosi functia register_shutdown_function($my_function) ce primeste ca parametru numele unei functii pe care o definesc eu (callback), si care va
fi apelata inainte ca scriptul php sa-si incheie executia. In cazul unei erori E_ERROR, scriptul isi va incheia executia exact acolo unde a aparut eroarea. Cu
ajutorul functiei PHP error_get_last(), preiau informatiile ultimei erori aparute, si in cazul in care e din familia E_ERROR (deci nu a fost prinsa cu
myErrorHandler()), o scriu in logul de erori, la fel cu ceea ce as fi facut si in myErrorHandler().

error_handling.php
1 <?php
2 error_reporting(E_ALL);
3
4 $error_log_file1 = 'c:/www/log_erori1.txt'; // aici scriem noi
5 erorile, personalizat, prin myErrorHandler. cele fatale sunt scrise
6 prin functia shutdown()
7 $error_log_file2 = 'c:/www/log_erori2.txt'; // aici lasam PHP sa
8 logheze totusi erorile ce nu sunt prinse de myErrorHandler, in caz ca
9 dintr-un motiv nu sunt prinse nici de shutdown.
10
11 /*
12 display_errors on in acest caz va afisa doar erorile care NU SUNT
13 PRINSE de myErrorHandler. Adica cele fatale. Insa, ne vom ocupa si de
14 ele mai tarziu.
15 */
16
17 /*
18 nu mai afisam erori, automat. le afisam in felul nostru cu
19 myErrorHandler, daca sunt fatale vor fi logate.
20 */
21
22 ini_set('display_startup_errors', 'off');
23 ini_set('display_errors', 'off');
24 ini_set('log_errors', 'on'); // erorile care nu sunt prinse de
25 myErrorHandler (cele fatale) vor fi logate automat de PHP. logam
26 erorile fatale prin shutdown, insa, in caz ca scapam ceva. ne uitam
27 in error_log_file2
28 ini_set('error_log', $error_log_file2);
29
30 set_error_handler('myErrorHandler', E_ALL); // setam functia
31 myErrorHandler sa se ocupe de erori. de toate (E_ALL)
32
33 // construiesc un array, cu cateva parti distincte ale mesajului de
34 eroare
35 function errorPieces($errno, $errstr, $errfile, $errline, $errcontext
36 = '')
37 {
38
39 $firstPart = '[' . $errno . ']'; // nr erorii intre []
40 $firstPart .= "\t"; // adaugam un tab
41 $firstPart .= '{' . $errstr . '}';
42
43 $secondPart = '(' . $errline . ' - ' . $errfile . ')';
44
45 $msg[0] = date('d M Y H:i:s');
46 $msg[1] = $firstPart;
47 $msg[2] = $secondPart;
48
49 return $msg;
50 }
51
52 // unesc partile mesajului de eroare astfel incat sa aiba caracterul
53 TAB (\t) intre ele, apoi adaug newline, pentru a obtine mesajul
54 complet de eroare
55 function fullErrorMsg($errorPieces)
56 {
57 $msgLog = join("\t", $errorPieces);
58 $msgLog .= "\n";
59 return $msgLog;
60 }
61
62
63 // definesc functia myErrorHandler
64 function myErrorHandler($errno, $errstr, $errfile, $errline,
65 $errcontext)
66 {
67 global $error_log_file1;
68
69 $stopScript = 0;
70
71 // cu errorPieces impart eroarea in cateva parti dinstincte.
72 $errorPieces[1] va fi mesajul catre utilizator.
73 $errorPieces = errorPieces($errno, $errstr, $errfile, $errline);
74 $userMessage = $errorPieces[1];
75 $msgLog = fullErrorMsg($errorPieces); // folosesc apoi errorPieces
76 ca argument pentru fullErrorMsg() astfel incat sa construiesc eroarea
77 completa ce o voi loga
78
79
80 switch ($errno) {
81 case E_USER_ERROR:
82 echo '<br />';
83 echo "<b>My ERROR</b><br />";
84 echo $userMessage . '<br />';
85 echo "Script incheiat<br />";
86 $stopScript = 1; // eroare grava. vreau sa ma opresc. dar nu
87 inca
88 break;
89
90 case E_USER_WARNING:
91 echo '<br />';
92 echo '<b>My WARNING</b><br />';
93 echo $userMessage . '<br />';
94 break;
95
96 case E_USER_NOTICE:
97 echo '<br />';
98 echo '<b>My NOTICE</b><br />';
99 echo $userMessage . '<br />';
100 break;
101
102 case E_NOTICE:
103 echo '<br />';
104 echo '<b>NOTICE</b><br />';
105 echo $userMessage . '<br />';
106 break;
107
108 case E_WARNING:
109 echo '<br />';
110 echo '<b>WARNING</b><br />';
111 echo $userMessage . '<br />';
112 break;
113
114 default:
115 echo '<br />';
116 echo '<b>Unknown error</b><br />';
117 echo $userMessage . '<br />';
118 break;
119
120 }
121
122 file_put_contents($error_log_file1, $msgLog, FILE_APPEND); //
123 scriu mesajul erorii in fisierul definit in $error_log_file1
124
125 if ($stopScript) {
126 die(); // in caz ca $stopScript e true, ma opresc.
127 }
128
129
130 /* Don't execute PHP internal error handler */
131 return true;
132 }
133
134 /************************************************** shutdown function
135 ************************************************/
136 function shutdown(){
137 global $error_log_file1;
138
139 $isError = false;
140
141 if ($error = error_get_last()) {
142 switch($error['type']){
143 case E_ERROR:
144 case E_CORE_ERROR:
145 case E_COMPILE_ERROR:
146 case E_USER_ERROR:
147 $isError = true;
148 break;
149 }
150 }
151
152 if ($isError){
153
154 $errno = $error["type"];
155 $errstr = $error["message"];
156 $errline = $error["line"];
157 $errfile = $error["file"];
158
159 $errorPieces = errorPieces($errno, $errstr, $errline,
160 $errfile);
161 $msgLog = fullErrorMsg($errorPieces);
162
163 /*
164 directorul curent se schimba in functia definita cu
165 register_shutdown_function(). (vezi manual). Adica, avem nevoie sa
166 folosim cai absolute ($error_log_file1), nu relative.
167 */
168
169 file_put_contents($error_log_file1, $msgLog, FILE_APPEND);
170
171 } else {
// echo "Script completed";
}
}

register_shutdown_function('shutdown');

/***************************** the main program


*********************************************************************
*****/

echo $i; // Notice


fopen(); // Warning

echo '<br /><b>Welcome to my website</b>';

$j = 5;
if ($j == 5)
// trigger_error('Eroare fatala. $j nu trebuie sa fie 5',
E_USER_ERROR);

ceva(); // Fatal Error (E_ERROR). Nu se afiseaza (display_errors


off), insa este logata prin shutdown() si este logata si automat de
PHP

echo '<br /><br />';


echo 'For now, my website is full of errors, but I am handling them';
echo '<br />';
?>

13.6.5.Tratarea erorilor ca exceptii

Exista posibilitatea de a transforma erorile generate de PHP in exceptii. Acest lucru depinde bineinteles de stilul propriu de programare, de aplicatia
propriu-zisa si de modul in care organizam managementul erorilor. Pentru a transforma erorile in exceptii, trebuie sa definim o functie care sa trateze
erorile, cu set_error_handler(), iar in functia respectiva sa aruncam o exceptie, ce va reprezenta de fapt eroarea respectiva. Exista o clasa deja predefinita
in PHP pentru acest scop, clasa ErrorException ce extinde Exception. De preferat este sa aruncam o exceptie din aceasta clasa, ErrorExcpetion, sau dintr-o
clasa definita de noi ce extinde aceasta clasa.

set_error_handler() va functiona asa cum am invatat, adica implicit prinde E_ALL, insa erorile fatale, din familia E_ERROR, nu sunt trimise acestei
functii, deci nu vor fi transformate nici in exceptii.

In exemplul de mai jos, transformam erorile in exceptii, mai putin cele de tip E_NOTICE, care in acest exemplu vor fi ignorate.

1 <?php
2 error_reporting(E_ALL);
3 ini_set('display_errors', 'on');
4
5 class MyErrorException extends ErrorException {}
6
7 // ******************* set error_handler *******************
8 function exception_error_handler($errno, $errstr, $errfile, $errline)
9{
10 if ($errno != E_NOTICE) {
11 throw new MyErrorException($errstr, 0, $errno, $errfile,
12 $errline);
13 }
14 }
15 set_error_handler("exception_error_handler", E_ALL);
16
17
18 /********************* programul principal ************************/
19
20 echo $j; // generam un notice;
21 trim(); // Warning - se transforma in: Fatal error: Uncaught
exception 'MyErrorException' with message 'Wrong parameter count for
trim()'

?>

Una din diferente, este ca acum erorile genereaza exceptii, iar exceptiile trebuiesc prinse, altfel genereaza o eroare fatala. Astfel, este necesar sa punem
anumite portiuni de cod in blocuri try... catch() pentru a prinde eventualele exceptii.

Este insa o modalitate pentru a trata exceptiile neprinse, si anume folosind functia set_exception_handler(). Aceasta functie primeste un singur
parametru, de tip callback, si anume functia ce vrem sa fie apelata pentru exceptiile neprinse in scriptul nostru.
Astfel, exemplul nostru devine:

1 <?php
2 error_reporting(E_ALL);
3 ini_set('display_errors', 'on');
4
5 class MyErrorException extends ErrorException {}
6
7 // ******************* set error_handler *******************
8 function exception_error_handler($errno, $errstr, $errfile, $errline)
9{
10 if ($errno != E_NOTICE) {
11 throw new MyErrorException($errstr, 0, $errno, $errfile,
12 $errline);
13 }
14 }
15 set_error_handler("exception_error_handler", E_ALL);
16
17
18 // **************** set exception handler *************************
19 function exception_handler($e) {
20 echo 'Exceptie neprinsa: ' . $e->getMessage();
21 }
22
23 set_exception_handler('exception_handler');
24
25
26
27 /********************* programul principal ************************/
28
29 echo $j; // generam un notice;
30 trim(); // Warning - se transforma in exceptie prin
31 exception_error_handler(), si apoi, pentru ca nu e prinsa, este
32 trimisa functiei exception_handler().

echo '<br /><br /><b>Welcome</b><br /><br />';

?>

Nota
Daca avem o eroare in codul din interiorul functiei exception_handler(), PHP va genera o eroare neclara, gen: " Fatal error: Exception thrown
without a stack frame in Unknown on line 0". Din acest motiv, codul trebuie bine verificat, si/sau introdus la randul lui intr-un bloc try... catch

Nota
Pentru a transmite un parametru de tip callback ce reprezinta o metoda statica a unei clase, ex: MyErrorException::shutdown , transmitem un array
in loc de string functiei respective. Primul element al array-ului (index 0) este numele clasei, iar al doilea element (index 1) este numele metodei.
Astfel: register_shutdown_function(array('MyErrorException', 'shutdown'));

Daca metoda n-ar fi fost statica (ar fi apartinut unui obiect), primul element al array-ului transmis era variabila obiectului respectiv.

Continuarea exemplului din subcapitolul anterior, astfel incat sa transformam unele erori in exceptii, si sa tratam atat erorile cat si exceptiile cat mai unitar
(cu aceeasi clasa/metoda), se afla aici: errors_as_exceptions.zip
13.7. Imbinarea tehnologiei Ajax cu PHP
Ajax (asynchronous JavaScript + XML) este denumirea metodei de a trimite catre serverul web cereri HTTP, fara a re-incarca sau a modifica afisarea
paginii principale afisata in browser. Astfel, aceste cereri mai sunt numite asincrone, sau cereri in background.

In web development, in ultimul timp, Ajax este din ce in ce mai folosit, si a schimbat interactiunea clasica a utilizatorilor cu site-urilor web, de la navigarea
din link in link, in care utilizatorul asteapta incarcarea unei noi pagini pentru orice actiune ce necesita comunicarea cu serverul, la actiuni independente, ce
nu reincarca pagina curenta, ci doar isi extrag datele necesare de pe server si la nevoie modifica doar anumite portiuni din pagina afisata in browser.
Bineinteles, o aplicatie web, combina de cele mai multe ori navigarea clasica cu cereri de tip Ajax.

Ajax se poate vedea in aplicatii ca Gmail, Google Maps, Google Suggest, Flickr, etc.

Ajax se realizeaza de obicei cu ajutorul tehnologiei JavaScript, mai precis o obiectului XMLHttpRequest, ce stie sa realizeze aceste cereri catre server, si
sa preia informatia.
Desi necesita lucrul cu JavaScript, Ajax este prezentat in acest curs pentru ca e o notiune ceva mai avansata, si poate fi testata foarte bine impreuna cu
PHP, si cu un server web.
Exista multe modalitati de a lucra cu Ajax, mai simple sau mai complicate, voi incerca sa ma concentrez pe un exemplu simplu, ce demonstreaza aceasta
tehnologie si poate fi ulterior o baza de start pentru scripturile in care vreti sa testati acest concept.

Exemplul complet il gasiti aici: ajax.zip


Disecarea exemplului
Pentru a rula exemplul, trebuie sa incarcati prin http://localhost/.... ajax.html. Daca doar faceti dublu click pe ajax.html, exemplul nu functioneaza pentru
ca browserul web nu va comunica cu Apache-ul, deci nu va trimite cereri http.
In ajax.html, este o casuta de search ce filtreaza rezultatele pe masura ce utilizatorul tasteaza termenul de cautare in casuta de search. Pentru fiecare
apasare de tasta, JavaScript capteaza tot string-ul din input-ul respectiv, si-l trimite prin ajax, prin get, scriptului ajax.php.
ajax.php cauta cu functia stristr() string-ul respectiv in fiecare stire, si returneaza stirile gasite. Exemplul nu e foarte practic, pentru ca in realitate ar fi
destul de costisitor (timp/resurse) sa interogam serverul de baze de date la fiecare apasare de taste, si lista de stiri din ajax.php ar fi extrasa dintr-o baza
de date. Insa, exemplul este potrivit pentru a intelege si a aplica ajax, si poate fi "transferat" usor catre alte aplicatii.

Nota
Pentru intelegerea si urmarirea executiei codului JavaScript, aveti nevoie de un debugger, gen Firebug. Metode gen console.log() sunt puse la
dispozitia programatorului de catre acest program.
Fisierul lib/firebug.js este inclus pentru a oferi obiectul console si browserelor ce nu au instalate ca plugin Firebug, astfel incat sa nu genereze erori
JavaScript.
In Firebug, in consola (F12), se pot observa foarte bine cererile http realizate cu Ajax.

Tot ce tine de Ajax se intampla in ajax.html si in lib/lib_ajax.js:

 Pasul 1
Utilizatorul tasteaza o litera in campul de tip text, avand name="q". La fiecare apasare de tasta, se apeleaza functia javascript doSearch();

 Pasul 2
Functia doSearch() stocheaza in variabila javascript "q", valoarea campului de tip text. queryEl este o variabila globala (definita in afara
functiei) ce reprezinta campul de tip text cu numele "q".
queryEl.value este textul scris de utilizator in campul respectiv.

 Pasul 3
Linia makeHttpRequest('ajax.php?q=' + q, 'doIt', 'loading', 0); este cea care face cererea de tip Ajax.
Functia makeHttpRequest() este definita in lib/lib_ajax.js si primeste urmatorii parametrii:
- primul parametru - fisierul catre care trimitem cererea http. Adaugam in cerere si parametrul "q", de tip GET, avand valoarea scrisa in
campul text
- al doilea parametru - un parametru de tip callback (are acelasi inteles ca in PHP), ce reprezinta un nume de functie definita de noi.
Aceasta functie (doIt() in cazul nostru) este apelata cand cererea http s-a efectuat cu succes, si primeste ca parametru raspunsul cererii (de
tip text simplu sau xml) - aici de tip text.
al treilea parametru, loading in cazul nostru, este tot o functie definita de noi ce este apelata pana cand se primeste raspunsul cererii
Ajax
al patrulea parametru, 0, reprezinta o cerere de tip GET. Poate fi "POST" in cazul in care vrem sa transmitem date prin POST.
 Pasul 4
Din momentul in care s-a initiat cererea, pana cand se primeste un raspuns, este apelata functia loading(); Functia loading() introduce un
text de asteptare in div-ul cu id-ul "results".

 Pasul 5
Cererea http initiata prin Ajax are un raspuns, efectuat cu succes. Se apeleaza functia doIt(content). Unde "content" este o variabila in care s-
a stocat raspunsul primit.

 Pasul 6
Functia doIt() modifica continutul divului results, cu textul primit de la ajax.php?q=a...

13.8. PHP si fisierele XML


XML (Extensible Markup Language) este un limbaj simplu, general, ce are scopul de a facilita pastrarea informatiilor intr-un format comun, standard, ce
poate fi citit usor de orice aplicatie in orice sistem de operare. XML este un standard W3C, aceeasi organizatie ce vegheaza asupra dezvoltarii limbajelor
pentru Web. XML este un limbaj format din taguri, avand reguli stricte, asemanator cu XHTML. De fapt, documentele XHTML sunt documente XML, dar
avand un set limitat de taguri .
In XML se pot defini taguri si atribute de catre utilizator, pentru stocarea informatiei dorite.

Nota
Puteti urmari tutorialul XML de pe www.w3schools.com pentru familiarizarea cu acest limbaj (Resurse).

XML a cunoscut o acceptare larga in comunitatea software, avand multiple aplicatii, unele deja celebre, cum este formatul RSSpentru transmiterea
noutatilor unui website.
Citirea documentelor XML in PHP
PHP5 a adus o serie de imbunatatiri cu privire la manipularea documentelor XML. Printre extensiile PHP ce se ocupa de XML sunt: SimpleXML, DOM, XML
Parser, XML Reader, XML Writer.

Voi folosi in continuare SimpleXML si apoi DOM, pentru a citi cursul BNR publicat si actualizat in fisierul xml:
http://www.bnr.ro/nbrfxrates.xml

Asa cum este deja clar din denumirea clasei, SimpleXML este modalitatea cea mai simpla de a accesa fisierele xml. Functioneaza bine pentru documentele
xml mici, relativ simple, cu o structura cunoscuta.

 $xml = new SimpleXMLElement($xml_str); - realizam un obiect de tip SimpleXMLElement apeland constructorul cu parametrul $xml_str ce
contine informatiile fisierului xml (un string).

 SimpleXMLElement construieste structura (de tip tree) documentului XML in memorie. Fiecare element XML devine un obiect
SimpleXMLElement ce are ca proprietati elementele XML copil. Daca un element are mai multi copii de acelasi fel, pot fi accesati similar cu un
array numeric pe baza specificarii index-ului intre paranteze drepte.
Astfel, folosind instructiunea $xml->Body->Cube[0], extragem elementul Cube, si il pastram in variabila $cube.

 Accesarea atributelor XML intr-un obiect SimpleXMLElement se realizeaza cu sintaxa de la array asociativ, specificand numele atributului ca si
cheie. Ex: $cube["date"].

 Cand avem nevoie de valoarea efectiva a unui element trebuie sa o printam (se transforma automat in string) sau sa o transformam in string,
altfel PHP va trata elementul respectiv ca obiect. Ex: (string)($rate)

SimpleXML.php
1 <?php
2 $currencies = array('usd', 'eur', 'gbp');
3
4 $filename = 'http://www.bnr.ro/nbrfxrates.xml';
5 $xml_str = file_get_contents($filename); // extragem fisierul intr-un
6 string
7
8 $xml = new SimpleXMLElement($xml_str); // $xml este acum un obiect
9 de tip SimpleXMLElement
10
11 $cube = $xml->Body->Cube[0]; // extragem primul element cu denumirea
12 Cube
13 $date = (string)($cube["date"]); // extragem atributul date din
14 elementul Cube (aflat in variabila $cube)
15 $dateTs = strtotime($date);
16
17 $currencyData["date"] = date('Y-m-d', $dateTs);
18
19
20 foreach ($cube->Rate as $rate) { // cube are mai multe elemente
21 numite Rate prin care putem itera cu foreach
22 $currency = strtolower($rate["currency"]); // extragem atributul
23 currency pentru elementele Rate
24
25 if (in_array($currency, $currencies)) {
26 $currencyData[$currency] = (string)($rate); // convertit la
string, obiectul $rate (corespunzator unul element Rate) ne va oferi
valoarea sa
}

print_r($currencyData);
?>

 Primele doua linii creeaza un obiect nou din clasa DomDocument si incarca fisierul aflat la $filename (poate fi url, sau cale catre un fisier).
$xml = new DomDocument;
$xml->Load($filename);

 metoda getElementsByTagName() a obiectului DomDocument va returna un obiect de tip DOMNodeList in care putem sa iteram cu foreach,
sau putem extrage noduri (elemente) individuale, folosind metoda item(index).

 Nodurile individuale sunt obiecte din clasa DOMElement. Putem extrage atribute ale unui element cu metoda getAttribute('nume_atribut'). Ex:
$cube->getAttribute('date');

 Valoarea unui element este proprietatea nodeValue a obiectului DOMElement corespunzator. Ex: $rate->nodeValue

DOM.php
1 <?php
2 $currencies = array('usd', 'eur', 'gbp');
3
4 $filename = 'http://www.bnr.ro/nbrfxrates.xml';
5
6
7 $xml = new DomDocument;
8 $xml->Load($filename);
9 $list = $xml->getElementsByTagName('Rate'); // $list este obiect de
10 tip DOMNodeList -> se poate itera cu foreach
11
12 $cubeList = $xml->getElementsByTagName('Cube'); // cubeList, similar,
13 obiect de tip DOMNodeList -> apeland metoda ->item(i), extragem
14 nodul cu indexul i.
15 $cube = $cubeList->item(0);
16
17 $date = $cube->getAttribute('date'); // extragem atributul date din
18 elementul Cube (aflat in variabila $cube)
19 $dateTs = strtotime($date);
20 $currencyData["date"] = date('Y-m-d', $dateTs);
21
22
23 foreach ($list as $rate) {
24 $currency = strtolower($rate->getAttribute('currency'));
25
26 if (in_array($currency, $currencies)) {
27 $value = (string)($rate->nodeValue);
28 $currencyData[$currency] = $value;
29 }
30
}
print_r($currencyData);
?>

13.9. Lucrul cu sabloane html. Clasa Template


In dezvoltarea aplicatiilor web se pot identifica doua parti dinstincte ale codului:

 codul de prezentare - cod predominant html si css, ce se ocupa de partea de afisare, prezentare, formatare, a elementelor paginii.
Spun predominant deoarece codul de prezentare poate fi si partial cod php. Ex: trecerea cu foreach printr-un array cu persoane, pentru
afisarea acestora intr-un tabel. Desi predominant va fi tabelul html, si probabil formatare in css, iteratia trebuie realizata cu foreach. In acest
caz, codul php este strans legat si apartine codului de prezentare

 logica aplicatiei - cod PHP/MySQL ce tine strict de functionalitatea aplicatiei web. Ex: lucrul cu baza de date, validarea datelor, logarea
utilizatorilor, managementul erorilor, etc

Aceste doua parti ale codului sunt frecvent intalnite sub numele presentation sau presentation logic versus application logic sau business logic.

In dezvoltarea unui website, sunt anumite portiuni de prezentare care se repeta (raman la fel) pe mai multe pagini. Ex: header, meniu, etc.
Bineinteles, nu este obligatoriu ca aceste portiuni repetitive sa apara pe toate paginile. Sau poate apar, insa se modifica. Ex: header-ul isi schimba poza,
meniul are alte categorii, etc
Aceste portiuni, sa le numim sabloane (templates), pot fi scrise in fisiere separate si apoi incluse in pagina noastra cu constructiile
include("header.php"); sau require("header.php"); Daca aceste fisiere contin doar cod .html, le putem salva ca fisiere .html si include in acelasi mod,
include("header.html") sau require("header.html").

Insa, daca doar includem portiunile repetitive cu include() avem inca urmatoarele neajunsuri:

 portiunile de prezentare care nu sunt repetitive, vor fi scrise in scriptul paginii respective, de pilda in contact.php

 astfel, codul de prezentare ce afiseaza pagina, va fi amestecat cu codul php ce tine strict de functionalitatea aplicatiei

 doar cu instructiunea include() nu putem construi in mod eficient sabloane compuse din alte sabloane

 in interiorul sabloanelor (header.php, menu.php, etc) avem acces si la alte variabile si resurse din interiorul aplicatiei php de care nu avem
nevoie. Pentru ca orice variabila globala definita anterior in script, este disponibila si in interiorul fisierelor incluse. Astfel putem usor gresi
(sau daca lucram in echipa , colegul nostru ce se ocupa de prezentare poate gresi) fiind tentati sa folosim cod ce tine de functionalitatea
aplicatiei in interiorul sabloanelor (de pilda, executarea unui sql asupra unei baze de date).

De fapt neajunsurile pe care le-am specificat mai sus se refera la faptul ca imbinam prezentarea cu logica.
De ce este acest lucru un dezavantaj ?

1. In lucrul in echipa, in care un programator se ocupa predominant de codul php/mysql si altul se ocupa de html/css, ideal este fiecare sa aiba fisiere
separate pe care lucreaza, si portiunile din aplicatie care-l intereseaza: programatorul va scrie cod php/mysql in fisierele aplicatiei, iar designerul, sau
programatorul client-side (html/css) va avea de lucru doar cu html/css in interiorul sabloanelor

2. Daca schimbam stilul de lucru, librariile, denumirea variabilelor, functiilor, claselor, in general codul aplicatiei web, fisierele ce contin prezentarea,
sabloanele, vor suferi modificari minime sau deloc.

Astfel, desi logica aplicatiei si prezentarea vor interactiona acolo unde este nevoie, ele nu sunt amestecate, si sunt destul de independente.

Acest mod de lucru ce realizeaza separarea celor doua parti presupune folosirea unor sabloane/templates si folosirea unuitemplate engine sau parte a
aplicatiei ce stie sa integreze aceste sabloane in aplicatie.
In constructia paginilor web, lucrul cu sabloane este destul de des intalnit, si considerat "best practice" (sau practica recomandata).

Exista numeroase librarii/clase ce prezinta solutii in folosirea sabloanelor cu PHP, si chiar dezvolta limbaje separate de PHP ce sunt intelese in interiorul
sabloanelor (ex: Smarty).

Voi prezenta in continuare o solutie relativ simpla de folosire a sabloanelor cu PHP, solutie ce se bazeaza pe o clasa numitaTemplate (Template.php) si pe
o functie ajutatoare numita tp(), prezenta in (f-template.php).
Puteti descarca cele doua fisiere aici: template.zip
Ne vom concentra asupra functiei tp() ce are urmatoarea semnatura:

1 <?php
2 function tp($template, $vars = null, $fs_templates = null) {
3 ...
4 ?>

Primul parametru, $template, este numele fisierului considerat sablon. Un standard ce poate fi folosit pentru denumirea template-urilor astfel incat sa se
distinga usor de celelalte fisiere este sa-i adaugam terminatia .tpl.php. Ex: contact.tpl.php va contine prezentarea paginii Contact, in schimb contact.php
va contine "business logic". In plus, fisierele sabloane se vor afla probabil in alt director, director numit de exemplu "templates". Functia are nevoie de un
al treilea parametru ($fs_templates) cu calea completa catre directorul respectiv. Insa, acest parametru poate fi omis, daca tinem calea catre directorul
"templates" in constanta DIR_FS_TEMPLATES.
Al doilea parametru este un array asociativ, cu elemente cheie => valoare, in care "cheie" va fi un string cu denumirea variabilei ce va fi disponibila in
interiorul sablonului, iar "valoare" va contine valoarea variabilei respective. Astfel, sablonul va beneficia doar de variabilele pe care i le furnizam. Acest
sablon poate fi fisier .html sau .php, depinde daca folosim cod .php sau nu. Eventualele variabile pe care le furnizam sabloanelor au rolul de prezentare,
sau de informatii ce trebuiesc afisate. Astfel, desi se poate folosi cod php in interiorul sabloanelor, el nu foloseste decat variabilele pe care le primeste fiind
oarecum "fortat" sa foloseasca cod de prezentare.

Presupun ca am urmatoarea structura a proiectului, pe harddisk:


c:/www/myproject/ contine:

 lib - diverse scripturi php ce tin de logica aplicatiei


 templates - directorul ce contine sabloanele - fisiere html sau tpl.php

 img - un folder cu imagini

Atunci, test1.php, o pagina simpla ce foloseste sablonul header.html din templates ar arata astfel:

test1.php
1 <?php
2 define('DIR_FS_TEMPLATES', 'c:/www/myproject/templates/');
3
4 include("lib/f-template.php");
5 include("lib/Template.php");
6
7
8 $header = tp('header.html');
9
10 echo $header;
11 ?>

iar header.html contine cod html pentru includerea unei imagini:

header.html
1 <img src="img/myheader.jpg" border="0" alt="" />

Nota
In interiorul sabloanelor, directorul curent disponibil in php este de fapt cel din test1.php. Astfel, tot ce includem (din html, sau php) va fi relativ la
locatia lui test1.php. Din acest motiv avem "img/myheader.jpg" pentru ca folderul img si test1.php se afla pe acelasi nivel.

Presupunem ca avem sabloane "dinamice" si atunci avem nevoie sa le transmitem variabile, si sa contina si cod php, bineinteles cu scop prezentational.
In urmatorul exemplu, in test2.php scriem codul pentru extragerea intamplatoare a unei poze pentru header, din 3 posibilitati. Transmitem apoi prin
$h_vars sablonului header.tpl.php variabila "headerPic" ce devine in sablon $headerPic, ce contine calea relativa catre poza aleasa.

test2.php
1 <?php
2 define('DIR_FS_TEMPLATES', 'c:/www/myproject/templates/');
3
4 include("lib/f-template.php");
5 include("lib/Template.php");
6
7 $pics = array('img/pic1.jpg', 'img/pic2.jpg', 'img/pic2.jpg');
8 $key = array_rand($pics); // array_rand() va selecta intamplator
9 (random) una din cele trei elemente ale array-ului si ii va returna
10 cheia.
11 $h_vars["headerPic"] = $pics[$key];
12
13
14 $header = tp('header.tpl.php', $h_vars);
15
echo $header;
?>

header.tpl.php
1 <img src="<?php echo $headerPic ?>" border="0" alt="" />
Nota
Folosirea sabloanelor prin intermediul clasei Template si a functiei tp() va fi folosita in aplicatia din ultimul capitol, astfel incat exemplele practice
de-acolo vor continua si explica mai departe acest mod de lucru.

13.10. Despre reinventarea rotii. Un exemplu: libraria PEAR


s"Reinventarea rotii" este o metafora universala, al carei sens il cunoastem cu totii. In programare, (deci si in PHP), merita o atentie deosebita pentru ca
foarte multe lucruri "deja s-au facut" si o mare parte din ele sunt realizate pe un caz general, independent de un proiect anume, special pentru a fi
refolosite acolo unde este nevoie.

Sensul acestei metafore este foarte legat de munca de zi cu zi a unui programator. "Reinventarea rotii" in programare se evita prin "refolosire de cod" sau,
in engleza, "code reuse".

Refolosirea de cod, pe scurt, are una din urmatoarele nuante, in functie de context:

 sa eviti duplicarea propriului cod in aplicatia pe care o construiesti; codul repetitiv trebuie organizat in functii, clase, etc

 sa refolosesti cod din propriile proiecte anterioare

 sa folosesti acolo unde e cazul librarii/functii/clase ce fac deja un anumit lucru daca acea librarie se integreaza bine in proiectul tau si ii
satisface cerintele

 sa gandesti propriul cod astfel incat sa fie usor de refolosit, intretinut, atat de tine cat si de altii

Functionalitati intalnite frecvent in aplicatiile web ce pot fi organizate in cod refolosibil sunt:

 generarea formularelor html prin PHP in loc sa le scriem doar in html. Acest lucru este de multe ori necesar datorita re-umplerii formularelor
cu informatii sau validarii

 succesiunea de operatiuni update/insert/delete ale inregistrarilor dintr-un tabel al bazei de date

 paginarea rezultatelor unei cautari. De multe ori, daca o cautare in aplicatia noastra web returneaza mii de rezultate, trebuie sa extragem
doar 10 sau 100, si sa oferim interfata de navigare intre aceste rezultate

 sistem de login - autentificarea utilizatorilor

 managementul erorilor

 managementul sesiunilor

 functii/clase (cele definite de utilizator) ce ofera functionalitate des intalnita in lucrul cu baza de date, cu data calendaristica, cu imagini,
validari, etc

 ....

Refolosirea de cod se poate face in functie de necesitatea proiectului (sau portiunii din proiectul respectiv) la un nivel mic, de exemplu refolosirea unei
functii simple, ce transforma un timestamp intr-o data in format romanesc, mergand progresiv la folosirea unei functii mai mari sau clase ce ofera o
functionalitate mai larga, de exemplu se ocupa de generarea fisierelor pdf din php, si mergand apoi pana la librarii sau framework-uri intretinute de echipe
de programatori ce ofera un complet set de functionalitati.

Refolosirea de cod extern (realizat de alti programatori) in proiectele proprii tine de stilul si preferinta fiecarui programator, si bineinteles de proiectul in
cauza, insa sunt urmatoarele lucruri de luat in calcul:

 Roata trebuie totusi reinventata de multe ori atunci cand cercetezi, inveti un anumit lucru, astfel incat sa intelegi lucrurile fundamentale si sa
poti construi peste acestea. In aceste cazuri, folosirea direct a unor librarii externe poate sa nu fie recomandata.
De exemplu, daca folosesti inca de la inceput o librarie in PHP ce se ocupa de "dedesubturile" uploadului de fisiere, fara sa realizezi cateva
uploaduri cap-coada folosind elementele de baza din PHP, s-ar putea sa nu stii ca de fapt acea librarie muta fisierul uploadat dintr-o locatie
temporara de pe server in locatia finala sau ca exista un camp hidden numit MAX_FILE_SIZE ce controleaza marimea fisierului, sau ca fisierul
incarcat pe server are automat ca owner serverul web, sau ca exista directiva upload_max_filesize in php.ini. Si atunci, orice problema in unul
din aceste puncte, sau mai rau, cateva probleme ce se mainfesta simultan in uploadul fisierelor, vor fi greu de rezolvat pentru cineva care nu
a realizat un upload simplu, si nu cunoaste bazele.

 Unele "roti" nu se potrivesc sau nu-si au rostul in anumite locuri. De exemplu, am un site de prezentare cu 3 pagini, dintre care o pagina de
contact cu un formular simplu. A folosi un framework sofisticat pentru realizarea acestui site, este probabil nepotrivit, datorita timpului pentru
a seta frameworkul respectiv si functionalitatea inutila incarcata comparativ cu functionalitatea de care este nevoie pentru situl respectiv.
Sau, in general, acest caz apare cand un lucru e mai simplu sa-l fac eu, decat sa incerc sa integrez ceva gata facut dar probabil prea mare
pentru scopul meu sau care nu se potriveste chiar la fix si oricum trebuie modificat.
Alt exemplu ar fi cand folosesc librarii ce nu se imbina eficient intre ele si nu pentru ca provin din surse diferite (librariile sunt gandite in
general sa "coopereze" cu alt cod) ci pentru ca probabil au fost programate intr-un stil diferit, incompatibil.

 Un cod extern, cu cat e mai sofisticat cu atat e mai greu sa inveti sa-l folosesti, aduce propriile bug-uri si e mult mai dificil de modificat, decat
propriul cod. Pentru ca propriul cod il cunosti, iti este familiar, este creatia ta, insa o librarie nu. Iar daca modifici codul extern, nu vei
beneficia de versiunile ulterioare alte librariei respective, pentru ca probabil nu va include modificarile tale (decat daca autorul librariei e de
acord).

 Exista cazul cand proiectele tale se bazeaza pe o librarie, care la un moment dat nu mai este intretinuta de autorii ei. Sau mai rau, merge
intr-o directie gresita din punctul tau de vedere. De exemplu, folosesti o librarie ce functioneaza perfect pe PHP4, furnizorul de gazduire te
obliga sa treci la PHP5, iar libraria respectiva nu functioneaza pe PHP5 si nici nu va functiona vreodata pentru ca nu mai este intretinuta. Va
trebui atunci sa modifici tu libraria respectiva sa mearga pe PHP5, sau sa modifici toate proiectele in care ai folosit-o, sa o inlocuiesti cu
altceva (alta librarie, sau propriul cod).
 Nu in ultimul rand, trebuie sa cercetam licenta codului pe care il folosim. De obicei este inclusa in fisiere text, in interiorul directorului
respectiv, sau chiar la inceputul fisierelor sursa, in comentarii

Astfel, trebuie intotdeauna sa punem in balanta cand si cum sa folosim codul extern. Uneori este singura solutie eficienta, alteori poate e mai bine sa re-
inventam roata, alteori balanta este echilibrata, si este greu de decis. Pentru ca librariile externe, odata cu avantaje aduc si dezavantajele mentionate.

PHP este un proiect open-source (vezi Resurse) si are o comunitate foarte puternica ce il foloseste, dezvolta, si imparte cod. Astfel, refolosirea de cod este
puternic incurajata atat in miscarea open-source in general cat si in cazul dezvoltarii cu PHP. Utilizata corect, refolosirea de cod se concretizeaza in
eficienta.

In afara de clase, sau functii, exista urmatorii termeni folositi in acest subcapitol, inca neclarificati:

 librarie - o colectie de clase/functii ce indeplinesc o anumita functionalitate sau set de functionalitati, dezvoltate si intretinute in mod
organizat de un programator sau mai multi programatori

 framework, in cazul nostru web framework - are acelasi scop cu o librarie, si anume, ofera un set de functionalitati frecvent intalnite in
aplicatiile web. Insa are urmatoarele diferente fata de o librarie: framework-ul nu se concentreaza doar pe o anumita functionalitate (de
exemplu generarea fisierelor pdf din php), in schimb incearca sa ofere solutii pentru problemele cele mai intalnite in proiectele web si intregul
cod este organizat unitar intr-o singura aplicatie ale carei componente interactioneaza. Aceasta aplicatie este gandita astfel incat sa fie extinsa
si modificata in proiectul final ce va fi construit pe baza acelui framework. In concluzie, implicarea unui framework in dezvoltarea unei aplicatii
web este mai stransa decat implicarea unei librarii.

Scopul acestei documentatii nu este sa recomande un mod de lucru sau altul, sau sa descrie o librarie sau un framework. Insa, am ales
libraria PEAR pentru cateva exemple simple de folosire a unei librarii externe.

Libraria PEAR
PEAR (http://pear.php.net) este un sistem de librarii intretinute si dezvoltate de o comunitate de programatori avand scopul comun de a oferi componente
reutilizabile programatorilor PHP.
PEAR are o documentatie oficiala, existenta pe site, ce ofera informatii despre instalarea librariei PEAR, despre instalarea pachetelor dorite, si ofera si
documentatie pentru fiecare pachet in parte. Un pachet este un set de fisiere, o librarie de sine statatoare, ce ofera o anumita functionalitate. Exemplu,
pachetul HTML_Table, sau HTML_QuickForm. In unele cazuri, un pachet depinde altele. In pagina pachetului sunt specificate dependintele pachetului
respectiv.

Instalarea librariei PEAR este descrisa in documentatie (http://pear.php.net/manual/en/installation.getting.php


), insa voi preciza si aici, pe scurt, pasii care trebuie urmati pentru instalarea sistemului PEAR si apoi instalarea individuala a unor pachete:

 Directorul in care este instalat limbajul PHP cu WAMP este intr-o locatie gen: C:\wamp\bin\php\php-nr-versiune\
In primul rand trebuie adaugata aceasta cale in variabila Windows, PATH.
Variabila PATH se schimba astfel:
- mouse dreapta pe My Computer
- Advanced -> Environment Variables
- variabila PATH -> adaugati la sfarsit ;C:\wamp\bin\php\php-nr-versiune\
in care inlocuiti cu calea efectiva de pe calculatorul vostru.

 In interiorul caii in care e instalat php-ul, gasiti go-pear.bat. Executati-l, prin dublu click. Cel mai simplu, este sa lasati caile catre directoarele
PEAR neschimbate.

 instalarea genereaza un fisier PEAR_ENV.reg ce adauga cateva variabile de tip ENV in registrii windows. Executati acest fisier prin dublu click.

 in acest moment, trebuie sa aveti disponibila comanda pear in linia de comanda. Rulata fara nici un argument, trebuie sa va afiseze o lista de
optiuni disponibile

 Navigati la adresa http://pear.php.net/go-pear si salvati acest fisier din browser cu denumirea go-pear.php

 deschideti din nou linia de comanda, si schimbati directorul acolo unde ati salvat go-pear.php. Rulati php go-pear.php

 Directorul in care sunt descarcate pachetele PEAR este probabil c:\wamp\bin\php\php-nr-versiune\PEAR . Verificati in php.ini daca este acest
director in include_path. In unul din pasii anteriori, PEAR a incercat sa modifice php.ini cu acest director, insa trebuie sa verificati daca este
corect. Linia din php.ini trebuie sa se refere la include_path din Windows (acolo unde caile directoarelor sunt separate prin ";"). Si, linia
respectiva nu trebuie sa fie comentata: comentariile in php.ini sunt liniile ce incep cu ";". Nu uitati sa restartati serverul web dupa ce ati
facut modificarea in php.ini.
Verificati apoi cu phpinfo() daca include_path contine directorul PEAR. (Atentie, in interiorul directorului c:\wamp\bin\php\php-nr-
versiune\PEAR , mai este un director PEAR. Ne intereseaza sa includem in php.ini primul director, cel parinte).

 Fisierul binar pear fiind disponibil in linia de comanda, poate fi folosit pentru a instala pachete PEAR.

 Rulati "pear install HTML_Table" . Va instala pachetul HTML_Table si pachetele de care depinde. Acest pachet este instalat in directorul
C:\wamp\bin\php\php-nr-versiune\PEAR\HTML.

 Rulati apoi "pear install HTML_QuickForm"

Pachetul HTML_Table va pune la dispozitie o clasa (HTML_Table) ce faciliteaza realizarea si modificarea tabelelor html si php.

1 <?php
2 include("HTML/Table.php"); // calea este cautata relativ la una din
3 caile din include_path
4
5 // constructorul clasei, primeste ca parametru un string ce va fi
6 inserat in interiorul tagului table. <table ...string..>
7 $t = new HTML_Table('border="1" cellpadding="2" style="border-
8 collapse:collapse;border: 1px solid #d1d1d1;"');
9
10
11 $d = array('Prenume', 'Nume', 'Varsta', 'Sex');
12 $t->addRow($d);
13
14 $d = array('Marius', 'Vizante', 37, 'm');
15 $t->addRow($d); // metoda addRow() primeste ca parametru un array, si
16 adauga un rand cu valorile array-ului in tabel
17
18 $d = array('Razvan', 'Oprea', 30, 'm');
19 $t->addRow($d);
20
21 $d = array('Maria', 'Nicolescu', 36, 'f');
22 $t->addRow($d);
23
24 $d = array('Madalina', 'Ghitescu', 33, 'f');
25 $t->addRow($d);
26
27
28 $t->altRowAttributes(1, 'style="background-color: #ebebeb"',
29 'style="background-color: #ffffff"'); /* seteaza stiluri alternante
30 pentru randuri */
31 $t->updateRowAttributes(0, 'style="font-weight: bold"'); //
32 actualizeaza randul cu indexul 0
33
34 $t->updateColAttributes(2, 'align="center"'); // actualizeaza coloana
cu indexul 2
$t->updateColAttributes(3, 'align="center"');

$htmlTable = $t->toHtml(); // returneaza tabelul format in cod html.

echo $htmlTable;
?>

Pachetul HTML_QuickForm este un pachet complex ce ofera metode pentru crearea, validarea si procesarea formularelor HTML.

1 <?php
2
3 require_once "HTML/QuickForm.php"; // calea este cautata relativ la
4 una din caile din include_path
5 require_once 'HTML/QuickForm/Renderer/Default.php'; // renderer-ul
6 este o clasa ce ajuta la afisarea formularului
7
8 $form =& new HTML_QuickForm('form', 'post', '');
9 $renderer =& new HTML_QuickForm_Renderer_Default(); // render-ul
10 implicit, genereaza un tabel cu 2 coloane. in prima sunt etichetele
11 (labels), in a doua este elementul de formular.
12
13 /*
14 metoda addElement folosita pentru adauga element in formular.
15 param1: tipul elementului
16 param2: numele campului
17 param2: eticheta - ceea ce va scrie in dreptul campului
18 */
19
20 // elements here
21 $form->addElement('text', 'firstName', 'Prenume');
22 $form->addElement('text', 'lastName', 'Nume');
23 $form->addElement('text', 'age', 'Varsta');
24
25 /* in cazul de mai jos, in variabila $select obtinem un obiect din
26 clasa HTML_QuickForm_select cu cateva metode specifice elementelor
27 select */
28 $select = $form->addElement('select', 'sex', 'Sex', array('' =>
29 'alege', 'm' => 'm', 'f' => 'f'));
30 $select->setSize(1);
31 $select->setMultiple(false);
32
33 // la nevoie, adaugam cod html
34 $form->addElement('html', '<tr><td colspan="2"><br /><br
35 /></td></tr>');
36
37 // butonul submit
38 $form->addElement('submit', 'btnSubmit', 'Submit', 'class="button"');
39
40 // reguli de validare. exista reguli gata facute, sau pot fi
41 realizate reguli personalizate.... vezi documentatie
42 $form->addRule('firstName', 'Completati acest camp', 'required');
43 $form->addRule('firstName', 'Prenume invalid', 'nopunctuation');
44
45 $form->addRule('lastName', 'Completati acest camp', 'required');
46 $form->addRule('lastName', 'Nume invalid', 'nopunctuation');
47
48 $form->addRule('age', 'Completati acest camp', 'required');
49 $form->addRule('age', 'Varsta invalida', 'numeric');
50 $form->addRule('age', 'Varsta iesita din limite', 'callback',
51 'checkAge');
52
53 // regula personalizata. daca functia returneaza 0, inseamna ca
54 regula nu a validat valoarea din campul respectiv
55 function checkAge($age)
56 {
57 $age = (int)$age;
58
59 if ($age < 5 or $age > 155) {
60 return 0;
61 }
62
63 return 1;
64
65 }
66
67 $form->addRule('sex', 'Completati acest camp', 'required');
68
69
70 // set required note
71 $form->setRequiredNote('<span class="required_sign">*</span> campuri
72 obligatorii');
73
74 // validate -> apelam aceasta metoda pentru a realiza validarea
75 formularului
76 $form->validate();
77
78
79
80 $doData = 0;
81
82
83 if (isset($_POST["btnSubmit"])) { // daca am apasat pe submit
84 if (!count($form->_errors)) { // daca nu sunt erori (erorile sunt
85 tinute in proprietatea _errors)
86 $doData = 1; // doData indica faptul ca vrem sa prelucram
87 formularul
88 } else {
89 $doData = 0;
90 }
91 }
92
93 if ($doData) { // prelucram formularul
echo 'prelucrez formularul...';
print_r($_POST);
}

if (!$doData) {

// afisez formularul
$form->accept($renderer); // leg obiectul $renderer de fomrularul
meu
$formHtml = $renderer->toHtml(); // afisarea o facem prin obiectul
$renderer
echo $formHtml;

?>

13.11. Bancuri in PHP


Mi-a venit ideea acestui subcapitol in urma acestei conversatii, extrase de pe un forum:
user1, intreaba:

Hey,
I need something that checks the difference between two times. The
format of the times is:

Apr 26, 2009 1:42 PM

Apr 26, 2009 5:44 PM

It would subtract those and then output the difference in minutes. For
example the times above would output 242 minutes. It also needs to check
for the dates too.

------------------------------------------------------------------------
----------------
user2, raspunde:

The easiest way would be

$time1 = 'Apr 26, 2009 1:42 PM';


$time2 = 'Apr 26, 2009 5:44 PM';

$total = $time1 - $time2;

echo $total;

------------------------------------------------------------------------
----------------
user3, raspunde catre user2

I am concerned that you might be retarded.

In continuare, o scurta lista de glume realizate de membri ai comunitatii PHP:


-----------------------------------------------------------------------
$cash = "Here's $100 for me <br />";
while(true)
{
echo $cash;
}

-----------------------------------------------------------------------
if("PHP" > "Perl") {

//it returns true

}
-----------------------------------------------------------------------

sleep("with hot girl");

-----------------------------------------------------------------------
CODE:

$query = mysql_query("SELECT asp_programmers FROM smarties");


if(mysql_num_rows($query) === 0){
die("ASP and smart???");
}

DISPLAY:

ASP and smart???

-----------------------------------------------------------------------

What's an object-oriented way to get rich?

(Inheritance)

-----------------------------------------------------------------------

13.12. Tema
Realizati un forum (comunitate virtuala) folosind cunostintele acumulate pana acum.
Forumul trebuie sa contina:
 inregistrare membri - username, email, parola, prenume, nume, varsta, sex, hobbie-uri, tara, poza profil

 posibilitatea de a adauga alte poze la profilul unui utilizator, pentru a fi vizualizate de alti membri

 Afisarea si postarea mesajelor in forum se face pe categorii

 login

 Fiecare utilizator inscris, si logat, poate posta mesaje

 Afisarea unui mesaj contine: utilizatorul ce a postat mesajul, subiect, mesaj, data postarii

 Daca in interiorul categoriilor, mesajele sunt grupate pe topic-uri sau nu, ramane la alegerea ta

 Interfata de administrare in care un administrator sa:


- stearga, modifice, caute, membri
- stearga, modifice, caute, mesaje
- suspende conturi (contul nu e sters insa nu mai are drept de a posta)