Você está na página 1de 36

Abstraes de Bancos de Dados

1/36

Abstrao de Bancos de Dados


ndice

AdoDB . . . . PDO . . . . . MySQL e PostgreSQL .

. . .

. . .

. . .

. . .

. . .

. . .

. . .

. . .

. . .

. . .

. . .

. . .

. . .

. . .

. . .

2 21 29

Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados

2/36

ADOdb
AdoDB - http://adodb.sourceforge.net/ AdoDB uma abstrao de bancos de dados para PHP. Atualmente tambm existe uma verso para Python. Download - http://adodb.sourceforge.net/#download Documentao - http://adodb.sourceforge.net/#docs Acessando bases de dados PostgreSQL no PHP com a biblioteca ADODB http://www.linhadecodigo.com.br/ArtigoImpressao.aspx?id=829 Apresentando a adobDB http://www.revistaphp.com.br/artigo.php?id=49 Apresentando a adobDB - 2 http://www.revistaphp.com.br/artigo.php?id=63 http://www.devshed.com/c/a/PHP/PHP-Application-Development-With-ADODB-part-1/ http://www.devshed.com/index2.php? option=content&task=view&id=179&pop=1&hide_ads=1&page=0&hide_js=1 Use ADO to list field definitions for tables http://code.activestate.com/recipes/104801/ ADOdb (Active Data Objects DataBase) uma abstrao de bancos de dados para PHP. Tambm oferece uma verso para Python. Atualmente suporta diversos SGBDs: MySQL, Oracle, Microsoft SQL Server, Sybase, Sybase SQL Anywhere, Informix, PostgreSQL, FrontBase, Interbase (Firebird and Borland variants), Foxpro, Access, ADO e ODBC. Via ODBC podemos tambm conectar com diversos SGBDs: Progress, SQLite, DB2 e outros. uma das mais ricas e eficientes abstraes existentes para PHP atualmente. Caso no se utilize uma abstrao no cdigo, ao migrar para outro SGBD o cdigo sofrer diversas alteraes e alm disso exigir o conhecimento das funes de ambos os SGBDs, mas utilizando algo como ADOdb a alterao ser apenas nos dados da conexo sem necessidade de conhecer as funes do PHP com os SGBDs.

Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados

3/36

Usando AdoDB
Exemplo prtico para mostrar alguns recursos da ADOdb. Site oficial - http://php.weblogs.com/ADODB Download - http://adodb.sourceforge.net/#download Documentaes - http://adodb.sourceforge.net/#docs Este tutorial teve como base os tutoriais do site oficial e tambm o timo tutorial: PHP Application Development With ADODB http://www.devshed.com/c/a/PHP/PHP-Application-Development-With-ADODB-part-1/ Banco de Dados para o exemplo: dbbiblioteca create database dbbiblioteca (com o postgresql mas para usar outro SGBD basta trocar os dados) Tabela - biblioteca CREATE TABLE biblioteca ( id serial NOT NULL PRIMARY KEY, titulo character(100), autor character(45), data date ); Vamos inserir alguns registros: INSERT INTO biblioteca (id, titulo, autor, data) VALUES (1, 'Os Sertes', 'Euclides da Cunha','2005-12-25'); INSERT INTO biblioteca (id, titulo, autor, data) VALUES (2, 'Os Lusadas', 'Cames','2005-12-25'); INSERT INTO biblioteca (id, titulo, autor, data) VALUES (3, 'A Divina Comdia', 'Dante','2005-1225'); INSERT INTO biblioteca (id, titulo, autor, data) VALUES (4, 'Contos', 'Voltaire','2005-12-25'); INSERT INTO biblioteca (id, titulo, autor, data) VALUES (5, 'O Conde de Monte Cristo', 'Alexandre Dumas Pai','2005-12-25'); Fazer o download e descompactar numa pasta do seu DocumentRoot. Neste exemplo descompactei no raiz. Alguns aliases para a conexo MySQL - mysql PostgreSQL - postgres Interbase/Firebird - ibase SQLite - sqlite Vamos agora criar alguns scripts PHP para acessar o banco usando ADOdb. Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados

4/36

Esta parte inicial se repetir em todos os scripts, portanto apenas farei a citao de "inicial" nos demais scripts <?php // Descomentar a linha abaixo para visualizar como plaintext no browser // header("Content-Type: text/plain"); // include the ADODB library include("adodb/adodb.inc.php"); // create an object instance // Configurar para uma conexo tipo PostgreSQL $db = NewADOConnection("postgres"); // MySQL seria "mysql" // Abrir uma conexo com o banco de dados // $db->Connect("servidor", "usuario", "senha", "banco") $db->Connect("localhost", "postgres", "postabir", "dbbiblioteca") or die("Falha na conexo!"); ?> // executar a consulta $query = "SELECT * FROM biblioteca"; $result = $db->Execute($query) or die("Erro na consulta: $query. " . $db->ErrorMsg()); // Iterao atravs do resultset // imprimir dados em colunas no formato TTULO - AUTOR while (!$result->EOF){ echo $result->fields[1] . " - " . $result->fields[2] . "<br>"; $result->MoveNext(); // Veja que funo til, como tambm o EOF // (End Of File, enquanto no chegar ao final) } // receber e imprimir o nmero de registros do resultset com muita simplicidade echo "<br>[" . $result->RecordCount() . " registros retornados]<br>"; // Fechar a conexo com o banco $db->Close(); ?> ADODB tambm oferece um nmero de mtodos alternativos para processar um resultset. Por exemplo, voc pode receber o resultset como um array associativo indexado de string, onde as chaves so nomes de campos e os valores os correspondentes valores dos campos.

Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados Um exemplo: (aqui cole o trecho inicial) referido acima // get resultset as associative array $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;

5/36

