Scrigroup - Documente si articole

     

HomeDocumenteUploadResurseAlte limbi doc
AccessAdobe photoshopAlgoritmiAutocadBaze de dateCC sharp
CalculatoareCorel drawDot netExcelFox proFrontpageHardware
HtmlInternetJavaLinuxMatlabMs dosPascal
PhpPower pointRetele calculatoareSqlTutorialsWebdesignWindows
WordXml


Un aspect important cand lucrǎm cu pg_fetch_array este lucrul cu alias-uri

php



+ Font mai mare | - Font mai mic



Un aspect important cand lucrǎm cu pg_fetch_array este lucrul cu alias-uri:

<?php

$connstr = 'dbname=phpdb user=postgres host=localhost';

$dbh = pg_connect($connstr);

if ($dbh)



$stat = pg_exec($dbh, 'SELECT cos(id) AS a FROM person');

$rows = pg_numrows($stat);

echo 'linii: $rows<br>n';

for ($i = 0; $i < $rows; $i++)

pg_close($dbh);

?>

Un alias este utilizat pentru campul denumit cos, care contine cosinusul lui id. Pentru a extrage datele din result, este necesar sǎ accesǎm alias-ul pentru a gǎsi rezultatul corect. Rezultatul este:

conexiunea la phpdb a fost stabilita
linii: 1
data: 0.54030230586814

In multe cazuri, este necesar sǎ extragem informatia despre rezultatul in sine. Anterior am vǎzut cum evaluǎm numǎrul de linii returnate de o interogare. In urmǎtorul exemplu vom vedea cum vom obtine informatii aditionale:

<?php

$connstr = 'dbname=phpdb user=postgres host=localhost';

$dbh = pg_connect($connstr);

if ($dbh)

$stat = pg_exec($dbh, 'SELECT id, name, location FROM person');

$myid = pg_fieldname($stat, 0);

echo 'campul cu numarul 1 este denumit $myid<br>n';

$myname = pg_fieldnum($stat, 'name') + 1;

echo ''name' este campul cu numarul $myname<br>';

$myloc = pg_fieldsize($stat, 2);

echo 'al treilea camp este de $myloc bytes lungime<br>';

pg_close($dbh);

?>

Pentru a depista numele unei coloane, putem utiliza pg_fieldname. Vom specifica numele result-ului si indexul coloanei ca parametri ai functiei, PHP si PostgreSQL ocupandu-se re restul. Pentru a gǎsi id-ul unei anumite coloane, PHP oferǎ functia pg_fieldnum. In acest caz numele result-ului si numele coloanei trebuie specificati in functie.

Ultima functie folositǎ in exemplul anterior este pg_fieldsize, care returneazǎ lungimea unei coloane. In situatia lungimii variabilei, functia va returna -1 deoarece lungimea nu poate fi evaluatǎ precis. Iesirea scriptului este:

conexiunea la phpdb a fost stabilita

campul cu numarul 1 este denumit id
'name' este campul cu numarul 2
al treilea camp este de -1 bytes lungime

Operatiile complexe cu o cantitate mare de date poate utiliza o cantitate mare de memorie. Dacǎ avem multe cereri consumatoare de memorie care trebuie procesate simultan, serverul Web poate rǎmane fǎrǎ memorie si performanta sistemului poate scǎdea semnificativ datoritǎ swapping-ului si comportamentului ineficient. Pentru a reduce cantitatea de memorie utilizatǎ pe durata operatiilor complexe, PHP oferǎ o comandǎ numitǎ pg_freeresult. Dacǎ rezultatul interogǎrii nu este necesar, comanda ne va ajuta sǎ eliberǎm memoria alocatǎ de PHP pentru a stoca result-ul returnat de PostgreSQL. In mod normal, memoria alocatǎ de PHP este eliberatǎ automat la sfarsitul scriptului. pg_freeresult poate fi utilizatǎ pentru a o elibera mai devreme. Ex:

<?php

$connstr = 'dbname=phpdb user=postgres host=localhost';

$dbh = pg_connect($connstr);

if ($dbh)

$result = pg_exec($dbh, 'SELECT cos(id) AS a FROM person');

for ($i = 0; $i < pg_numrows($result); $i++)

$stat = pg_freeresult($result);

if ($stat)

pg_close($dbh);

?>

In acest exemplu, memoria a fost eliberatǎ manual si scriptul va verifica dacǎ comanda a avut succes:

conexiunea la phpdb a fost stabilita
data: 0.54030230586814
memoria a fost eliberata cu succes

Manipularea si monitorizarea erorilor

Manipularea erorilor este un aspect foarte important. PHP si PostgreSQL dispun de un mecanism de manipulare a erorilor care sunt sigure si usor de folosit.

Vom crea o tabelǎ pentru a stoca numerele de telefon:

phpdb=# CREATE TABLE phone (id serial, name text, phone text NOT NULL);

NOTICE: CREATE TABLE will create implicit sequence 'phone_id_seq' for SERIAL

column 'phone.id'

NOTICE: CREATE TABLE/UNIQUE will create implicit index 'phone_id_key' for

table 'phone'

CREATE

Ultima coloanǎ nu a fost definitǎ ca NOT NULL, ceea ce inseamnǎ cǎ o valoare trebuie adǎugatǎ la coloanǎ. In urmǎtorul pas vom scrie un script care va introduce date in tabelǎ.

<?php

$connstr = 'dbname=phpdb user=postgres host=localhost';

$dbh = pg_connect($connstr);

if ($dbh)

$stat = pg_exec($dbh, 'INSERT INTO phone (name) VALUES ('Florin')');

if ($stat)

else

pg_close($dbh);

?>

Dupǎ conectarea la baza de date, declaratia INSERT a fost executatǎ. Deoarece nu a fost specificat numǎrul de telefon, a apǎrut o eroare care a fost afisatǎ pe ecran utilizand pg_errormessage. Manipulatorul bazei de date, nu valoarea returnatǎ de declaratia de executat, a fost specificatǎ in functie. Output-ul scriptului este:

