Dienstag, 7. Februar 2012

entwickler.com Magazine Konferenzen Entwickler Akademie Entwickler-Forum Jobbörse Bücher
Software & Support Media





April 2006
aus PHP Magazin Ausgabe: 3.2004
Wunderbar wechselbar
Datenbankabstraktion mit ADOdb
von Daniel Koch

Die Entwicklung im Hinblick auf Datenbanken und Websprachen schreitet rasend schnell voran. Auch für Sie als Entwickler bedeutet dies ein stetiges in Bewegung bleiben müssen. Häufig wird bei entsprechenden Neuerungen aber leider immer wieder das Rad neu Erfunden. So wird Code oft plattformabhängig entwickelt bzw. an eine bestimmte Datenbank oder Programmiersprache gebunden. All diese Punkte machen die Entwicklung von Anwendungen, die das Prädikat dynamisch im wahrsten Sinne des Wortes verdienen, schwierig. Auf den folgenden Seiten wird gezeigt, wie Sie Ihren Code wirklich dynamisch, nämlich mittels Datenbankabstraktion, entwickeln können.


Einführung
Die Entwicklung von Datenbankanwendungen ist zeit- und kostenintensiv. Gehen wir davon aus, dass Sie den Erfolg Ihres Internetauftritts unterschätzt haben und bereits nach kurzer Zeit nicht mehr mit einer MySQL-Datenbank auskommen. Stattdessen fassen Sie nun beispielsweise die Anschaffung einer Oracle-Datenbank ins Auge. Was an sich kein gravierendes Problem darstellt, entwickelt sich rasch zu einem, wenn Sie an die Umstellung Ihrer PHP-Skripte denken. Schließlich müssen diese nun an die Oracle-Datenbank angepasst werden. Warum diese Skript-Umstellung vorgenommen werden muss, liegt auf der Hand. Zwar orientieren sich Datenbanken an einem gewissen SQL-Standard, dennoch hat jede Datenbank so ihre eigenen Erweiterungen und Eigenheiten. So versuchen beispielsweise MySQL und Oracle den SQL-92-Standard einzuhalten. Wobei Oracle diesen Standard zwar einhält, aber eben auch noch viel mehr leisten kann. Und eben dieses Mehr an Funktionalität macht die Umstellung von einer Datenbank auf die andere so schwierig. Dieses Problem zu umgehen, hilft die Datenbankabstraktion, die in diesem Artikel anhand von ADOdb vorgestellt wird. Mögliche Einwände gegen ADOdb, wie beispielsweise die PEAR-Alternative PEAR:DB oder die PHPLib, werden hier bewusst außen vor gelassen. All denjenigen, die dennoch einen Vergleich zwischen ADOdb und PEAR::DB anstrengen wollen, sei die Seite [1] empfohlen. Hier werden die wichtigsten Features beider Systeme miteinander verglichen.


<table width="400" border="0" cellpadding="0" cellspacing="1" bgcolor="#000000">
<tr>
<td>
<table width="400" border="0" cellpadding="4" cellspacing="0" bgcolor="#FFFFFF">
<tr>
<td>Die folgenden Datenbanken werden von ADOdb unterstützt:

MySQL, Oracle, Microsoft SQL Server, Sybase, Informix, PostgreSQL, FrontBase, SQLite, Interbase, Foxpro, Access, ADO, DB2, SAP DB, ODBC</td>
</tr>
</table>
</td>
</tr>
</table>

Was ist eine Datenbankabstraktion?
Wenn Sie mit Datenbanken arbeiten, haben Sie sicherlich bereits gemerkt, dass jede ihre Eigenheiten hat. (so unterscheiden sich beispielsweise häufig die einsetzbaren Datentypen). Wollen Sie also Ihren PHP-Code von einer MySQL- auf eine Oracle-Datenbank umstellen, müssen Sie all diese Unterschiede kennen und beseitigen. Und genau an diesem Punkt greift die Datenbankabstraktion. Denn hierdurch ist es möglich, einen einmal erstellten Programmcode auch nach einem Datenbankwechsel (fast) unverändert zu übernehmen. Datenbankabstraktionen erlauben einen einfacheren Zugriff auf Datenbanken durch
  • eine automatische Verbindungsaufnahme zur Datenbank
  • die Speicherung der Zugriffsparameter in einer Include-Datei
  • das Verbergen von datenbankspezifischen Eigenschaften.