// execute query $query = "SELECT * FROM biblioteca"; $result = $db->Execute($query) or die("Error in query: $query. " . $db->ErrorMsg()); // iterate through resultset // print column data in format TITLE - AUTHOR while (!$result->EOF) { echo $result->fields['titulo'] . " - " . $result->fields['autor'] . "<br>"; $result->MoveNext(); } // get and print number of rows in resultset echo "<br>[" . $result->RecordCount() . " registros retornados]<br>"; // close database connection $db->Close(); ?> Voc pode usar o mtodo GetAll() no lugar do Execute() que retorna o resultset completo com um array bidimensional de pares campo-valor. Este array pode ento ser processado com um simples "foreach" ou um loop "for". Um exemplo: // execute query $query = "SELECT * FROM biblioteca"; $result = $db->GetAll($query) or die("Error in query: $query. " . $db->ErrorMsg()); // clean up $db->Close(); // uncomment the following line to see the returned array. // print_r($result); // iterate through resultset // print column data in format TITLE - AUTHOR foreach ($result as $row) { echo $row[1] . " - " . $row[2] . "<br>"; Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados } // get and print number of rows in resultset echo "<br>[" . sizeof($result) . " registros retornados]<br>"; ?>

6/36

Vejamos agora um exemplo com as funes RecordCount() e FieldCount(): // execute query $query = "SELECT * FROM biblioteca"; $result = $db->Execute($query) or die("Error in query: $query. " . $db->ErrorMsg()); // get and print number of rows in resultset echo $result->RecordCount() . " registros retornados<br>"; // get and print number of fields in resultset echo $result->FieldCount() . " campos retornados<br>"; // clean up $db->Close(); ?> Podemos obter informaes sobre cada campo com o mtodo FetchField(), que retorna um objeto contendo informaes detalhadas sobre as propriedades dos campos, incluindo seus nomes e tipos. Um exemplo: // execute query $query = "SELECT * FROM biblioteca"; $result = $db->Execute($query) or die("Error in query: $query. " . $db->ErrorMsg()); // get field information for($x=0; $x<$result->FieldCount(); $x++) { print_r($result->FetchField($x)); } // clean up $db->Close(); ?> Para a execuo de consultas INSERT em tabela contendo chave primria com auto-incremento podemos obter o ltimo ID gerado do auto-incremento usando o mtodo Insert_ID(). Exemplo: // execute query $titulo = $db->qstr("It's Not Me, It's You!"); Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados

7/36

$autor = $db->qstr("J. Luser"); $query = "INSERT INTO biblioteca (titulo, autor) VALUES ($titulo, $autor)"; $result = $db->Execute($query) or die("Erro na consulta: $query. " . $db->ErrorMsg()); // print auto-generated ID if ($result) { echo "O ltimo ID inserido foi " . $db->Insert_ID(); } // clean up $db->Close(); ?> Obs.: o mtodo qstr() usado para "escapar" caracteres especiais em consultas com strings. Quando estamos utilizando consultas que afetam registros de tabelas, como insert, delete ou update o mtodo Affected_Rows() retorna o nmero de registros afetados. // execute query $query = "DELETE FROM biblioteca WHERE author = 'Euclides da Cunha'"; $result = $db->Execute($query) or die("Erro na consulta: $query. " . $db->ErrorMsg()); // return number of affected rows if ($result) { echo $db->Affected_Rows() . " registros excludos"; } // clean up $db->Close(); ?>

Quando precisamos restringir o nmero de registros recebidos podemos usar o mtodo SelectLimit(). // execute query // receber 2 registros, iniciando do terceiro, ou seja, o terceiro e o quarto registros $query = "SELECT * FROM biblioteca"; $result = $db->SelectLimit($query, 2, 3) or die("Erro na consulta: $query. " . $db->ErrorMsg()); // iterate through resultset while (!$result->EOF) { echo $result->fields[1] . " - " . $result->fields[2] . "<br>"; Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados $result->MoveNext(); } // clean up $db->Close(); ?>

8/36

Alerta: Cuidado com o copiar e colar. Este exemplo acima e vrios outros acusaram erro ao executar. Normalmente o erro era na linha (echo $result->fields[1] . " - " . $result->fields[2] . "<br>";). O original estava no Write do OpenOffice. Normalmente apenas excluo os espaos antes do echo e t resolvido ou ento redigito apenas a linha do erro. Algumas vezes precisei remover alguns espaos aps o ponto e vrgula. Tambm podemos obter uma lista dos bancos e tabelas do SGBD, atravs dos mtodos MetaDatabases() e MetaTables(). // get database list echo "Bancos:<br>"; foreach($db->MetaDatabases() as $d){ echo "=> $d<br>"; } // get table list echo "<br>Tabelas no banco atual:<br>"; foreach($db->MetaTables() as $table) { echo "=> $table<br>"; } // clean up $db->Close(); ?> Quando precisamos executar uma consulta vrias vezes, como por exemplo diversos INSERTs. O ADOdb conta com diversos recursos teis. Vejamos: // prepara a consulta e a deixa em "banho maria", sem a executar ainda $query = $db->Prepare("INSERT INTO biblioteca (id, titulo, autor) VALUES (?, ?, ?)"); // ler lista titulo-autor do arquivo CSV $data = file("lista.txt"); // iterao atravs de cada linha do arquivo foreach ($data as $l){ // separa com vrgulas Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados

9/36

$arr = explode(",", $l); // insere os valores na consulta preparada anteriormente $result = $db->Execute($query, array($arr[0], '$arr[1]', '$arr[2]')) or die("Erro na consulta: $query. " . $db->ErrorMsg()); } // clean up $db->Close; ?> Atentar para o fato de que o prepare apenas deixa a consulta pronta e o execute finaliza a execuo. Isto melhora muito o desempenho quando temos muitas consultas a realizar. Uso de transaes. Caso o SGBD tenha suporte: // turn off auto-commit // begin transaction block $db->BeginTrans(); // first query $query = "INSERT INTO biblioteca (titulo, autor) VALUES ('Titulo A', 'Autor B')"; $result = $db->Execute($query) or die("Erro na consulta: $query. " . $db->ErrorMsg()); // use ID from first query in second query if ($result) { $id = $db->Insert_ID(); $query = "INSERT INTO purchase_info (id, price) VALUES ($id, 'USD 39.99')"; $result = $db->Execute($query) or die("Error in query: $query. " . $db->ErrorMsg()); } // if no failures if ($result) { // commit $db->CommitTrans(); } // else rollback else { $db->RollbackTrans(); } // clean up $db->Close; ?>

Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados

10/36

ADOdb tembm oferece suporte para cache de consultas. Que oferece um excelente ganho de desempenho, principalmente nos casos em que precisamos executar uma mesma consulta diversas vezes. Para ver a diferena abaixo temos uma consulta normal: // execute query $query = "SELECT * FROM biblioteca"; $result = $db->Execute($query) or die("Erroo na consulta: $query. " . $db->ErrorMsg()); // iterate through resultset // print column data in format TITLE - AUTHOR while (!$result->EOF) { echo $result->fields[1] . " - " . $result->fields[2] . "<br>"; $result->MoveNext(); } // get and print number of rows in resultset echo "<br>[" . $result->RecordCount() . " registros retornados]<br>"; // close database connection $db->Close(); ?> Agora usando o cache de consulta: // execute query $query = "SELECT * FROM biblioteca"; $result = $db->CacheExecute(300,$query) or die("Erro na consulta: $query. " . $db->ErrorMsg()); // iterate through resultset // print column data in format TITLE - AUTHOR while (!$result->EOF) { echo $result->fields[1] . " - " . $result->fields[2] . "<br>"; $result->MoveNext(); } // get and print number of rows in resultset echo "<br>[" . $result->RecordCount() . " registros retornados]<br>"; // close database connection $db->Close(); ?>

Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados

11/36

Algo que d um bom trabalho criar um select que seja populado de uma tabela. O menu drop-down. O ADOdb tem um mtodo especificamente para esta finalidade. <html> <head></head> <body> <?php // include the ADODB library include("adodb/adodb.inc.php"); // create an object instance // configure it for a PostgreSQL connection $db = NewADOConnection("postgres"); // open connection to database $db->Connect("localhost", "postgres", "postabir", "dbbiblioteca") or die("Unable to connect!"); // execute query $query = "SELECT titulo, id FROM biblioteca"; // O primeiro ser exibido e o segundo armazenar o resultado $result = $db->Execute($query) or die("Erro na consulta: $query. " . $db->ErrorMsg()); // print HTML menu print $result->GetMenu("biblioteca", '', false); // primeiro parmetro o nome do select // close database connection $db->Close(); ?> </body> </html> ADOdb tambm pode exportar um resultset para diversos formatos: - texto separado por vrgula - texto separado por tabulao - tabela HTML Estes recursos no fazem parte da classe ADODB, portanto precisaremos importar outras classes. <?php // uncomment this to see plaintext output in your browser // header("Content-Type: text/plain"); // include the ADODB library include("adodb/adodb.inc.php"); // include conversion functions Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados include("adodb/toexport.inc.php"); // create an object instance // configure library for a PostgreSQL connection $db = NewADOConnection("postgres");

12/36

// open connection to database $db->Connect("localhost", "postgres", "postabir", "dbbiblioteca") or die("Unable to connect!"); // execute query $query = "SELECT title, id FROM library"; $result = $db->Execute($query) or die("Error in query: $query. " . $db->ErrorMsg()); // return a CSV string echo rs2csv($result); // close database connection $db->Close(); ?> Podemos suprimir a primeira linha (nomes dos campos), adicionando um parmetro para a chamada de rs2csv(): // return a CSV string echo rs2csv($result, false); Formatando com separado por tab: Apenas troque a funo (mtodo) de rs2csv() para rs2tab(). Formatando a sada para tabela HTML: Para esta precisamos de outro importe, confira: <html> <head></head> <body> <?php // uncomment this to see plaintext output in your browser // header("Content-Type: text/plain"); // include the ADODB library include("adodb/adodb.inc.php"); // include conversion functions include("adodb/tohtml.inc.php"); Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados // create an object instance // configure it for a PostgreSQL connection $db = NewADOConnection("postgres");

13/36

// open connection to database $db->Connect("localhost", "postgres", "postabir", "dbbiblioteca") or die("Unable to connect!"); // execute query $query = "SELECT titulo, id FROM biblioteca"; $result = $db->Execute($query) or die("Erro na consulta: $query. " . $db->ErrorMsg()); // return a table echo rs2html($result); // close database connection $db->Close(); ?> </body> </html> Formatando Data de Sada <?php // Select a table, display the first two columns. // If the second column is a date or timestamp, reformat the date to Brazilian d/m/Y. // uncomment this to see plaintext output in your browser // header("Content-Type: text/plain"); // include the ADODB library include("adodb/adodb.inc.php"); // create an object instance // configure library for a PostgreSQL connection $db = NewADOConnection("postgres"); // Antes alterar a tabela adicionando o campo data: // \c dbbiblioteca // ALTER TABLE biblioteca ADD COLUMN data date; // open connection to database $db->Connect("localhost", "postgres", "postabir", "dbbiblioteca") or die("Unable to connect!"); $recordSet = &$db->Execute('select id,data from biblioteca'); if (!$recordSet) print $db->ErrorMsg(); Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados else while (!$recordSet->EOF) { $fld = $recordSet->FetchField(1); $type = $recordSet->MetaType($fld->type);

14/36