conexiunea la phpdb a fost stabilita
Warning: pg_exec() [
function.pg-exec]: Query failed: ERROR: null value in column 'phone' violates not-null constraint in c:wampwwwscriptslab2_script14.php on line 6
a aparut o eroare
ERROR: null value in column 'phone' violates not-null constraint

In primul rand pg_exec afiseazǎ o eroare. Dupǎ ce mesajul de eroare a fost afisat, rezultatul lui pg_errormessage a fost afisat pe ecran. PostgreSQL ne spune cǎ valoarea NULL nu poate fi adǎugatǎ in tabel deoarece a treia coloanǎ a fost declaratǎ ca NOT NULL. Vom vedea un alt exemplu:

<?php

$connstr = 'dbname=phpdb user=postgres host=localhost';

$dbh = pg_connect($connstr);

if ($dbh)

echo 'prima incercare<br>n';

$stat = pg_exec($dbh, 'INSERT INTO phone (name) VALUES ('Susan')');

echo '<br>a doua incercare<br>n';

$stat = pg_exec($dbh, 'INSERT INTO phone (name, phone) VALUES

('Susan', '3432434')');

if ($stat)

else

pg_close($dbh);

?>

Prima declaratie SQL trimisǎ serverului incalcǎ constrangerea definitǎ in a treia coloanǎ. A doua declaratie SQL este corectǎ si datele vor fi adǎugate in tabelǎ. Cel mai important aspect in acest exemplu este sǎ observǎm cǎ pg_errormessage nu returneazǎ o eroare dacǎ declaratia SQL anterioarǎ a fost executatǎ cu succes. Pare destul de clar dar nu este: in unele sisteme de baze de date, functiile returneazǎ intotdeauna cea mai recentǎ eroare chiar dacǎ o declaratie corectǎ a fost executatǎ dupǎ ce o eroare a apǎrut. Mesajul generat de scriptul PHP este:

conexiunea la phpdb a fost stabilta
prima incercare

Warning: pg_exec() [
function.pg-exec]: Query failed: ERROR: null value in column 'phone' violates not-null constraint in c:wampwwwscriptslab2_script15.php on line 7

a doua incercare
datele au fost introduse cu succes
corect:

In unele cazuri este necesar sǎ aflǎm cate linii au fost afectate de interogare. Indeosebi atunci cand realizǎm operatii de UPDATE, este util sǎ aflǎm ce anume se intamplǎ in interiorul bazei de date. Comanda utilizatǎ pentru a extrage numǎrul de linii afectate de declaratia SQL este pg_cmdtuples. Ex:

<?php

$connstr = 'dbname=phpdb user=postgres host=localhost';

$dbh = pg_connect($connstr);

if ($dbh)

$stat = pg_exec($dbh, 'UPDATE phone SET phone='123456'

WHERE name='Susan'');

if ($stat)

pg_close($dbh);

?>

In acest scenariu numǎrul de telefon al lui Susan a fost actualizat. In baza noastrǎ de date Susan a a fost adǎugatǎ odatǎ, din acest motiv pg_cmdtuples returnand 1. Pe ecran va fi afisat:

conexiunea la phpdb a fost stabilita
UPDATE realizat cu succes
1

Manipularea erorilor este o sarcinǎ usor de realizat cand lucrǎm cu PHP si PostgreSQL, fiind necesare doar cateva comenzi pentru manipularea erorilor.

Manipularea unei cantitǎti mari de date

Dacǎ lucrǎm cu mai mult de cateva inregistrǎri, utilizarea lui INSERT este prea lentǎ. PostgreSQL oferǎ comanda COPY, care poate fi utilizatǎ pentru a introduce mai mult de o inregistrare intr-o tabelǎ odatǎ.

Utilizarea lui COPY este diferitǎ fatǎ de lucrul cu setul de comenzi INSERT. Ex:

<?php

$connstr = 'dbname=phpdb user=postgres host=localhost';

$dbh = pg_connect($connstr);

if ($dbh)

echo 'pornim procesul <br>n';

echo 'inceput: '.date('Y-m-d H:i:s').'<br>n';

$result = pg_exec($dbh, 'COPY testdata FROM stdin');

for ($i = 0; $i < 40000; $i++)

}

pg_put_line($dbh, '.n');

pg_end_copy($dbh);

echo 'sfarsit: '.date('Y-m-d H:i:s').'<br>n';

pg_close($dbh);

echo 'sfarsitul procesului <br>n';

?>

Inainte de a rula scriptul trebuie sǎ creem tabela testdata:

CREATE TABLE testdata (idx int4, val numeric(9,8));

Dupǎ conectarea la baza de date, antetul comenzii COPY este trimis cǎtre server. Dupǎ aceasta, PostgreSQL asteaptǎ datele panǎ cand . este gǎsit. Fiecare linie de date este trimisǎ cǎtre baza de date prin utilizarea comenzii pg_put_line.

Tabela in care dorim sǎ adǎugǎm date contine douǎ coloane. Prima coloanǎ contine un numǎr si a doua coloanǎ contine cosinusul acelui numǎr. Dupǎ ce datele au fost trimise cǎtre PostgreSQL, comanda COPY este terminatǎ prin utilizarea lui pg_end_copy. Pentru a vedea cat de repede lucreazǎ comanda COPY, pe ecran este afisatǎ ora curentǎ:

conexiunea la phpdb a fost stabilita
pornim procesul
inceput: 2005-10-19 19:03:22
sfarsit: 2005-10-19 19:03:24
sfarsitul procesului

Comanda COPY nu a durat mai mult de douǎ secunde, testul find realizat pe un procesor Pentium 4 la 1514 Mhz.

Vom sterge inregistrǎrile din tabelǎ:

phpdb=# DELETE FROM testdata;

Pentru a intelege de ce comanda COPY trebuie folositǎ, urmǎtorul exemplu ajunge la acelasi rezultat folosind comanda INSERT:

<?php

$connstr = 'dbname=phpdb user=postgres host=localhost';

$dbh = pg_connect($connstr);

if ($dbh)

echo 'incepem procesul <br>n';

echo 'inceput: '.date('Y-m-d H:i:s').'<br>n';

for ($i = 0; $i < 40000; $i++)

}

