Abstracção de SGDBs em PHP – AdoDB

Nos dias que correm, são muitos os que já se aventuraram no desenvolvimento de aplicações web-based. Quando essas aplicações começam a ganhar notoriedade, há uma grande possibilidade de serem usadas noutro ambiente diferente daquele em que sempre desenvolvemos. Um dos problemas comuns é o facto de termos de usar um software de gestão de base de dados (SGDB) diferente e, como escrevemos a aplicação para usar um determinado SGDB, somos obrigados a modificá-la para podermos utilizar outro. Para evitar estes incómodos, existem bibliotecas que servem de camada de abstração de SGDBs.

O que é uma camada de abstracção?

Uma camada de abstracção é simplesmente um elo de ligação entre uma aplicação e dados externos (sejam bases de dados, documentos de texto, etc). Ou seja, a aplicação não liga directamente aos dados externos, mas faz um pedido à camada de abstracção e esta, por sua vez, faz o pedido aos dados, independentemente do seu tipo. A classe ADOdb tem precisamente essa função, é precisamente igual escrevermos uma aplicação que use um determinado SGBD ou outro, o resultado será sempre igual e, as alterações mínimas.

Uso da class

Para utilizarmos esta classe a primeira coisa que temos que fazer é o download da mesma, descomprimi-la e guardá-la num directório acessível pelo servidor HTTP. Após a execução dos passos supracitados devemos proceder à inclusão da class na nossa aplicação, da seguinte forma:

include "pasta/adodb.inc.php";
include "pasta/adodb-exceptions.inc.php";

Depois, devemos criar a nova instância do objecto ADO (ActiveX Data Object) e fazer a conexão à base de dados pretendida, por exemplo (neste exemplo vou usar o conector de MySQL, mas poderia usar outro qualquer):

// Criação da nova instância do objecto
$BD = NewADOConnection('mysql');
// Dados do servidor de MySQL
$servidor="localhost";
$utilizador="root";
$password="123456";
$nomebd="adodb_pap";
// Conexão à base de dados
$BD->Connect($servidor, $utilizador, $password, $nomebd) or die("Erro ao ligar à Base de dados!");

Após aberta a ligação já podemos inserir, alterar e remover dados. Para esse efeito vamos criar um recordset, que é um array com os dados consultados. Para criá-lo utilizamos o seguinte bloco de código:

$rs = $BD->Execute("select * from alunos where codaluno=?",1);
 
// ou
 
$rs = $BD->Execute("select * from alunos where nome='José' ");

Na primeira consulta, vamos ter todos os dados do aluno cujo código é 1, já na segunda vamos obter todos os dados de todos os alunos que se chamam José. Para imprimir todos os registos da consulta realizada temos que percorrê-la do início ao fim, com uma das seguintes formas:

//1ª Forma
while (!$rs->EOF)
{
    print_r($rs->fields);
    $rs->MoveNext();
}
 
//2ª Forma
while ($array = $rs->FetchRow())
{
    print_r($array);
}

A diferença entre os métodos é que o primeiro costuma ser usado nas linguagens criadas pela Microsoft (ASP) e o segundo método pelo PHP .

Esta classe permite-nos também o tratamento de excepções quando, por exemplo, fazemos uma consulta sobre uma tabela que não existe:

try
{
     $rs=$BD->Execute("select * from alunox where codaluno=5");
}
catch (exception $e) 
{ 
     print_r("<b>Erro</b>:".$e->msg);
}

O bloco de código supracitado tenta executar a consulta mas, se não o conseguir, vai dar o seguinte output: ” Erro: Mensagem de Erro” .

Para verificar se o recordset contém algum registo existem várias formas, podemos utilizar:

$rs= $BD->Execute("Select * from alunos where nota>20");
 
//1ª Forma
if($rs->RecordCount()>0)
   echo "Existem ".$rs->RecordCount()." registos que correspondem à consulta!";
else
   echo "Não existem registos nesta consulta!";
 
//2ª Forma
if($rs->EOF)
   echo "Não existem registos nesta consulta!";
else
   echo "Existem ".$rs->RecordCount()." registos que correspondem à consulta!";

No fim de realizarmos todas as tarefas na base de dados, é um bom hábito fechar a ligação, para não sobrecarregarmos o servidor:

$BD->Close();

Segurança

Quando estamos a programar para web, cada vez mais temos de ter em atenção a segurança. Para tal, convém evitar falhas de SQL Injection (ver edição anterior) e, mais uma vez, esta class só facilita essa tarefa, tendo o método Quote($string) para fazer o “escape” de caracteres potencialmente perigosos. Suponhamos que temos uma página de consulta por Código de Aluno:

ADOdb: teste de SQL injection

Se tentarmos fazer SQL injection e passarmos por exemplo “1 OR 1=1#” para a página seguinte vamos obter:

if($_POST['injeccao']) {
echo "Dados recebidos por POST:". $_POST['injeccao']
 
	is_numeric($_POST['injeccao']) ? $codaluno = $_POST['injeccao'] : $codaluno = $BD->Quote($_POST['injeccao'])
 
	echo "Dados tratados para a consulta:". $codaluno;
 
	$rs = $BD->Execute("Select * from alunos where codaluno=?", $codaluno);
 
	if($rs->EOF)
echo "Erro: não foram encontrados registos que correspondessem à consulta realizada";
 
	while(!$rs->EOF) {
print_r($rs->fields("Nome"));
$rs->MoveNext();
}
 
	echo "Caso permiterissemos SQL injection, obteriamos este resultado:";
 
	$rs = $BD->Execute("Select * from alunos where codaluno=?", $codaluno);
 
	while(!$rs->EOF) {
print_r($rs->fields("Nome"));
$rs->MoveNext();
}
}

ADOdb: resultado do teste de SQL injection

Bibliografia

  1. http://phplens.com/adodb/
  2. http://adodb.sourceforge.org

Conclusão

O objectivo deste artigo é dar a conhecer esta classe ainda pouco explorada. Devido à sua facilidade de uso e segurança torna-se indispensável conhecê-la minimamente. No entanto, não foram abordados todos os aspectos neste artigo, por isso, recomenda-se que o leitor leia a documentação da classe nos links acima referidos.