if ( $type == 'D' || $type == 'T') print $recordSet->fields[0].' '. $recordSet->UserDate($recordSet->fields[1],'d/m/Y').'<BR>'; else print $recordSet->fields[0].' '.$recordSet->fields[1].'<BR>'; $recordSet->MoveNext(); } $recordSet->Close(); # optional $db->Close(); # optional ?> Exporting in CSV or Tab-Delimited Format <?php // Exporting in CSV or Tab-Delimited Format // uncomment this to see plaintext output in your browser // header("Content-Type: text/plain"); include_once('adodb/toexport.inc.php'); // include the ADODB library include("adodb/adodb.inc.php"); // create an object instance // configure library for a PostgreSQL connection $db = NewADOConnection("postgres"); // open connection to database $db->Connect("localhost", "postgres", "postabir", "dbbiblioteca") or die("Unable to connect!"); $rs = $db->Execute('select titulo as "Ttulo", autor as "Autor" from biblioteca'); print "<pre>"; print rs2csv($rs); # return a string, CSV format print '<hr>'; $rs->MoveFirst(); # note que alguns databases no suportam MoveFirst print rs2tab($rs,false); # return a string, tab-delimited Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados

15/36

# false == suppress field names in first line print '<hr>'; $rs->MoveFirst(); rs2tabout($rs); # send to stdout directly (there is also an rs2csvout function) print "</pre>"; $rs->MoveFirst(); $fp = fopen($path, "w"); if ($fp) { rs2csvfile($rs, $fp); # write to file (there is also an rs2tabfile function) fclose($fp); } ?> INSERT com Arquivo SCV <?php // uncomment this to see plaintext output in your browser // header("Content-Type: text/plain"); // include the ADODB library include("adodb/adodb.inc.php"); // create an object instance // configure library for a PostgreSQL connection $db = NewADOConnection("postgres"); // open connection to database $db->Connect("localhost", "postgres", "postabir", "dbbiblioteca") or die("Unable to connect!"); // prepare query $query = $db->Prepare("INSERT INTO biblioteca (id, titulo, autor) VALUES (?, ?)"); // read title-author list in from CSV file $data = file("lista.txt"); // iterate through each line in file foreach ($data as $l){ // split on comma $arr = explode(",", $l); // insert values into prepared query $result = $db->Execute($query, array($arr[0], $arr[1])) or die("Error in query: $query. " . $db>ErrorMsg()); } // clean up Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados $db->Close; echo "Arquivo CSV inserido com sucesso!"; ?> Arquivo lista.txt Sandlias do Pescador, Morris West Ana Karenina, Leon Tolstoi Terras do Sem Fim, Jorge Amado Helena, Machado de Assis Paginao com muita Simplicidade <?php // Paginao com muita simplicidade // uncomment this to see plaintext output in your browser // header("Content-Type: text/plain"); // include the ADODB library include("adodb/adodb.inc.php"); include_once('adodb/adodb-pager.inc.php'); session_start(); // create an object instance // configure library for a PostgreSQL connection $db = NewADOConnection("postgres");

16/36

// open connection to database $db->Connect("localhost", "postgres", "postabir", "dbbiblioteca") or die("Unable to connect!"); $sql = "select * from biblioteca "; $pager = new ADODB_Pager($db,$sql); $pager->Render($rows_per_page=5); ?> Tratamento de Strings <?php // Insert a row to the Orders table containing dates and strings that need to be // quoted before they can be accepted by the database, eg: the single-quote in the word John's. // uncomment this to see plaintext output in your browser // header("Content-Type: text/plain"); Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados // include the ADODB library include("adodb/adodb.inc.php"); // create an object instance // configure library for a PostgreSQL connection $db = NewADOConnection("postgres");

17/36

// open connection to database $db->Connect("localhost", "postgres", "postabir", "dbbiblioteca") or die("Unable to connect!"); $autor = $db->qstr("John's Old Shoppe"); // Tratamento de string com qstr antes de inserir no banco $sql = "insert into biblioteca (titulo,id,data,autor) "; $sql .= "values ('Teste2',36,'2006-10-10',$autor)"; // Veja o original para detalhes if ($db->Execute($sql) === false) { // S insere se no ocorrer erro print 'error inserting: '.$db->ErrorMsg().'<BR>'; } echo "Inserido com sucesso!"; ?> Debugando <? include('adodb.inc.php'); # load code common to ADOdb $conn = &ADONewConnection('access'); # create a connection $conn->PConnect('northwind'); # connect to MS-Access, northwind dsn $shipto = $conn->qstr("John's Old Shoppe"); $sql = "insert into orders (customerID,EmployeeID,OrderDate,ShipName) "; $sql .= "values ('ANATR',2,".$conn->FormatDate(time()).",$shipto)"; $conn->debug = true; if ($conn->Execute($sql) === false) print 'error inserting'; ?> Conectando-se a dois bancos de dados de SGBDs diferentes ao mesmo tempo <? include('adodb.inc.php'); # load code common to ADOdb $conn1 = &ADONewConnection('mysql'); # create a mysql connection $conn2 = &ADONewConnection('oracle'); # create a oracle connection $conn1->PConnect($server, $userid, $password, $database); $conn2->PConnect(false, $ora_userid, $ora_pwd, $oraname); $conn1->Execute('insert ...'); $conn2->Execute('update ...'); Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados ?> Recordset Filters

18/36

Sometimes we want to pre-process all rows in a recordset before we use it. For example, we want to ucwords all text in recordset. include_once('adodb/rsfilter.inc.php'); include_once('adodb/adodb.inc.php'); // ucwords() every element in the recordset function do_ucwords(&$arr,$rs) { foreach($arr as $k => $v) { $arr[$k] = ucwords($v); } } $db = NewADOConnection('mysql'); $db->PConnect('server','user','pwd','db'); $rs = $db->Execute('select ... from table'); $rs = RSFilter($rs,'do_ucwords'); Executing the SQL $result = $db->Execute("SELECT * FROM employees"); if ($result === false) die("failed"); Inserts and Updates Let's say you want to insert the following data into a database. ID = 3 TheDate=mktime(0,0,0,8,31,2001) /* 31st August 2001 */ Note= sugar why don't we call it off $sql = "INSERT INTO table (id, thedate,note) values (" . $ID . ',' . $db->DBDate($TheDate) .',' . $db->qstr($Note).")"; $db->Execute($sql);

Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados MetaTypes

19/36

You can find out more information about each of the fields (I use the words fields and columns interchangebly) you are selecting by calling the recordset method FetchField($fieldoffset). This will return an object with 3 properties: name, type and max_length. For example: $recordset = $conn->Execute("select adate from table"); $f0 = $recordset->FetchField(0); Then $f0->name will hold 'adata', $f0->type will be set to 'date'. If the max_length is unknown, it will be set to -1. One problem with handling different databases is that each database often calls the same type by a different name. For example a timestamp type is called datetime in one database and time in another. So ADODB has a special MetaType($type, $max_length) function that standardises the types to the following: C: character and varchar types X: text or long character (eg. more than 255 bytes wide). B: blob or binary image D: date T: timestamp L: logical (boolean) I: integer N: numeric (float, double, money) In the above date example, $recordset = $conn->Execute("select adate from table"); $f0 = $recordset->FetchField(0); $type = $recordset->MetaType($f0->type, $f0->max_length); print $type; /* should print 'D' */

Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados

20/36

PDO - PHP Data Objects


Site oficial - http://www.php.net/manual/pt_BR/book.pdo.php uma abstrao de bancos de dados nativa do PHP, para a verso 5.1 ou superior. No requer download, apenas habilitar o PHP para o respectivo SGBD no php.ini ou instalar o pacote. Exemplo: php_mysql, pdo_pgsql, etc. Tutoriais A Crash Course id PDO - http://resources.comparity.net/pdf/pdo.pdf Easy Access With PDO CRUD http://www.phpro.org/tutorials/Easy-Access-With-PDO-CRUD.html Introduction to PDO http://www.phpro.org/tutorials/Introduction-to-PHP-PDO.html Exemplo de uso: Framework gil verso com PDO: http://ribafs.org/download/php/fw_agil/fw_agil_pdo.zip

Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados Exemplo de uso do Framework gil com PDO Conexo <?php $host='localhost'; $user='root'; $password='ribafs'; $database='estoque'; $port = '3306'; $sgbd='mysql'; // mysql or pgsql (only)

21/36

try { $dbh = new PDO("$sgbd:host=$host;dbname=$database", $user, $password); } catch (PDOException $e) { print "Error!: " . $e->getMessage() . "<br/>"; die(); } ?> Exemplos de funes usando PHP // Return only text fields function fields_text($result){ global $sgbd,$dbh; $i = $result->columnCount(); for ($j = 0; $j < $i; $j++) { $fieldname = pdo_field_name($result, $j); $type=pdo_field_type($result, $j); if(strtolower($type)=='varchar' || strtolower($type)=='char' || strtolower($type)=='text' || strtolower($type)=='string' || strtolower($type)=='date' || strtolower($type)=='time' || strtolower($type)=='timestamp'){ $ftype .= $fieldname.','; } } return $ftype; } // Return all field names in table function pdo_names_fields($table){ global $dbh; $stmt = $dbh->query("select * from $table"); $name=array(); Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados for($x=0;$x<$stmt->columnCount();$x++){ $column = $stmt->getColumnMeta($x); array_push($name, $column[name]); }

22/36

return $name; } // Inspired in: http://www.sitepoint.com/forums/showthread.php?t=497257 //print_r (pdo_names_fields($table)); function pdo_field_name($result,$nr){ global $dbh; $column = $result->getColumnMeta($nr); $name = $column[name]; return $name; } //print pdo_field_name($result,1); function pdo_field_type($result,$nr){ global $dbh; $column = $result->getColumnMeta($nr); $type = $column[native_type]; return $type; } //print pdo_field_type($result,4); // Return primary key field name. Only to mysql or pgsql. function primary_key($table){ global $database,$sgbd,$dbh; if($sgbd=='mysql'){ $sql="SELECT c.COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE c WHERE c.TABLE_SCHEMA = '$database' AND c.TABLE_NAME = '$table' AND c.CONSTRAINT_NAME = 'PRIMARY'"; $result=$dbh->query($sql); $reg=$result->fetch(); $nr=$result->columnCount(); return $reg[0]; }elseif($sgbd=='pgsql'){ $str=" SELECT ta.attname AS column_name Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados

23/36

FROM pg_class bc, pg_index i, pg_attribute ta, pg_attribute ia WHERE bc.oid = i.indrelid AND ia.attrelid = i.indexrelid AND ta.attrelid = bc.oid AND bc.relname = '$table' AND ta.attrelid = i.indrelid AND ta.attnum = i.indkey[ia.attnum-1] ORDER BY column_name; "; $result = $dbh->query($str); $fld = $result->fetch(); $pk = $fld[0]; return $pk; } } // print primary_key($table); // Others SGBDs enter the primary key directly in start paging.php: /* // $pk = primary_key($table); // Comment this if($table =='table1') $pk='pk1'; if($table =='table2') $pk='pk2'; if($table =='table3') $pk='pk3'; ... */ // Combo preenchida com dados de tabela define('ST',"onFocus=\"status_msg.value='Campo $fieldname'\" onBlur=\"status_msg.value=''\""); function combo($field, $default, $table, $status=ST){ global $dbh; $result=$dbh->query("SELECT $field FROM $table ORDER BY $field"); $cb .= "<select name=\"$field\" $status>\n"; $cb .= "<option value=\"0\">Selecione</option>\n"; $row=0; while($row = $result->fetch()){ $exibir=htmlentities($row[$field]); if($row[$field]==$default){ $cb .= "<option value=\"$row[$field]\" SELECTED>$exibir</option>\n"; }else{ $cb .= "<option value=\"$row[$field]\">$exibir</option>\n"; } } $cb .= "</select>"; return $cb; } // combo("fieldref", "valuefielddefault", "tableref"); // print combo("cliente", 6, "pedidos");

Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados // Return table names from database function table_names(){ global $database,$sgbd,$dbh;

24/36