Microsoft-Entwickler kennen diese Möglichkeit bereits. Schließlich setzt Microsoft seit geraumer Zeit auf ADO (ActiveX Data Objects). Daher wird vor allem für ASP-Erfahrene ein möglicher Umstieg von ASP- auf PHP-Anwendungen via ADOdb sehr einfach fallen. Denn nicht nur, dass das Grundprinzip identisch ist, auch die Syntax ist vergleichbar. Was wenig verwunderlich ist, schließlich setzt ADOdb auf ADO auf.


Um die folgenden Beispiele auch praktisch nachvollziehen zu können, sollten Sie sich ADOdb unter [2] herunterladen. Beachten Sie, dass Sie mindestens PHP 4.0.4 benötigen. Entpacken Sie das Archiv in ein Verzeichnis des Webservers.

Èin einführendes Beispiel
Die im Zusammenhang mit PHP am häufigsten eingesetzte Datenbank ist MySQL. Demzufolge kann davon ausgegangen werden, dass der folgende Code allgemein verstanden wird:

$db = mysql_connect("localhost", "user", "password");
mysql_select_db("mydb",$db);
$ergebnis = mysql_query("SELECT * FROM kontakt",$db);


Die Syntax dürfte vertraut sein. Es wird lediglich eine Verbindung zur MySQL-Datenbank hergestellt und die Datensätze der Tabelle kontakt werden selektiert. Schauen wir uns nun den gleichen Part, wie er über ADOdb realisiert wird, an:

include("adodb.inc.php");
$db = &ADONewConnection('mysql');
$db->Connect("localhost", "usert", "password", "mydb");
$ergebnis = $db->Execute("SELECT * FROM kontakt")


Bereits bei dem ersten Blick auf den Quellcode fällt auf, dass der ADOdb-Teil etwas aufwändiger ist. Dies ist allerdings kein Hinweis darauf, dass ADOdb kompliziert ist, sondern zeigt, dass ADOdb bei der Verbindungsaufnahme höhere Anforderungen erfüllen muss. Um dieser Komplexität Rechnung zu tragen, wird ein objektorientierter Ansatz verwendet. Wobei Sie von dieser Objektorientierung zunächst einmal nicht viel bemerken werden, liegt diese doch ausschließlich in den Include-Dateien. Über adodb.inc.php wird die Include-Datei eingebunden. Hierin sind alle datenbankrelevanten Informationen enthalten. Mittels der Funktion ADONewConnection() werden die entsprechenden Funktionen für die als Parameter angegebene Datenbank eingebunden. In unserem Beispiel werden folglich also die MySQL-Funktionen geladen. Soll stattdessen der Zugriff auf eine Oracle-Datenbank erfolgen, müsste der Funktionsaufruf folgendermaßen aussehen: ADONewConnection('oracle')


Mittels Connect() wird die Verbindung zur Datenbank hergestellt. In dem Verzeichnis drivers finden Sie die entsprechenden Include-Dateien für alle von ADOdb unterstützten Datenbanken. Wollen Sie sich mit den Codebesonderheiten der verschiedenen Datenbanken vertraut machen, hilft ein Blick hierhinein.
Nach der Verbindungsaufnahme können jetzt die Datensätze ausgelesen werden. Um an die Datensätze zu gelangen, wird hier auf eine while()-Schleife zurückgegriffen:

while (!$ergebnis->EOF) {
for ($i=0, $max=$ergebnis->FieldCount(); $i < $max; $i++)
print $ergebnis->fields[$i].' ';
$ergebnis->MoveNext();
print "<br>n";
}


Das Auslesen der Datensätze wird hier wie das Auslesen einer Datei realisiert. Für jede Zeile wird mittels EOF (End-of-File) überprüft, ob das Ende der Datei erreicht ist. Solange die letzte Zeile noch nicht erreicht ist, greift die innere for()-Schleife. Nach jedem Schleifendurchlauf wird mittels MoveNext() der nächste Datensatz ausgewählt. Noch ein Wort zu dem Array fields[]: Das Array fields[] wird von der PHP-Datenbankerweiterung bereitgestellt. Dabei ist allerdings zu berücksichtigen, dass nicht alle Datenbankerweiterungen das Array nach Feldnamen indizieren. Um eine Indizierung nach Feldnamen zu erreichen, müssen Sie die globale Variable &ADODB_FETCH_MODE verwenden:

$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
$rs1 = $db->Execute('select * from table');
$ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
$rs2 = $db->Execute('select * from table');
print_r($rs1->fields); # shows array([0]=>'v0',[1] =>'v1')
print_r($rs2->fields); # shows array(['col1']=>'v0',['col2'] =>'v1')


Das Beispiel macht deutlich, dass die beiden Datensätze rs1 und rs2 unterschiedliche Modi zum Abholen verwenden. Somit ist es möglich, dass auf die Bedürfnisse der jeweiligen Datenbank entsprechend reagiert werden kann.

ADOdb und Microsofts ADO
Gerade für Microsoft-Programmierer stellt ADOdb einen guten Einstieg in die PHP-Datenbankwelt dar. Schließlich ist ADOdb eng mit Microsofts ADO verwandt. Bis auf einige wenige Unterschiede ist die Syntax identisch. Sind Sie also beispielsweise ein Verfechter von ASP, dürften Sie sich bereits nach kurzer Zeit in ADOdb zu Hause fühlen. Die folgende Auflistung zeigt die wichtigsten Unterschiede zwischen ADOdb und ADO:
  • ADO-Eigenschaften wurden und werden in ADOdb als Funktionen implementiert.
  • Recordsets werden nur dann unterstützt, wenn sie von einem Connection-Objekt erstellt wurden.
  • ADORecordSet->Move() verwendet nicht die relative, sondern die absolute Positionierung. Bookmarks werden ebenfalls nicht unterstützt.
  • ADO Parameter-Objekte werden nicht unterstützt. Stattdessen stellt ADOdb die ADOConnection::Parameter()-Funktion zur Verfügung.

Wie Sie sehen gibt es zwar Unterschiede, diese fallen aber im großen und ganzen so marginal aus, dass sie nicht wirklich einen Hinderungsgrund für eine erste Kontaktaufnahme mit ADOdb darstellen.

Probleme beim Umgang mit unterschiedlichen Datenbanken
Wenn Sie bereits mit mehreren unterschiedlichen Datenbanken gearbeitet haben, werden Sie wissen, dass jede Datenbank in gewissen Bereichen einer anderen Syntax folgt. So kommt es vor allem bei Datumsangaben und Sonderzeichen häufig zur Problemen. Nehmen wir an, dass die folgenden Daten in eine Datenbank eingefügt werden sollen:

ID = 3
Datum=mktime(0,0,0,2,19,2004)
Kommentar= Don't Worry, Be Happy


Nach dem Wechsel der Datenbank funktioniert INSERT wahrscheinlich nicht mehr. Dies hat in diesem Beispiel zwei Gründe: Zunächst einmal behandeln fast alle Datenbanken Datumsangaben unterschiedlich. Während in MySQL-Datenbanken das Format für Datumsangaben YYYY-MM-DD ist, folgen Oracle-Datenbanken der Syntax DD-MON-YY. Das nächste Problem der Beispielsyntax stellt Dont't dar. Kann dies in MySQL-Datenbanken in dieser Form übernommen werden, muss beispielsweise für Access Dont''t verwendet werden. Aber sowohl für das Datums- wie auch für das Sonderzeichen-Problem stellt ADOdb geeignete Funktionen bereit, durch die die Inkompatibilitäten zwischen den Datenbanken aufgehoben werden können. Die folgende Syntax löst durch die Verwendung der beiden ADOdb-Funktionen DBDate() und qstr() das Datums- und das Sonderzeichen-Dilemma:

$sql = "INSERT INTO table (id, datum, kommentar) values ("
. $ID . ','
. $db->DBDate($Datum) .','
. $db->qstr($Kommentar).")";
$db->Execute($sql);


Ausführliche Informationen zu den beiden Funktionen erhalten Sie unter [3]. An dieser Stelle nur so viel: Durch die gezeigte Syntax können auch die als normalerweise schwierig geltenden Datums- und Sonderzeichen-INSERTs ohne Probleme bei einem Datenbankwechsel übernommen werden. ADOdb hält aber noch eine Vielzahl anderer Funktionen bereit, durch die die Datenbankunterschiede ausgeglichen werden können. So existiert beispielsweise die MetaType()-Funktion, durch die Feldtypen standardisiert werden können.