echo 'sfarsit: '.date('Y-m-d H:i:s').'<br>n';

pg_close($dbh);

echo 'sfarsitul procesului <br>n';

?>

Rezultatul cand am utilizat INSERT este:

conexiunea la phpdb a fost stabilita
incepem procesul
inceput: 2005-10-19 20:00:27

Fatal error: Maximum execution time of 30 seconds exceeded in c:wampwwwscriptslab2_script18.php on line 10

Procesul ia mai mult de 30 de secunde, in acest interval fiind introduse doar 22068 de inregistrǎri. Cu cat avem mai multe date de procesat, cu atat performanta va spori dacǎ utilizǎm COPY. Tehnic, pg_put_line trimite un sir terminat in NULL cǎtre procesul backend manipuland conexiunea cu PostgreSQL. Dupǎ trimiterea datelor cǎtre baza de date, procesul de backend si frontend trebuie sǎ fie sincronizat, aceasta realizandu-se utilizand pg_end_copy.

Regǎsirea obiectelor din baza de date

Cand lucrǎm cu PHP orientat obiect, poate fi de ajutor regǎsirea datelor din tabel ca obiecte. Astfel PHP oferǎ o comandǎ numitǎ pg_fetch_object, care poate fi utilizatǎ la fel ca pg_fetch_array si pg_fetch_row. Pentru a vedea cum lucreazǎ aceastǎ comandǎ, vom crea o tabelǎ si vom introduce cateva date:

phpdb=# CREATE TABLE plant(id int4, name text, color text);

CREATE TABLE

phpdb=# INSERT INTO plant VALUES (1, 'Sambucus nigra', 'galben');

INSERT 221721 1

phpdb=# INSERT INTO plant VALUES (2, 'Abies', 'verde');

INSERT 221722 1

phpdb=# INSERT INTO plant VALUES (3, 'Colchicum autumnale', 'roz');

INSERT 221723 1

Dacǎ nu a fost semnalatǎ nici o eroare, am creat o tabelǎ care contine informatii despre trei plante si trei culori. In urmǎtorul exemplu vom regǎsi datele ca obiecte:

<?php

$connstr = 'dbname=phpdb user=postgres host=localhost';

$dbh = pg_connect($connstr);

$sql = 'SELECT id, name, color FROM plant WHERE id=1';

$result = pg_exec($dbh, $sql);

$data = pg_fetch_object($result, 0);

echo 'Daca aveti gripa puteti bea un ceai de $data->name<br>n';

echo 'Luati partile de $data->color ale plantei si fierbieti-le.<br>n';

pg_close($dbh);

?>

Pentru a aceesa diferite componente ale obiectului, trebuie utilizat operatorul ->. Singura diferentǎ intre utilizarea unui array si utilizarea obiectelor constǎ in sintaxa pe care trebuie sǎ o utilizǎm. Output-ul scriptului este:

Daca aveti gripa puteti bea un ceai de Sambucus nigra
Luati partile de galben ale plantei si fierbieti-le.

"Trasarea" conexiunii PostgreSQL

In scopul realizǎrii unui debug, "trasarea" unei conexiuni la serverul PosgreSQL poate fi utilǎ. "Trasarea" unei conexiuni se referǎ la faptul cǎ datele transmise de la si inapoi este monitorizat si poate fi utilizat pentru a descoperi ceea ce are loc in interiorul PostgreSQL. In general, informatia generatǎ este utilǎ doar dacǎ suntem familari cu protocolul intern al PosgreSQL. Vom vedea cum "trasarea" poate fi pornitǎ si opritǎ:

<?php

$dbh = pg_connect('host=localhost user=postgres dbname=phpdb');

if (!$dbh)

$status = pg_trace('/tmp/trace.log');

$result = pg_exec($dbh, 'SELECT id, name, color FROM plant LIMIT 1');

$rows = pg_numrows($result);

for ($i = 0; $i < $rows; $i++)

?>

Scopul este sǎ selectǎm o inregistrare din tabelǎ numitǎ plant si sǎ stocǎm informatia de "trasare" in /tmp/trace.log. Pentru a activa monitorizarea, PHP oferǎ o functie numitǎ pg_trace. La executie scriptul va afisa pe ecran:

1, Sambucus nigra, galben

In plus, fisierul log a fost creat si contine liniile:

To backend> Q

To backend> SELECT id, name, color FROM plant LIMIT 1

From backend> P

From backend> 'blank'

From backend> T