if($sgbd=='mysql'){ $sql = "SELECT DISTINCT(c.TABLE_NAME) FROM INFORMATION_SCHEMA.COLUMNS c WHERE c.TABLE_SCHEMA = '$database'"; }elseif($sgbd=='pgsql'){ $sql = "SELECT relname FROM pg_class WHERE relname !~ '^(pg_|sql_)' AND relkind = 'r';"; } $result = $dbh->query($sql); while ($row = $result->fetch()) { $table .= $row[0].','; } $total=strlen($table); $table=substr($table, -$total,$total-1); return $table; } //print table_names(); // Return fields and table referenceds only of the first field with FK function foreign_key($table){ global $database, $sgbd, $dbh; if($sgbd=='mysql'){ $sql="SELECT REFERENCED_TABLE_NAME,REFERENCED_COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE c WHERE c.TABLE_SCHEMA = '$database' AND c.TABLE_NAME = '$table' AND not isnull(REFERENCED_TABLE_NAME)"; }elseif($sgbd=='pgsql'){ $sql=" SELECT ccu.table_name AS references_table, ccu.column_name AS references_field FROM information_schema.table_constraints tc LEFT JOIN information_schema.key_column_usage kcu ON tc.constraint_catalog = kcu.constraint_catalog AND tc.constraint_schema = kcu.constraint_schema AND tc.constraint_name = kcu.constraint_name LEFT JOIN information_schema.referential_constraints rc ON tc.constraint_catalog = rc.constraint_catalog AND tc.constraint_schema = rc.constraint_schema AND tc.constraint_name = rc.constraint_name LEFT JOIN information_schema.constraint_column_usage ccu ON rc.unique_constraint_catalog = ccu.constraint_catalog Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados

25/36

AND rc.unique_constraint_schema = ccu.constraint_schema AND rc.unique_constraint_name = ccu.constraint_name WHERE tc.table_name = '$table' and tc.constraint_type='FOREIGN KEY'; "; /* Adapted from: http://www.alberton.info/postgresql_meta_info.html */ } $result=$dbh->query($sql); $row=0; $regs=array(); $nf=$result->columnCount(); while ($data = $result->fetch()) { for($x=0;$x < $nf;$x++){ array_push($regs, $data[$x]); } $row++; } return $regs; } /*$table='pedidos'; $ret = foreign_key($table); $nrfk = count($ret); print "TabRef1 - ".$ret[0].'<br>'; print "FldRef1 - ".$ret[1].'<br>'; print "TabRef2 - ".$ret[2].'<br>'; print "FldRef2 - ".$ret[3].'<br>'; //... */ Exemplo de uso extrado do script paging.php do Framework gil PDO // Labels $i = 0; echo '<h2>'.ucfirst($table).'</h2>'; echo "<table border=1><tr>"; while($i < $res->columnCount()) { $column = pdo_field_name($res,$i); $type = pdo_field_type($res,$i); if($type != 'blob' || $type != 'text'){ echo "<td>&nbsp;<b>".ucfirst($column)."</b>&nbsp;</td>"; } $i ++; } echo "<td colspan=2 align=center><b>$action_lng</td></tr>"; Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados // Values while($field = $res->fetch()){ echo "<tr>"; $i =0; while($i < $res->columnCount()){ //$column = pdo_field_name($res,$i); $type = pdo_field_type($res,$i);

26/36

if($lang == 'br'){ // Dates in format dd/mm/yyyy if(strtolower($type) == 'date') { $dt = explode('-',$field[$i]); $datefield = $dt[2].'/'.$dt[1].'/'.$dt[0]; echo "<td>&nbsp;".$datefield."&nbsp;</td>"; }elseif(strtolower($type) != 'blob' && strtolower($type) != 'text'){ echo "<td>&nbsp;".$field[$i]."&nbsp;</td>"; } }else{ if($type != 'blob' || $type != 'text'){ echo "<td>&nbsp;".$field[$i]."&nbsp;</td>"; } } $i++; } ?> <!-- jAlerts --> <script src="./includes/jquery_alerts/jquery-1.3.2.min.js" type="text/javascript"></script> <script src="./includes/jquery_alerts/jquery.ui.draggable.js" type="text/javascript"></script> <script src="./includes/jquery_alerts/jquery.alerts.js" type="text/javascript"></script> <script type="text/javascript"> $(document).ready( function() { $(".confirm_button").click( function() { jConfirm('<?php echo $delconf_lng;?>', '<?php echo $conf_lng;?>', function(r) { if(r){ location='deletebd.php?<?=$pk?>=<?=$field[$pk]?>&table=<?=$table?>'; } }); }); }); </script> <td>&nbsp;<input type="button" name="edit" value="<?=$edit_lng?>" onClick="location='<? =$table?>_updfrm.php?<?=$pk?>=<?=$field[$pk]?>'"></td> <td>&nbsp;<input type="button" name="delete" class="confirm_button" value="<?=$del_lng? Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados >" ></td></tr> <?php } echo "</table>"; // Paging links paging($tr,$rpp,$pg);

27/36

echo "<br><br><a href=".$table."_insfrm.php><b>$add_lng $tablef</b></a>"; // Search for($x=0;$x<$nf;$x++){ $fn = pdo_field_name($res,$x); $flds .= "<option value='$fn'>".ucfirst($fn)."</option>"; } ?>

Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados

28/36

Simples Abstrao para MySQL e PostgreSQL


No desenvolvimento do Framework gil acabei por elaborando uma pequena abstrao de bancos de dados restrita apenas ao MySQL e PostgreSQL, de forma que preciso apenas indicar o SGBD e o cdigo funciona dos dois SGBDs MySQL e PostgreSQL. Download - http://ribafs.org/download/php/fw_agil/fw_agil3.zip Exemplo simples de abstrao que aceita tanto MySQL quanto PostgreSQL: Exemplo de conexo: <?php $sgbd='my'; $host='localhost'; $user='root'; $password='ribafs'; $database='estoque'; $port='3306'; //Conect if($sgbd=='my'){ $conexao=mysql_connect('localhost:3306', 'root', 'ribafs') or die (mysql_error()); //Select $db_sel=mysql_select_db('estoque') or die (mysql_error()); }elseif($sgbd=='pg'){ $conexao=pg_connect("host=localhost user=root password=ribafs dbname=estoque port=3306") or die(pg_last_error()); } ?> Funes da abstrao // Return fields and table referenceds only of the first field with FK function foreign_key($table){ global $database, $sgbd; if($sgbd=='my'){ $sql="SELECT COLUMN_NAME, REFERENCED_TABLE_NAME,REFERENCED_COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE c WHERE c.TABLE_SCHEMA = '$database' AND c.TABLE_NAME = '$table' AND not isnull(REFERENCED_TABLE_NAME)"; $qry=mysql_query($sql); $row=0; $regs=array(); Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados $nf=mysql_num_fields($qry); while ($data = mysql_fetch_array($qry)) { for($x=0;$x < $nf;$x++){ array_push($regs, $data[$x]); } $row++; }

29/36

return $regs; }elseif($sgbd=='pg'){ $sql="SELECT kcu.column_name as local_field, ccu.table_name AS references_table, ccu.column_name AS references_field FROM information_schema.table_constraints tc LEFT JOIN information_schema.key_column_usage kcu ON tc.constraint_catalog = kcu.constraint_catalog AND tc.constraint_schema = kcu.constraint_schema AND tc.constraint_name = kcu.constraint_name LEFT JOIN information_schema.referential_constraints rc ON tc.constraint_catalog = rc.constraint_catalog AND tc.constraint_schema = rc.constraint_schema AND tc.constraint_name = rc.constraint_name LEFT JOIN information_schema.constraint_column_usage ccu ON rc.unique_constraint_catalog = ccu.constraint_catalog AND rc.unique_constraint_schema = ccu.constraint_schema AND rc.unique_constraint_name = ccu.constraint_name WHERE tc.table_name = '$table' and tc.constraint_type='FOREIGN KEY'; "; /* Adapted from: http://www.alberton.info/postgresql_meta_info.html */ $qry=pg_query($sql); //$row=0; $regs=array(); $nf=pg_num_fields($qry); while ($data = pg_fetch_array($qry)) { for($x=0;$x < $nf;$x++){ array_push($regs, $data[$x]); } //$row++; } return $regs; } } /* $table='prateleiras'; $ret = foreign_key($table); Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados $nrfk = count($ret); print "FldLoc1 - ".$ret[0].'<br>'; print "TabRef1 - ".$ret[1].'<br>'; print "FldRef1 - ".$ret[2].'<br>'; print "FldLoc2 - ".$ret[3].'<br>'; print "TabRef2 - ".$ret[4].'<br>'; print "FldRef2 - ".$ret[5].'<br>'; //... */ //dropdown function combo($field, $default_value = null, $table) { //this code is bringing in the values for the dropdown. $query="select * from $table order by $field";

30/36

/* You can add order by clause to the sql statement if the names are to be displayed in alphabetical order */ if($sgbd=='my'){ $result = mysql_query ($query); while($row=mysql_fetch_array($result)){//Array or records stored if($row[$field] == $default_value) { $combo .= "<option value=$row[0] selected='selected'>$row[$field]</option>"; }else{ $combo .= "<option value=$row[0]>$row[$field]</option>"; } } return $combo; }elseif($sgbd=='pg'){ $result = pg_query ($query); while($row=pg_fetch_array($result)){//Array or records stored if($row[$field] == $default_value) { $combo .= "<option value=$row[0] selected='selected'>$row[$field]</option>"; }else{ $combo .= "<option value=$row[0]>$row[$field]</option>"; } } return $combo; } } // Adapted from: http://codingforums.com/showthread.php?t=161047 //print combo('clientes','nome',$default_value = 'Elias Pereira Brito');

Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados

31/36

// Original in: http://www.scriptbrasil.com.br/forum/lofiversion/index.php/t62271.html function table_names(){ global $database,$sgbd; if($sgbd=='my'){ $resultado_tabelas = mysql_list_tables($database); $qntd_tabelas = mysql_numrows($resultado_tabelas); for ($i = 0; $i < $qntd_tabelas; $i++) { $tables .= mysql_tablename($resultado_tabelas, $i).','; } return $tables; }elseif($sgbd=='pg'){ $resultado_tabelas = pg_query("SELECT relname FROM pg_class WHERE relname !~ '^(pg_|sql_)' AND relkind = 'r';"); $qntd_tabelas = pg_num_rows($resultado_tabelas); $tables=''; while ($row = pg_fetch_array($resultado_tabelas)) { $tables .= $row[0].','; } return $tables; } } //print_r(table_names()); // Retorna o tamanho dos campos na tabela function field_len($table,$nr_field){ $sql=" SELECT a.attnum AS ordinal_position, a.attname AS field, t.typname AS type, a.attlen AS max_character_maximum_length, a.atttypmod AS len FROM pg_class c, pg_attribute a, pg_type t WHERE c.relname = '$table' AND a.attnum > 0 AND a.attrelid = c.oid AND a.atttypid = t.oid ORDER BY a.attnum; "; $result=pg_query($sql); Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados $nr=pg_num_rows($result);

32/36

for($x=0;$x<$nr;$x++){ $arr = pg_fetch_array($result); if($arr["type"]=='int2' || $arr["type"]=='int4' || $arr["type"]=='int8' || $arr["type"]=='numeric'){ $len .= '12'.','; }elseif($arr["type"]=='bpchar' || $arr["type"]=='varchar'){ $len .= ($arr["len"]-4).','; }elseif($arr["type"]=='date'){ $len .= '8'.','; }elseif($arr["type"]=='time'){ $len .= 5; }elseif($arr["type"]=='timestamp'){ $len .= '13'.','; } } $len=explode(',',$len); $len=$len[$nr_field]; return $len; } /* for ($j = 1; $j < 6; $j++) { $len = field_len('clientes', $j-1); print "<input name=\"$fieldname\" type=\"text\" size=\"$len\" maxlength=\"$len\" ></td></tr>\n"; } */ // Return primary key field name function primary_key($table){ global $database,$sgbd; if($sgbd=='my'){ $sql="SELECT c.COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE c WHERE c.TABLE_SCHEMA = '$database' AND c.TABLE_NAME = '$table' AND c.CONSTRAINT_NAME = 'PRIMARY'"; $ret=array(); $qry=mysql_query($sql); $reg=mysql_fetch_array($qry); for($x=0;$x<mysql_num_rows($qry);$x++){ array_push($ret,$reg[0]); } Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados

33/36

return $ret; }elseif($sgbd=='pg'){ $str="SELECT ta.attname AS column_name FROM pg_class bc, pg_index i, pg_attribute ta, pg_attribute ia WHERE bc.oid = i.indrelid AND ia.attrelid = i.indexrelid AND ta.attrelid = bc.oid AND bc.relname = '$table' AND ta.attrelid = i.indrelid AND ta.attnum = i.indkey[ia.attnum-1] ORDER BY column_name; "; $ret=array(); $qry = pg_query($str); for($x=0;$x<pg_num_rows($qry);$x++){ $reg = pg_fetch_array($qry,$x); array_push($ret,$reg[0]); } return $ret; } } Exemplo de uso (paging.php): $c=0; $pk = primary_key($table); // Suporta PK com apenas um campo if($sgbd=='my'){ $sql_tr= mysql_query("select * from $table order by $pk"); $tr=mysql_num_rows($sql_tr); //tr - total of registers if (isset($_GET[rpp])) {$rpp = $_GET[rpp];} else {$rpp = $records;} // $rpp - registers per page if (isset($_GET[pg])) {$pg = $_GET[pg];} else {$pg = 0;} $start = $pg * $rpp ; $sql = "select * from $table order by $pk LIMIT $start,$rpp"; $res = mysql_query($sql); $nf = mysql_num_fields($res); }elseif($sgbd=='pg'){ $sql_tr= pg_query("select * from $table order by $pk"); $tr=pg_num_rows($sql_tr); //tr - total of registers if (isset($_GET[rpp])) {$rpp = $_GET[rpp];} else {$rpp = $records;} // $rpp - registers per page if (isset($_GET[pg])) {$pg = $_GET[pg];} else {$pg = 0;} $start = $pg * $rpp ;

Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados

34/36

$sql = "select * from $table order by $pk LIMIT $rpp OFFSET $start"; $res = pg_query($sql); $nf = pg_num_fields($res); } // Labels $i = 0; echo '<h2>'.ucfirst($table).'</h2>'; echo "<table border=1><tr>"; if($sgbd=='my'){ while($i < mysql_num_fields($res)) { $column = mysql_field_name($res,$i); $type = mysql_field_type($res,$i); if($type != 'blob'){ echo "<td><b>&nbsp;".ucfirst($column)."&nbsp;</b></td>"; } $i++; } }elseif($sgbd=='pg'){ while($i < pg_num_fields($res)) { $column = pg_field_name($res,$i); $type = pg_field_type($res,$i); if($type != 'text'){ echo "<td><b>&nbsp;".ucfirst($column)."&nbsp;</b></td>"; } $i++; } } echo "<td colspan=2 align=center><b>$action_lng</td></tr>"; function fetch_array($res){ global $sgbd; if($sgbd=='my'){ return mysql_fetch_array($res); }elseif($sgbd=='pg'){ return pg_fetch_array($res); } } // Values while($field = fetch_array($res)){ echo "<tr>";

Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados $i =0; if($sgbd=='my'){ while($i < mysql_num_fields($res)){ $column = mysql_field_name($res,$i); $type = mysql_field_type($res,$i); if($lang == 'br'){ if($type == 'date') { $dt = explode('-',$field[$i]); $datefield = $dt[2].'/'.$dt[1].'/'.$dt[0]; echo "<td>&nbsp;".$datefield."&nbsp;</td>"; }elseif($type != 'blob'){ echo "<td>&nbsp;".$field[$i]."&nbsp;</td>"; } }else{ if($type != 'blob'){ echo "<td>&nbsp;".$field[$i]."&nbsp;</td>"; } } $i++; } }elseif($sgbd=='pg'){ while($i < pg_num_fields($res)){ $column = pg_field_name($res,$i); $type = pg_field_type($res,$i); if($lang == 'br'){ if($type == 'date') { $dt = explode('-',$field[$i]); $datefield = $dt[2].'/'.$dt[1].'/'.$dt[0]; echo "<td>&nbsp;".$datefield."&nbsp;</td>"; }elseif($type != 'text'){ echo "<td>&nbsp;".$field[$i]."&nbsp;</td>"; } }else{ if($type != 'text'){ echo "<td>&nbsp;".$field[$i]."&nbsp;</td>"; } } $i++; } } ?>

35/36

<td>&nbsp;<input type="button" name="edit" value="<?php echo $edit_lng;?>" onClick="location='<?php echo $table.'/'.$table;?>_updfrm.php?<?php echo $pk.'='.$field[$pk];? Ribamar FS - http://cursos.ribafs.org

Abstraes de Bancos de Dados

36/36

>';"></td> <td>&nbsp;<input type="button" name="delete" value="<?php echo $del_lng;?>" onClick="if(confirm('Tem certeza?')) {location='deletebd.php?<?php echo $pk.'='. $field[$pk].'&table='.$table;?>';}"></td></tr> <?php }/* end while($field = mysql_fetch_array($res)){ */ echo "</table>"; // Paging links paging($tr,$rpp,$pg); echo "<br><br><a href=$table/".$table."_insfrm.php><b>$add_lng $tablef</b></a>"; // Search for($x=0;$x<$nf;$x++){ if($sgbd=='my') { $fn = mysql_field_name($res,$x); }elseif($sgbd=='pg'){ $fn = pg_field_name($res,$x); } $flds .= "<option value='$fn'>".ucfirst($fn)."</option>"; } ?>

Ribamar FS - http://cursos.ribafs.org