Um wirklich effektiv mit ADOdb arbeiten zu können, müssen Sie aber auch entsprechendes SQL verwenden. Denn zwar arbeiten Datenbanken auf SQL-Basis, die SQL-Dialekte unterscheiden sich allerdings. Das gilt zumindest für speziellere Anwendungen. Denn die grundlegenden SQL-Elemente beherrschen die meisten Datenbanken. Gehen wir aber beispielsweise davon aus, dass aus einer Tabelle die ersten zehn Datensätze ausgelesen werden sollen:

select * from table limit 10 // MySQL
select * from (select * from table) where rownum <= 10 // Oracle
select * from table fetch first 10 rows only // DB2
select first 10 * from table // Informix
select top 10 * from table // Access


Wie Sie sehen, sind die Syntaxunterschiede doch recht groß. Wollen Sie also eine solche Abfrage bei einem Datenbankwechsel übernehmen, müssten Sie die SELECT-Anweisung dementsprechend anpassen. Nun ist aber klar, dass es in Ihrem PHP-Programm nicht nur eine Abfrage gibt. Folglich müssten Sie also das gesamte Programm durchsehen und die SQL-Statements modifizieren. Und genau an dieser Stelle wäre dann die Frage berechtigt, was denn überhaupt der Sinn einer Datenbankabstraktion mit ADOdb ist. Zum Glück hält ADOdb aber eine Vielzahl an Funktionen bereit, durch die Syntaxunterschiede zwischen den Datenbanken ausgeglichen werden können. So löst beispielsweise die Funktion SelectLimit() unser zuvor beschriebenes SELECT-Problem. Ein Beispiel:

$connection->SelectLimit('select * from table', 10);


Wenn Sie auf SelectLimit() zurückgreifen, funktioniert Ihre Syntax auch nach einem Datenbankwechsel. Wie Sie Ihre Anwendung so programmieren, dass diese auch auf andere Datenbanken übertragen werden kann, erfahren Sie in dem erstklassigen Tutorial Tips on Writing Portable SQL Code. Das Tutorial steht unter [4] zur Verfügung.

Erweiterte Funktionen
ADOdb bietet einige Möglichkeiten, mit denen Anwendungen ganz einfach umgesetzt werden können. An dieser Stelle werden einige hiervon vorgestellt. Vergleichbar ist das Grundprinzip dieser Funktionen etwa mit dem von PEAR. Auch in ADOdb können Sie mittels einer sehr einfachen Syntax aufwändige Applikationen erstellen. So ist es beispielsweise möglich, <SELECT>-Felder zu generieren oder Vor- und Zurück-Schaltflächen für die einzelnen Datensätze einer Datenbankabfrage ausgeben zu lassen. Einen ausführlichen Überblick über die erweiterten Funktionen erhalten Sie unter [5]. Sämtliche Funktionen sind einfach zu handhaben und sind zumeist gut dokumentiert.

Menüs generieren
Anhand eines einfachen Beispiels soll gezeigt werden, wie Sie die Datensätze einer MySQL-Datenbank innerhalb eines <SELECT>-Feldes anzeigen können. Wollten Sie eine solche Anwendung mittels normalem PHP realisieren, müssten Sie die Datensätze zunächst auslesen, mit einer Schleife durchlaufen und anschließend ausgeben. Zwar ist auch dieses Vorgehen nicht sonderlich aufwändig, dennoch bietet ADOdb hier eine elegantere Variante:

<?
include('adodb.inc.php');
$conn = &ADONewConnection('mysql');
$conn->PConnect('localhost','user','','password'
$sql = 'select Name, Vorname from Kunden';
$rs = $conn->Execute($sql);
print $rs->GetMenu('KundenMenue','Tony Hawks');
?>


Um ein Menü zu generieren, wird die Funktion GetMenu() verwendet. Weiterführende Informationen zu dieser Funktion finden Sie unter [6]. In dem hieraus generierten Menü KundenMenue wird der Eintrag Tony Hawks als Default-Wert angezeigt. Um die Funktionsweise der GetMenu()-Funktion nachvollziehen zu können, reicht bereits ein Blick in den generierten HTML-Code.

Navigation leicht gemacht
Es kommt immer wieder einmal vor, dass die aus einer Datenbank ausgelesenen Datensätze mit einer Blätterfunktionalität versehen werden sollen. Bei einer Blätterfunktion kann mittels Vor- und Zurück-Schaltflächen zwischen verschiedenen Datensätzen gewechselt werden. Eine solche Funktion über normales PHP umzusetzen, ist sehr aufwändig, zumindest im Vergleich zu der ADOdb-Lösung. Die folgende Syntax zeigt, wie einfach sich eine Blätterfunktion über ADOdb realisieren lässt:

include_once('../adodb.inc.php');
include_once('../adodb-pager.inc.php');
session_start();
$db = NewADOConnection('mysql');
$db->Connect('localhost','user','','password');
$sql = "select * from Kunden";
$pager = new ADODB_Pager($db,$sql);
$pager->Render($rows_per_page=4);


Hierdurch werden pro Seite vier Datensätze angezeigt. Auf jeder Seite befinden sich Hyperlinks, durch die zu den jeweils vorherigen bzw. nächsten vier Datensätzen gesprungen werden kann. Das Herzstück dieser Syntax ist die über include_once() eingebundene Datei adodb-pager.inc.php. Über diese Datei kann das Aussehen der Blätterfunktion vollständig gesteuert werden.

Daten exportieren
Mit ADOdb können Sie Daten aus einer Datenbank in das CSV-Format oder als Tab-getrennte Werte exportieren. Der Vorteil hiervon liegt auf der Hand. So können die einmal exportierten Daten beispielsweise in einer Datei gespeichert und anschließend in ein anderes Programm (beispielsweise Excel) importiert werden. ADOdb hält für den Export verschiedene Möglichkeiten bereit. Auch für diese Funktionen muss wieder eine entsprechende Include-Datei, nämlich toexport.inc.php, eingebunden werden. Für den Export existieren mehrere Funktionen, die anhand einfacher Beispiele vorgestellt werden sollen:

include_once('adodb/toexport.inc.php');
include_once('adodb/adodb.inc.php');
$db = &NewADOConnection('mysql');
$db->Connect($server, $userid, $password, $database);
$rs = $db->Execute('select vname as "Vorname", nname as "Nachname" from Kontakt');

print "<pre>";
print rs2csv($rs);
$rs->MoveFirst();
rs2tab($rs,false);
print "</pre>";

$rs->MoveFirst();
$fp = fopen($path, "w");
if ($fp) {
rs2csvfile($rs, $fp);
fclose($fp);}


Zunächst müssen die zu exportierenden Daten ausgewählt werden. Um die selektierten Daten in das CSV-Format zu exportieren, wird die Funktion rs2csv() verwendet. Als Parameter werden die entsprechenden Datensätze erwartet. Die Funktion rs2tab() ist für den Export von Tab-getrennten Werten zuständig. Da Daten im Regelfall nur dann exportiert werden, wenn Sie in anderen Anwendungen weiterverarbeitet werden sollen, wird häufig eine Funktion benötigt, durch die die exportierten Daten in eine Datei geschrieben werden können. Durch die Funktion rs2csvfile() ist es ganz einfach möglich, die ausgelesenen Datensätze im CSV-Format in eine Datei zu exportieren.

Sessionverwaltung
ADOdb unterstützt auch die Verwendung von Session-Variablen. Auch wenn normalerweise für das Session-Handling Dateien verwendet werden, können Sie auch auf Datenbanken zum Speichern der benötigten Informationen zurückgreifen. Dabei werden die Session-Variablen als Recordset innerhalb einer Datenbanktabelle gespeichert. Um Sessions verwenden zu können, legen Sie sich innerhalb einer Datenbank die Tabelle sessions an. Diese sollte die folgende Struktur besitzen:

create table sessions (
SESSKEY char(32) not null,
EXPIRY int(11) unsigned not null,
DATA text not null,
primary key (SESSKEY),
key (EXPIRY)
)


Im ADOdb-Hauptverzeichnis finden Sie die Datei adodb-session.php. In dieser müssen die folgenden Variablen entsprechend angepasst werden:

$ADODB_SESSION_DRIVER='database driver, eg. mysql or ibase';
$ADODB_SESSION_CONNECT='server to connect to';
$ADODB_SESSION_USER ='user';
$ADODB_SESSION_PWD ='password';
$ADODB_SESSION_DB ='database';


Wenn Sie diese Informationen eingegeben haben, können Sie bereits eine ADOdb-basierte Sessionverwaltung aufbauen. Das folgende Listing zeigt eine einfache Anwendung von ADOdb-Sessions:

GLOBAL $HTTP_SESSION_VARS;
include('adodb.inc.php');
include('adodb-session.php');
session_start();
session_register('AVAR');
$HTTP_SESSION_VARS['AVAR'] += 1;
print "<p>variable={$HTTP_SESSION_VARS['AVAR']}</p>";


Nach jeder Aktualisierung wird hier der Wert der Variable AVAR jeweils erhöht. Sie sehen also, auch die Sessionverwaltung lässt sich mittels ADOdb recht unkompliziert realisieren. Sollten Sie noch nicht über ausreichende Kenntnisse zur Sessionverwaltung verfügen, finden Sie unter [7] einen guten Artikel zu diesem Thema. Zwar beziehen sich die dort bereitgestellten Informationen auf MySQL-Datenbanken, das Grundprinzip ist aber dennoch identisch. Weiterführende Informationen über die Sessionverwaltung via ADOdb finden sie unter [8].

ADOdb und PHP 5
Mit der neuen ADOdb-Version wurde auch auf PHP 5 reagiert. Wobei es hier sicherlich noch einige Weiterentwicklungen geben wird. An dieser Stelle sollen kurz die wichtigsten Neuerungen, nämlich der Foreach-Iterator und das Exception-Handling, vorgestellt werden:

$ADODB_FETCH_MODE = ADODB_FETCH_NUM;
$rs = $db->Execute($sql);
foreach($rs as $k => $row) {
echo "r1=".$row[0]." r2=".$row[1]."<br>";
}


Mittels des foreach-Iterators kann ein Recordset ganz einfach durchlaufen werden. Eine weitere Neuerung bezüglich PHP 5 ist die Fehlerbehandlung. Auch hierzu wieder ein Beispiel:

include("../adodb-exceptions.inc.php");
include("../adodb.inc.php");
try {
$db = NewADOConnection("oci8");
$db->Connect('','scott','bad-password');
} catch (exception $e) {
var_dump($e);
}


Um die Möglichkeiten der Fehlerbehandlung nutzen zu können, müssen Sie die Datei adodb-exceptions.inc.php einbinden. Hierüber können Sie dann Fehler, die während der Verarbeitung Ihres PHP-Programms auftreten, abfangen.

Fazit
ADOdb ist eine Datenbankabstraktion, die gegenüber anderen Lösungen wie beispielsweise PEAR::DB einige Vorteile bietet. Dabei richtet sich ADOdb aber nicht nur an PHP-, sondern auch an eingefleischte Windows-Programmierer, die es bislang gewohnt waren, via ASP auf Datenbanken zuzugreifen. Denen dürfte der Umstieg bzw. Einstieg in PHP dank ADOdb sicherlich um einiges einfacher fallen. Aber auch PHP-Programmierern steht mit ADOdb eine gute Alternative zur herkömmlichen Datenbankprogrammierung zur Verfügung. Schließlich lassen sich, vorausgesetzt die ADOdb-Anwendung wird mit portablem SQL entwickelt, die Datenbank-Skripte auch noch nach einem Datenbankwechsel verwenden. Datenbankabstraktionen wie ADOdb können folglich also bei einer effektiveren und kostengünstigeren Entwicklung behilflich sein.

Daniel Koch ist Gründer der Agentur Medienwerke (www.medienwerke.de/) aus Berlin. Er hat mehrere Bücher rund um die Themen Programmierung und Software veröffentlicht. Sie erreichen ihn unter dk@medienwerke.de.

Links und Referenzen


    Hat Ihnen dieser Artikel gefallen? Dann abonnieren Sie das PHP Magazin direkt über unser

zur vorherigen Seite
zurück
an den Anfang der Seite
nach oben
Diesen Artikel drucken
drucken
Diesen Artikel weiterempfehlen
empfehlen

Software & Support Media GmbH