From backend (#2)> 3

From backend> 'id'

From backend (#4)> 23

From backend (#2)> 4

From backend (#4)> -1

From backend> 'name'

From backend (#4)> 25

From backend (#2)> 65535

From backend (#4)> -1

From backend> 'color'

From backend (#4)> 25

From backend (#2)> 65535

From backend (#4)> -1

From backend> D

From backend (1)>

From backend (#4)> 5

From backend (1)> 1

From backend (#4)> 18

From backend (14)> Sambucus nigra

From backend (#4)> 10

From backend (6)> galben

From backend> C

From backend> 'SELECT'

From backend> Z

From backend> Z

To backend> X

Dupǎ cum se poate observa, au fost scrise in fisier mai multe informatii de logging. Pentru a utiliza efectiv aceste informatii de logging, trebuie sǎ privim in detaliu interiorul PostgreSQL. Pentru a opri monitorizarea vom utiliza pg_untrace.

Blocarea

Dacǎ scriem software pentru un server Web frecvent utilizat, trebuie sǎ avem in vedere si blocarea. De obicei, blocarea este realizatǎ de PostgreSQL intern, dar este posibil sǎ influentǎm blocarea in mod explicit. In multe situatii aceasta este necesar si ne poate ajuta sǎ rezolvǎm usor anumite probleme.

Cel mai important aspect cand lucrǎm cu blocarea explicitǎ, este sǎ vedem cum scripturile concurente trateazǎ blocarea. Blocarea se poate realiza printr-o singurǎ comandǎ:

phpdb=# h LOCK

Command: LOCK

Description: lock a table

Syntax:

LOCK [ TABLE ] name [, ] [ IN lockmode MODE ] [ NOWAIT ]

where lockmode is one of:

ACCESS SHARE | ROW SHARE | ROW EXCLUSIVE | SHARE UPDATE EXCLUSIVE

| SHARE | SHARE ROW EXCLUSIVE | EXCLUSIVE | ACCESS EXCLUSIVE

LOCK oferǎ multe optiuni pentru definirea modului in care este blocatǎ o tabelǎ. Un aspect important il reprezintǎ modul in care PostgreSQL trateazǎ blocarea care nu este specificatǎ explicit. Ex:

<?php

$dbh = pg_connect('host=localhost user=postgres dbname=phpdb');

if (!$dbh)

execute('INSERT INTO plant VALUES (4, 'pin', 'verde')');

execute('LOCK plant IN EXCLUSIVE MODE');

execute('INSERT INTO plant VALUES (5, 'trandafir', 'rosu')');

function execute($sql)

?>

Functia apelatǎ realizeazǎ o combinatie a executiei declaratiei SQL si a manipulǎrii erorilor. Aceasta este util deoarece manipularea erorilor trebuie implementatǎ o singurǎ datǎ. In plus, perioada de inceput si perioada de sfarsit a declaratiei SQL este afisatǎ. Aceastǎ informatie este necesarǎ pentru a observa efectele blocǎrii.

Prima inregistrare este adǎugatǎ in tabelǎ. In pasul urmǎtor tabela este blocatǎ exclusiv si o inregistrare aditionalǎ este adǎugatǎ in tabelǎ. Dupǎ prima executie a scriptului, in plant putem gǎsi douǎ valori aditionale:

phpdb=# select * from plant;

id | name | color

1 | Sambucus nigra | galben

2 | Abies | verde

3 | Colchicum autumnale | roz

4 | pin | verde

5 | trandafir | rosu

(5 rows)

Informatia de logging afisatǎ de script nu contine nimic special:

start: 2005-10-23 11:33:34 --- INSERT INTO plant VALUES (4, 'pin', 'verde')
end: 2005-10-23 11:33:34 --- INSERT INTO plant VALUES (4, 'pin', 'verde')
start: 2005-10-23 11:33:34 --- LOCK plant IN EXCLUSIVE MODE
end: 2005-10-23 11:33:34 --- LOCK plant IN EXCLUSIVE MODE
start: 2005-10-23 11:33:34 --- INSERT INTO plant VALUES (5, 'trandafir', 'rosu')
end: 2005-10-23 11:33:34 --- INSERT INTO plant VALUES (5, 'trandafir', 'rosu')

Totul a fost procesat intr-o singurǎ secundǎ. Sǎ vdem ce se va afisa cand scriptul este executat a doua oarǎ:

start: 2005-10-25 13:35:51 --- INSERT INTO plant VALUES (4, 'pin', 'verde')
end: 2005-10-25 13:35:51 --- INSERT INTO plant VALUES (4, 'pin', 'verde')
start: 2005-10-25 13:35:51 --- LOCK plant IN EXCLUSIVE MODE
end: 2005-10-25 13:35:51 --- LOCK plant IN EXCLUSIVE MODE
start: 2005-10-25 13:35:51 --- INSERT INTO plant VALUES (5, 'trandafir', 'rosu')
end: 2005-10-25 13:35:51 --- INSERT INTO plant VALUES (5, 'trandafir', 'rosu')

Blocarea nu afecteazǎ scriptul executat dupǎ ce prima oarǎ a fost terminat. Cand conexiunea la PostgreSQL este inchisǎ de PHP in mod automat, toate blocǎrile fǎcute de aceastǎ conexiune vor fi eliberate automat. Scriptul PHP care acceseazǎ tabela plant in perioada in care primul script PHP a blocat tabela si scriptul a fost terminat trebuie sǎ astepte panǎ cand blocarea este eliberatǎ. Dacǎ scriptul necesitǎ mult timp pentru a avea succes, aceasta va conduce la scǎderea semnificativǎ a performantei sistemului.

PHP si tranzactii

Tranzactiile si blocǎrile sunt in stransǎ legǎturǎ unul cu altul. Vom vedea ce se intamplǎ in cazul in care tranzactiile nu au fost "comise" manual:

<?php

$dbh = pg_connect('host=localhost user=postgres dbname=phpdb');

if (!$dbh)

execute('BEGIN;');

execute('INSERT INTO plant VALUES (6, 'cactus', 'verde')');

function execute($sql)

?>

Tranzactia a fost pornitǎ. In urmǎtorul pas este adǎugatǎ o valoare in tabelǎ, dar tranzactia nu este comisǎ manual. Astfel noua valoare nu poate fi gǎsitǎ in tabel:

phpdb=# SELECT * FROM plant WHERE id=6;

id | name | color

(0 rows)

Cand scriptul a fost executat, PHP inchide conexiunea la PostgreSQL si baza de date executǎ implicit un ROLLBACK. In acest mod, nici o datǎ din tranzactiile necomise vor afacta datele noastre.

Situatia diferǎ cand tranzactia este terminatǎ explicit:

<?php

$dbh = pg_connect('host=localhost user=postgres dbname=phpdb');

if (!$dbh)

execute('BEGIN;');

execute('INSERT INTO plant VALUES (6, 'cactus', 'verde')');

execute('COMMIT;');

function execute($sql)

?>

De aceastǎ datǎ inregistrarea poate fi gǎsitǎ in tabelǎ deoarece tranzactia a fost comisǎ corect.

phpdb=# SELECT * FROM plant WHERE id=6;

id | name | color

6 | cactus | verde

(1 row)

Dacǎ utilizǎm BEGIN si COMMIT explicit, fiecare comandǎ va fi executǎ ca o tranzactie separatǎ. Acest aspect este important deoarece nu trebuie sǎ tratǎm tranzactiile explicit. PHP nu oferǎ utilitare pentru manipularea tranzactiilor, aceasta realizandu-se prin declaratii SQL.

Interfata de programare PHP pentru PostgreSQL se bazeazǎ pe librǎrii C. Inserarea, extragerea si selectarea datelor poate fi realizatǎ prin trimiterea declaratiilor SQL cǎtre baza de date. Pentru a extrage datele din result PostgreSQL oferǎ diferite metode; datele pot fi extrase ca linii, inregistrǎri sau obiecte.

Lucrul cu BLOB-uri

Fiecare bazǎ de date suportǎ o metodǎ de stocare a fisierelor in baza de date. Aceasta este foarte important in cazul utilitarelor de management al continutului. Unii preferǎ stocarea fisierelor in sistemul de fisiere, nu in baza de date. In loc de a incǎrca un fisier in baza de date, putem stoca doar numele fisierului in baza de date. Problema cu acest algoritm este cǎ consistenta datelor din baza de date si sistemul de fisiere trebuie verificatǎ. In plus, este necesar un backup al fisierelor si bazelor de date individual, si nu este usor dumping-ul bazelor da date care includ BLOB-uri (Binary Large Objects).

Lucrul cu BLOB-urile PostgreSQL utilizand SQL

PostgreSQL oferǎ un set de functii usor de utilizat pentru lucrul cu BLOB-uri. BLOB-urile nu sutn stocate intr-o tabelǎ ci ca obiecte in baza de date. Obiectul id al BLOB-ului poate fi stocat intr-o tabelǎ si nu va fi perdut in baza de date. Vom crea o tabelǎ pentru stocarea id-urilor obiectelor si o descriere a fisierelor pe care id-ul obiect in indicǎ:

phpdb=# CREATE TABLE ext4(file_oid oid, description text);

CREATE TABLE

Prima coloanǎ a tabelei contine id-ul obiectului fisierului la care facem referire. A doua coloanǎ contine descrierea fisierului.

Cand se creaza o noua tabela care contine id-urile obiectului, trebuie sa nu o numim oid.

phpdb=# CREATE TABLE ext5(oid oid, description text);

ERROR: name of column 'oid' conflicts with an existing system column

La nivel intern PostgreSQL utilizeaza o coloana pentru stocarea id-ului obiectului unei linii intr-o tabela. Pentru a afisa obiectul id din tabela, trebuie adaugat oid la lista coloanelor pe care dorim sa le afisam.

phpdb=# SELECT oid, * FROM ext4;

oid | file_oid | description

44294 | 44293 | file used to store user data

44296 | 44295 | hostnames

Incepand cu PostgreSQL 7.2, este posibil sa creem tabele fara a avea o coloana care sa contina un id al obiectului:

phpdb=# CREATE TABLE ext5(oid oid, description text) WITHOUT OIDS;

CREATE TABLE

Este suficient sa adaugam WITHOUT OIDS la declaratia CREATE TABLE, si nu vor exista conflicte daca numele coloanelor vor fi dublate.

phpdb=# d ext5;

Table 'public.ext5'

Column | Type | Modifiers

oid | oid |

description | text |

Dupa cum putem observa, tabela a fost creata cu succes.

Pentru a importa un fisier in baza de date, putem folosi lo_import:

As you can see, the table has been created successfully.

Let's get back to the first example you saw in this section. To import a file into the database, you can use lo_import:

phpdb=# SELECT lo_import('/etc/passwd');

lo_import

17254

(1 row)

Functia returneaza un object_id: fisierul a fost stocat in baza de date dar nu a fost importat intr-o tabela. Pentru a introduce id-ul obiectului returnat de lo_import, putem folosi o declaratie INSERT.

phpdb=# INSERT INTO ext4 VALUES (17254, 'file used to store user data');

INSERT 17256 1

Utilizarea a doua comenzi nu este cea mai buna cale petru a realiza acest tip de operatie. Pentru a importa un fisier si a adauga o inregistrare in tabela, putem scrie o declaratie SQL de genul:

phpdb=# INSERT INTO ext4 VALUES (lo_import('/etc/hosts'), 'hostnames');

INSERT 17258 1

Pentru a vedea daca inregistrarea a fost generata cu succes, vom interoga tabela:

phpdb=# SELECT * FROM ext4;

file_oid | description

17254 | file used to store user data

17257 | hostnames

(2 rows)

Doua inregistrari au fost adaugate in tabela. Sa vedem acum cum exportam BLOB-urile. Pentru a exporta un BLOB, PostgreSQL ofera comanda lo_export:

phpdb=# SELECT lo_export(17254, '/tmp/tmpfile.txt');

lo_export

1

(1 row)

Primul parametru specificat in functie este id-ul obiect al fisierului. Al doilea parametru defineste numele fisierului pe care dorim sa-l exportam ca BLOB. Dupa ce un fisier a fost importat in baza de date PostgreSQL, numele fisierului original este pierdut. Cand exportam din nou fisierul, trebuie sa atribuim din nou nume fisierului. Sa vizualizam continutul noului fisier. Cu ajutorul lui head -n3, vor fi afisate primele 3 linii:

salexis@b2-1$ head -n3 /tmp/tmpfile.txt

# $FreeBSD: src/etc/master.passwd,v 1.39 2004/08/01 21:33:47 markm Exp $

root:*:0:0:Charlie &:/root:/bin/csh

Fisierul a fost exportat cu succes. Urmatorul exemplu, afiseaza modul cum un obiect care include si intrarea id a obiectului in ext4 poate fi eliminat:

phpdb=# BEGIN;

BEGIN

phpdb=# SELECT lo_unlink(17254);

lo_unlink

1

(1 row)

phpdb=# DELETE FROM ext4 WHERE file_oid=17254;

DELETE 1

phpdb=# COMMIT;

COMMIT

Este recomandata realizarea operatiei intr-o singura tranzactie astfel incat operatiile concurente sa nu afecteze lucrul cu baza de date. lo_unlink elimina un BLOB.

Pe langa functiile prezentate PostgreSQL ofera functii aditionale pentru manipularea BLOB-urilor, cum ar fi lo_open and lo_write.

Lucrul cu BLOB-urile utulizand PHP

Functiile PHP legate de PostgreSQL si BLOB-uri sunt usor de utilizat. Functiile sunt disponibile pentru toate operatiile de import, export, crearea de noi obiecte sau scrierea datelor intr-un obiect.

Urmatorul exemplu demonstreaza cum poate fi importat si sters un fisier in baza de date:

<?php

$dbh = pg_connect('host=localhost user=postgres dbname=phpdb');

if (!$dbh)

pg_exec($dbh, 'BEGIN');

$oid = pg_loimport('/etc/passwd', $dbh);

if (!$oid)

echo 'Id-ul obiectului: $oid<br>n';

$status = pg_lounlink($dbh, $oid);

if (!$status)

pg_exec($dbh, 'COMMIT');

?>

Functiile PHP pentru lucrul cu BLOB-uri poate fi utilizat doar in cadrul unei tranzactii. Din acest motiv, o tranzactie este pornita inainte ca fisierul sa fie inserat in baza de date prin utilizarea lui pg_loimport. Vom specifica doar numele fisierului pe care dorim sa-l importam si manipulatorul de conexiune pentru functie; daca suntem in interiorul ueni tranzactii, operatia va avea succes daca nu exista o eroare legata de drepturile utilizatorului.

pg_loimport returneaza obiectul id-ul al noului obiect, care este afisat pe ecran utilizand comanda echo. In final, noul obiect este sters:

Id-ul obiectului: 17262

Cand lucram cu date multimedia, este deseori necesar sa trimitem datele intr-un fisier stocat intr-o baza de date PostgreSQL direct catre browser. Astfel PHP ofera o comanda numita pg_loreadall. Pentru a utiliza aceasta functie, fisierul trebuie deschis utilzand pg_loopen.

<?php

$dbh = pg_connect('host=localhost user=postgres dbname=phpdb');

if (!$dbh)

pg_exec($dbh, 'BEGIN');

$oid = pg_loimport('/etc/passwd', $dbh);

if (!$oid)

$file = pg_loopen($dbh, $oid, 'rw');

pg_loreadall($file);

$status = pg_lounlink($dbh, $oid);

if (!$status)

pg_exec($dbh, 'COMMIT');

?>

pg_loreadall returneaza void si nu returneaza data ca o variabila; continutul BLOB-ului este trimis direct catre browser. Rezultatul este:

# $FreeBSD: src/etc/master.passwd,v 1.39 2004/08/01 21:33:47 markm Exp $ # root:*:0:0:Charlie &:/root:/bin/csh toor:*:0:0:Bourne-again Superuser:/root: daemon:*:1:1:Owner of many system processes:/root:/usr/sbin/nologin operator:*:2:5:System &:/:/usr/sbin/nologin bin:*:3:7:Binaries Commands and Source:/:/usr/sbin/nologin tty:*:4:65533:Tty Sandbox:/:/usr/sbin/nologin kmem:*:5:65533:KMem Sandbox:/:/usr/sbin/nologin games:*:7:13:Games pseudo-user:/usr/games:/usr/sbin/nologin news:*:8:8:News Subsystem:/:/usr/sbin/nologin man:*:9:9:Mister Man Pages:/usr/share/man:/usr/sbin/nologin sshd:*:22:22:Secure Shell Daemon:/var/empty:/usr/sbin/nologin smmsp:*:25:25:Sendmail Submission User:/var/spool/clientmqueue:/usr/sbin/nologin mailnull:*:26:26:Sendmail Default User:/var/spool/mqueue:/usr/sbin/nologin bind:*:53:53:Bind Sandbox:/:/usr/sbin/nologin proxy:*:62:62:Packet Filter pseudo-user:/nonexistent:/usr/sbin/nologin _pflogd:*:64:64:pflogd privsep user:/var/empty:/usr/sbin/nologin uucp:*:66:66:UUCP pseudo-user:/var/spool/uucppublic:/usr/local/libexec/uucp/uucico pop:*:68:6:Post Office Owner:/nonexistent:/usr/sbin/nologin www:*:80:80:World Wide Web Owner:/nonexistent:/usr/sbin/nologin nobody:*:65534:65534:Unprivileged user:/nonexistent:/usr/sbin/nologin salexis:*:1001:1001:Alexandru Sireteanu:/home/salexis:/usr/local/bin/bash postfix:*:125:125:Postfix Mail System:/var/spool/postfix:/usr/sbin/nologin clamav:*:106:106:Clam Antivirus:/nonexistent:/sbin/nologin mysql:*:88:88:MySQL Daemon:/nonexistent:/sbin/nologin pgsql:*:70:70:PostgreSQL Daemon:/usr/local/pgsql:/bin/sh oracle:*:71:71:Oracle:/usr/local/oracle7:/bin/sh

Putem importa si exporta fisiere, dar in unele situatii BLOB-ul trebuie modificat. PHP si PostgreSQL ofera functii similare cu functiile C utilizate pentru interactiunea cu fisierele. Pentru a crea un obiect gol, vom folosi pg_locreate, iar pentru a scrie date intr-un BLOB, vom utiliza pg_lowrite. Vom vedea un exemplu de adaugare a cuvantului SUSI la un BLOB gol.

<?php

$dbh = pg_connect('host=localhost user=postgres dbname=phpdb');

if (!$dbh)

pg_exec($dbh, 'BEGIN');

$oid = pg_locreate($dbh);

if (!$oid)

echo 'id-ul obiectului: $oid<br>n';

$file = pg_loopen($dbh, $oid, 'rw');

pg_lowrite($file, 'SUSI');

pg_loclose($file);

pg_exec($dbh, 'COMMIT');

?>

Sa vedem ce date gasim in fisier. BLOB-ul poate fi exportat intr-un fisier:

phpdb=# SELECT lo_export(17268, '/tmp/test_lowrite.txt');

lo_export

-----------

1

(1 row)

si putem afisa continutul fisierului pe ecran:

salexis@b2-1$ cat /tmp/test_lowrite.txt; echo

SUSI

SUSI a fost adaugat la BLOB si fisierul a fost inchis corect. Pentru a afisa datele din BLOB, putem scrie un script PHP:

<?php

$dbh = pg_connect('host=localhost user=postgres dbname=phpdb');

if (!$dbh)

pg_exec($dbh, 'BEGIN');

$file = pg_loopen($dbh, 17268, 'r');

$data = pg_loread($file, 4);

echo 'data: $data<br>n';

pg_loclose($file);

pg_exec($dbh, 'COMMIT');

?>

In primul rand este deschis BLOBsi sunt extrasi 4 bytes de date din BLOB utilizand pg_loread. Dupa aceasta datele sunt afisate pe ecran:

data: SUSI

Managementul Upload-ului de fisiere

Managementul fisierelor poate fi realizat cu orice browser care este in acord cu RFC-1867, ca Mozilla si Netscape. Uploadul fisierelor se referǎ la posibilitatea de a stoca un fisier pe un server Web unde poate fi utilizat pentru o prelucrare ulteriorǎ.Nu conteazǎ dacǎ fisierul este in format ASCII sau binar deorece el este procesat ca o unitate byte cu byte. De obicei fisierele sunt incǎrcate cu o cerere POST, ca in exemplul:

<html>

<head>

<title>Titlu</title>

</head>

<body>

<h1>Lucrul cu Upload-ul de fisiere</h1>

<form id='data' method='post' action='input_file.php'

enctype='multipart/form-data'>

<p>

Alege un fisier: <br>

<input name='testfile' type='file' size='50' maxlength='100000'><br>

<input name='submit' type='submit'>

</p>

</form>

</body>

</html>

Dupǎ antet si titlu, distingem formularul. Primul camp din formular utilizeazǎ file ca tip. Campul va fi folosit pentru upload-ul de fisiere. Dintre parametri distingem lungimea maximǎ a fisierului care va fi incǎrcat. Urmǎtorul camp contine butonul Submit Query pentru inceperea cererii POST:

Fisierul responsabil pentru managementul upload-ului de fisiere se numeste input_file.php:

<?php

if ($testfile)

else

}

else

?>

Campul din fisierul PHP responsabil cu realizarea upload-ului se numeste testfile. PHP defineste automat o variabilǎ avand acelasi nume cu campul din fisierul HTML. Se poate verifica dacǎ variabila este definitǎ sǎ verficǎm dacǎ fisierul a foat incǎrcat cu succes. $testfile contine numele fisierului de pe serverul Web iar $testfile_name contine numele original al fisierului de pe masina utilizatorului. La upload, fisierul nu va avea numele original de pe serverul Web deoarece aceasta poate cauza o problemǎ legatǎ de numele identice. In plus a fost definit si $testfile_size, care contine dimensiunea fisierului in bytes. Rezultatul va fi:

userfile: /tmp/phpTdZESc

userfile_name: example.tar.gz

userfile_size: 7194

Dupǎ cum se poate observa, continutul lui $testfile este putin criptic, avantajul constand in faptul cǎ numele fisierelor generate de PHP sunt intotdeauna unice.

Stocarea fisierelor ca text toasted

Datele pot fi convertite ca cod hexa si stocate intr-o variabilǎ text. De la PostgreSQL 7.0, dimensiunea variabilelor text a fost limitatǎ la dimensiunea unei singure pagini, care este de obicei 8192 bytes. Odatǎ cu aparitia lui PostgreSQL 7.1, lucrurile s-au schimbat si textul se numeste tip de datǎ toasted, ceea ce inseamnǎ cǎ un camp poate fi mai mare decat o paginǎ utilizatǎ de PostgreSQL intern. De obicei, un camp poate avea maxim 1GB. Dacǎ se doreste lucrul cu campuri mai mari de 1GB, vom utiliza interfata BLOB a PostgreSQL.

Sǎ vedem cum continutul unui fisier poate fi stocat intr-o coloanǎ text. Vom crea o tabelǎ pentru stocarea fisierelor.

phpdb=> CREATE TABLE filesystem(name text, data text, tstamp timestamp);

CREATE TABLE

Vom scrie o micǎ aplicatie rin care vom importa un fisier (/etc/passwd) in baza de date:

<?php

# numele fisierului pe care dorim sa-l importam

$filename = '/etc/passwd';

$dbh = pg_connect('host=localhost user=postgres dbname=phpdb');

if (!$dbh)

# deschiderea fisierului si extragerea informatiilor despre acesta

$fp = fopen($filename, 'r');

$fstats = fstat($fp);

$data = fread($fp, $fstats[6]);

# conversia datelor la date hexa

$hexdata = bin2hex($data);

# introducerea datelor in baza de date

$sql = 'INSERT INTO filesystem VALUES

('$filename', '$hexdata', now())';

$stat = pg_exec($dbh, $sql);

if (!$stat)

else

?>

Dupǎ conectarea la baza de date, fisierul este deschis pentru citire utilizand fopen. Manipulatorul de fisier returnat de fopen este necesar pentru fstats. Cu ajutorul lui fstats, informatiile referitoare la dimensiune si inode pot fi afisate. Este necesarǎ dimensiunea fisierului pentru a vedea cate date au fost citite utilizand fread. Dupǎ ce datele sunt citite, ele sunt codate utilizand bin2hex. $hexdata este apoi introdus apoi in baza de date si pe ecran este afisat un mesaj. Vom verifica dacǎ datele au fost importate cu succes:

phpdb=# SELECT name, length(data), tstamp FROM filesystem;

name | length | tstamp

/etc/passwd | 2400 | 2005-10-31 23:42:53.644758+01

(1 row)

Numele fisierului este stocat in prima coloanǎ. Continutul celei de-a doua coloane nu este afisat complet deoarece nu este folosit pentru a afisa datele hexazecimale. Campul are dimensiunea totalǎ 2400 byes. Dacǎ ne uitǎm la /etc/passwd, observǎm cǎ cantitatea de depozitare necesarǎ s-a dublat:

ls -l /etc/passwd

-rw-r--r--  1 root root 1200 Dez 15 01:13 /etc/passwd

Exportul datelor este la fel de simplu ca importul datelor:

<?php

# numele fisierului pe care dorim sa-l extragem

$filename = '/etc/passwd';

# conectarea la baza de date

$dbh = pg_connect('host=localhost user=postgres dbname=phpdb');

if (!$dbh)

# selectarea datelor

$sql = 'SELECT name, data, tstamp FROM filesystem

WHERE name='$filename'';

$result = pg_exec($dbh, $sql);

$data = pg_fetch_row($result, 0) or

exit ('a aparut o eroare<br>');

$bindata = hex2bin($data[1]);

# compararea datelor

$fp = fopen($filename, 'r');

$fstats = fstat($fp);

$data = fread($fp, $fstats[6]);

if ($bindata == $data)

else

function hex2bin($data)

?>

In primul randm inregistrarea contine fisierul necesar a fi afisat din baza de date. In urmǎtorul pas, continutul celei de-a doua coloane este transformat in formatul original prin functia hex2bin. La sfarsitul programului PHP putem observa cum lucreazǎ hex2bin: lungimea sirului specificat in functie este evaluat si apoi sirul decodat este returnat programului principal. Acum $bindata contine datele originale, si datele sunt comparate cu datele din fisierul original /etc/passwd. Rezultatul este:

the data is the same

Exemplu de utilitar pentru managementul imaginilor

Idea este de a arǎta cum datele pot fi extrase din baza de date si trimise browser-ului direct.

Vom crea o tabelǎ pentru a stoca date despre imagini:

CREATE TABLE pic_db (

id serial, -- id-ul of imaginii

name text, -- numele imaginii

picoid oid, -- id-ul obiectului imaginii

added timestamp DEFAULT now()

Codul HTML pentru incǎrcarea fisierelor este:

<html>

<head>

<title>Titlu</title>

</head>

<body>

<?php

echo '<b>Lista imaginilor din tabela </b><br>n';

# conectarea la baza de date

$dbh = pg_connect('dbname=phpdb user=postgres');

if (!$dbh)

$result = pg_exec($dbh, 'SELECT id, name, picoid, added FROM pic_db');

$rows = pg_numrows($result);

for ($i = 0; $i < $rows; $i++)

?>

<br><br><hr>

<b>Incarcarea fisierelor:</b>

<form id='data' method='post' action='input_file.php'

enctype='multipart/form-data'>

<p>

Alegeti un fisier: <br>

<input name='testfile' type='file' size='50' maxlength='100000'><br>

<input name='submit' type='submit'>

</p>

</form>

</body>

</html>

Dupǎ ce a fost afisat header-ul, incepe scriptul PHP. Conexiunea la baza de date este stabilitǎ si informatia referitoare la imagini care este deja in baza de date este afisatǎ. Fiecare nume de fisier este afisat si o legǎturǎ cǎtre detail.php este generatǎ. Detail.php va contine codul pentru extragerea imaginii. Dupǎ generarea legǎturilor, este afisat un formular. Acest formular poate fi utilizat pentru incǎrcarea fisierelor aditionale:

Input_file.php este apelat cand cineva executǎ clic pe butonul Submit Query, Conexiunea la baza de date este deschisǎ si fisierul incǎrcat de utilizator este importat in baza de date. Dacǎ fisierul este importat cu succes, este afisat un mesaj. Fisierul input_file.php:

<?php

# conectarea la baza de date

$dbh = pg_connect('dbname=phpdb user=postgres');

if (!$dbh)

# verific incarcarea fisierului

if ($testfile)

else

}

else

}

pg_close($dbh);

?>

Scriptul numit detail.php este utilizat pentru a afisa o imagine pe ecran:

<?php

# conectarea la baza de date

$dbh = pg_connect('dbname=phpdb user=postgres');

if (!$dbh)

$sql = 'SELECT id, name, picoid, added FROM pic_db WHERE id=$id';

$result = pg_exec($dbh, $sql);

$data = pg_fetch_row($result, 0);

if (!$data)

else

$img = pg_loreadall($ofp);

print $img;

pg_loclose($ofp);

pg_exec($dbh, 'END');

}

?>

Conexiunea la baza de date este stabilitǎ. Id-ul obiect al imaginii este extras. Pentru a deshide BLOB-ul, trebuie pornitǎ tranzactia. Pg_loopen returneazǎ un manipulator care poate fi utilizat pentru operatii ca citirea fisierelor din BLOB. In final, toate manipulatoarele si tranzactiile sunt inchise. In plus, datele sunt trimise cǎtre browser.



Politica de confidentialitate | Termeni si conditii de utilizare



DISTRIBUIE DOCUMENTUL

Comentarii


Vizualizari: 1755
Importanta: rank

Comenteaza documentul:

Te rugam sa te autentifici sau sa iti faci cont pentru a putea comenta

Creaza cont nou

Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved